diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 11402129..71cd7eda 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1,2 @@ +github: mailcow custom: ["https://www.servercow.de/mailcow?lang=en#sal"] diff --git a/.github/ISSUE_TEMPLATE/pr_to_nighty_template.yml b/.github/ISSUE_TEMPLATE/pr_to_nighty_template.yml index 8854ac9d..d9f87858 100644 --- a/.github/ISSUE_TEMPLATE/pr_to_nighty_template.yml +++ b/.github/ISSUE_TEMPLATE/pr_to_nighty_template.yml @@ -1,13 +1,3 @@ -## :memo: Brief description - - - - -## :computer: Commits - - - - ## :file_folder: Modified files - + \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..68ead39f --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,38 @@ + + +## Contribution Guidelines + +* [ ] I've read the [contribution guidelines](https://github.com/mailcow/mailcow-dockerized/blob/master/CONTRIBUTING.md) and wholeheartedly agree them + + + +## What does this PR include? + +### Short Description + + + +### Affected Containers + + + + + +## Did you run tests? + +### What did you tested? + + + +### What were the final results? (Awaited, got) + + \ No newline at end of file diff --git a/.github/workflows/check_prs_if_on_staging.yml b/.github/workflows/check_prs_if_on_staging.yml index 060481d6..3e779a44 100644 --- a/.github/workflows/check_prs_if_on_staging.yml +++ b/.github/workflows/check_prs_if_on_staging.yml @@ -10,7 +10,7 @@ jobs: if: github.event.pull_request.base.ref != 'staging' #check if the target branch is not staging steps: - name: Send message - uses: thollander/actions-comment-pull-request@v2.4.3 + uses: thollander/actions-comment-pull-request@v2.5.0 with: GITHUB_TOKEN: ${{ secrets.CHECKIFPRISSTAGING_ACTION_PAT }} message: | diff --git a/.github/workflows/rebuild_backup_image.yml b/.github/workflows/rebuild_backup_image.yml index 649d76a1..bf5caddf 100644 --- a/.github/workflows/rebuild_backup_image.yml +++ b/.github/workflows/rebuild_backup_image.yml @@ -26,7 +26,7 @@ jobs: password: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . platforms: linux/amd64,linux/arm64 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d7a3d86d..fae8f1d5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,33 +1,52 @@ -# Contribution Guidelines (Last modified on 18th December 2023) +# Contribution Guidelines +**_Last modified on 15th August 2024_** First of all, thank you for wanting to provide a bugfix or a new feature for the mailcow community, it's because of your help that the project can continue to grow! -## Pull Requests (Last modified on 18th December 2023) +As we want to keep mailcow's development structured we setup these Guidelines which helps you to create your issue/pull request accordingly. + +**PLEASE NOTE, THAT WE MIGHT CLOSE ISSUES/PULL REQUESTS IF THEY DON'T FULLFIL OUR WRITTEN GUIDELINES WRITTEN INSIDE THIS DOCUMENT**. So please check this guidelines before you propose a Issue/Pull Request. + +## Topics + +- [Pull Requests](#pull-requests) +- [Issue Reporting](#issue-reporting) + - [Guidelines](#issue-reporting-guidelines) + - [Issue Report Guide](#issue-report-guide) + +## Pull Requests +**_Last modified on 15th August 2024_** However, please note the following regarding pull requests: 1. **ALWAYS** create your PR using the staging branch of your locally cloned mailcow instance, as the pull request will end up in said staging branch of mailcow once approved. Ideally, you should simply create a new branch for your pull request that is named after the type of your PR (e.g. `feat/` for function updates or `fix/` for bug fixes) and the actual content (e.g. `sogo-6.0.0` for an update from SOGo to version 6 or `html-escape` for a fix that includes escaping HTML in mailcow). -2. Please **keep** this pull request branch **clean** and free of commits that have nothing to do with the changes you have made (e.g. commits from other users from other branches). *If you make changes to the `update.sh` script or other scripts that trigger a commit, there is usually a developer mode for clean working in this case. -3. **Test your changes before you commit them as a pull request.** If possible, write a small **test log** or demonstrate the functionality with a **screenshot or GIF**. *We will of course also test your pull request ourselves, but proof from you will save us the question of whether you have tested your own changes yourself.* -4. Please **ALWAYS** create the actual pull request against the staging branch and **NEVER** directly against the master branch. *If you forget to do this, our moobot will remind you to switch the branch to staging.* -5. Wait for a merge commit: It may happen that we do not accept your pull request immediately or sometimes not at all for various reasons. Please do not be disappointed if this is the case. We always endeavor to incorporate any meaningful changes from the community into the mailcow project. -6. If you are planning larger and therefore more complex pull requests, it would be advisable to first announce this in a separate issue and then start implementing it after the idea has been accepted in order to avoid unnecessary frustration and effort! +2. **ALWAYS** report/request issues/features in the english language, even though mailcow is a german based company. This is done to allow other GitHub users to reply to your issues/requests too which did not speak german or other languages besides english. +3. Please **keep** this pull request branch **clean** and free of commits that have nothing to do with the changes you have made (e.g. commits from other users from other branches). *If you make changes to the `update.sh` script or other scripts that trigger a commit, there is usually a developer mode for clean working in this case.* +4. **Test your changes before you commit them as a pull request.** If possible, write a small **test log** or demonstrate the functionality with a **screenshot or GIF**. *We will of course also test your pull request ourselves, but proof from you will save us the question of whether you have tested your own changes yourself.* +5. **Please use** the pull request template we provide once creating a pull request. *HINT: During editing you encounter comments which looks like: ``. These can be removed or kept, as they will not rendered later on GitHub! Please only create actual content without the said comments.* +6. Please **ALWAYS** create the actual pull request against the staging branch and **NEVER** directly against the master branch. *If you forget to do this, our moobot will remind you to switch the branch to staging.* +7. Wait for a merge commit: It may happen that we do not accept your pull request immediately or sometimes not at all for various reasons. Please do not be disappointed if this is the case. We always endeavor to incorporate any meaningful changes from the community into the mailcow project. +8. If you are planning larger and therefore more complex pull requests, it would be advisable to first announce this in a separate issue and then start implementing it after the idea has been accepted in order to avoid unnecessary frustration and effort! --- -## Issue Reporting (Last modified on 18th December 2023) +## Issue Reporting +**_Last modified on 15th August 2024_** If you plan to report a issue within mailcow please read and understand the following rules: +### Issue Reporting Guidelines + 1. **ONLY** use the issue tracker for bug reports or improvement requests and NOT for support questions. For support questions you can either contact the [mailcow community on Telegram](https://docs.mailcow.email/#community-support-and-chat) or the mailcow team directly in exchange for a [support fee](https://docs.mailcow.email/#commercial-support). 2. **ONLY** report an error if you have the **necessary know-how (at least the basics)** for the administration of an e-mail server and the usage of Docker. mailcow is a complex and fully-fledged e-mail server including groupware components on a Docker basement and it requires a bit of technical know-how for debugging and operating. -3. **ONLY** report bugs that are contained in the latest mailcow release series. *The definition of the latest release series includes the last major patch (e.g. 2023-12) and all minor patches (revisions) below it (e.g. 2023-12a, b, c etc.).* New issue reports published starting from January 1, 2024 must meet this criterion, as versions below the latest releases are no longer supported by us. -4. When reporting a problem, please be as detailed as possible and include even the smallest changes to your mailcow installation. Simply fill out the corresponding bug report form in detail and accurately to minimize possible questions. -5. **Before you open an issue/feature request**, please first check whether a similar request already exists in the mailcow tracker on GitHub. If so, please include yourself in this request. -6. When you create a issue/feature request: Please note that the creation does **not guarantee an instant implementation or fix by the mailcow team or the community**. -7. Please **ALWAYS** anonymize any sensitive information in your bug report or feature request before submitting it. +3. **ALWAYS** report/request issues/features in the english language, even though mailcow is a german based company. This is done to allow other GitHub users to reply to your issues/requests too which did not speak german or other languages besides english. +4. **ONLY** report bugs that are contained in the latest mailcow release series. *The definition of the latest release series includes the last major patch (e.g. 2023-12) and all minor patches (revisions) below it (e.g. 2023-12a, b, c etc.).* New issue reports published starting from January 1, 2024 must meet this criterion, as versions below the latest releases are no longer supported by us. +5. When reporting a problem, please be as detailed as possible and include even the smallest changes to your mailcow installation. Simply fill out the corresponding bug report form in detail and accurately to minimize possible questions. +6. **Before you open an issue/feature request**, please first check whether a similar request already exists in the mailcow tracker on GitHub. If so, please include yourself in this request. +7. When you create a issue/feature request: Please note that the creation does **not guarantee an instant implementation or fix by the mailcow team or the community**. +8. Please **ALWAYS** anonymize any sensitive information in your bug report or feature request before submitting it. -### Quick guide to reporting problems: +### Issue Report Guide 1. Read your logs; follow them to see what the reason for your problem is. 2. Follow the leads given to you in your logfiles and start investigating. 3. Restarting the troubled service or the whole stack to see if the problem persists. @@ -36,4 +55,4 @@ If you plan to report a issue within mailcow please read and understand the foll 6. [Create an issue](https://github.com/mailcow/mailcow-dockerized/issues/new/choose) over at our GitHub repository if you think your problem might be a bug or a missing feature you badly need. But please make sure, that you include **all the logs** and a full description to your problem. 7. Ask your questions in our community-driven [support channels](https://docs.mailcow.email/#community-support-and-chat). -## When creating an issue/feature request or a pull request, you will be asked to confirm these guidelines. \ No newline at end of file +## When creating an issue/feature request or a pull request, you will be asked to confirm these guidelines. diff --git a/data/Dockerfiles/acme/Dockerfile b/data/Dockerfiles/acme/Dockerfile index 254b5b33..8aa16ad5 100644 --- a/data/Dockerfiles/acme/Dockerfile +++ b/data/Dockerfiles/acme/Dockerfile @@ -1,8 +1,8 @@ -FROM alpine:3.18 +FROM alpine:3.20 + +LABEL maintainer = "The Infrastructure Company GmbH " -LABEL maintainer "The Infrastructure Company GmbH GmbH " -ARG PIP_BREAK_SYSTEM_PACKAGES=1 RUN apk upgrade --no-cache \ && apk add --update --no-cache \ bash \ @@ -15,9 +15,7 @@ RUN apk upgrade --no-cache \ tini \ tzdata \ python3 \ - py3-pip \ - && pip3 install --upgrade pip \ - && pip3 install acme-tiny + acme-tiny --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community/ COPY acme.sh /srv/acme.sh COPY functions.sh /srv/functions.sh diff --git a/data/Dockerfiles/acme/acme.sh b/data/Dockerfiles/acme/acme.sh index 1cd456a4..3c7658d8 100755 --- a/data/Dockerfiles/acme/acme.sh +++ b/data/Dockerfiles/acme/acme.sh @@ -33,6 +33,10 @@ if [[ "${ONLY_MAILCOW_HOSTNAME}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then ONLY_MAILCOW_HOSTNAME=y fi +if [[ "${AUTODISCOVER_SAN}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then + AUTODISCOVER_SAN=y +fi + # Request individual certificate for every domain if [[ "${ENABLE_SSL_SNI}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then ENABLE_SSL_SNI=y @@ -113,13 +117,13 @@ fi chmod 600 ${ACME_BASE}/key.pem log_f "Waiting for database..." -while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent > /dev/null; do +while ! /usr/bin/mariadb-admin status --ssl=false --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent > /dev/null; do sleep 2 done log_f "Database OK" log_f "Waiting for Nginx..." -until $(curl --output /dev/null --silent --head --fail http://nginx:8081); do +until $(curl --output /dev/null --silent --head --fail http://nginx.${COMPOSE_PROJECT_NAME}_mailcow-network:8081); do sleep 2 done log_f "Nginx OK" @@ -133,7 +137,7 @@ log_f "Resolver OK" # Waiting for domain table log_f "Waiting for domain table..." while [[ -z ${DOMAIN_TABLE} ]]; do - curl --silent http://nginx/ >/dev/null 2>&1 + curl --silent http://nginx.${COMPOSE_PROJECT_NAME}_mailcow-network/ >/dev/null 2>&1 DOMAIN_TABLE=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'domain'" -Bs) [[ -z ${DOMAIN_TABLE} ]] && sleep 10 done @@ -211,7 +215,11 @@ while true; do ADDITIONAL_SAN_ARR+=($i) fi done + + if [[ ${AUTODISCOVER_SAN} == "y" ]]; then + # Fetch certs for autoconfig and autodiscover subdomains ADDITIONAL_WC_ARR+=('autodiscover' 'autoconfig') + fi if [[ ${SKIP_IP_CHECK} != "y" ]]; then # Start IP detection diff --git a/data/Dockerfiles/acme/reload-configurations.sh b/data/Dockerfiles/acme/reload-configurations.sh index d5461a4d..8d194b68 100644 --- a/data/Dockerfiles/acme/reload-configurations.sh +++ b/data/Dockerfiles/acme/reload-configurations.sh @@ -2,32 +2,32 @@ # Reading container IDs # Wrapping as array to ensure trimmed content when calling $NGINX etc. -NGINX=($(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"nginx-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" | tr "\n" " ")) -DOVECOT=($(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"dovecot-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" | tr "\n" " ")) -POSTFIX=($(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"postfix-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" | tr "\n" " ")) +NGINX=($(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"nginx-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" | tr "\n" " ")) +DOVECOT=($(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"dovecot-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" | tr "\n" " ")) +POSTFIX=($(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"postfix-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" | tr "\n" " ")) reload_nginx(){ echo "Reloading Nginx..." - NGINX_RELOAD_RET=$(curl -X POST --insecure https://dockerapi/containers/${NGINX}/exec -d '{"cmd":"reload", "task":"nginx"}' --silent -H 'Content-type: application/json' | jq -r .type) + NGINX_RELOAD_RET=$(curl -X POST --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${NGINX}/exec -d '{"cmd":"reload", "task":"nginx"}' --silent -H 'Content-type: application/json' | jq -r .type) [[ ${NGINX_RELOAD_RET} != 'success' ]] && { echo "Could not reload Nginx, restarting container..."; restart_container ${NGINX} ; } } reload_dovecot(){ echo "Reloading Dovecot..." - DOVECOT_RELOAD_RET=$(curl -X POST --insecure https://dockerapi/containers/${DOVECOT}/exec -d '{"cmd":"reload", "task":"dovecot"}' --silent -H 'Content-type: application/json' | jq -r .type) + DOVECOT_RELOAD_RET=$(curl -X POST --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${DOVECOT}/exec -d '{"cmd":"reload", "task":"dovecot"}' --silent -H 'Content-type: application/json' | jq -r .type) [[ ${DOVECOT_RELOAD_RET} != 'success' ]] && { echo "Could not reload Dovecot, restarting container..."; restart_container ${DOVECOT} ; } } reload_postfix(){ echo "Reloading Postfix..." - POSTFIX_RELOAD_RET=$(curl -X POST --insecure https://dockerapi/containers/${POSTFIX}/exec -d '{"cmd":"reload", "task":"postfix"}' --silent -H 'Content-type: application/json' | jq -r .type) + POSTFIX_RELOAD_RET=$(curl -X POST --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${POSTFIX}/exec -d '{"cmd":"reload", "task":"postfix"}' --silent -H 'Content-type: application/json' | jq -r .type) [[ ${POSTFIX_RELOAD_RET} != 'success' ]] && { echo "Could not reload Postfix, restarting container..."; restart_container ${POSTFIX} ; } } restart_container(){ for container in $*; do echo "Restarting ${container}..." - C_REST_OUT=$(curl -X POST --insecure https://dockerapi/containers/${container}/restart --silent | jq -r '.msg') + C_REST_OUT=$(curl -X POST --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${container}/restart --silent | jq -r '.msg') echo "${C_REST_OUT}" done } diff --git a/data/Dockerfiles/backup/Dockerfile b/data/Dockerfiles/backup/Dockerfile index f9d849b1..61c8bbe5 100644 --- a/data/Dockerfiles/backup/Dockerfile +++ b/data/Dockerfiles/backup/Dockerfile @@ -1,3 +1,3 @@ -FROM debian:bullseye-slim +FROM debian:bookworm-slim RUN apt update && apt install pigz \ No newline at end of file diff --git a/data/Dockerfiles/clamd/Dockerfile b/data/Dockerfiles/clamd/Dockerfile index 8e107516..1850d4be 100644 --- a/data/Dockerfiles/clamd/Dockerfile +++ b/data/Dockerfiles/clamd/Dockerfile @@ -1,6 +1,6 @@ -FROM alpine:3.19 +FROM alpine:3.20 -LABEL maintainer "The Infrastructure Company GmbH GmbH " +LABEL maintainer = "The Infrastructure Company GmbH " RUN apk upgrade --no-cache \ && apk add --update --no-cache \ diff --git a/data/Dockerfiles/dockerapi/Dockerfile b/data/Dockerfiles/dockerapi/Dockerfile index 3dd1d232..bbd4542e 100644 --- a/data/Dockerfiles/dockerapi/Dockerfile +++ b/data/Dockerfiles/dockerapi/Dockerfile @@ -1,6 +1,6 @@ -FROM alpine:3.19 +FROM alpine:3.20 -LABEL maintainer "The Infrastructure Company GmbH GmbH " +LABEL maintainer = "The Infrastructure Company GmbH " ARG PIP_BREAK_SYSTEM_PACKAGES=1 WORKDIR /app @@ -24,4 +24,4 @@ COPY main.py /app/main.py COPY modules/ /app/modules/ ENTRYPOINT ["/bin/sh", "/app/docker-entrypoint.sh"] -CMD exec python main.py \ No newline at end of file +CMD ["python", "main.py"] \ No newline at end of file diff --git a/data/Dockerfiles/dockerapi/modules/DockerApi.py b/data/Dockerfiles/dockerapi/modules/DockerApi.py index ea1c104e..56019909 100644 --- a/data/Dockerfiles/dockerapi/modules/DockerApi.py +++ b/data/Dockerfiles/dockerapi/modules/DockerApi.py @@ -358,8 +358,8 @@ class DockerApi: for line in cmd_response.split("\n"): if '$2$' in line: hash = line.strip() - hash_out = re.search('\$2\$.+$', hash).group(0) - rspamd_passphrase_hash = re.sub('[^0-9a-zA-Z\$]+', '', hash_out.rstrip()) + hash_out = re.search(r'\$2\$.+$', hash).group(0) + rspamd_passphrase_hash = re.sub(r'[^0-9a-zA-Z\$]+', '', hash_out.rstrip()) rspamd_password_filename = "/etc/rspamd/override.d/worker-controller-password.inc" cmd = '''/bin/echo 'enable_password = "%s";' > %s && cat %s''' % (rspamd_passphrase_hash, rspamd_password_filename, rspamd_password_filename) cmd_response = self.exec_cmd_container(container, cmd, user="_rspamd") diff --git a/data/Dockerfiles/dovecot/Dockerfile b/data/Dockerfiles/dovecot/Dockerfile index 9433dd2e..4b004cdf 100644 --- a/data/Dockerfiles/dovecot/Dockerfile +++ b/data/Dockerfiles/dovecot/Dockerfile @@ -1,11 +1,12 @@ -FROM alpine:3.19 -LABEL maintainer "The Infrastructure Company GmbH GmbH " +FROM alpine:3.20 + +LABEL maintainer="The Infrastructure Company GmbH " # renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?.*)$ ARG GOSU_VERSION=1.16 -ENV LANG C.UTF-8 -ENV LC_ALL C.UTF-8 +ENV LANG=C.UTF-8 +ENV LC_ALL=C.UTF-8 # Add groups and users before installing Dovecot to not break compatibility RUN addgroup -g 5000 vmail \ @@ -24,6 +25,7 @@ RUN addgroup -g 5000 vmail \ envsubst \ ca-certificates \ curl \ + coreutils \ jq \ lua \ lua-cjson \ @@ -62,7 +64,7 @@ RUN addgroup -g 5000 vmail \ perl-package-stash-xs \ perl-par-packer \ perl-parse-recdescent \ - perl-lockfile-simple --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community/ \ + perl-lockfile-simple \ libproc \ perl-readonly \ perl-regexp-common \ @@ -104,13 +106,12 @@ RUN addgroup -g 5000 vmail \ dovecot-pigeonhole-plugin \ dovecot-pop3d \ dovecot-fts-solr \ + dovecot-fts-flatcurve \ && arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \ && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$arch" \ && chmod +x /usr/local/bin/gosu \ && gosu nobody true -# RUN cpan LockFile::Simple - COPY trim_logs.sh /usr/local/bin/trim_logs.sh COPY clean_q_aged.sh /usr/local/bin/clean_q_aged.sh COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf @@ -129,6 +130,7 @@ COPY stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh COPY quarantine_notify.py /usr/local/bin/quarantine_notify.py COPY quota_notify.py /usr/local/bin/quota_notify.py COPY repl_health.sh /usr/local/bin/repl_health.sh +COPY optimize-fts.sh /usr/local/bin/optimize-fts.sh ENTRYPOINT ["/docker-entrypoint.sh"] -CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh index a9545f33..2f0bfadf 100755 --- a/data/Dockerfiles/dovecot/docker-entrypoint.sh +++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh @@ -2,7 +2,7 @@ set -e # Wait for MySQL to warm-up -while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do +while ! mariadb-admin status --ssl=false --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do echo "Waiting for database to come up..." sleep 2 done @@ -29,6 +29,7 @@ ${REDIS_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null # Create missing directories [[ ! -d /etc/dovecot/sql/ ]] && mkdir -p /etc/dovecot/sql/ [[ ! -d /etc/dovecot/lua/ ]] && mkdir -p /etc/dovecot/lua/ +[[ ! -d /etc/dovecot/conf.d/ ]] && mkdir -p /etc/dovecot/conf.d/ [[ ! -d /var/vmail/_garbage ]] && mkdir -p /var/vmail/_garbage [[ ! -d /var/vmail/sieve ]] && mkdir -p /var/vmail/sieve [[ ! -d /etc/sogo ]] && mkdir -p /etc/sogo @@ -109,7 +110,14 @@ EOF echo -n ${ACL_ANYONE} > /etc/dovecot/acl_anyone -if [[ "${SKIP_SOLR}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then +if [[ "${FLATCURVE_EXPERIMENTAL}" =~ ^([yY][eE][sS]|[yY]) ]]; then +echo -e "\e[33mActivating Flatcurve as FTS Backend...\e[0m" +echo -e "\e[33mDepending on your previous setup a full reindex might be needed... \e[0m" +echo -e "\e[34mVisit https://docs.mailcow.email/manual-guides/Dovecot/u_e-dovecot-fts/#fts-related-dovecot-commands to learn how to reindex\e[0m" +echo -n 'quota acl zlib mail_crypt mail_crypt_acl mail_log notify fts fts_flatcurve listescape replication' > /etc/dovecot/mail_plugins +echo -n 'quota imap_quota imap_acl acl zlib imap_zlib imap_sieve mail_crypt mail_crypt_acl notify mail_log fts fts_flatcurve listescape replication' > /etc/dovecot/mail_plugins_imap +echo -n 'quota sieve acl zlib mail_crypt mail_crypt_acl fts fts_flatcurve notify listescape replication' > /etc/dovecot/mail_plugins_lmtp +elif [[ "${SKIP_SOLR}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then echo -n 'quota acl zlib mail_crypt mail_crypt_acl mail_log notify listescape replication' > /etc/dovecot/mail_plugins echo -n 'quota imap_quota imap_acl acl zlib imap_zlib imap_sieve mail_crypt mail_crypt_acl notify listescape replication mail_log' > /etc/dovecot/mail_plugins_imap echo -n 'quota sieve acl zlib mail_crypt mail_crypt_acl notify listescape replication' > /etc/dovecot/mail_plugins_lmtp @@ -239,6 +247,51 @@ function script_deinit() end EOF +# Temporarily set FTS depending on user choice inside mailcow.conf. Will be removed as soon as Solr is dropped +if [[ "${FLATCURVE_EXPERIMENTAL}" =~ ^([yY][eE][sS]|[yY])$ ]]; then +cat < /etc/dovecot/conf.d/fts.conf +# Autogenerated by mailcow +plugin { + fts_autoindex = yes + fts_autoindex_exclude = \Junk + fts_autoindex_exclude2 = \Trash + fts = flatcurve + + # Maximum term length can be set via the 'maxlen' argument (maxlen is + # specified in bytes, not number of UTF-8 characters) + fts_tokenizer_email_address = maxlen=100 + fts_tokenizer_generic = algorithm=simple maxlen=30 + + # These are not flatcurve settings, but required for Dovecot FTS. See + # Dovecot FTS Configuration link above for further information. + fts_languages = en es de + fts_tokenizers = generic email-address + + # OPTIONAL: Recommended default FTS core configuration + fts_filters = normalizer-icu snowball stopwords + fts_filters_en = lowercase snowball english-possessive stopwords +} +EOF +elif [[ ! "${SKIP_SOLR}" =~ ^([yY][eE][sS]|[yY])$ ]]; then +cat < /etc/dovecot/conf.d/fts.conf +# Autogenerated by mailcow +plugin { + fts = solr + fts_autoindex = yes + fts_autoindex_exclude = \Junk + fts_autoindex_exclude2 = \Trash + fts_solr = url=http://solr:8983/solr/dovecot-fts/ + + fts_tokenizers = generic email-address + fts_tokenizer_generic = algorithm=simple + + fts_filters = normalizer-icu snowball stopwords + fts_filters_en = lowercase snowball english-possessive stopwords +} +EOF +fi + + # Replace patterns in app-passdb.lua sed -i "s/__DBUSER__/${DBUSER}/g" /etc/dovecot/lua/passwd-verify.lua sed -i "s/__DBPASS__/${DBPASS}/g" /etc/dovecot/lua/passwd-verify.lua @@ -343,7 +396,6 @@ mail_replica = tcp:${MAILCOW_REPLICA_IP}:${DOVEADM_REPLICA_PORT} EOF fi - # 401 is user dovecot if [[ ! -s /mail_crypt/ecprivkey.pem || ! -s /mail_crypt/ecpubkey.pem ]]; then openssl ecparam -name prime256v1 -genkey | openssl pkey -out /mail_crypt/ecprivkey.pem @@ -359,14 +411,6 @@ sievec /var/vmail/sieve/global_sieve_after.sieve sievec /usr/lib/dovecot/sieve/report-spam.sieve sievec /usr/lib/dovecot/sieve/report-ham.sieve -for file in /var/vmail/*/*/sieve/*.sieve ; do - if [[ "$file" == "/var/vmail/*/*/sieve/*.sieve" ]]; then - continue - fi - sievec "$file" "$(dirname "$file")/../.dovecot.svbin" - chown vmail:vmail "$(dirname "$file")/../.dovecot.svbin" -done - # Fix permissions chown root:root /etc/dovecot/sql/*.conf chown root:dovecot /etc/dovecot/sql/dovecot-dict-sql-sieve* /etc/dovecot/sql/dovecot-dict-sql-quota* /etc/dovecot/lua/passwd-verify.lua @@ -387,7 +431,8 @@ chmod +x /usr/lib/dovecot/sieve/rspamd-pipe-ham \ /usr/local/bin/maildir_gc.sh \ /usr/local/sbin/stop-supervisor.sh \ /usr/local/bin/quota_notify.py \ - /usr/local/bin/repl_health.sh + /usr/local/bin/repl_health.sh \ + /usr/local/bin/optimize-fts.sh # Prepare environment file for cronjobs printenv | sed 's/^\(.*\)$/export \1/g' > /source_env.sh diff --git a/data/Dockerfiles/dovecot/optimize-fts.sh b/data/Dockerfiles/dovecot/optimize-fts.sh new file mode 100644 index 00000000..a6e8f91d --- /dev/null +++ b/data/Dockerfiles/dovecot/optimize-fts.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +if [[ "${SKIP_SOLR}" =~ ^([yY][eE][sS]|[yY])+$ && ! "${FLATCURVE_EXPERIMENTAL}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then + exit 0 +else + doveadm fts optimize -A +fi \ No newline at end of file diff --git a/data/Dockerfiles/dovecot/rspamd-pipe-ham b/data/Dockerfiles/dovecot/rspamd-pipe-ham index 732af858..b9a84f1b 100755 --- a/data/Dockerfiles/dovecot/rspamd-pipe-ham +++ b/data/Dockerfiles/dovecot/rspamd-pipe-ham @@ -3,8 +3,8 @@ FILE=/tmp/mail$$ cat > $FILE trap "/bin/rm -f $FILE" 0 1 2 3 13 15 -cat ${FILE} | /usr/bin/curl -H "Flag: 11" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/fuzzydel -cat ${FILE} | /usr/bin/curl -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/learnham -cat ${FILE} | /usr/bin/curl -H "Flag: 13" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/fuzzyadd +cat ${FILE} | /usr/bin/curl -H "Flag: 11" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/fuzzydel +cat ${FILE} | /usr/bin/curl -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/learnham +cat ${FILE} | /usr/bin/curl -H "Flag: 13" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/fuzzyadd exit 0 diff --git a/data/Dockerfiles/dovecot/rspamd-pipe-spam b/data/Dockerfiles/dovecot/rspamd-pipe-spam index a4b91a01..3f02c487 100755 --- a/data/Dockerfiles/dovecot/rspamd-pipe-spam +++ b/data/Dockerfiles/dovecot/rspamd-pipe-spam @@ -3,8 +3,8 @@ FILE=/tmp/mail$$ cat > $FILE trap "/bin/rm -f $FILE" 0 1 2 3 13 15 -cat ${FILE} | /usr/bin/curl -H "Flag: 13" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/fuzzydel -cat ${FILE} | /usr/bin/curl -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/learnspam -cat ${FILE} | /usr/bin/curl -H "Flag: 11" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/fuzzyadd +cat ${FILE} | /usr/bin/curl -H "Flag: 13" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/fuzzydel +cat ${FILE} | /usr/bin/curl -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/learnspam +cat ${FILE} | /usr/bin/curl -H "Flag: 11" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/fuzzyadd exit 0 diff --git a/data/Dockerfiles/dovecot/sa-rules.sh b/data/Dockerfiles/dovecot/sa-rules.sh index 89911c19..2a513805 100755 --- a/data/Dockerfiles/dovecot/sa-rules.sh +++ b/data/Dockerfiles/dovecot/sa-rules.sh @@ -11,21 +11,25 @@ else fi # Deploy -curl --connect-timeout 15 --retry 10 --max-time 30 http://www.spamassassin.heinlein-support.de/$(dig txt 1.4.3.spamassassin.heinlein-support.de +short | tr -d '"' | tr -dc '0-9').tar.gz --output /tmp/sa-rules-heinlein.tar.gz -if gzip -t /tmp/sa-rules-heinlein.tar.gz; then - tar xfvz /tmp/sa-rules-heinlein.tar.gz -C /tmp/sa-rules-heinlein - cat /tmp/sa-rules-heinlein/*cf > /etc/rspamd/custom/sa-rules +if curl --connect-timeout 15 --retry 10 --max-time 30 https://www.spamassassin.heinlein-support.de/$(dig txt 1.4.3.spamassassin.heinlein-support.de +short | tr -d '"' | tr -dc '0-9').tar.gz --output /tmp/sa-rules-heinlein.tar.gz; then + if gzip -t /tmp/sa-rules-heinlein.tar.gz; then + tar xfvz /tmp/sa-rules-heinlein.tar.gz -C /tmp/sa-rules-heinlein + cat /tmp/sa-rules-heinlein/*cf > /etc/rspamd/custom/sa-rules + fi +else + echo "Failed to download SA rules. Exiting." + exit 0 # Must be 0 otherwise dovecot would not start at all fi sed -i -e 's/\([^\\]\)\$\([^\/]\)/\1\\$\2/g' /etc/rspamd/custom/sa-rules if [[ "$(cat /etc/rspamd/custom/sa-rules | md5sum | cut -d' ' -f1)" != "${HASH_SA_RULES}" ]]; then CONTAINER_NAME=rspamd-mailcow - CONTAINER_ID=$(curl --silent --insecure https://dockerapi/containers/json | \ + CONTAINER_ID=$(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/json | \ jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | \ jq -rc "select( .name | tostring | contains(\"${CONTAINER_NAME}\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id") if [[ ! -z ${CONTAINER_ID} ]]; then - curl --silent --insecure -XPOST --connect-timeout 15 --max-time 120 https://dockerapi/containers/${CONTAINER_ID}/restart + curl --silent --insecure -XPOST --connect-timeout 15 --max-time 120 https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${CONTAINER_ID}/restart fi fi diff --git a/data/Dockerfiles/netfilter/Dockerfile b/data/Dockerfiles/netfilter/Dockerfile index 8a561f06..86f9e3f6 100644 --- a/data/Dockerfiles/netfilter/Dockerfile +++ b/data/Dockerfiles/netfilter/Dockerfile @@ -1,5 +1,6 @@ -FROM alpine:3.19 -LABEL maintainer "The Infrastructure Company GmbH " +FROM alpine:3.20 + +LABEL maintainer = "The Infrastructure Company GmbH " WORKDIR /app diff --git a/data/Dockerfiles/netfilter/main.py b/data/Dockerfiles/netfilter/main.py index 62e0dda7..c5667dc5 100644 --- a/data/Dockerfiles/netfilter/main.py +++ b/data/Dockerfiles/netfilter/main.py @@ -80,16 +80,16 @@ def refreshF2bregex(): global exit_code if not r.get('F2B_REGEX'): f2bregex = {} - f2bregex[1] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)' - f2bregex[2] = 'Rspamd UI: Invalid password by ([0-9a-f\.:]+)' - f2bregex[3] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed: (?!.*Connection lost to authentication server).+' - f2bregex[4] = 'warning: non-SMTP command from .*\[([0-9a-f\.:]+)]:.+' - f2bregex[5] = 'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+' - f2bregex[6] = '-login: Disconnected.+ \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),' - f2bregex[7] = '-login: Aborted login.+ \(auth failed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+' - f2bregex[8] = '-login: Aborted login.+ \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+' - f2bregex[9] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked' - f2bregex[10] = '([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+' + f2bregex[1] = r'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)' + f2bregex[2] = r'Rspamd UI: Invalid password by ([0-9a-f\.:]+)' + f2bregex[3] = r'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed: (?!.*Connection lost to authentication server).+' + f2bregex[4] = r'warning: non-SMTP command from .*\[([0-9a-f\.:]+)]:.+' + f2bregex[5] = r'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+' + f2bregex[6] = r'-login: Disconnected.+ \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),' + f2bregex[7] = r'-login: Aborted login.+ \(auth failed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+' + f2bregex[8] = r'-login: Aborted login.+ \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+' + f2bregex[9] = r'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked' + f2bregex[10] = r'([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+' r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False)) else: try: @@ -114,8 +114,6 @@ def ban(address): global lock refreshF2boptions() - BAN_TIME = int(f2boptions['ban_time']) - BAN_TIME_INCREMENT = bool(f2boptions['ban_time_increment']) MAX_ATTEMPTS = int(f2boptions['max_attempts']) RETRY_WINDOW = int(f2boptions['retry_window']) NETBAN_IPV4 = '/' + str(f2boptions['netban_ipv4']) @@ -150,7 +148,7 @@ def ban(address): if bans[net]['attempts'] >= MAX_ATTEMPTS: cur_time = int(round(time.time())) - NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** bans[net]['ban_counter'] + NET_BAN_TIME = calcNetBanTime(bans[net]['ban_counter']) logger.logCrit('Banning %s for %d minutes' % (net, NET_BAN_TIME / 60 )) if type(ip) is ipaddress.IPv4Address and int(f2boptions['manage_external']) != 1: with lock: @@ -277,12 +275,11 @@ def snat6(snat_target): tables.snat6(snat_target, os.getenv('IPV6_NETWORK', 'fd4d:6169:6c63:6f77::/64')) def autopurge(): + global f2boptions + while not quit_now: time.sleep(10) refreshF2boptions() - 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']) QUEUE_UNBAN = r.hgetall('F2B_QUEUE_UNBAN') if QUEUE_UNBAN: @@ -290,9 +287,9 @@ def autopurge(): unban(str(net)) for net in bans.copy(): if bans[net]['attempts'] >= MAX_ATTEMPTS: - NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** bans[net]['ban_counter'] + NET_BAN_TIME = calcNetBanTime(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: + if TIME_SINCE_LAST_ATTEMPT > NET_BAN_TIME: unban(net) def mailcowChainOrder(): @@ -306,6 +303,16 @@ def mailcowChainOrder(): if quit_now: return quit_now, exit_code = tables.checkIPv6ChainOrder() +def calcNetBanTime(ban_counter): + global f2boptions + + BAN_TIME = int(f2boptions['ban_time']) + MAX_BAN_TIME = int(f2boptions['max_ban_time']) + BAN_TIME_INCREMENT = bool(f2boptions['ban_time_increment']) + NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** ban_counter + NET_BAN_TIME = max([BAN_TIME, min([NET_BAN_TIME, MAX_BAN_TIME])]) + return NET_BAN_TIME + def isIpNetwork(address): try: ipaddress.ip_network(address, False) diff --git a/data/Dockerfiles/netfilter/modules/Logger.py b/data/Dockerfiles/netfilter/modules/Logger.py index 25562965..0ba2f42a 100644 --- a/data/Dockerfiles/netfilter/modules/Logger.py +++ b/data/Dockerfiles/netfilter/modules/Logger.py @@ -13,9 +13,12 @@ class Logger: tolog['time'] = int(round(time.time())) tolog['priority'] = priority tolog['message'] = message - if self.r is not None: - self.r.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False)) print(message) + if self.r is not None: + try: + self.r.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False)) + except Exception as ex: + print('Failed logging to redis: %s' % (ex)) def logWarn(self, message): self.log('warn', message) diff --git a/data/Dockerfiles/netfilter/modules/NFTables.py b/data/Dockerfiles/netfilter/modules/NFTables.py index 4cb0110a..7740fa59 100644 --- a/data/Dockerfiles/netfilter/modules/NFTables.py +++ b/data/Dockerfiles/netfilter/modules/NFTables.py @@ -452,6 +452,8 @@ class NFTables: continue rule = _object["rule"]["expr"][0]["match"] + if not "payload" in rule["left"]: + continue left_opt = rule["left"]["payload"] if not left_opt["protocol"] == _family: continue diff --git a/data/Dockerfiles/olefy/Dockerfile b/data/Dockerfiles/olefy/Dockerfile index bd6e0af3..3b272913 100644 --- a/data/Dockerfiles/olefy/Dockerfile +++ b/data/Dockerfiles/olefy/Dockerfile @@ -1,5 +1,6 @@ -FROM alpine:3.19 -LABEL maintainer "The Infrastructure Company GmbH " +FROM alpine:3.20 + +LABEL maintainer = "The Infrastructure Company GmbH " ARG PIP_BREAK_SYSTEM_PACKAGES=1 WORKDIR /app diff --git a/data/Dockerfiles/phpfpm/Dockerfile b/data/Dockerfiles/phpfpm/Dockerfile index 22036b9b..0ac722b2 100644 --- a/data/Dockerfiles/phpfpm/Dockerfile +++ b/data/Dockerfiles/phpfpm/Dockerfile @@ -1,5 +1,6 @@ FROM php:8.2-fpm-alpine3.18 -LABEL maintainer "The Infrastructure Company GmbH " + +LABEL maintainer = "The Infrastructure Company GmbH " # renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced extractVersion=^v(?.*)$ ARG APCU_PECL_VERSION=5.1.23 diff --git a/data/Dockerfiles/phpfpm/docker-entrypoint.sh b/data/Dockerfiles/phpfpm/docker-entrypoint.sh index 37370113..798a2585 100755 --- a/data/Dockerfiles/phpfpm/docker-entrypoint.sh +++ b/data/Dockerfiles/phpfpm/docker-entrypoint.sh @@ -3,7 +3,7 @@ function array_by_comma { local IFS=","; echo "$*"; } # Wait for containers -while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do +while ! mariadb-admin status --ssl=false --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do echo "Waiting for SQL..." sleep 2 done @@ -23,7 +23,8 @@ done # Check mysql_upgrade (master and slave) CONTAINER_ID= until [[ ! -z "${CONTAINER_ID}" ]] && [[ "${CONTAINER_ID}" =~ ^[[:alnum:]]*$ ]]; do - CONTAINER_ID=$(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" 2> /dev/null | jq -rc "select( .name | tostring | contains(\"mysql-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" 2> /dev/null) + CONTAINER_ID=$(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" 2> /dev/null | jq -rc "select( .name | tostring | contains(\"mysql-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" 2> /dev/null) + echo "Could not get mysql-mailcow container id... trying again" sleep 2 done echo "MySQL @ ${CONTAINER_ID}" @@ -34,7 +35,7 @@ until [[ ${SQL_UPGRADE_STATUS} == 'success' ]]; do echo "Tried to upgrade MySQL and failed, giving up after ${SQL_LOOP_C} retries and starting container (oops, not good)" break fi - SQL_FULL_UPGRADE_RETURN=$(curl --silent --insecure -XPOST https://dockerapi/containers/${CONTAINER_ID}/exec -d '{"cmd":"system", "task":"mysql_upgrade"}' --silent -H 'Content-type: application/json') + SQL_FULL_UPGRADE_RETURN=$(curl --silent --insecure -XPOST https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${CONTAINER_ID}/exec -d '{"cmd":"system", "task":"mysql_upgrade"}' --silent -H 'Content-type: application/json') SQL_UPGRADE_STATUS=$(echo ${SQL_FULL_UPGRADE_RETURN} | jq -r .type) SQL_LOOP_C=$((SQL_LOOP_C+1)) echo "SQL upgrade iteration #${SQL_LOOP_C}" @@ -43,7 +44,7 @@ until [[ ${SQL_UPGRADE_STATUS} == 'success' ]]; do echo "MySQL applied an upgrade, debug output:" echo ${SQL_FULL_UPGRADE_RETURN} sleep 3 - while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do + while ! mariadb-admin status --ssl=false --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do echo "Waiting for SQL to return, please wait" sleep 2 done @@ -59,12 +60,12 @@ done # doing post-installation stuff, if SQL was upgraded (master and slave) if [ ${SQL_CHANGED} -eq 1 ]; then - POSTFIX=$(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" 2> /dev/null | jq -rc "select( .name | tostring | contains(\"postfix-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" 2> /dev/null) + POSTFIX=$(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" 2> /dev/null | jq -rc "select( .name | tostring | contains(\"postfix-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" 2> /dev/null) if [[ -z "${POSTFIX}" ]] || ! [[ "${POSTFIX}" =~ ^[[:alnum:]]*$ ]]; then echo "Could not determine Postfix container ID, skipping Postfix restart." else echo "Restarting Postfix" - curl -X POST --silent --insecure https://dockerapi/containers/${POSTFIX}/restart | jq -r '.msg' + curl -X POST --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${POSTFIX}/restart | jq -r '.msg' echo "Sleeping 5 seconds..." sleep 5 fi @@ -73,7 +74,7 @@ fi # Check mysql tz import (master and slave) TZ_CHECK=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT CONVERT_TZ('2019-11-02 23:33:00','Europe/Berlin','UTC') AS time;" -BN 2> /dev/null) if [[ -z ${TZ_CHECK} ]] || [[ "${TZ_CHECK}" == "NULL" ]]; then - SQL_FULL_TZINFO_IMPORT_RETURN=$(curl --silent --insecure -XPOST https://dockerapi/containers/${CONTAINER_ID}/exec -d '{"cmd":"system", "task":"mysql_tzinfo_to_sql"}' --silent -H 'Content-type: application/json') + SQL_FULL_TZINFO_IMPORT_RETURN=$(curl --silent --insecure -XPOST https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${CONTAINER_ID}/exec -d '{"cmd":"system", "task":"mysql_tzinfo_to_sql"}' --silent -H 'Content-type: application/json') echo "MySQL mysql_tzinfo_to_sql - debug output:" echo ${SQL_FULL_TZINFO_IMPORT_RETURN} fi diff --git a/data/Dockerfiles/postfix/Dockerfile b/data/Dockerfiles/postfix/Dockerfile index 236062d7..5449360b 100644 --- a/data/Dockerfiles/postfix/Dockerfile +++ b/data/Dockerfiles/postfix/Dockerfile @@ -1,5 +1,6 @@ -FROM debian:bullseye-slim -LABEL maintainer "The Infrastructure Company GmbH GmbH " +FROM debian:bookworm-slim + +LABEL maintainer = "The Infrastructure Company GmbH " ARG DEBIAN_FRONTEND=noninteractive ENV LC_ALL C @@ -59,4 +60,4 @@ EXPOSE 588 ENTRYPOINT ["/docker-entrypoint.sh"] -CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] diff --git a/data/Dockerfiles/postfix/postfix.sh b/data/Dockerfiles/postfix/postfix.sh index b3098d3a..8ffb76f6 100755 --- a/data/Dockerfiles/postfix/postfix.sh +++ b/data/Dockerfiles/postfix/postfix.sh @@ -5,7 +5,7 @@ trap "postfix stop" EXIT [[ ! -d /opt/postfix/conf/sql/ ]] && mkdir -p /opt/postfix/conf/sql/ # Wait for MySQL to warm-up -while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do +while ! mariadb-admin status --ssl=false --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do echo "Waiting for database to come up..." sleep 2 done @@ -415,12 +415,6 @@ postscreen_dnsbl_sites = wl.mailspike.net=127.0.0.[18;19;20]*-2 b.barracudacentral.org=127.0.0.2*7 bl.mailspike.net=127.0.0.2*5 bl.mailspike.net=127.0.0.[10;11;12]*4 - dnsbl.sorbs.net=127.0.0.10*8 - dnsbl.sorbs.net=127.0.0.5*6 - dnsbl.sorbs.net=127.0.0.7*3 - dnsbl.sorbs.net=127.0.0.8*2 - dnsbl.sorbs.net=127.0.0.6*2 - dnsbl.sorbs.net=127.0.0.9*2 EOF fi DNSBL_CONFIG=$(grep -v '^#' /opt/postfix/conf/dns_blocklists.cf | grep '\S') diff --git a/data/Dockerfiles/postfix/syslog-ng-redis_slave.conf b/data/Dockerfiles/postfix/syslog-ng-redis_slave.conf index 558305ec..cb1d1aa0 100644 --- a/data/Dockerfiles/postfix/syslog-ng-redis_slave.conf +++ b/data/Dockerfiles/postfix/syslog-ng-redis_slave.conf @@ -1,4 +1,4 @@ -@version: 3.28 +@version: 3.38 @include "scl.conf" options { chain_hostnames(off); diff --git a/data/Dockerfiles/postfix/syslog-ng.conf b/data/Dockerfiles/postfix/syslog-ng.conf index a1ccd07e..0990f1c0 100644 --- a/data/Dockerfiles/postfix/syslog-ng.conf +++ b/data/Dockerfiles/postfix/syslog-ng.conf @@ -1,4 +1,4 @@ -@version: 3.28 +@version: 3.38 @include "scl.conf" options { chain_hostnames(off); diff --git a/data/Dockerfiles/rspamd/Dockerfile b/data/Dockerfiles/rspamd/Dockerfile index 2511a6f2..df15a0be 100644 --- a/data/Dockerfiles/rspamd/Dockerfile +++ b/data/Dockerfiles/rspamd/Dockerfile @@ -1,9 +1,10 @@ -FROM debian:bullseye-slim -LABEL maintainer "The Infrastructure Company GmbH GmbH " +FROM debian:bookworm-slim +LABEL maintainer = "The Infrastructure Company GmbH " ARG DEBIAN_FRONTEND=noninteractive -ARG CODENAME=bullseye -ENV LC_ALL C +ARG RSPAMD_VER=rspamd_3.9.1-1~82f43560f +ARG CODENAME=bookworm +ENV LC_ALL=C RUN apt-get update && apt-get install -y \ tzdata \ @@ -11,12 +12,16 @@ RUN apt-get update && apt-get install -y \ gnupg2 \ apt-transport-https \ dnsutils \ - netcat \ - && apt-key adv --fetch-keys https://rspamd.com/apt-stable/gpg.key \ - && echo "deb https://rspamd.com/apt-stable/ $CODENAME main" > /etc/apt/sources.list.d/rspamd.list \ - && apt-get update \ - && apt-get --no-install-recommends -y install rspamd redis-tools procps nano \ - && rm -rf /var/lib/apt/lists/* \ + netcat-traditional \ + wget \ + redis-tools \ + procps \ + nano \ + lua-cjson \ + && arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \ + && wget -P /tmp https://rspamd.com/apt-stable/pool/main/r/rspamd/${RSPAMD_VER}~${CODENAME}_${arch}.deb\ + && apt install -y /tmp/${RSPAMD_VER}~${CODENAME}_${arch}.deb \ + && rm -rf /var/lib/apt/lists/* /tmp/*\ && apt-get autoremove --purge \ && apt-get clean \ && mkdir -p /run/rspamd \ @@ -25,7 +30,6 @@ RUN apt-get update && apt-get install -y \ && sed -i 's/#analysis_keyword_table > 0/analysis_cat_table.macro_exist == "M"/g' /usr/share/rspamd/lualib/lua_scanners/oletools.lua COPY settings.conf /etc/rspamd/settings.conf -COPY metadata_exporter.lua /usr/share/rspamd/plugins/metadata_exporter.lua COPY set_worker_password.sh /set_worker_password.sh COPY docker-entrypoint.sh /docker-entrypoint.sh diff --git a/data/Dockerfiles/rspamd/docker-entrypoint.sh b/data/Dockerfiles/rspamd/docker-entrypoint.sh index 8af7619c..cf09ee48 100755 --- a/data/Dockerfiles/rspamd/docker-entrypoint.sh +++ b/data/Dockerfiles/rspamd/docker-entrypoint.sh @@ -124,4 +124,190 @@ for file in /hooks/*; do fi done +# If DQS KEY is set in mailcow.conf add Spamhaus DQS RBLs +if [[ ! -z ${SPAMHAUS_DQS_KEY} ]]; then + cat < /etc/rspamd/custom/dqs-rbl.conf + # Autogenerated by mailcow. DO NOT TOUCH! + spamhaus { + rbl = "${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net"; + from = false; + } + spamhaus_from { + from = true; + received = false; + rbl = "${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net"; + returncodes { + SPAMHAUS_ZEN = [ "127.0.0.2", "127.0.0.3", "127.0.0.4", "127.0.0.5", "127.0.0.6", "127.0.0.7", "127.0.0.9", "127.0.0.10", "127.0.0.11" ]; + } + } + spamhaus_authbl_received { + # Check if the sender client is listed in AuthBL (AuthBL is *not* part of ZEN) + rbl = "${SPAMHAUS_DQS_KEY}.authbl.dq.spamhaus.net"; + from = false; + received = true; + ipv6 = true; + returncodes { + SH_AUTHBL_RECEIVED = "127.0.0.20" + } + } + spamhaus_dbl { + # Add checks on the HELO string + rbl = "${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net"; + helo = true; + rdns = true; + dkim = true; + disable_monitoring = true; + returncodes { + RBL_DBL_SPAM = "127.0.1.2"; + RBL_DBL_PHISH = "127.0.1.4"; + RBL_DBL_MALWARE = "127.0.1.5"; + RBL_DBL_BOTNET = "127.0.1.6"; + RBL_DBL_ABUSED_SPAM = "127.0.1.102"; + RBL_DBL_ABUSED_PHISH = "127.0.1.104"; + RBL_DBL_ABUSED_MALWARE = "127.0.1.105"; + RBL_DBL_ABUSED_BOTNET = "127.0.1.106"; + RBL_DBL_DONT_QUERY_IPS = "127.0.1.255"; + } + } + spamhaus_dbl_fullurls { + ignore_defaults = true; + no_ip = true; + rbl = "${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net"; + selector = 'urls:get_host' + disable_monitoring = true; + returncodes { + DBLABUSED_SPAM_FULLURLS = "127.0.1.102"; + DBLABUSED_PHISH_FULLURLS = "127.0.1.104"; + DBLABUSED_MALWARE_FULLURLS = "127.0.1.105"; + DBLABUSED_BOTNET_FULLURLS = "127.0.1.106"; + } + } + spamhaus_zrd { + # Add checks on the HELO string also for DQS + rbl = "${SPAMHAUS_DQS_KEY}.zrd.dq.spamhaus.net"; + helo = true; + rdns = true; + dkim = true; + disable_monitoring = true; + returncodes { + RBL_ZRD_VERY_FRESH_DOMAIN = ["127.0.2.2", "127.0.2.3", "127.0.2.4"]; + RBL_ZRD_FRESH_DOMAIN = [ + "127.0.2.5", "127.0.2.6", "127.0.2.7", "127.0.2.8", "127.0.2.9", "127.0.2.10", "127.0.2.11", "127.0.2.12", "127.0.2.13", "127.0.2.14", "127.0.2.15", "127.0.2.16", "127.0.2.17", "127.0.2.18", "127.0.2.19", "127.0.2.20", "127.0.2.21", "127.0.2.22", "127.0.2.23", "127.0.2.24" + ]; + RBL_ZRD_DONT_QUERY_IPS = "127.0.2.255"; + } + } + "SPAMHAUS_ZEN_URIBL" { + enabled = true; + rbl = "${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net"; + resolve_ip = true; + checks = ['urls']; + replyto = true; + emails = true; + ipv4 = true; + ipv6 = true; + emails_domainonly = true; + returncodes { + URIBL_SBL = "127.0.0.2"; + URIBL_SBL_CSS = "127.0.0.3"; + URIBL_XBL = ["127.0.0.4", "127.0.0.5", "127.0.0.6", "127.0.0.7"]; + URIBL_PBL = ["127.0.0.10", "127.0.0.11"]; + URIBL_DROP = "127.0.0.9"; + } + } + SH_EMAIL_DBL { + ignore_defaults = true; + replyto = true; + emails_domainonly = true; + disable_monitoring = true; + rbl = "${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net"; + returncodes = { + SH_EMAIL_DBL = [ + "127.0.1.2", + "127.0.1.4", + "127.0.1.5", + "127.0.1.6" + ]; + SH_EMAIL_DBL_ABUSED = [ + "127.0.1.102", + "127.0.1.104", + "127.0.1.105", + "127.0.1.106" + ]; + SH_EMAIL_DBL_DONT_QUERY_IPS = [ "127.0.1.255" ]; + } + } + SH_EMAIL_ZRD { + ignore_defaults = true; + replyto = true; + emails_domainonly = true; + disable_monitoring = true; + rbl = "${SPAMHAUS_DQS_KEY}.zrd.dq.spamhaus.net"; + returncodes = { + SH_EMAIL_ZRD_VERY_FRESH_DOMAIN = ["127.0.2.2", "127.0.2.3", "127.0.2.4"]; + SH_EMAIL_ZRD_FRESH_DOMAIN = [ + "127.0.2.5", "127.0.2.6", "127.0.2.7", "127.0.2.8", "127.0.2.9", "127.0.2.10", "127.0.2.11", "127.0.2.12", "127.0.2.13", "127.0.2.14", "127.0.2.15", "127.0.2.16", "127.0.2.17", "127.0.2.18", "127.0.2.19", "127.0.2.20", "127.0.2.21", "127.0.2.22", "127.0.2.23", "127.0.2.24" + ]; + SH_EMAIL_ZRD_DONT_QUERY_IPS = [ "127.0.2.255" ]; + } + } + "DBL" { + # override the defaults for DBL defined in modules.d/rbl.conf + rbl = "${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net"; + disable_monitoring = true; + } + "ZRD" { + ignore_defaults = true; + rbl = "${SPAMHAUS_DQS_KEY}.zrd.dq.spamhaus.net"; + no_ip = true; + dkim = true; + emails = true; + emails_domainonly = true; + urls = true; + returncodes = { + ZRD_VERY_FRESH_DOMAIN = ["127.0.2.2", "127.0.2.3", "127.0.2.4"]; + ZRD_FRESH_DOMAIN = ["127.0.2.5", "127.0.2.6", "127.0.2.7", "127.0.2.8", "127.0.2.9", "127.0.2.10", "127.0.2.11", "127.0.2.12", "127.0.2.13", "127.0.2.14", "127.0.2.15", "127.0.2.16", "127.0.2.17", "127.0.2.18", "127.0.2.19", "127.0.2.20", "127.0.2.21", "127.0.2.22", "127.0.2.23", "127.0.2.24"]; + } + } + spamhaus_sbl_url { + ignore_defaults = true + rbl = "${SPAMHAUS_DQS_KEY}.sbl.dq.spamhaus.net"; + checks = ['urls']; + disable_monitoring = true; + returncodes { + SPAMHAUS_SBL_URL = "127.0.0.2"; + } + } + + SH_HBL_EMAIL { + ignore_defaults = true; + rbl = "_email.${SPAMHAUS_DQS_KEY}.hbl.dq.spamhaus.net"; + emails_domainonly = false; + selector = "from('smtp').lower;from('mime').lower"; + ignore_whitelist = true; + checks = ['emails', 'replyto']; + hash = "sha1"; + returncodes = { + SH_HBL_EMAIL = [ + "127.0.3.2" + ]; + } + } + + spamhaus_dqs_hbl { + symbol = "HBL_FILE_UNKNOWN"; + rbl = "_file.${SPAMHAUS_DQS_KEY}.hbl.dq.spamhaus.net."; + selector = "attachments('rbase32', 'sha256')"; + ignore_whitelist = true; + ignore_defaults = true; + returncodes { + SH_HBL_FILE_MALICIOUS = "127.0.3.10"; + SH_HBL_FILE_SUSPICIOUS = "127.0.3.15"; + } + } +EOF +else + rm -rf /etc/rspamd/custom/dqs-rbl.conf +fi + exec "$@" diff --git a/data/Dockerfiles/rspamd/metadata_exporter.lua b/data/Dockerfiles/rspamd/metadata_exporter.lua deleted file mode 100644 index 48a5ffce..00000000 --- a/data/Dockerfiles/rspamd/metadata_exporter.lua +++ /dev/null @@ -1,632 +0,0 @@ ---[[ -Copyright (c) 2016, Andrew Lewis -Copyright (c) 2016, Vsevolod Stakhov - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -]]-- - -if confighelp then - return -end - --- A plugin that pushes metadata (or whole messages) to external services - -local redis_params -local lua_util = require "lua_util" -local rspamd_http = require "rspamd_http" -local rspamd_util = require "rspamd_util" -local rspamd_logger = require "rspamd_logger" -local ucl = require "ucl" -local E = {} -local N = 'metadata_exporter' - -local settings = { - pusher_enabled = {}, - pusher_format = {}, - pusher_select = {}, - mime_type = 'text/plain', - defer = false, - mail_from = '', - mail_to = 'postmaster@localhost', - helo = 'rspamd', - email_template = [[From: "Rspamd" <$mail_from> -To: $mail_to -Subject: Spam alert -Date: $date -MIME-Version: 1.0 -Message-ID: <$our_message_id> -Content-type: text/plain; charset=utf-8 -Content-Transfer-Encoding: 8bit - -Authenticated username: $user -IP: $ip -Queue ID: $qid -SMTP FROM: $from -SMTP RCPT: $rcpt -MIME From: $header_from -MIME To: $header_to -MIME Date: $header_date -Subject: $header_subject -Message-ID: $message_id -Action: $action -Score: $score -Symbols: $symbols]], -} - -local function get_general_metadata(task, flatten, no_content) - local r = {} - local ip = task:get_from_ip() - if ip and ip:is_valid() then - r.ip = tostring(ip) - else - r.ip = 'unknown' - end - r.user = task:get_user() or 'unknown' - r.qid = task:get_queue_id() or 'unknown' - r.subject = task:get_subject() or 'unknown' - r.action = task:get_metric_action('default') - - local s = task:get_metric_score('default')[1] - r.score = flatten and string.format('%.2f', s) or s - - local fuzzy = task:get_mempool():get_variable("fuzzy_hashes", "fstrings") - if fuzzy and #fuzzy > 0 then - local fz = {} - for _,h in ipairs(fuzzy) do - table.insert(fz, h) - end - if not flatten then - r.fuzzy = fz - else - r.fuzzy = table.concat(fz, ', ') - end - else - r.fuzzy = 'unknown' - end - - local rcpt = task:get_recipients('smtp') - if rcpt then - local l = {} - for _, a in ipairs(rcpt) do - table.insert(l, a['addr']) - end - if not flatten then - r.rcpt = l - else - r.rcpt = table.concat(l, ', ') - end - else - r.rcpt = 'unknown' - end - local from = task:get_from('smtp') - if ((from or E)[1] or E).addr then - r.from = from[1].addr - else - r.from = 'unknown' - end - local syminf = task:get_symbols_all() - if flatten then - local l = {} - for _, sym in ipairs(syminf) do - local txt - if sym.options then - local topt = table.concat(sym.options, ', ') - txt = sym.name .. '(' .. string.format('%.2f', sym.score) .. ')' .. ' [' .. topt .. ']' - else - txt = sym.name .. '(' .. string.format('%.2f', sym.score) .. ')' - end - table.insert(l, txt) - end - r.symbols = table.concat(l, '\n\t') - else - r.symbols = syminf - end - local function process_header(name) - local hdr = task:get_header_full(name) - if hdr then - local l = {} - for _, h in ipairs(hdr) do - table.insert(l, h.decoded) - end - if not flatten then - return l - else - return table.concat(l, '\n') - end - else - return 'unknown' - end - end - if not no_content then - r.header_from = process_header('from') - r.header_to = process_header('to') - r.header_subject = process_header('subject') - r.header_date = process_header('date') - r.message_id = task:get_message_id() - end - return r -end - -local formatters = { - default = function(task) - return task:get_content(), {} - end, - email_alert = function(task, rule, extra) - local meta = get_general_metadata(task, true) - local display_emails = {} - local mail_targets = {} - meta.mail_from = rule.mail_from or settings.mail_from - local mail_rcpt = rule.mail_to or settings.mail_to - if type(mail_rcpt) ~= 'table' then - table.insert(display_emails, string.format('<%s>', mail_rcpt)) - table.insert(mail_targets, mail_rcpt) - else - for _, e in ipairs(mail_rcpt) do - table.insert(display_emails, string.format('<%s>', e)) - table.insert(mail_targets, mail_rcpt) - end - end - if rule.email_alert_sender then - local x = task:get_from('smtp') - if x and string.len(x[1].addr) > 0 then - table.insert(mail_targets, x) - table.insert(display_emails, string.format('<%s>', x[1].addr)) - end - end - if rule.email_alert_user then - local x = task:get_user() - if x then - table.insert(mail_targets, x) - table.insert(display_emails, string.format('<%s>', x)) - end - end - if rule.email_alert_recipients then - local x = task:get_recipients('smtp') - if x then - for _, e in ipairs(x) do - if string.len(e.addr) > 0 then - table.insert(mail_targets, e.addr) - table.insert(display_emails, string.format('<%s>', e.addr)) - end - end - end - end - meta.mail_to = table.concat(display_emails, ', ') - meta.our_message_id = rspamd_util.random_hex(12) .. '@rspamd' - meta.date = rspamd_util.time_to_string(rspamd_util.get_time()) - return lua_util.template(rule.email_template or settings.email_template, meta), { mail_targets = mail_targets} - end, - json = function(task) - return ucl.to_format(get_general_metadata(task), 'json-compact') - end -} - -local function is_spam(action) - return (action == 'reject' or action == 'add header' or action == 'rewrite subject') -end - -local selectors = { - default = function(task) - return true - end, - is_spam = function(task) - local action = task:get_metric_action('default') - return is_spam(action) - end, - is_spam_authed = function(task) - if not task:get_user() then - return false - end - local action = task:get_metric_action('default') - return is_spam(action) - end, - is_reject = function(task) - local action = task:get_metric_action('default') - return (action == 'reject') - end, - is_reject_authed = function(task) - if not task:get_user() then - return false - end - local action = task:get_metric_action('default') - return (action == 'reject') - end, -} - -local function maybe_defer(task, rule) - if rule.defer then - rspamd_logger.warnx(task, 'deferring message') - task:set_pre_result('soft reject', 'deferred', N) - end -end - -local pushers = { - redis_pubsub = function(task, formatted, rule) - local _,ret,upstream - local function redis_pub_cb(err) - if err then - rspamd_logger.errx(task, 'got error %s when publishing on server %s', - err, upstream:get_addr()) - return maybe_defer(task, rule) - end - return true - end - ret,_,upstream = rspamd_redis_make_request(task, - redis_params, -- connect params - nil, -- hash key - true, -- is write - redis_pub_cb, --callback - 'PUBLISH', -- command - {rule.channel, formatted} -- arguments - ) - if not ret then - rspamd_logger.errx(task, 'error connecting to redis') - maybe_defer(task, rule) - end - end, - http = function(task, formatted, rule) - local function http_callback(err, code) - if err then - rspamd_logger.errx(task, 'got error %s in http callback', err) - return maybe_defer(task, rule) - end - if code ~= 200 then - rspamd_logger.errx(task, 'got unexpected http status: %s', code) - return maybe_defer(task, rule) - end - return true - end - local hdrs = {} - if rule.meta_headers then - local gm = get_general_metadata(task, false, true) - local pfx = rule.meta_header_prefix or 'X-Rspamd-' - for k, v in pairs(gm) do - if type(v) == 'table' then - hdrs[pfx .. k] = ucl.to_format(v, 'json-compact') - else - hdrs[pfx .. k] = v - end - end - end - rspamd_http.request({ - task=task, - url=rule.url, - body=formatted, - callback=http_callback, - mime_type=rule.mime_type or settings.mime_type, - headers=hdrs, - }) - end, - send_mail = function(task, formatted, rule, extra) - local lua_smtp = require "lua_smtp" - local function sendmail_cb(ret, err) - if not ret then - rspamd_logger.errx(task, 'SMTP export error: %s', err) - maybe_defer(task, rule) - end - end - - lua_smtp.sendmail({ - task = task, - host = rule.smtp, - port = rule.smtp_port or settings.smtp_port or 25, - from = rule.mail_from or settings.mail_from, - recipients = extra.mail_targets or rule.mail_to or settings.mail_to, - helo = rule.helo or settings.helo, - timeout = rule.timeout or settings.timeout, - }, formatted, sendmail_cb) - end, -} - -local opts = rspamd_config:get_all_opt(N) -if not opts then return end -local process_settings = { - select = function(val) - selectors.custom = assert(load(val))() - end, - format = function(val) - formatters.custom = assert(load(val))() - end, - push = function(val) - pushers.custom = assert(load(val))() - end, - custom_push = function(val) - if type(val) == 'table' then - for k, v in pairs(val) do - pushers[k] = assert(load(v))() - end - end - end, - custom_select = function(val) - if type(val) == 'table' then - for k, v in pairs(val) do - selectors[k] = assert(load(v))() - end - end - end, - custom_format = function(val) - if type(val) == 'table' then - for k, v in pairs(val) do - formatters[k] = assert(load(v))() - end - end - end, - pusher_enabled = function(val) - if type(val) == 'string' then - if pushers[val] then - settings.pusher_enabled[val] = true - else - rspamd_logger.errx(rspamd_config, 'Pusher type: %s is invalid', val) - end - elseif type(val) == 'table' then - for _, v in ipairs(val) do - if pushers[v] then - settings.pusher_enabled[v] = true - else - rspamd_logger.errx(rspamd_config, 'Pusher type: %s is invalid', val) - end - end - end - end, -} -for k, v in pairs(opts) do - local f = process_settings[k] - if f then - f(opts[k]) - else - settings[k] = v - end -end -if type(settings.rules) ~= 'table' then - -- Legacy config - settings.rules = {} - if not next(settings.pusher_enabled) then - if pushers.custom then - rspamd_logger.infox(rspamd_config, 'Custom pusher implicitly enabled') - settings.pusher_enabled.custom = true - else - -- Check legacy options - if settings.url then - rspamd_logger.warnx(rspamd_config, 'HTTP pusher implicitly enabled') - settings.pusher_enabled.http = true - end - if settings.channel then - rspamd_logger.warnx(rspamd_config, 'Redis Pubsub pusher implicitly enabled') - settings.pusher_enabled.redis_pubsub = true - end - if settings.smtp and settings.mail_to then - rspamd_logger.warnx(rspamd_config, 'SMTP pusher implicitly enabled') - settings.pusher_enabled.send_mail = true - end - end - end - if not next(settings.pusher_enabled) then - rspamd_logger.errx(rspamd_config, 'No push backend enabled') - return - end - if settings.formatter then - settings.format = formatters[settings.formatter] - if not settings.format then - rspamd_logger.errx(rspamd_config, 'No such formatter: %s', settings.formatter) - return - end - end - if settings.selector then - settings.select = selectors[settings.selector] - if not settings.select then - rspamd_logger.errx(rspamd_config, 'No such selector: %s', settings.selector) - return - end - end - for k in pairs(settings.pusher_enabled) do - local formatter = settings.pusher_format[k] - local selector = settings.pusher_select[k] - if not formatter then - settings.pusher_format[k] = settings.formatter or 'default' - rspamd_logger.infox(rspamd_config, 'Using default formatter for %s pusher', k) - else - if not formatters[formatter] then - rspamd_logger.errx(rspamd_config, 'No such formatter: %s - disabling %s', formatter, k) - settings.pusher_enabled.k = nil - end - end - if not selector then - settings.pusher_select[k] = settings.selector or 'default' - rspamd_logger.infox(rspamd_config, 'Using default selector for %s pusher', k) - else - if not selectors[selector] then - rspamd_logger.errx(rspamd_config, 'No such selector: %s - disabling %s', selector, k) - settings.pusher_enabled.k = nil - end - end - end - if settings.pusher_enabled.redis_pubsub then - redis_params = rspamd_parse_redis_server(N) - if not redis_params then - rspamd_logger.errx(rspamd_config, 'No redis servers are specified') - settings.pusher_enabled.redis_pubsub = nil - else - local r = {} - r.backend = 'redis_pubsub' - r.channel = settings.channel - r.defer = settings.defer - r.selector = settings.pusher_select.redis_pubsub - r.formatter = settings.pusher_format.redis_pubsub - settings.rules[r.backend:upper()] = r - end - end - if settings.pusher_enabled.http then - if not settings.url then - rspamd_logger.errx(rspamd_config, 'No URL is specified') - settings.pusher_enabled.http = nil - else - local r = {} - r.backend = 'http' - r.url = settings.url - r.mime_type = settings.mime_type - r.defer = settings.defer - r.selector = settings.pusher_select.http - r.formatter = settings.pusher_format.http - settings.rules[r.backend:upper()] = r - end - end - if settings.pusher_enabled.send_mail then - if not (settings.mail_to and settings.smtp) then - rspamd_logger.errx(rspamd_config, 'No mail_to and/or smtp setting is specified') - settings.pusher_enabled.send_mail = nil - else - local r = {} - r.backend = 'send_mail' - r.mail_to = settings.mail_to - r.mail_from = settings.mail_from - r.helo = settings.hello - r.smtp = settings.smtp - r.smtp_port = settings.smtp_port - r.email_template = settings.email_template - r.defer = settings.defer - r.selector = settings.pusher_select.send_mail - r.formatter = settings.pusher_format.send_mail - settings.rules[r.backend:upper()] = r - end - end - if not next(settings.pusher_enabled) then - rspamd_logger.errx(rspamd_config, 'No push backend enabled') - return - end -elseif not next(settings.rules) then - lua_util.debugm(N, rspamd_config, 'No rules enabled') - return -end -if not settings.rules or not next(settings.rules) then - rspamd_logger.errx(rspamd_config, 'No rules enabled') - return -end -local backend_required_elements = { - http = { - 'url', - }, - smtp = { - 'mail_to', - 'smtp', - }, - redis_pubsub = { - 'channel', - }, -} -local check_element = { - selector = function(k, v) - if not selectors[v] then - rspamd_logger.errx(rspamd_config, 'Rule %s has invalid selector %s', k, v) - return false - else - return true - end - end, - formatter = function(k, v) - if not formatters[v] then - rspamd_logger.errx(rspamd_config, 'Rule %s has invalid formatter %s', k, v) - return false - else - return true - end - end, -} -local backend_check = { - default = function(k, rule) - local reqset = backend_required_elements[rule.backend] - if reqset then - for _, e in ipairs(reqset) do - if not rule[e] then - rspamd_logger.errx(rspamd_config, 'Rule %s misses required setting %s', k, e) - settings.rules[k] = nil - end - end - end - for sett, v in pairs(rule) do - local f = check_element[sett] - if f then - if not f(sett, v) then - settings.rules[k] = nil - end - end - end - end, -} -backend_check.redis_pubsub = function(k, rule) - if not redis_params then - redis_params = rspamd_parse_redis_server(N) - end - if not redis_params then - rspamd_logger.errx(rspamd_config, 'No redis servers are specified') - settings.rules[k] = nil - else - backend_check.default(k, rule) - end -end -setmetatable(backend_check, { - __index = function() - return backend_check.default - end, -}) -for k, v in pairs(settings.rules) do - if type(v) == 'table' then - local backend = v.backend - if not backend then - rspamd_logger.errx(rspamd_config, 'Rule %s has no backend', k) - settings.rules[k] = nil - elseif not pushers[backend] then - rspamd_logger.errx(rspamd_config, 'Rule %s has invalid backend %s', k, backend) - settings.rules[k] = nil - else - local f = backend_check[backend] - f(k, v) - end - else - rspamd_logger.errx(rspamd_config, 'Rule %s has bad type: %s', k, type(v)) - settings.rules[k] = nil - end -end - -local function gen_exporter(rule) - return function (task) - if task:has_flag('skip') then return end - local selector = rule.selector or 'default' - local selected = selectors[selector](task) - if selected then - lua_util.debugm(N, task, 'Message selected for processing') - local formatter = rule.formatter or 'default' - local formatted, extra = formatters[formatter](task, rule) - if formatted then - pushers[rule.backend](task, formatted, rule, extra) - else - lua_util.debugm(N, task, 'Formatter [%s] returned non-truthy value [%s]', formatter, formatted) - end - else - lua_util.debugm(N, task, 'Selector [%s] returned non-truthy value [%s]', selector, selected) - end - end -end - -if not next(settings.rules) then - rspamd_logger.errx(rspamd_config, 'No rules enabled') - lua_util.disable_module(N, "config") -end -for k, r in pairs(settings.rules) do - rspamd_config:register_symbol({ - name = 'EXPORT_METADATA_' .. k, - type = 'idempotent', - callback = gen_exporter(r), - priority = 10, - flags = 'empty,explicit_disable,ignore_passthrough', - }) -end diff --git a/data/Dockerfiles/sogo/Dockerfile b/data/Dockerfiles/sogo/Dockerfile index 59fc6680..7b8b1c71 100644 --- a/data/Dockerfiles/sogo/Dockerfile +++ b/data/Dockerfiles/sogo/Dockerfile @@ -1,12 +1,13 @@ -FROM debian:bullseye-slim -LABEL maintainer "The Infrastructure Company GmbH GmbH " +FROM debian:bookworm-slim + +LABEL maintainer="The Infrastructure Company GmbH " ARG DEBIAN_FRONTEND=noninteractive -ARG DEBIAN_VERSION=bullseye +ARG DEBIAN_VERSION=bookworm ARG SOGO_DEBIAN_REPOSITORY=http://www.axis.cz/linux/debian # renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?.*)$ ARG GOSU_VERSION=1.17 -ENV LC_ALL C +ENV LC_ALL=C # Prerequisites RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \ @@ -54,4 +55,4 @@ RUN chmod +x /bootstrap-sogo.sh \ ENTRYPOINT ["/docker-entrypoint.sh"] -CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf \ No newline at end of file +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] \ No newline at end of file diff --git a/data/Dockerfiles/sogo/bootstrap-sogo.sh b/data/Dockerfiles/sogo/bootstrap-sogo.sh index aa15525c..51880ea6 100755 --- a/data/Dockerfiles/sogo/bootstrap-sogo.sh +++ b/data/Dockerfiles/sogo/bootstrap-sogo.sh @@ -1,7 +1,7 @@ #!/bin/bash # Wait for MySQL to warm-up -while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do +while ! mariadb-admin status --ssl=false --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do echo "Waiting for database to come up..." sleep 2 done @@ -150,6 +150,8 @@ cat < /var/lib/sogo/GNUstep/Defaults/sogod.plist YES SOGoEncryptionKey ${RAND_PASS} + OCSAdminURL + mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_admin OCSCacheFolderURL mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_cache_folder OCSEMailAlarmsFolderURL diff --git a/data/Dockerfiles/sogo/syslog-ng-redis_slave.conf b/data/Dockerfiles/sogo/syslog-ng-redis_slave.conf index 9b460bd3..7abfc4b5 100644 --- a/data/Dockerfiles/sogo/syslog-ng-redis_slave.conf +++ b/data/Dockerfiles/sogo/syslog-ng-redis_slave.conf @@ -1,4 +1,4 @@ -@version: 3.28 +@version: 3.38 @include "scl.conf" options { chain_hostnames(off); diff --git a/data/Dockerfiles/sogo/syslog-ng.conf b/data/Dockerfiles/sogo/syslog-ng.conf index 889a3f32..f16a2920 100644 --- a/data/Dockerfiles/sogo/syslog-ng.conf +++ b/data/Dockerfiles/sogo/syslog-ng.conf @@ -1,4 +1,4 @@ -@version: 3.28 +@version: 3.38 @include "scl.conf" options { chain_hostnames(off); diff --git a/data/Dockerfiles/solr/solr.sh b/data/Dockerfiles/solr/solr.sh index 1c5c6f51..03ab7912 100755 --- a/data/Dockerfiles/solr/solr.sh +++ b/data/Dockerfiles/solr/solr.sh @@ -1,7 +1,15 @@ #!/bin/bash -if [[ "${SKIP_SOLR}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then +if [[ "${FLATCURVE_EXPERIMENTAL}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then + echo "FLATCURVE_EXPERIMENTAL=y, skipping Solr but enabling Flatcurve as FTS for Dovecot!" + echo "Solr will be removed in the future!" + sleep 365d + exit 0 +elif [[ "${SKIP_SOLR}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then echo "SKIP_SOLR=y, skipping Solr..." + echo "HINT: You could try the newer FTS Backend Flatcurve, which is currently in experimental state..." + echo "Simply set FLATCURVE_EXPERIMENTAL=y inside your mailcow.conf and restart the stack afterwards!" + echo "Solr will be removed in the future!" sleep 365d exit 0 fi @@ -57,5 +65,11 @@ if [[ "${1}" == "--bootstrap" ]]; then exit 0 fi +echo "Starting up Solr..." +echo -e "\e[31mSolr is deprecated! You can try the new FTS System now by enabling FLATCURVE_EXPERIMENTAL=y inside mailcow.conf and restarting the stack\e[0m" +echo -e "\e[31mSolr will be removed completely soon!\e[0m" + +sleep 15 + exec gosu solr solr-foreground diff --git a/data/Dockerfiles/unbound/Dockerfile b/data/Dockerfiles/unbound/Dockerfile index 3090895b..7e4f18de 100644 --- a/data/Dockerfiles/unbound/Dockerfile +++ b/data/Dockerfiles/unbound/Dockerfile @@ -1,18 +1,21 @@ -FROM alpine:3.18 +FROM alpine:3.20 -LABEL maintainer "The Infrastructure Company GmbH GmbH " +LABEL maintainer = "The Infrastructure Company GmbH " RUN apk add --update --no-cache \ curl \ bind-tools \ + coreutils \ unbound \ bash \ openssl \ drill \ tzdata \ + syslog-ng \ + supervisor \ && curl -o /etc/unbound/root.hints https://www.internic.net/domain/named.cache \ && chown root:unbound /etc/unbound \ - && adduser unbound tty \ + && adduser unbound tty \ && chmod 775 /etc/unbound EXPOSE 53/udp 53/tcp @@ -21,9 +24,13 @@ COPY docker-entrypoint.sh /docker-entrypoint.sh # healthcheck (dig, ping) COPY healthcheck.sh /healthcheck.sh +COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf +COPY supervisord.conf /etc/supervisor/supervisord.conf +COPY stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh + RUN chmod +x /healthcheck.sh -HEALTHCHECK --interval=30s --timeout=30s CMD [ "/healthcheck.sh" ] +HEALTHCHECK --interval=30s --timeout=10s \ + CMD sh -c '[ -f /tmp/healthcheck_status ] && [ "$(cat /tmp/healthcheck_status)" -eq 0 ] || exit 1' ENTRYPOINT ["/docker-entrypoint.sh"] - -CMD ["/usr/sbin/unbound"] +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] diff --git a/data/Dockerfiles/unbound/healthcheck.sh b/data/Dockerfiles/unbound/healthcheck.sh index 8da79bd7..7d918112 100644 --- a/data/Dockerfiles/unbound/healthcheck.sh +++ b/data/Dockerfiles/unbound/healthcheck.sh @@ -1,72 +1,102 @@ #!/bin/bash -# Skip Unbound (DNS Resolver) Healthchecks (NOT Recommended!) -if [[ "${SKIP_UNBOUND_HEALTHCHECK}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then - SKIP_UNBOUND_HEALTHCHECK=y -fi +STATUS_FILE="/tmp/healthcheck_status" +RUNS=0 -# Declare log function for logfile inside container -function log_to_file() { - echo "$(date +"%Y-%m-%d %H:%M:%S"): $1" > /var/log/healthcheck.log +# Declare log function for logfile to stdout +function log_to_stdout() { +echo "$(date +"%Y-%m-%d %H:%M:%S"): $1" } # General Ping function to check general pingability function check_ping() { - declare -a ipstoping=("1.1.1.1" "8.8.8.8" "9.9.9.9") +declare -a ipstoping=("1.1.1.1" "8.8.8.8" "9.9.9.9") +local fail_tolerance=1 +local failures=0 - for ip in "${ipstoping[@]}" ; do - ping -q -c 3 -w 5 "$ip" - if [ $? -ne 0 ]; then - log_to_file "Healthcheck: Couldn't ping $ip for 5 seconds... Gave up!" - log_to_file "Please check your internet connection or firewall rules to fix this error, because a simple ping test should always go through from the unbound container!" - return 1 - fi +for ip in "${ipstoping[@]}" ; do + success=false + for ((i=1; i<=3; i++)); do + ping -q -c 3 -w 5 "$ip" > /dev/null + if [ $? -eq 0 ]; then + success=true + break + else + log_to_stdout "Healthcheck: Failed to ping $ip on attempt $i. Trying again..." + fi done + + if [ "$success" = false ]; then + log_to_stdout "Healthcheck: Couldn't ping $ip after 3 attempts. Marking this IP as failed." + ((failures++)) + fi +done + +if [ $failures -gt $fail_tolerance ]; then + log_to_stdout "Healthcheck: Too many ping failures ($fail_tolerance failures allowed, you got $failures failures), marking Healthcheck as unhealthy..." + return 1 +fi + +return 0 - log_to_file "Healthcheck: Ping Checks WORKING properly!" - return 0 } # General DNS Resolve Check against Unbound Resolver himself function check_dns() { - declare -a domains=("mailcow.email" "github.com" "hub.docker.com") +declare -a domains=("fuzzy.mailcow.email" "github.com" "hub.docker.com") +local fail_tolerance=1 +local failures=0 - for domain in "${domains[@]}" ; do - for ((i=1; i<=3; i++)); do - dig +short +timeout=2 +tries=1 "$domain" @127.0.0.1 > /dev/null - if [ $? -ne 0 ]; then - log_to_file "Healthcheck: DNS Resolution Failed on $i attempt! Trying again..." - if [ $i -eq 3 ]; then - log_to_file "Healthcheck: DNS Resolution not possible after $i attempts... Gave up!" - log_to_file "Maybe check your outbound firewall, as it needs to resolve DNS over TCP AND UDP!" - return 1 - fi +for domain in "${domains[@]}" ; do + success=false + for ((i=1; i<=3; i++)); do + dig_output=$(dig +short +timeout=2 +tries=1 "$domain" @127.0.0.1 2>/dev/null) + dig_rc=$? + + if [ $dig_rc -ne 0 ] || [ -z "$dig_output" ]; then + log_to_stdout "Healthcheck: DNS Resolution Failed on attempt $i for $domain! Trying again..." + else + success=true + break fi - done done - - log_to_file "Healthcheck: DNS Resolver WORKING properly!" - return 0 + if [ "$success" = false ]; then + log_to_stdout "Healthcheck: DNS Resolution not possible after 3 attempts for $domain... Gave up!" + ((failures++)) + fi +done + +if [ $failures -gt $fail_tolerance ]; then + log_to_stdout "Healthcheck: Too many DNS failures ($fail_tolerance failures allowed, you got $failures failures), marking Healthcheck as unhealthy..." + return 1 +fi + +return 0 } -if [[ ${SKIP_UNBOUND_HEALTHCHECK} == "y" ]]; then - log_to_file "Healthcheck: ALL CHECKS WERE SKIPPED! Unbound is healthy!" - exit 0 -fi +while true; do -# run checks, if check is not returning 0 (return value if check is ok), healthcheck will exit with 1 (marked in docker as unhealthy) -check_ping + if [[ ${SKIP_UNBOUND_HEALTHCHECK} == "y" ]]; then + log_to_stdout "Healthcheck: ALL CHECKS WERE SKIPPED! Unbound is healthy!" + echo "0" > $STATUS_FILE + sleep 365d + fi -if [ $? -ne 0 ]; then - exit 1 -fi + # run checks, if check is not returning 0 (return value if check is ok), healthcheck will exit with 1 (marked in docker as unhealthy) + check_ping + PING_STATUS=$? -check_dns + check_dns + DNS_STATUS=$? -if [ $? -ne 0 ]; then - exit 1 -fi + if [ $PING_STATUS -ne 0 ] || [ $DNS_STATUS -ne 0 ]; then + echo "1" > $STATUS_FILE -log_to_file "Healthcheck: ALL CHECKS WERE SUCCESSFUL! Unbound is healthy!" -exit 0 \ No newline at end of file + else + echo "0" > $STATUS_FILE + fi + + sleep 30 + +done \ No newline at end of file diff --git a/data/Dockerfiles/unbound/stop-supervisor.sh b/data/Dockerfiles/unbound/stop-supervisor.sh new file mode 100755 index 00000000..acd40273 --- /dev/null +++ b/data/Dockerfiles/unbound/stop-supervisor.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +printf "READY\n"; + +while read line; do + echo "Processing Event: $line" >&2; + kill -3 $(cat "/var/run/supervisord.pid") +done < /dev/stdin + +rm -rf /tmp/healthcheck_status \ No newline at end of file diff --git a/data/Dockerfiles/unbound/supervisord.conf b/data/Dockerfiles/unbound/supervisord.conf new file mode 100644 index 00000000..b47c8b11 --- /dev/null +++ b/data/Dockerfiles/unbound/supervisord.conf @@ -0,0 +1,32 @@ +[supervisord] +nodaemon=true +user=root +pidfile=/var/run/supervisord.pid + +[program:syslog-ng] +command=/usr/sbin/syslog-ng --foreground --no-caps +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autostart=true + +[program:unbound] +command=/usr/sbin/unbound +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=true + +[program:unbound-healthcheck] +command=/bin/bash /healthcheck.sh +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=true + +[eventlistener:processes] +command=/usr/local/sbin/stop-supervisor.sh +events=PROCESS_STATE_STOPPED, PROCESS_STATE_EXITED, PROCESS_STATE_FATAL diff --git a/data/Dockerfiles/unbound/syslog-ng.conf b/data/Dockerfiles/unbound/syslog-ng.conf new file mode 100644 index 00000000..de858f9e --- /dev/null +++ b/data/Dockerfiles/unbound/syslog-ng.conf @@ -0,0 +1,21 @@ +@version: 4.5 +@include "scl.conf" +options { + chain_hostnames(off); + flush_lines(0); + use_dns(no); + use_fqdn(no); + owner("root"); group("adm"); perm(0640); + stats(freq(0)); + keep_timestamp(no); + bad_hostname("^gconfd$"); +}; +source s_dgram { + unix-dgram("/dev/log"); + internal(); +}; +destination d_stdout { pipe("/dev/stdout"); }; +log { + source(s_dgram); + destination(d_stdout); +}; diff --git a/data/Dockerfiles/watchdog/Dockerfile b/data/Dockerfiles/watchdog/Dockerfile index 73acde68..f8aa262b 100644 --- a/data/Dockerfiles/watchdog/Dockerfile +++ b/data/Dockerfiles/watchdog/Dockerfile @@ -1,5 +1,6 @@ -FROM alpine:3.18 -LABEL maintainer "The Infrastructure Company GmbH " +FROM alpine:3.20 + +LABEL maintainer = "The Infrastructure Company GmbH " # Installation RUN apk add --update \ @@ -36,4 +37,4 @@ RUN apk add --update \ COPY watchdog.sh /watchdog.sh COPY check_mysql_slavestatus.sh /usr/lib/nagios/plugins/check_mysql_slavestatus.sh -CMD /watchdog.sh +CMD ["/watchdog.sh"] diff --git a/data/Dockerfiles/watchdog/watchdog.sh b/data/Dockerfiles/watchdog/watchdog.sh index cb342c13..81d65d90 100755 --- a/data/Dockerfiles/watchdog/watchdog.sh +++ b/data/Dockerfiles/watchdog/watchdog.sh @@ -33,7 +33,7 @@ if [[ ! -p /tmp/com_pipe ]]; then fi # Wait for containers -while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do +while ! mariadb-admin status --ssl=false --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do echo "Waiting for SQL..." sleep 2 done @@ -169,9 +169,13 @@ function notify_error() { return 1 fi + # Escape subject and body (https://stackoverflow.com/a/2705678) + ESCAPED_SUBJECT=$(echo ${SUBJECT} | sed -e 's/[\/&]/\\&/g') + ESCAPED_BODY=$(echo ${BODY} | sed -e 's/[\/&]/\\&/g') + # Replace subject and body placeholders - WEBHOOK_BODY=$(echo ${WATCHDOG_NOTIFY_WEBHOOK_BODY} | sed "s/\$SUBJECT\|\${SUBJECT}/$SUBJECT/g" | sed "s/\$BODY\|\${BODY}/$BODY/g") - + WEBHOOK_BODY=$(echo ${WATCHDOG_NOTIFY_WEBHOOK_BODY} | sed -e "s/\$SUBJECT\|\${SUBJECT}/$ESCAPED_SUBJECT/g" -e "s/\$BODY\|\${BODY}/$ESCAPED_BODY/g") + # POST to webhook curl -X POST -H "Content-Type: application/json" ${CURL_VERBOSE} -d "${WEBHOOK_BODY}" ${WATCHDOG_NOTIFY_WEBHOOK} @@ -191,12 +195,12 @@ get_container_ip() { else sleep 0.5 # get long container id for exact match - CONTAINER_ID=($(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring == \"${1}\") | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id")) + CONTAINER_ID=($(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring == \"${1}\") | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id")) # returned id can have multiple elements (if scaled), shuffle for random test CONTAINER_ID=($(printf "%s\n" "${CONTAINER_ID[@]}" | shuf)) if [[ ! -z ${CONTAINER_ID} ]]; then for matched_container in "${CONTAINER_ID[@]}"; do - CONTAINER_IPS=($(curl --silent --insecure https://dockerapi/containers/${matched_container}/json | jq -r '.NetworkSettings.Networks[].IPAddress')) + CONTAINER_IPS=($(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${matched_container}/json | jq -r '.NetworkSettings.Networks[].IPAddress')) for ip_match in "${CONTAINER_IPS[@]}"; do # grep will do nothing if one of these vars is empty [[ -z ${ip_match} ]] && continue @@ -716,7 +720,7 @@ rspamd_checks() { From: watchdog@localhost Empty -' | usr/bin/curl --max-time 10 -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/scan | jq -rc .default.required_score | sed 's/\..*//' ) +' | usr/bin/curl --max-time 10 -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/scan | jq -rc .default.required_score | sed 's/\..*//' ) if [[ ${SCORE} -ne 9999 ]]; then echo "Rspamd settings check failed, score returned: ${SCORE}" 2>> /tmp/rspamd-mailcow 1>&2 err_count=$(( ${err_count} + 1)) @@ -1095,12 +1099,12 @@ while true; do elif [[ ${com_pipe_answer} =~ .+-mailcow ]]; then kill -STOP ${BACKGROUND_TASKS[*]} sleep 10 - CONTAINER_ID=$(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"${com_pipe_answer}\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id") + CONTAINER_ID=$(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"${com_pipe_answer}\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id") if [[ ! -z ${CONTAINER_ID} ]]; then if [[ "${com_pipe_answer}" == "php-fpm-mailcow" ]]; then - HAS_INITDB=$(curl --silent --insecure -XPOST https://dockerapi/containers/${CONTAINER_ID}/top | jq '.msg.Processes[] | contains(["php -c /usr/local/etc/php -f /web/inc/init_db.inc.php"])' | grep true) + HAS_INITDB=$(curl --silent --insecure -XPOST https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${CONTAINER_ID}/top | jq '.msg.Processes[] | contains(["php -c /usr/local/etc/php -f /web/inc/init_db.inc.php"])' | grep true) fi - S_RUNNING=$(($(date +%s) - $(curl --silent --insecure https://dockerapi/containers/${CONTAINER_ID}/json | jq .State.StartedAt | xargs -n1 date +%s -d))) + S_RUNNING=$(($(date +%s) - $(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${CONTAINER_ID}/json | jq .State.StartedAt | xargs -n1 date +%s -d))) if [ ${S_RUNNING} -lt 360 ]; then log_msg "Container is running for less than 360 seconds, skipping action..." elif [[ ! -z ${HAS_INITDB} ]]; then @@ -1108,7 +1112,7 @@ while true; do sleep 60 else log_msg "Sending restart command to ${CONTAINER_ID}..." - curl --silent --insecure -XPOST https://dockerapi/containers/${CONTAINER_ID}/restart + curl --silent --insecure -XPOST https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${CONTAINER_ID}/restart notify_error "${com_pipe_answer}" log_msg "Wait for restarted container to settle and continue watching..." sleep 35 diff --git a/data/assets/templates/pw_reset_html.tpl b/data/assets/templates/pw_reset_html.tpl new file mode 100644 index 00000000..481f8cbe --- /dev/null +++ b/data/assets/templates/pw_reset_html.tpl @@ -0,0 +1,29 @@ + + + + + + +Hello {{username2}},

+ +Somebody requested a new password for the {{hostname}} account associated with {{username}}.
+Date of the password reset request: {{date}}

+ +You can reset your password by clicking the link below:
+{{link}}

+ +The link will be valid for the next {{token_lifetime}} minutes.

+ +If you did not request a new password, please ignore this email.
+ + diff --git a/data/assets/templates/pw_reset_text.tpl b/data/assets/templates/pw_reset_text.tpl new file mode 100644 index 00000000..fabe1e71 --- /dev/null +++ b/data/assets/templates/pw_reset_text.tpl @@ -0,0 +1,11 @@ +Hello {{username2}}, + +Somebody requested a new password for the {{hostname}} account associated with {{username}}. +Date of the password reset request: {{date}} + +You can reset your password by clicking the link below: +{{link}} + +The link will be valid for the next {{token_lifetime}} minutes. + +If you did not request a new password, please ignore this email. diff --git a/data/conf/dovecot/dovecot.conf b/data/conf/dovecot/dovecot.conf index 6b7b2fa6..3a76a521 100644 --- a/data/conf/dovecot/dovecot.conf +++ b/data/conf/dovecot/dovecot.conf @@ -10,6 +10,7 @@ auth_mechanisms = plain login #mail_debug = yes #auth_debug = yes +#log_debug = category=fts-flatcurve # Activate Logging for Flatcurve FTS Searchings log_path = syslog disable_plaintext_auth = yes # Uncomment on NFS share @@ -194,9 +195,6 @@ plugin { acl_shared_dict = file:/var/vmail/shared-mailboxes.db acl = vfile acl_user = %u - fts = solr - fts_autoindex = yes - fts_solr = url=http://solr:8983/solr/dovecot-fts/ quota = dict:Userquota::proxy::sqlquota quota_rule2 = Trash:storage=+100%% sieve = /var/vmail/sieve/%u.sieve @@ -305,6 +303,7 @@ replication_dsync_parameters = -d -l 30 -U -n INBOX !include_try /etc/dovecot/extra.conf !include_try /etc/dovecot/sogo-sso.conf !include_try /etc/dovecot/shared_namespace.conf +!include_try /etc/dovecot/conf.d/fts.conf # default_client_limit = 10400 default_vsz_limit = 1024 M diff --git a/data/conf/dovecot/dovecot.folders.conf b/data/conf/dovecot/dovecot.folders.conf index 99c9670f..fa687267 100644 --- a/data/conf/dovecot/dovecot.folders.conf +++ b/data/conf/dovecot/dovecot.folders.conf @@ -289,5 +289,20 @@ namespace inbox { mailbox "Kladde" { special_use = \Drafts } + mailbox "Πρόχειρα" { + special_use = \Drafts + } + mailbox "Απεσταλμένα" { + special_use = \Sent + } + mailbox "Κάδος απορριμάτων" { + special_use = \Trash + } + mailbox "Ανεπιθύμητα" { + special_use = \Junk + } + mailbox "Αρχειοθετημένα" { + special_use = \Archive + } prefix = -} \ No newline at end of file +} diff --git a/data/conf/postfix/anonymize_headers.pcre b/data/conf/postfix/anonymize_headers.pcre index 061a4bc0..1a59d53a 100644 --- a/data/conf/postfix/anonymize_headers.pcre +++ b/data/conf/postfix/anonymize_headers.pcre @@ -1,6 +1,6 @@ if /^\s*Received:.*Authenticated sender.*\(Postcow\)/ #/^Received: from .*? \([\w-.]* \[.*?\]\)\s+\(Authenticated sender: (.+)\)\s+by.+\(Postcow\) with (E?SMTPS?A?) id ([A-F0-9]+).+;.*?/ -/^Received: from .*? \([\w-.]* \[.*?\]\)(.*|\n.*)\(Authenticated sender: (.+)\)\s+by.+\(Postcow\) with (.*)/ +/^Received: from .*? \([\w\-.]* \[.*?\]\)(.*|\n.*)\(Authenticated sender: (.+)\)\s+by.+\(Postcow\) with (.*)/ REPLACE Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with $3 endif if /^\s*Received: from.* \(.*dovecot-mailcow.*mailcow-network.*\).*\(Postcow\)/ diff --git a/data/conf/postfix/main.cf b/data/conf/postfix/main.cf index 572300db..6a87f2ec 100644 --- a/data/conf/postfix/main.cf +++ b/data/conf/postfix/main.cf @@ -114,14 +114,14 @@ smtpd_tls_loglevel = 1 # Mandatory protocols and ciphers are used when a connections is enforced to use TLS # Does _not_ apply to enforced incoming TLS settings per mailbox -smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 -lmtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 -smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 +smtp_tls_mandatory_protocols = >=TLSv1.2 +lmtp_tls_mandatory_protocols = >=TLSv1.2 +smtpd_tls_mandatory_protocols = >=TLSv1.2 smtpd_tls_mandatory_ciphers = high -smtp_tls_protocols = !SSLv2, !SSLv3 -lmtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 -smtpd_tls_protocols = !SSLv2, !SSLv3 +smtp_tls_protocols = >=TLSv1.2 +lmtp_tls_protocols = >=TLSv1.2 +smtpd_tls_protocols = >=TLSv1.2 smtpd_tls_security_level = may tls_preempt_cipherlist = yes @@ -163,12 +163,12 @@ transport_maps = pcre:/opt/postfix/conf/custom_transport.pcre, proxy:mysql:/opt/postfix/conf/sql/mysql_transport_maps.cf smtp_sasl_auth_soft_bounce = no postscreen_discard_ehlo_keywords = silent-discard, dsn, chunking -smtpd_discard_ehlo_keywords = chunking -compatibility_level = 2 +smtpd_discard_ehlo_keywords = chunking, silent-discard +compatibility_level = 3.7 smtputf8_enable = no # Define protocols for SMTPS and submission service -submission_smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 -smtps_smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 +submission_smtpd_tls_mandatory_protocols = >=TLSv1.2 +smtps_smtpd_tls_mandatory_protocols = >=TLSv1.2 parent_domain_matches_subdomains = debug_peer_list,fast_flush_domains,mynetworks,qmqpd_authorized_clients # DO NOT EDIT ANYTHING BELOW # diff --git a/data/conf/postfix/master.cf b/data/conf/postfix/master.cf index 63ce875d..df91a390 100644 --- a/data/conf/postfix/master.cf +++ b/data/conf/postfix/master.cf @@ -4,7 +4,6 @@ smtp inet n - n - 1 postscreen -o postscreen_upstream_proxy_protocol=haproxy -o syslog_name=haproxy smtpd pass - - n - - smtpd - -o smtpd_helo_restrictions=permit_mynetworks,reject_non_fqdn_helo_hostname -o smtpd_sasl_auth_enable=no -o smtpd_sender_restrictions=permit_mynetworks,reject_unlisted_sender,reject_unknown_sender_domain diff --git a/data/conf/postfix/postscreen_access.cidr b/data/conf/postfix/postscreen_access.cidr index e8273ecc..78ffc3a8 100644 --- a/data/conf/postfix/postscreen_access.cidr +++ b/data/conf/postfix/postscreen_access.cidr @@ -1,6 +1,6 @@ -# Whitelist generated by Postwhite v3.4 on Thu Feb 1 00:13:50 UTC 2024 +# Whitelist generated by Postwhite v3.4 on Thu Aug 1 00:16:45 UTC 2024 # https://github.com/stevejenkins/postwhite/ -# 2089 total rules +# 1954 total rules 2a00:1450:4000::/36 permit 2a01:111:f400::/48 permit 2a01:111:f403:8000::/50 permit @@ -13,40 +13,39 @@ 2.207.151.53 permit 3.70.123.177 permit 3.93.157.0/24 permit +3.94.40.108 permit 3.129.120.190 permit -3.137.16.58 permit 3.210.190.0/24 permit 8.20.114.31 permit 8.25.194.0/23 permit 8.25.196.0/23 permit -8.39.54.0/23 permit -8.40.222.0/23 permit +10.162.0.0/16 permit 12.130.86.238 permit -13.70.32.43 permit -13.72.50.45 permit -13.74.143.28 permit -13.78.233.182 permit -13.92.31.129 permit 13.110.208.0/21 permit 13.110.209.0/24 permit 13.110.216.0/22 permit 13.110.224.0/20 permit 13.111.0.0/16 permit +13.111.191.0/24 permit 15.200.21.50 permit 15.200.44.248 permit 15.200.201.185 permit +17.41.0.0/16 permit 17.57.155.0/24 permit 17.57.156.0/24 permit 17.58.0.0/16 permit +17.142.0.0/15 permit 18.156.89.250 permit 18.157.243.190 permit 18.194.95.56 permit 18.198.96.88 permit 18.208.124.128/25 permit 18.216.232.154 permit -18.234.1.244 permit +18.235.27.253 permit 18.236.40.242 permit +18.236.56.161 permit 20.51.6.32/30 permit +20.51.98.61 permit 20.52.52.2 permit 20.52.128.133 permit 20.59.80.4/30 permit @@ -64,10 +63,8 @@ 20.107.239.64/30 permit 20.112.250.133 permit 20.118.139.208/30 permit -20.185.213.160/27 permit -20.185.213.224/27 permit +20.141.10.196 permit 20.185.214.0/27 permit -20.185.214.2 permit 20.185.214.32/27 permit 20.185.214.64/27 permit 20.231.239.246 permit @@ -91,38 +88,37 @@ 27.123.204.172 permit 27.123.204.188/30 permit 27.123.204.192 permit -27.123.206.0/24 permit 27.123.206.50/31 permit 27.123.206.56/29 permit 27.123.206.76/30 permit 27.123.206.80/28 permit 31.25.48.222 permit 34.195.217.107 permit -34.202.239.6 permit 34.212.163.75 permit 34.215.104.144 permit +34.218.116.3 permit 34.225.212.172 permit -34.247.168.44 permit 35.161.32.253 permit 35.167.93.243 permit 35.176.132.251 permit 35.190.247.0/24 permit 35.191.0.0/16 permit +35.205.92.9 permit +35.242.169.159 permit 37.218.248.47 permit 37.218.249.47 permit 37.218.251.62 permit 39.156.163.64/29 permit -40.71.187.0/24 permit 40.92.0.0/15 permit 40.92.0.0/16 permit 40.107.0.0/16 permit 40.112.65.63 permit 43.228.184.0/22 permit 44.206.138.57 permit -44.209.42.157 permit +44.217.45.156 permit 44.236.56.93 permit 44.238.220.251 permit -46.19.168.0/23 permit +46.19.170.16 permit 46.226.48.0/21 permit 46.228.36.37 permit 46.228.36.38/31 permit @@ -162,7 +158,6 @@ 46.228.38.144/29 permit 46.228.38.152/31 permit 46.228.38.154 permit -46.228.39.0/24 permit 46.228.39.64/27 permit 46.228.39.96/30 permit 46.228.39.100/30 permit @@ -183,30 +178,28 @@ 50.18.125.237 permit 50.18.126.162 permit 50.31.32.0/19 permit -50.56.130.220 permit -50.56.130.221 permit -51.137.58.21 permit -51.140.75.55 permit -51.144.100.179 permit +50.31.36.205 permit +50.56.130.220/30 permit +52.1.14.157 permit 52.5.230.59 permit 52.27.5.72 permit 52.27.28.47 permit 52.28.63.81 permit 52.36.138.31 permit 52.37.142.146 permit +52.50.24.208 permit 52.58.216.183 permit 52.59.143.3 permit 52.60.41.5 permit 52.60.115.116 permit 52.61.91.9 permit 52.71.0.205 permit -52.82.172.0/22 permit 52.94.124.0/28 permit 52.95.48.152/29 permit 52.95.49.88/29 permit 52.96.91.34 permit 52.96.111.82 permit -52.96.214.50 permit +52.96.172.98 permit 52.96.222.194 permit 52.96.222.226 permit 52.96.223.2 permit @@ -215,8 +208,6 @@ 52.100.0.0/14 permit 52.103.0.0/17 permit 52.119.213.144/28 permit -52.160.39.140 permit -52.165.175.144 permit 52.185.106.240/28 permit 52.200.59.0/24 permit 52.205.61.79 permit @@ -227,37 +218,29 @@ 52.222.75.85 permit 52.222.89.228 permit 52.234.172.96/28 permit +52.235.253.128 permit 52.236.28.240/28 permit -52.244.206.214 permit -52.247.53.144 permit -52.250.107.196 permit -52.250.126.174 permit 54.90.148.255 permit +54.165.19.38 permit 54.172.97.247 permit 54.174.52.0/24 permit -54.174.53.128/30 permit 54.174.57.0/24 permit 54.174.59.0/24 permit 54.174.60.0/23 permit 54.174.63.0/24 permit 54.186.193.102 permit 54.191.223.56 permit -54.194.61.95 permit -54.195.113.45 permit 54.213.20.246 permit 54.214.39.184 permit -54.216.77.168 permit -54.221.227.204 permit 54.240.0.0/18 permit 54.240.64.0/19 permit 54.240.96.0/19 permit 54.241.16.209 permit 54.244.54.130 permit 54.244.242.0/24 permit -54.246.232.180 permit 54.255.61.23 permit 62.13.128.0/24 permit -62.13.128.150 permit +62.13.128.196 permit 62.13.129.128/25 permit 62.13.136.0/22 permit 62.13.140.0/22 permit @@ -265,14 +248,13 @@ 62.13.148.0/23 permit 62.13.150.0/23 permit 62.13.152.0/23 permit +62.13.159.196 permit 62.17.146.128/26 permit 62.179.121.0/24 permit 62.201.172.0/27 permit 62.201.172.32/27 permit 62.253.227.114 permit -63.32.13.159 permit 63.80.14.0/23 permit -63.111.28.137 permit 63.128.21.0/24 permit 63.143.57.128/25 permit 63.143.59.128/25 permit @@ -285,24 +267,9 @@ 64.79.155.193 permit 64.79.155.205 permit 64.79.155.206 permit -64.89.44.85 permit -64.89.45.80 permit -64.89.45.194 permit -64.89.45.196 permit 64.127.115.252 permit 64.132.88.0/23 permit 64.132.92.0/24 permit -64.147.123.17 permit -64.147.123.18 permit -64.147.123.19 permit -64.147.123.20 permit -64.147.123.21 permit -64.147.123.24 permit -64.147.123.25 permit -64.147.123.26 permit -64.147.123.27 permit -64.147.123.28 permit -64.147.123.29 permit 64.147.123.128/27 permit 64.207.219.7 permit 64.207.219.8 permit @@ -357,26 +324,10 @@ 65.110.161.77 permit 65.123.29.213 permit 65.123.29.220 permit -65.154.166.0/24 permit 65.212.180.36 permit 66.102.0.0/20 permit -66.111.4.25 permit -66.111.4.26 permit -66.111.4.27 permit -66.111.4.28 permit -66.111.4.29 permit -66.111.4.221 permit -66.111.4.222 permit -66.111.4.224 permit -66.111.4.225 permit -66.111.4.229 permit -66.111.4.230 permit 66.119.150.192/26 permit -66.135.202.0/27 permit -66.135.215.0/24 permit -66.135.222.1 permit 66.162.193.226/31 permit -66.163.184.0/21 permit 66.163.184.0/24 permit 66.163.185.0/24 permit 66.163.186.0/24 permit @@ -389,7 +340,6 @@ 66.196.80.112/28 permit 66.196.80.144/29 permit 66.196.80.193 permit -66.196.81.0/24 permit 66.196.81.104/29 permit 66.196.81.112/29 permit 66.196.81.120 permit @@ -432,12 +382,10 @@ 66.249.80.0/20 permit 67.23.31.6 permit 67.72.99.26 permit -67.195.22.0/24 permit 67.195.22.113 permit 67.195.22.116/30 permit 67.195.23.144/30 permit 67.195.23.148 permit -67.195.60.0/24 permit 67.195.60.45 permit 67.195.60.46/31 permit 67.195.60.48/31 permit @@ -445,7 +393,6 @@ 67.195.60.146 permit 67.195.60.155 permit 67.195.60.156 permit -67.195.87.0/24 permit 67.195.87.64 permit 67.195.87.81 permit 67.195.87.82/31 permit @@ -470,7 +417,6 @@ 67.228.37.4/30 permit 67.231.145.42 permit 67.231.153.30 permit -68.142.230.0/24 permit 68.142.230.64/31 permit 68.142.230.69 permit 68.142.230.70/31 permit @@ -496,9 +442,7 @@ 69.171.232.0/24 permit 69.171.244.0/23 permit 70.37.151.128/25 permit -70.42.149.0/24 permit 70.42.149.35 permit -72.3.237.64/28 permit 72.14.192.0/18 permit 72.21.192.0/19 permit 72.21.217.142 permit @@ -529,7 +473,6 @@ 72.30.237.180/30 permit 72.30.237.184/31 permit 72.30.237.204/30 permit -72.30.238.0/23 permit 72.30.238.116/30 permit 72.30.238.120/31 permit 72.30.238.128 permit @@ -560,12 +503,7 @@ 72.30.239.228/31 permit 72.30.239.244/30 permit 72.30.239.248/31 permit -72.34.168.76 permit -72.34.168.80 permit -72.34.168.85 permit -72.34.168.86 permit 72.52.72.32/28 permit -74.6.128.0/21 permit 74.6.128.0/24 permit 74.6.129.0/24 permit 74.6.130.0/24 permit @@ -600,7 +538,6 @@ 75.2.70.75 permit 76.223.128.0/19 permit 76.223.176.0/20 permit -77.238.176.0/22 permit 77.238.176.0/24 permit 77.238.177.0/24 permit 77.238.178.0/24 permit @@ -621,7 +558,6 @@ 77.238.189.142 permit 77.238.189.146/31 permit 77.238.189.148/30 permit -81.7.169.128/25 permit 81.223.46.0/27 permit 82.165.159.2 permit 82.165.159.3 permit @@ -642,8 +578,6 @@ 84.116.50.0/23 permit 85.158.136.0/21 permit 86.61.88.25 permit -87.198.219.130 permit -87.198.219.153 permit 87.238.80.0/21 permit 87.248.103.12 permit 87.248.103.21 permit @@ -683,6 +617,7 @@ 87.253.232.0/21 permit 89.22.108.0/24 permit 91.211.240.0/22 permit +94.169.2.0/23 permit 94.245.112.0/27 permit 94.245.112.10/31 permit 95.131.104.0/21 permit @@ -696,7 +631,6 @@ 98.136.44.181 permit 98.136.44.182/31 permit 98.136.44.184 permit -98.136.164.0/24 permit 98.136.164.36/31 permit 98.136.164.64/29 permit 98.136.164.72/30 permit @@ -704,7 +638,6 @@ 98.136.164.78 permit 98.136.172.32/30 permit 98.136.172.36/31 permit -98.136.185.0/24 permit 98.136.185.29 permit 98.136.185.42/31 permit 98.136.185.46 permit @@ -739,7 +672,6 @@ 98.136.215.184 permit 98.136.215.208/30 permit 98.136.215.212/31 permit -98.136.217.0/24 permit 98.136.217.1 permit 98.136.217.2 permit 98.136.217.3 permit @@ -749,14 +681,12 @@ 98.136.217.12/30 permit 98.136.217.16/30 permit 98.136.217.20/30 permit -98.136.218.0/24 permit 98.136.218.39 permit 98.136.218.40/29 permit 98.136.218.48/28 permit 98.136.218.67 permit 98.136.218.68/30 permit 98.136.218.72/30 permit -98.137.12.0/24 permit 98.137.12.48/30 permit 98.137.12.52/31 permit 98.137.12.54 permit @@ -794,7 +724,6 @@ 98.137.13.132 permit 98.137.13.137 permit 98.137.13.138 permit -98.137.64.0/21 permit 98.137.64.0/24 permit 98.137.65.0/24 permit 98.137.66.0/24 permit @@ -818,7 +747,6 @@ 98.138.83.176/31 permit 98.138.83.179 permit 98.138.83.180/31 permit -98.138.84.0/22 permit 98.138.84.37 permit 98.138.84.38/31 permit 98.138.84.40/29 permit @@ -859,7 +787,6 @@ 98.138.87.148/31 permit 98.138.87.192/30 permit 98.138.87.196/31 permit -98.138.88.0/22 permit 98.138.88.105 permit 98.138.88.106 permit 98.138.88.128/30 permit @@ -899,7 +826,6 @@ 98.138.91.2/31 permit 98.138.91.4/31 permit 98.138.91.6 permit -98.138.100.0/23 permit 98.138.100.220/30 permit 98.138.100.224/30 permit 98.138.100.228/31 permit @@ -909,7 +835,6 @@ 98.138.104.100 permit 98.138.104.112/30 permit 98.138.104.116 permit -98.138.120.0/24 permit 98.138.120.36/30 permit 98.138.120.48/28 permit 98.138.197.46/31 permit @@ -1002,12 +927,10 @@ 98.138.213.238/31 permit 98.138.213.240/31 permit 98.138.213.242 permit -98.138.215.0/24 permit 98.138.215.12/30 permit 98.138.215.16/28 permit 98.138.217.216/30 permit 98.138.217.220/31 permit -98.138.226.0/24 permit 98.138.226.30/31 permit 98.138.226.56/29 permit 98.138.226.64/30 permit @@ -1033,21 +956,18 @@ 98.138.227.108/31 permit 98.138.227.128/30 permit 98.138.227.132/31 permit -98.138.229.0/24 permit 98.138.229.24/29 permit 98.138.229.32/31 permit 98.138.229.122/31 permit 98.138.229.138/31 permit 98.138.229.154/31 permit 98.138.229.170/31 permit -98.139.164.0/24 permit 98.139.164.96/30 permit 98.139.164.100/30 permit 98.139.164.104/29 permit 98.139.164.112/30 permit 98.139.172.112/30 permit 98.139.172.116/31 permit -98.139.175.0/24 permit 98.139.175.65 permit 98.139.175.66/31 permit 98.139.175.68/30 permit @@ -1072,10 +992,8 @@ 98.139.210.196/31 permit 98.139.210.202/31 permit 98.139.210.204/30 permit -98.139.211.0/24 permit 98.139.211.160/30 permit 98.139.211.192/28 permit -98.139.212.0/23 permit 98.139.212.160/28 permit 98.139.212.176/29 permit 98.139.212.184/30 permit @@ -1090,7 +1008,6 @@ 98.139.214.155 permit 98.139.214.156/30 permit 98.139.214.221 permit -98.139.215.0/24 permit 98.139.215.228/31 permit 98.139.215.230 permit 98.139.215.248/30 permit @@ -1149,14 +1066,12 @@ 98.139.220.243 permit 98.139.220.245 permit 98.139.220.253 permit -98.139.221.0/24 permit 98.139.221.43 permit 98.139.221.60/30 permit 98.139.221.156/30 permit 98.139.221.232/30 permit 98.139.221.236/31 permit 98.139.221.250 permit -98.139.244.0/24 permit 98.139.244.47 permit 98.139.244.49 permit 98.139.244.50/31 permit @@ -1211,7 +1126,6 @@ 104.47.108.0/23 permit 104.130.96.0/28 permit 104.130.122.0/23 permit -104.214.25.77 permit 106.10.144.64/27 permit 106.10.144.100/31 permit 106.10.144.103 permit @@ -1237,7 +1151,6 @@ 106.10.146.52/31 permit 106.10.146.224/30 permit 106.10.146.228/31 permit -106.10.148.0/24 permit 106.10.148.48/30 permit 106.10.148.52/31 permit 106.10.148.68/30 permit @@ -1250,7 +1163,6 @@ 106.10.149.30 permit 106.10.149.160/30 permit 106.10.149.164/31 permit -106.10.150.0/23 permit 106.10.150.23 permit 106.10.150.24/30 permit 106.10.150.28/31 permit @@ -1289,7 +1201,6 @@ 106.10.151.250/31 permit 106.10.151.252/31 permit 106.10.151.254 permit -106.10.167.0/24 permit 106.10.167.72 permit 106.10.167.128/27 permit 106.10.167.160/28 permit @@ -1311,7 +1222,6 @@ 106.10.174.120/30 permit 106.10.174.154/31 permit 106.10.174.156/30 permit -106.10.176.0/24 permit 106.10.176.32/29 permit 106.10.176.48 permit 106.10.176.112 permit @@ -1330,7 +1240,6 @@ 106.10.196.43 permit 106.10.196.44/30 permit 106.10.196.48 permit -106.10.240.0/22 permit 106.10.240.0/24 permit 106.10.241.0/24 permit 106.10.242.0/24 permit @@ -1338,6 +1247,8 @@ 106.10.244.0/24 permit 106.39.212.64/29 permit 106.50.16.0/28 permit +107.20.18.111 permit +107.20.210.250 permit 108.174.0.0/24 permit 108.174.0.215 permit 108.174.3.0/24 permit @@ -1348,6 +1259,7 @@ 108.175.30.45 permit 108.177.8.0/21 permit 108.177.96.0/19 permit +108.179.144.0/20 permit 109.237.142.0/24 permit 111.221.23.128/25 permit 111.221.26.0/27 permit @@ -1356,7 +1268,6 @@ 111.221.112.0/21 permit 112.19.199.64/29 permit 112.19.242.64/29 permit -116.214.12.0/24 permit 116.214.12.47 permit 116.214.12.48/31 permit 116.214.12.56/31 permit @@ -1372,10 +1283,7 @@ 117.120.16.0/21 permit 119.42.242.52/31 permit 119.42.242.156 permit -121.244.91.48 permit -122.15.156.182 permit 123.126.78.64/29 permit -124.108.96.0/24 permit 124.108.96.24/31 permit 124.108.96.28/31 permit 124.108.96.70/31 permit @@ -1430,25 +1338,14 @@ 134.170.141.64/26 permit 134.170.143.0/24 permit 134.170.174.0/24 permit -135.84.80.0/24 permit -135.84.81.0/24 permit -135.84.82.0/24 permit -135.84.83.0/24 permit 135.84.216.0/22 permit -136.143.160.0/24 permit -136.143.161.0/24 permit -136.143.178.49 permit -136.143.182.0/23 permit -136.143.184.0/24 permit -136.143.188.0/24 permit -136.143.190.0/23 permit 136.147.128.0/20 permit 136.147.135.0/24 permit 136.147.176.0/20 permit 136.147.176.0/24 permit 136.147.182.0/24 permit +136.147.224.0/20 permit 136.179.50.206 permit -138.91.172.26 permit 139.60.152.0/22 permit 139.138.35.44 permit 139.138.46.121 permit @@ -1459,6 +1356,12 @@ 139.180.17.0/24 permit 141.148.159.229 permit 141.193.32.0/23 permit +141.193.184.32/27 permit +141.193.184.64/26 permit +141.193.184.128/25 permit +141.193.185.32/27 permit +141.193.185.64/26 permit +141.193.185.128/25 permit 143.55.224.0/21 permit 143.55.232.0/22 permit 143.55.236.0/22 permit @@ -1472,8 +1375,7 @@ 144.178.38.0/24 permit 145.253.228.160/29 permit 145.253.239.128/29 permit -146.20.14.105 permit -146.20.14.107 permit +146.20.14.104/30 permit 146.20.112.0/26 permit 146.20.113.0/24 permit 146.20.191.0/24 permit @@ -1488,11 +1390,13 @@ 148.105.0.0/16 permit 148.105.8.0/21 permit 149.72.0.0/16 permit +149.72.223.204 permit 149.72.248.236 permit 149.97.173.180 permit 150.230.98.160 permit 152.67.105.195 permit 152.69.200.236 permit +152.70.155.126 permit 155.248.208.51 permit 157.55.0.192/26 permit 157.55.1.128/26 permit @@ -1503,7 +1407,6 @@ 157.55.61.0/24 permit 157.55.157.128/25 permit 157.55.225.0/25 permit -157.55.254.216 permit 157.56.24.0/25 permit 157.56.120.128/26 permit 157.56.232.0/21 permit @@ -1545,14 +1448,11 @@ 161.71.64.0/20 permit 162.247.216.0/22 permit 163.47.180.0/22 permit -163.47.180.0/23 permit 163.114.130.16 permit 163.114.132.120 permit -164.177.132.168 permit -164.177.132.169 permit -164.177.132.170 permit -164.177.132.171 permit -165.173.128.0/24 permit +163.114.134.16 permit +163.114.135.16 permit +164.177.132.168/30 permit 166.78.68.0/22 permit 166.78.68.221 permit 166.78.69.169 permit @@ -1561,6 +1461,7 @@ 167.89.0.0/17 permit 167.89.46.159 permit 167.89.54.103 permit +167.89.60.95 permit 167.89.64.9 permit 167.89.65.0 permit 167.89.65.53 permit @@ -1572,8 +1473,6 @@ 167.89.75.164 permit 167.89.101.2 permit 167.89.101.192/28 permit -167.216.129.210 permit -167.216.131.180 permit 167.220.67.232/29 permit 168.138.5.36 permit 168.138.73.51 permit @@ -1581,10 +1480,6 @@ 168.245.12.252 permit 168.245.46.9 permit 168.245.127.231 permit -169.148.129.0/24 permit -169.148.131.0/24 permit -169.148.142.10 permit -169.148.144.0/25 permit 170.10.68.0/22 permit 170.10.128.0/24 permit 170.10.129.0/24 permit @@ -1622,14 +1517,14 @@ 182.50.76.0/22 permit 182.50.78.64/28 permit 183.240.219.64/29 permit -185.4.120.0/23 permit -185.4.122.0/24 permit +185.4.120.0/22 permit 185.12.80.0/22 permit 185.58.84.93 permit 185.80.93.204 permit 185.80.93.227 permit 185.80.95.31 permit 185.90.20.0/22 permit +185.138.56.128/25 permit 185.189.236.0/22 permit 185.211.120.0/22 permit 185.250.236.0/22 permit @@ -1646,7 +1541,6 @@ 188.125.68.184 permit 188.125.68.186 permit 188.125.68.192 permit -188.125.69.0/24 permit 188.125.69.105 permit 188.125.69.110 permit 188.125.69.112 permit @@ -1689,9 +1583,6 @@ 192.0.64.0/18 permit 192.18.139.154 permit 192.30.252.0/22 permit -192.64.236.0/24 permit -192.64.237.0/24 permit -192.64.238.0/24 permit 192.161.144.0/20 permit 192.162.87.0/24 permit 192.237.158.0/23 permit @@ -1707,7 +1598,6 @@ 193.122.128.100 permit 193.123.56.63 permit 194.19.134.0/25 permit -194.64.234.128/27 permit 194.64.234.129 permit 194.106.220.0/23 permit 194.113.24.0/22 permit @@ -1733,6 +1623,9 @@ 198.61.254.231 permit 198.178.234.57 permit 198.244.48.0/20 permit +198.244.59.30 permit +198.244.59.33 permit +198.244.59.35 permit 198.244.60.0/22 permit 198.245.80.0/20 permit 198.245.81.0/24 permit @@ -1741,13 +1634,7 @@ 199.16.156.0/22 permit 199.33.145.1 permit 199.33.145.32 permit -199.34.22.36 permit 199.59.148.0/22 permit -199.67.80.2 permit -199.67.82.2 permit -199.67.84.0/24 permit -199.67.86.0/24 permit -199.67.88.0/24 permit 199.101.161.130 permit 199.101.162.0/25 permit 199.122.120.0/21 permit @@ -1772,7 +1659,6 @@ 203.188.194.251 permit 203.188.195.240/30 permit 203.188.195.244/31 permit -203.188.197.0/24 permit 203.188.197.193 permit 203.188.197.194/31 permit 203.188.197.196/30 permit @@ -1782,7 +1668,6 @@ 203.188.197.216/29 permit 203.188.197.232/29 permit 203.188.197.240/29 permit -203.188.200.0/24 permit 203.188.200.56/31 permit 203.188.200.58 permit 203.188.200.60/30 permit @@ -1798,19 +1683,14 @@ 203.209.230.76/31 permit 204.11.168.0/21 permit 204.13.11.48/29 permit -204.13.11.48/30 permit 204.14.232.0/21 permit 204.14.232.64/28 permit 204.14.234.64/28 permit -204.29.186.0/23 permit 204.75.142.0/24 permit 204.79.197.212 permit 204.92.114.187 permit 204.92.114.203 permit 204.92.114.204/31 permit -204.132.224.66 permit -204.141.32.0/23 permit -204.141.42.0/23 permit 204.220.160.0/20 permit 204.232.168.0/24 permit 205.139.110.0/24 permit @@ -1829,6 +1709,7 @@ 205.251.233.36 permit 206.25.247.143 permit 206.25.247.155 permit +206.55.144.0/20 permit 206.165.246.80/29 permit 206.191.224.0/19 permit 206.246.157.1 permit @@ -1846,14 +1727,12 @@ 207.46.132.128/27 permit 207.46.198.0/25 permit 207.46.200.0/27 permit -207.46.225.107 permit 207.58.147.64/28 permit 207.67.38.0/24 permit 207.67.98.192/27 permit 207.68.176.0/26 permit 207.68.176.96/27 permit -207.97.204.96 permit -207.97.204.97 permit +207.97.204.96/29 permit 207.126.144.0/20 permit 207.171.160.0/19 permit 207.211.30.64/26 permit @@ -1867,11 +1746,7 @@ 208.43.21.28/30 permit 208.43.21.64/29 permit 208.43.21.72/30 permit -208.46.212.80 permit -208.46.212.208/31 permit -208.46.212.210 permit 208.64.132.0/22 permit -208.71.40.0/24 permit 208.71.40.63 permit 208.71.40.64/31 permit 208.71.40.174/31 permit @@ -1890,18 +1765,15 @@ 208.71.41.172/31 permit 208.71.41.188/30 permit 208.71.41.192/31 permit -208.71.42.0/24 permit 208.71.42.190/31 permit 208.71.42.192/28 permit 208.71.42.208/30 permit 208.71.42.212/31 permit 208.71.42.214 permit 208.72.249.240/29 permit -208.74.204.0/22 permit +208.74.204.5 permit 208.74.204.9 permit 208.75.120.0/22 permit -208.75.121.246 permit -208.75.122.246 permit 208.82.237.96/29 permit 208.82.237.104/31 permit 208.82.238.96/29 permit @@ -1920,10 +1792,8 @@ 209.67.98.46 permit 209.67.98.59 permit 209.85.128.0/17 permit -212.82.96.0/24 permit 212.82.96.32/27 permit 212.82.96.64/29 permit -212.82.98.0/24 permit 212.82.98.32/29 permit 212.82.98.64/27 permit 212.82.98.96/30 permit @@ -2005,7 +1875,6 @@ 216.17.150.251 permit 216.22.15.224/27 permit 216.24.224.0/20 permit -216.39.60.0/23 permit 216.39.60.154/31 permit 216.39.60.156/30 permit 216.39.60.160/30 permit @@ -2023,14 +1892,12 @@ 216.39.61.170 permit 216.39.61.175 permit 216.39.61.238/31 permit -216.39.62.0/24 permit 216.39.62.32/28 permit 216.39.62.48/29 permit 216.39.62.56/30 permit 216.39.62.60/31 permit 216.39.62.136/29 permit 216.39.62.144/31 permit -216.46.168.0/24 permit 216.58.192.0/19 permit 216.66.217.240/29 permit 216.71.138.33 permit @@ -2043,12 +1910,8 @@ 216.98.158.0/24 permit 216.99.5.67 permit 216.99.5.68 permit -216.109.114.0/24 permit 216.109.114.32/27 permit 216.109.114.64/29 permit -216.113.160.0/24 permit -216.113.172.0/25 permit -216.113.175.0/24 permit 216.128.126.97 permit 216.136.162.65 permit 216.136.162.120/29 permit @@ -2087,6 +1950,8 @@ 2620:109:c00d:104::/64 permit 2620:10d:c090:400::8:1 permit 2620:10d:c091:400::8:1 permit +2620:10d:c09b:400::8:1 permit +2620:10d:c09c:400::8:1 permit 2620:119:50c0:207::/64 permit 2620:119:50c0:207::215 permit 2800:3f0:4000::/36 permit diff --git a/data/conf/rspamd/dynmaps/footer.php b/data/conf/rspamd/dynmaps/footer.php index 36b307c1..545c45ec 100644 --- a/data/conf/rspamd/dynmaps/footer.php +++ b/data/conf/rspamd/dynmaps/footer.php @@ -56,21 +56,42 @@ $empty_footer = json_encode(array( error_log("FOOTER: checking for domain " . $domain . ", user " . $username . " and address " . $from . PHP_EOL); try { - $stmt = $pdo->prepare("SELECT `plain`, `html`, `mbox_exclude`, `skip_replies` FROM `domain_wide_footer` + // try get $target_domain if $domain is an alias_domain + $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` + WHERE `alias_domain` = :alias_domain"); + $stmt->execute(array( + ':alias_domain' => $domain + )); + $alias_domain = $stmt->fetch(PDO::FETCH_ASSOC); + if (!$alias_domain) { + $target_domain = $domain; + } else { + $target_domain = $alias_domain['target_domain']; + } + + // get footer associated with the domain + $stmt = $pdo->prepare("SELECT `plain`, `html`, `mbox_exclude`, `alias_domain_exclude`, `skip_replies` FROM `domain_wide_footer` WHERE `domain` = :domain"); $stmt->execute(array( - ':domain' => $domain + ':domain' => $target_domain )); $footer = $stmt->fetch(PDO::FETCH_ASSOC); + + // check if the sender is excluded if (in_array($from, json_decode($footer['mbox_exclude']))){ $footer = false; } + if (in_array($domain, json_decode($footer['alias_domain_exclude']))){ + $footer = false; + } if (empty($footer)){ echo $empty_footer; exit; } error_log("FOOTER: " . json_encode($footer) . PHP_EOL); + // footer will be applied + // get custom mailbox attributes to insert into the footer $stmt = $pdo->prepare("SELECT `custom_attributes` FROM `mailbox` WHERE `username` = :username"); $stmt->execute(array( ':username' => $username diff --git a/data/conf/rspamd/local.d/composites.conf b/data/conf/rspamd/local.d/composites.conf index cde34b57..9bb84424 100644 --- a/data/conf/rspamd/local.d/composites.conf +++ b/data/conf/rspamd/local.d/composites.conf @@ -21,6 +21,10 @@ FREEMAIL_TO_UNDISC_RCPT { SOGO_CONTACT_EXCLUDE { expression = "(-WHITELISTED_FWD_HOST | -g+:policies) & ^SOGO_CONTACT & !DMARC_POLICY_ALLOW"; } +# Remove MAILCOW_WHITE symbol for senders with broken policy recieved not from fwd hosts +MAILCOW_WHITE_EXCLUDE { + expression = "^MAILCOW_WHITE & (-DMARC_POLICY_REJECT | -DMARC_POLICY_QUARANTINE | -R_SPF_PERMFAIL) & !WHITELISTED_FWD_HOST"; +} # Spoofed header from and broken policy (excluding sieve host, rspamd host, whitelisted senders, authenticated senders and forward hosts) SPOOFED_UNAUTH { expression = "!MAILCOW_AUTH & !MAILCOW_WHITE & !RSPAMD_HOST & !SIEVE_HOST & MAILCOW_DOMAIN_HEADER_FROM & !WHITELISTED_FWD_HOST & -g+:policies"; @@ -103,4 +107,4 @@ CLAMD_JS_MALWARE { expression = "CLAM_SECI_JS & !MAILCOW_WHITE"; description = "JS malware found, Securite JS malware Flag set through ClamAV"; score = 8; -} \ No newline at end of file +} diff --git a/data/conf/rspamd/local.d/options.inc b/data/conf/rspamd/local.d/options.inc index fcf499d7..105bbdcd 100644 --- a/data/conf/rspamd/local.d/options.inc +++ b/data/conf/rspamd/local.d/options.inc @@ -6,3 +6,4 @@ disable_monitoring = true; # In case a task times out (like DNS lookup), soft reject the message # instead of silently accepting the message without further processing. soft_reject_on_timeout = true; +local_addrs = /etc/rspamd/custom/mailcow_networks.map; diff --git a/data/conf/rspamd/local.d/rbl.conf b/data/conf/rspamd/local.d/rbl.conf index f132b4d6..7f2976a0 100644 --- a/data/conf/rspamd/local.d/rbl.conf +++ b/data/conf/rspamd/local.d/rbl.conf @@ -1,23 +1,8 @@ rbls { - sorbs { - symbol = "RBL_SORBS"; - rbl = "dnsbl.sorbs.net"; - returncodes { - # http:// www.sorbs.net/general/using.shtml - RBL_SORBS_HTTP = "127.0.0.2"; - RBL_SORBS_SOCKS = "127.0.0.3"; - RBL_SORBS_MISC = "127.0.0.4"; - RBL_SORBS_SMTP = "127.0.0.5"; - RBL_SORBS_RECENT = "127.0.0.6"; - RBL_SORBS_WEB = "127.0.0.7"; - RBL_SORBS_DUL = "127.0.0.10"; - RBL_SORBS_BLOCK = "127.0.0.8"; - RBL_SORBS_ZOMBIE = "127.0.0.9"; - } - } interserver_ip { symbol = "RBL_INTERSERVER_IP"; rbl = "rbl.interserver.net"; + from = true; ipv6 = false; returncodes { RBL_INTERSERVER_BAD_IP = "127.0.0.2"; @@ -35,4 +20,7 @@ rbls { RBL_INTERSERVER_BAD_URI = "127.0.0.2"; } } -} + +.include(try=true,override=true,priority=5) "$LOCAL_CONFDIR/custom/dqs-rbl.conf" + +} \ No newline at end of file diff --git a/data/conf/rspamd/local.d/rbl_group.conf b/data/conf/rspamd/local.d/rbl_group.conf index 4e3dce71..916de4ef 100644 --- a/data/conf/rspamd/local.d/rbl_group.conf +++ b/data/conf/rspamd/local.d/rbl_group.conf @@ -5,46 +5,6 @@ symbols = { "RBL_UCEPROTECT_LEVEL2" { score = 1.5; } - "RBL_SORBS" { - score = 0.0; - description = "Unrecognised result from SORBS RBL"; - } - "RBL_SORBS_HTTP" { - score = 2.5; - description = "List of Open HTTP Proxy Servers."; - } - "RBL_SORBS_SOCKS" { - score = 2.5; - description = "List of Open SOCKS Proxy Servers."; - } - "RBL_SORBS_MISC" { - score = 1.0; - description = "List of open Proxy Servers not listed in the SOCKS or HTTP lists."; - } - "RBL_SORBS_SMTP" { - score = 4.0; - description = "List of Open SMTP relay servers."; - } - "RBL_SORBS_RECENT" { - score = 2.0; - description = "List of hosts that have been noted as sending spam/UCE/UBE to the admins of SORBS within the last 28 days (includes new.spam.dnsbl.sorbs.net)."; - } - "RBL_SORBS_WEB" { - score = 2.0; - description = "List of web (WWW) servers which have spammer abusable vulnerabilities (e.g. FormMail scripts)"; - } - "RBL_SORBS_DUL" { - score = 2.0; - description = "Dynamic IP Address ranges (NOT a Dial Up list!)"; - } - "RBL_SORBS_BLOCK" { - score = 0.5; - description = "List of hosts demanding that they never be tested by SORBS."; - } - "RBL_SORBS_ZOMBIE" { - score = 2.0; - description = "List of networks hijacked from their original owners, some of which have already used for spamming."; - } "RECEIVED_SPAMHAUS_XBL" { weight = 0.0; description = "Received address is listed in ZEN XBL"; @@ -57,4 +17,261 @@ symbols = { score = 4.0; description = "Listed on Interserver RBL"; } + + "SPAMHAUS_ZEN" { + weight = 7.0; + } + "SH_AUTHBL_RECEIVED" { + weight = 4.0; + } + "RBL_DBL_SPAM" { + weight = 7.0; + } + "RBL_DBL_PHISH" { + weight = 7.0; + } + "RBL_DBL_MALWARE" { + weight = 7.0; + } + "RBL_DBL_BOTNET" { + weight = 7.0; + } + "RBL_DBL_ABUSED_SPAM" { + weight = 3.0; + } + "RBL_DBL_ABUSED_PHISH" { + weight = 3.0; + } + "RBL_DBL_ABUSED_MALWARE" { + weight = 3.0; + } + "RBL_DBL_ABUSED_BOTNET" { + weight = 3.0; + } + "RBL_ZRD_VERY_FRESH_DOMAIN" { + weight = 7.0; + } + "RBL_ZRD_FRESH_DOMAIN" { + weight = 4.0; + } + "ZRD_VERY_FRESH_DOMAIN" { + weight = 7.0; + } + "ZRD_FRESH_DOMAIN" { + weight = 4.0; + } + "SH_EMAIL_DBL" { + weight = 7.0; + } + "SH_EMAIL_DBL_ABUSED" { + weight = 7.0; + } + "SH_EMAIL_ZRD_VERY_FRESH_DOMAIN" { + weight = 7.0; + } + "SH_EMAIL_ZRD_FRESH_DOMAIN" { + weight = 4.0; + } + "RBL_DBL_DONT_QUERY_IPS" { + weight = 0.0; + } + "RBL_ZRD_DONT_QUERY_IPS" { + weight = 0.0; + } + "SH_EMAIL_ZRD_DONT_QUERY_IPS" { + weight = 0.0; + } + "SH_EMAIL_DBL_DONT_QUERY_IPS" { + weight = 0.0; + } + "DBL" { + weight = 0.0; + description = "DBL unknown result"; + groups = ["spamhaus"]; + } + "DBL_SPAM" { + weight = 7; + description = "DBL uribl spam"; + groups = ["spamhaus"]; + } + "DBL_PHISH" { + weight = 7; + description = "DBL uribl phishing"; + groups = ["spamhaus"]; + } + "DBL_MALWARE" { + weight = 7; + description = "DBL uribl malware"; + groups = ["spamhaus"]; + } + "DBL_BOTNET" { + weight = 7; + description = "DBL uribl botnet C&C domain"; + groups = ["spamhaus"]; + } + + + "DBLABUSED_SPAM_FULLURLS" { + weight = 5.5; + description = "DBL uribl abused legit spam"; + groups = ["spamhaus"]; + } + "DBLABUSED_PHISH_FULLURLS" { + weight = 5.5; + description = "DBL uribl abused legit phish"; + groups = ["spamhaus"]; + } + "DBLABUSED_MALWARE_FULLURLS" { + weight = 5.5; + description = "DBL uribl abused legit malware"; + groups = ["spamhaus"]; + } + "DBLABUSED_BOTNET_FULLURLS" { + weight = 5.5; + description = "DBL uribl abused legit botnet"; + groups = ["spamhaus"]; + } + + "DBL_ABUSE" { + weight = 5.5; + description = "DBL uribl abused legit spam"; + groups = ["spamhaus"]; + } + "DBL_ABUSE_REDIR" { + weight = 1.5; + description = "DBL uribl abused spammed redirector domain"; + groups = ["spamhaus"]; + } + "DBL_ABUSE_PHISH" { + weight = 5.5; + description = "DBL uribl abused legit phish"; + groups = ["spamhaus"]; + } + "DBL_ABUSE_MALWARE" { + weight = 5.5; + description = "DBL uribl abused legit malware"; + groups = ["spamhaus"]; + } + "DBL_ABUSE_BOTNET" { + weight = 5.5; + description = "DBL uribl abused legit botnet C&C"; + groups = ["spamhaus"]; + } + "DBL_PROHIBIT" { + weight = 0.0; + description = "DBL uribl IP queries prohibited!"; + groups = ["spamhaus"]; + } + "DBL_BLOCKED_OPENRESOLVER" { + weight = 0.0; + description = "You are querying Spamhaus from an open resolver, please see https://www.spamhaus.org/returnc/pub/"; + groups = ["spamhaus"]; + } + "DBL_BLOCKED" { + weight = 0.0; + description = "You are exceeding the query limit, please see https://www.spamhaus.org/returnc/vol/"; + groups = ["spamhaus"]; + } + "SPAMHAUS_ZEN_URIBL" { + weight = 0.0; + description = "Spamhaus ZEN URIBL: Filtered result"; + groups = ["spamhaus"]; + } + "URIBL_SBL" { + weight = 6.5; + description = "A domain in the message body resolves to an IP listed in Spamhaus SBL"; + one_shot = true; + groups = ["spamhaus"]; + } + "URIBL_SBL_CSS" { + weight = 6.5; + description = "A domain in the message body resolves to an IP listed in Spamhaus SBL CSS"; + one_shot = true; + groups = ["spamhaus"]; + } + "URIBL_PBL" { + weight = 0.01; + description = "A domain in the message body resolves to an IP listed in Spamhaus PBL"; + one_shot = true; + groups = ["spamhaus"]; + } + "URIBL_DROP" { + weight = 6.5; + description = "A domain in the message body resolves to an IP listed in Spamhaus DROP"; + one_shot = true; + groups = ["spamhaus"]; + } + "URIBL_XBL" { + weight = 5.0; + description = "A domain in the message body resolves to an IP listed in Spamhaus XBL"; + one_shot = true; + groups = ["spamhaus"]; + } + "SPAMHAUS_SBL_URL" { + weight = 6.5; + description = "A numeric URL in the message body is listed in Spamhaus SBL"; + one_shot = true; + groups = ["spamhaus"]; + } + + "SH_HBL_EMAIL" { + weight = 7; + description = "Email listed in HBL"; + groups = ["spamhaus"]; + } + + "SH_HBL_FILE_MALICIOUS" { + weight = 7; + description = "An attachment hash is listed in Spamhaus HBL as malicious"; + groups = ["spamhaus"]; + } + + "SH_HBL_FILE_SUSPICIOUS" { + weight = 5; + description = "An attachment hash is listed in Spamhaus HBL as suspicious"; + groups = ["spamhaus"]; + } + + "RBL_SPAMHAUS_CW_BTC" { + score = 7; + description = "Bitcoin found in Spamhaus cryptowallet list"; + groups = ["spamhaus"]; + } + + "RBL_SPAMHAUS_CW_ETH" { + score = 7; + description = "Ethereum found in Spamhaus cryptowallet list"; + groups = ["spamhaus"]; + } + + "RBL_SPAMHAUS_CW_BCH" { + score = 7; + description = "Bitcoinhash found in Spamhaus cryptowallet list"; + groups = ["spamhaus"]; + } + + "RBL_SPAMHAUS_CW_XMR" { + score = 7; + description = "Monero found in Spamhaus cryptowallet list"; + groups = ["spamhaus"]; + } + + "RBL_SPAMHAUS_CW_LTC" { + score = 7; + description = "Litecoin found in Spamhaus cryptowallet list"; + groups = ["spamhaus"]; + } + + "RBL_SPAMHAUS_CW_XRP" { + score = 7; + description = "Ripple found in Spamhaus cryptowallet list"; + groups = ["spamhaus"]; + } + + "RBL_SPAMHAUS_HBL_URL" { + score = 7; + description = "URL found in spamhaus HBL blocklist"; + groups = ["spamhaus"]; + } + } diff --git a/data/conf/rspamd/local.d/statistic.conf b/data/conf/rspamd/local.d/statistic.conf index 1ca3e082..baa3f1c2 100644 --- a/data/conf/rspamd/local.d/statistic.conf +++ b/data/conf/rspamd/local.d/statistic.conf @@ -1,12 +1,14 @@ classifier "bayes" { + # name = "custom"; # 'name' parameter must be set if multiple classifiers are defined + learn_condition = 'return require("lua_bayes_learn").can_learn'; + new_schema = true; tokenizer { name = "osb"; } backend = "redis"; min_tokens = 11; min_learns = 5; - new_schema = true; - expire = 2592000; + expire = 7776000; statfile { symbol = "BAYES_HAM"; spam = false; diff --git a/data/conf/rspamd/lua/rspamd.local.lua b/data/conf/rspamd/lua/rspamd.local.lua index 45506f3b..5f23ef6b 100644 --- a/data/conf/rspamd/lua/rspamd.local.lua +++ b/data/conf/rspamd/lua/rspamd.local.lua @@ -621,10 +621,24 @@ rspamd_config:register_symbol({ local nct = string.format('%s: %s/%s; charset=utf-8', 'Content-Type', rewrite.new_ct.type, rewrite.new_ct.subtype) out[#out + 1] = nct + -- update Content-Type header + task:set_milter_reply({ + remove_headers = {['Content-Type'] = 0}, + }) + task:set_milter_reply({ + add_headers = {['Content-Type'] = string.format('%s/%s; charset=utf-8', rewrite.new_ct.type, rewrite.new_ct.subtype)} + }) return elseif name:lower() == 'content-transfer-encoding' then out[#out + 1] = string.format('%s: %s', 'Content-Transfer-Encoding', 'quoted-printable') + -- update Content-Transfer-Encoding header + task:set_milter_reply({ + remove_headers = {['Content-Transfer-Encoding'] = 0}, + }) + task:set_milter_reply({ + add_headers = {['Content-Transfer-Encoding'] = 'quoted-printable'} + }) seen_cte = true return end diff --git a/data/conf/rspamd/meta_exporter/pipe.php b/data/conf/rspamd/meta_exporter/pipe.php index 88e66e8e..1858ee66 100644 --- a/data/conf/rspamd/meta_exporter/pipe.php +++ b/data/conf/rspamd/meta_exporter/pipe.php @@ -52,7 +52,7 @@ $headers = getallheaders(); $qid = $headers['X-Rspamd-Qid']; $fuzzy = $headers['X-Rspamd-Fuzzy']; -$subject = $headers['X-Rspamd-Subject']; +$subject = iconv_mime_decode($headers['X-Rspamd-Subject']); $score = $headers['X-Rspamd-Score']; $rcpts = $headers['X-Rspamd-Rcpt']; $user = $headers['X-Rspamd-User']; diff --git a/data/conf/rspamd/meta_exporter/pushover.php b/data/conf/rspamd/meta_exporter/pushover.php index 10265d15..f122b281 100644 --- a/data/conf/rspamd/meta_exporter/pushover.php +++ b/data/conf/rspamd/meta_exporter/pushover.php @@ -53,7 +53,7 @@ $qid = $headers['X-Rspamd-Qid']; $rcpts = $headers['X-Rspamd-Rcpt']; $sender = $headers['X-Rspamd-From']; $ip = $headers['X-Rspamd-Ip']; -$subject = $headers['X-Rspamd-Subject']; +$subject = iconv_mime_decode($headers['X-Rspamd-Subject']); $messageid= $json_body->message_id; $priority = 0; diff --git a/data/conf/sogo/sogo.conf b/data/conf/sogo/sogo.conf index 8d4dd93d..d398eb05 100644 --- a/data/conf/sogo/sogo.conf +++ b/data/conf/sogo/sogo.conf @@ -16,6 +16,9 @@ SOGoFoldersSendEMailNotifications = YES; SOGoForwardEnabled = YES; + // Option to set Users as admin to globally manage calendar permissions etc. Disabled by default + // SOGoSuperUsernames = ("moo@example.com"); + SOGoUIAdditionalJSFiles = ( js/theme.js, js/custom-sogo.js @@ -38,6 +41,7 @@ SOGoLanguage = English; SOGoMailAuxiliaryUserAccountsEnabled = YES; + // SOGoCreateIdentitiesDisabled = NO; SOGoMailCustomFromEnabled = YES; SOGoMailingMechanism = smtp; SOGoSMTPAuthenticationType = plain; diff --git a/data/web/admin.php b/data/web/admin.php index d0fcbc99..5dd7b3c6 100644 --- a/data/web/admin.php +++ b/data/web/admin.php @@ -107,6 +107,7 @@ $template_data = [ 'f2b_banlist_url' => getBaseUrl() . "/api/v1/get/fail2ban/banlist/" . $f2b_data['banlist_id'], 'q_data' => quarantine('settings'), 'qn_data' => quota_notification('get'), + 'pw_reset_data' => reset_password('get_notification'), 'rsettings_map' => file_get_contents('http://nginx:8081/settings.php'), 'rsettings' => $rsettings, 'rspamd_regex_maps' => $rspamd_regex_maps, diff --git a/data/web/debug.php b/data/web/debug.php index 52052f68..9c338009 100644 --- a/data/web/debug.php +++ b/data/web/debug.php @@ -39,9 +39,13 @@ foreach ($containers as $container => $container_info) { $StartedAt['month'], $StartedAt['day'], $StartedAt['year'])); - $user_tz = new DateTimeZone(getenv('TZ')); - $date->setTimezone($user_tz); - $started = $date->format('r'); + try { + $user_tz = new DateTimeZone(getenv('TZ')); + $date->setTimezone($user_tz); + $started = $date->format('r'); + } catch(Exception $e) { + $started = '?'; + } } else { $started = '?'; diff --git a/data/web/edit.php b/data/web/edit.php index 83ae1467..4c5cd89e 100644 --- a/data/web/edit.php +++ b/data/web/edit.php @@ -59,7 +59,8 @@ if (isset($_SESSION['mailcow_cc_role'])) { 'domain_details' => $result, 'domain_footer' => $domain_footer, 'mailboxes' => mailbox('get', 'mailboxes', $_GET["domain"]), - 'aliases' => mailbox('get', 'aliases', $_GET["domain"], 'address') + 'aliases' => mailbox('get', 'aliases', $_GET["domain"], 'address'), + 'alias_domains' => mailbox('get', 'alias_domains', $_GET["domain"]) ]; } } diff --git a/data/web/inc/ajax/container_ctrl.php b/data/web/inc/ajax/container_ctrl.php index f0e220f9..48c21cb1 100644 --- a/data/web/inc/ajax/container_ctrl.php +++ b/data/web/inc/ajax/container_ctrl.php @@ -1,4 +1,11 @@ '', "\r" => '', "\t" => '
']); + $message = htmlspecialchars($log['msg'], ENT_QUOTES); + $message = strtr($message, ["\n" => '', "\r" => '', "\t" => '
']); $alerts[trim($log['type'], '"')][] = trim($message, '"'); } $alert = array_filter(array_unique($alerts)); diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 3cff09b9..25d08b9f 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -284,17 +284,17 @@ function last_login($action, $username, $sasl_limit_days = 7, $ui_offset = 1) { } if (!$sasl[$k]['location']) { $curl = curl_init(); - curl_setopt($curl, CURLOPT_URL,"https://dfdata.bella.network/lookup/" . $sasl[$k]['real_rip']); + curl_setopt($curl, CURLOPT_URL,"https://dfdata.bella.network/country/" . $sasl[$k]['real_rip']); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_USERAGENT, 'Moocow'); curl_setopt($curl, CURLOPT_TIMEOUT, 5); $ip_data = curl_exec($curl); if (!curl_errno($curl)) { $ip_data_array = json_decode($ip_data, true); - if ($ip_data_array !== false and !empty($ip_data_array['location']['shortcountry'])) { - $sasl[$k]['location'] = $ip_data_array['location']['shortcountry']; + if ($ip_data_array !== false and !empty($ip_data_array['shortcountry'])) { + $sasl[$k]['location'] = $ip_data_array['shortcountry']; try { - $redis->hSet('IP_SHORTCOUNTRY', $sasl[$k]['real_rip'], $ip_data_array['location']['shortcountry']); + $redis->hSet('IP_SHORTCOUNTRY', $sasl[$k]['real_rip'], $ip_data_array['shortcountry']); } catch (RedisException $e) { $_SESSION['return'][] = array( @@ -1073,13 +1073,17 @@ function update_sogo_static_view($mailbox = null) { function edit_user_account($_data) { global $lang; global $pdo; + $_data_log = $_data; !isset($_data_log['user_new_pass']) ?: $_data_log['user_new_pass'] = '*'; !isset($_data_log['user_new_pass2']) ?: $_data_log['user_new_pass2'] = '*'; !isset($_data_log['user_old_pass']) ?: $_data_log['user_old_pass'] = '*'; + $username = $_SESSION['mailcow_cc_username']; $role = $_SESSION['mailcow_cc_role']; $password_old = $_data['user_old_pass']; + $pw_recovery_email = $_data['pw_recovery_email']; + if (filter_var($username, FILTER_VALIDATE_EMAIL === false) || $role != 'user') { $_SESSION['return'][] = array( 'type' => 'danger', @@ -1088,20 +1092,24 @@ function edit_user_account($_data) { ); return false; } - $stmt = $pdo->prepare("SELECT `password` FROM `mailbox` - WHERE `kind` NOT REGEXP 'location|thing|group' - AND `username` = :user"); - $stmt->execute(array(':user' => $username)); - $row = $stmt->fetch(PDO::FETCH_ASSOC); - if (!verify_hash($row['password'], $password_old)) { - $_SESSION['return'][] = array( - 'type' => 'danger', - 'log' => array(__FUNCTION__, $_data_log), - 'msg' => 'access_denied' - ); - return false; - } - if (!empty($_data['user_new_pass']) && !empty($_data['user_new_pass2'])) { + + // edit password + if (!empty($password_old) && !empty($_data['user_new_pass']) && !empty($_data['user_new_pass2'])) { + $stmt = $pdo->prepare("SELECT `password` FROM `mailbox` + WHERE `kind` NOT REGEXP 'location|thing|group' + AND `username` = :user"); + $stmt->execute(array(':user' => $username)); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!verify_hash($row['password'], $password_old)) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'access_denied' + ); + return false; + } + $password_new = $_data['user_new_pass']; $password_new2 = $_data['user_new_pass2']; if (password_check($password_new, $password_new2) !== true) { @@ -1116,8 +1124,29 @@ function edit_user_account($_data) { ':password_hashed' => $password_hashed, ':username' => $username )); + + update_sogo_static_view(); } - update_sogo_static_view(); + // edit password recovery email + elseif (isset($pw_recovery_email)) { + if (!isset($_SESSION['acl']['pw_reset']) || $_SESSION['acl']['pw_reset'] != "1" ) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' + ); + return false; + } + + $pw_recovery_email = (!filter_var($pw_recovery_email, FILTER_VALIDATE_EMAIL)) ? '' : $pw_recovery_email; + $stmt = $pdo->prepare("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.recovery_email', :recovery_email) + WHERE `username` = :username"); + $stmt->execute(array( + ':recovery_email' => $pw_recovery_email, + ':username' => $username + )); + } + $_SESSION['return'][] = array( 'type' => 'success', 'log' => array(__FUNCTION__, $_data_log), @@ -1560,7 +1589,7 @@ function unset_tfa_key($_data) { } function get_tfa($username = null, $id = null) { global $pdo; - if (isset($_SESSION['mailcow_cc_username'])) { + if (empty($username) && isset($_SESSION['mailcow_cc_username'])) { $username = $_SESSION['mailcow_cc_username']; } elseif (empty($username)) { @@ -2261,6 +2290,386 @@ function uuid4() { return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); } +function reset_password($action, $data = null) { + global $pdo; + global $redis; + global $mailcow_hostname; + global $PW_RESET_TOKEN_LIMIT; + global $PW_RESET_TOKEN_LIFETIME; + + $_data_log = $data; + if (isset($_data_log['new_password'])) $_data_log['new_password'] = '*'; + if (isset($_data_log['new_password2'])) $_data_log['new_password2'] = '*'; + + switch ($action) { + case 'check': + $token = $data; + + $stmt = $pdo->prepare("SELECT `t1`.`username` FROM `reset_password` AS `t1` JOIN `mailbox` AS `t2` ON `t1`.`username` = `t2`.`username` WHERE `t1`.`token` = :token AND `t1`.`created` > DATE_SUB(NOW(), INTERVAL :lifetime MINUTE) AND `t2`.`active` = 1;"); + $stmt->execute(array( + ':token' => preg_replace('/[^a-zA-Z0-9-]/', '', $token), + ':lifetime' => $PW_RESET_TOKEN_LIFETIME + )); + $return = $stmt->fetch(PDO::FETCH_ASSOC); + return empty($return['username']) ? false : $return['username']; + break; + case 'issue': + $username = $data; + + // perform cleanup + $stmt = $pdo->prepare("DELETE FROM `reset_password` WHERE created < DATE_SUB(NOW(), INTERVAL :lifetime MINUTE);"); + $stmt->execute(array(':lifetime' => $PW_RESET_TOKEN_LIFETIME)); + + if (filter_var($username, FILTER_VALIDATE_EMAIL) === false) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => 'access_denied' + ); + return false; + } + + $pw_reset_notification = reset_password('get_notification', 'raw'); + if (!$pw_reset_notification) return false; + if (empty($pw_reset_notification['from']) || empty($pw_reset_notification['subject'])) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => 'password_reset_na' + ); + return false; + } + + $stmt = $pdo->prepare("SELECT * FROM `mailbox` + WHERE `username` = :username"); + $stmt->execute(array(':username' => $username)); + $mailbox_data = $stmt->fetch(PDO::FETCH_ASSOC); + + if (empty($mailbox_data)) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => 'password_reset_invalid_user' + ); + return false; + } + + $mailbox_attr = json_decode($mailbox_data['attributes'], true); + if (empty($mailbox_attr['recovery_email']) || filter_var($mailbox_attr['recovery_email'], FILTER_VALIDATE_EMAIL) === false) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => "password_reset_invalid_user" + ); + return false; + } + + $stmt = $pdo->prepare("SELECT * FROM `reset_password` + WHERE `username` = :username"); + $stmt->execute(array(':username' => $username)); + $generated_token_count = count($stmt->fetchAll(PDO::FETCH_ASSOC)); + if ($generated_token_count >= $PW_RESET_TOKEN_LIMIT) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => "reset_token_limit_exceeded" + ); + return false; + } + + $token = implode('-', array( + strtoupper(bin2hex(random_bytes(3))), + strtoupper(bin2hex(random_bytes(3))), + strtoupper(bin2hex(random_bytes(3))), + strtoupper(bin2hex(random_bytes(3))), + strtoupper(bin2hex(random_bytes(3))) + )); + + $stmt = $pdo->prepare("INSERT INTO `reset_password` (`username`, `token`) + VALUES (:username, :token)"); + $stmt->execute(array( + ':username' => $username, + ':token' => $token + )); + + $reset_link = getBaseURL() . "/reset-password?token=" . $token; + + $request_date = new DateTime(); + $locale_date = locale_get_default(); + $date_formatter = new IntlDateFormatter( + $locale_date, + IntlDateFormatter::FULL, + IntlDateFormatter::FULL + ); + $formatted_request_date = $date_formatter->format($request_date); + + // set template vars + // subject + $pw_reset_notification['subject'] = str_replace('{{hostname}}', $mailcow_hostname, $pw_reset_notification['subject']); + $pw_reset_notification['subject'] = str_replace('{{link}}', $reset_link, $pw_reset_notification['subject']); + $pw_reset_notification['subject'] = str_replace('{{username}}', $username, $pw_reset_notification['subject']); + $pw_reset_notification['subject'] = str_replace('{{username2}}', $mailbox_attr['recovery_email'], $pw_reset_notification['subject']); + $pw_reset_notification['subject'] = str_replace('{{date}}', $formatted_request_date, $pw_reset_notification['subject']); + $pw_reset_notification['subject'] = str_replace('{{token_lifetime}}', $PW_RESET_TOKEN_LIFETIME, $pw_reset_notification['subject']); + // text + $pw_reset_notification['text_tmpl'] = str_replace('{{hostname}}', $mailcow_hostname, $pw_reset_notification['text_tmpl']); + $pw_reset_notification['text_tmpl'] = str_replace('{{link}}', $reset_link, $pw_reset_notification['text_tmpl']); + $pw_reset_notification['text_tmpl'] = str_replace('{{username}}', $username, $pw_reset_notification['text_tmpl']); + $pw_reset_notification['text_tmpl'] = str_replace('{{username2}}', $mailbox_attr['recovery_email'], $pw_reset_notification['text_tmpl']); + $pw_reset_notification['text_tmpl'] = str_replace('{{date}}', $formatted_request_date, $pw_reset_notification['text_tmpl']); + $pw_reset_notification['text_tmpl'] = str_replace('{{token_lifetime}}', $PW_RESET_TOKEN_LIFETIME, $pw_reset_notification['text_tmpl']); + // html + $pw_reset_notification['html_tmpl'] = str_replace('{{hostname}}', $mailcow_hostname, $pw_reset_notification['html_tmpl']); + $pw_reset_notification['html_tmpl'] = str_replace('{{link}}', $reset_link, $pw_reset_notification['html_tmpl']); + $pw_reset_notification['html_tmpl'] = str_replace('{{username}}', $username, $pw_reset_notification['html_tmpl']); + $pw_reset_notification['html_tmpl'] = str_replace('{{username2}}', $mailbox_attr['recovery_email'], $pw_reset_notification['html_tmpl']); + $pw_reset_notification['html_tmpl'] = str_replace('{{date}}', $formatted_request_date, $pw_reset_notification['html_tmpl']); + $pw_reset_notification['html_tmpl'] = str_replace('{{token_lifetime}}', $PW_RESET_TOKEN_LIFETIME, $pw_reset_notification['html_tmpl']); + + + $email_sent = reset_password('send_mail', array( + "from" => $pw_reset_notification['from'], + "to" => $mailbox_attr['recovery_email'], + "subject" => $pw_reset_notification['subject'], + "text" => $pw_reset_notification['text_tmpl'], + "html" => $pw_reset_notification['html_tmpl'] + )); + + if (!$email_sent){ + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => "recovery_email_failed" + ); + return false; + } + + list($localPart, $domainPart) = explode('@', $mailbox_attr['recovery_email']); + if (strlen($localPart) > 1) { + $maskedLocalPart = $localPart[0] . str_repeat('*', strlen($localPart) - 1); + } else { + $maskedLocalPart = "*"; + } + $_SESSION['return'][] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => array("recovery_email_sent", $maskedLocalPart . '@' . $domainPart) + ); + return array( + "username" => $username, + "issue" => "success" + ); + break; + case 'reset': + $token = $data['token']; + $new_password = $data['new_password']; + $new_password2 = $data['new_password2']; + $username = $data['username']; + $check_tfa = $data['check_tfa']; + + if (!$username || !$token) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => 'invalid_reset_token' + ); + return false; + } + + # check new password + if (!password_check($new_password, $new_password2)) { + return false; + } + + if ($check_tfa){ + // check for tfa authenticators + $authenticators = get_tfa($username); + if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) { + $_SESSION['pending_mailcow_cc_username'] = $username; + $_SESSION['pending_pw_reset_token'] = $token; + $_SESSION['pending_pw_new_password'] = $new_password; + $_SESSION['pending_tfa_methods'] = $authenticators['additional']; + $_SESSION['return'][] = array( + 'type' => 'info', + 'log' => array(__FUNCTION__, $user, '*'), + 'msg' => 'awaiting_tfa_confirmation' + ); + return false; + } + } + + # set new password + $password_hashed = hash_password($new_password); + $stmt = $pdo->prepare("UPDATE `mailbox` SET + `password` = :password_hashed, + `attributes` = JSON_SET(`attributes`, '$.passwd_update', NOW()) + WHERE `username` = :username"); + $stmt->execute(array( + ':password_hashed' => $password_hashed, + ':username' => $username + )); + + // perform cleanup + $stmt = $pdo->prepare("DELETE FROM `reset_password` WHERE `username` = :username;"); + $stmt->execute(array( + ':username' => $username + )); + + $_SESSION['return'][] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => 'password_changed_success' + ); + return true; + break; + case 'get_notification': + $type = $data; + + try { + $settings['from'] = $redis->Get('PW_RESET_FROM'); + $settings['subject'] = $redis->Get('PW_RESET_SUBJ'); + $settings['html_tmpl'] = $redis->Get('PW_RESET_HTML'); + $settings['text_tmpl'] = $redis->Get('PW_RESET_TEXT'); + if (empty($settings['html_tmpl']) && empty($settings['text_tmpl'])) { + $settings['html_tmpl'] = file_get_contents("/tpls/pw_reset_html.tpl"); + $settings['text_tmpl'] = file_get_contents("/tpls/pw_reset_text.tpl"); + } + + if ($type != "raw") { + $settings['html_tmpl'] = htmlspecialchars($settings['html_tmpl']); + $settings['text_tmpl'] = htmlspecialchars($settings['text_tmpl']); + } + } + catch (RedisException $e) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => array('redis_error', $e) + ); + return false; + } + + return $settings; + break; + case 'send_mail': + $from = $data['from']; + $to = $data['to']; + $text = $data['text']; + $html = $data['html']; + $subject = $data['subject']; + + if (!filter_var($from, FILTER_VALIDATE_EMAIL)) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => 'from_invalid' + ); + return false; + } + if (!filter_var($to, FILTER_VALIDATE_EMAIL)) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => 'to_invalid' + ); + return false; + } + if (empty($subject)) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => 'subject_empty' + ); + return false; + } + if (empty($text)) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => 'text_empty' + ); + return false; + } + + ini_set('max_execution_time', 0); + ini_set('max_input_time', 0); + $mail = new PHPMailer; + $mail->Timeout = 10; + $mail->SMTPOptions = array( + 'ssl' => array( + 'verify_peer' => false, + 'verify_peer_name' => false, + 'allow_self_signed' => true + ) + ); + $mail->isSMTP(); + $mail->Host = 'postfix-mailcow'; + $mail->SMTPAuth = false; + $mail->Port = 25; + $mail->setFrom($from); + $mail->Subject = $subject; + $mail->CharSet ="UTF-8"; + if (!empty($html)) { + $mail->Body = $html; + $mail->AltBody = $text; + } + else { + $mail->Body = $text; + } + $mail->XMailer = 'MooMail'; + $mail->AddAddress($to); + if (!$mail->send()) { + return false; + } + $mail->ClearAllRecipients(); + + return true; + break; + } + + if ($_SESSION['mailcow_cc_role'] != "admin") { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => 'access_denied' + ); + return false; + } + + switch ($action) { + case 'edit_notification': + $subject = $data['subject']; + $from = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $data['from']); + + $from = (!filter_var($from, FILTER_VALIDATE_EMAIL)) ? "" : $from; + $subject = (empty($subject)) ? "" : $subject; + $text = (empty($data['text_tmpl'])) ? "" : $data['text_tmpl']; + $html = (empty($data['html_tmpl'])) ? "" : $data['html_tmpl']; + + try { + $redis->Set('PW_RESET_FROM', $from); + $redis->Set('PW_RESET_SUBJ', $subject); + $redis->Set('PW_RESET_HTML', $html); + $redis->Set('PW_RESET_TEXT', $text); + } + catch (RedisException $e) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => array('redis_error', $e) + ); + return false; + } + + $_SESSION['return'][] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $action, $_data_log), + 'msg' => 'saved_settings' + ); + break; + } +} + function get_logs($application, $lines = false) { if ($lines === false) { diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index 0f48efbd..c927ce49 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -184,6 +184,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { 'msg' => 'global_filter_written' ); return true; + break; case 'filter': $sieve = new Sieve\SieveParser(); if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) { @@ -1249,6 +1250,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $_data['quarantine_notification'] = (in_array('quarantine_notification', $_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['pw_reset'] = (in_array('pw_reset', $_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']); @@ -1264,14 +1266,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $_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']); + $_data['pw_reset'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_pw_reset']); } try { $stmt = $pdo->prepare("INSERT INTO `user_acl` (`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`, `pw_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, :pw_reset) "); $stmt->execute(array( ':username' => $username, ':spam_alias' => $_data['spam_alias'], @@ -1287,7 +1290,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ':quarantine_attachments' => $_data['quarantine_attachments'], ':quarantine_notification' => $_data['quarantine_notification'], ':quarantine_category' => $_data['quarantine_category'], - ':app_passwds' => $_data['app_passwds'] + ':app_passwds' => $_data['app_passwds'], + ':pw_reset' => $_data['pw_reset'] )); } catch (PDOException $e) { @@ -1576,6 +1580,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0; $attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0; $attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0; + $attr['acl_pw_reset'] = (in_array('pw_reset', $_data['acl'])) ? 1 : 0; } else { $_data['acl'] = (array)$_data['acl']; $attr['acl_spam_alias'] = 0; @@ -2865,21 +2870,22 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0; } if (!empty($is_now)) { - $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; + $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; (int)$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($is_now['attributes']['force_pw_update']); - (int)$sogo_access = (isset($_data['sogo_access']) && isset($_SESSION['acl']['sogo_access']) && $_SESSION['acl']['sogo_access'] == "1") ? intval($_data['sogo_access']) : intval($is_now['attributes']['sogo_access']); - (int)$imap_access = (isset($_data['imap_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['imap_access']) : intval($is_now['attributes']['imap_access']); - (int)$pop3_access = (isset($_data['pop3_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['pop3_access']) : intval($is_now['attributes']['pop3_access']); - (int)$smtp_access = (isset($_data['smtp_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']); - (int)$sieve_access = (isset($_data['sieve_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['sieve_access']) : intval($is_now['attributes']['sieve_access']); - (int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['mailbox_relayhost']) && $_SESSION['acl']['mailbox_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['attributes']['relayhost']); - (int)$quota_m = (isset_has_content($_data['quota'])) ? intval($_data['quota']) : ($is_now['quota'] / 1048576); - $name = (!empty($_data['name'])) ? ltrim(rtrim($_data['name'], '>'), '<') : $is_now['name']; - $domain = $is_now['domain']; - $quota_b = $quota_m * 1048576; - $password = (!empty($_data['password'])) ? $_data['password'] : null; - $password2 = (!empty($_data['password2'])) ? $_data['password2'] : null; - $tags = (is_array($_data['tags']) ? $_data['tags'] : array()); + (int)$sogo_access = (isset($_data['sogo_access']) && isset($_SESSION['acl']['sogo_access']) && $_SESSION['acl']['sogo_access'] == "1") ? intval($_data['sogo_access']) : intval($is_now['attributes']['sogo_access']); + (int)$imap_access = (isset($_data['imap_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['imap_access']) : intval($is_now['attributes']['imap_access']); + (int)$pop3_access = (isset($_data['pop3_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['pop3_access']) : intval($is_now['attributes']['pop3_access']); + (int)$smtp_access = (isset($_data['smtp_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']); + (int)$sieve_access = (isset($_data['sieve_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['sieve_access']) : intval($is_now['attributes']['sieve_access']); + (int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['mailbox_relayhost']) && $_SESSION['acl']['mailbox_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['attributes']['relayhost']); + (int)$quota_m = (isset_has_content($_data['quota'])) ? intval($_data['quota']) : ($is_now['quota'] / 1048576); + $name = (!empty($_data['name'])) ? ltrim(rtrim($_data['name'], '>'), '<') : $is_now['name']; + $domain = $is_now['domain']; + $quota_b = $quota_m * 1048576; + $password = (!empty($_data['password'])) ? $_data['password'] : null; + $password2 = (!empty($_data['password2'])) ? $_data['password2'] : null; + $pw_recovery_email = (isset($_data['pw_recovery_email'])) ? $_data['pw_recovery_email'] : $is_now['attributes']['recovery_email']; + $tags = (is_array($_data['tags']) ? $_data['tags'] : array()); } else { $_SESSION['return'][] = array( @@ -3132,31 +3138,43 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ':address' => $username, ':active' => $active )); - $stmt = $pdo->prepare("UPDATE `mailbox` SET - `active` = :active, - `name`= :name, - `quota` = :quota_b, - `attributes` = JSON_SET(`attributes`, '$.force_pw_update', :force_pw_update), - `attributes` = JSON_SET(`attributes`, '$.sogo_access', :sogo_access), - `attributes` = JSON_SET(`attributes`, '$.imap_access', :imap_access), - `attributes` = JSON_SET(`attributes`, '$.sieve_access', :sieve_access), - `attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access), - `attributes` = JSON_SET(`attributes`, '$.relayhost', :relayhost), - `attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access) - WHERE `username` = :username"); - $stmt->execute(array( - ':active' => $active, - ':name' => $name, - ':quota_b' => $quota_b, - ':force_pw_update' => $force_pw_update, - ':sogo_access' => $sogo_access, - ':imap_access' => $imap_access, - ':pop3_access' => $pop3_access, - ':sieve_access' => $sieve_access, - ':smtp_access' => $smtp_access, - ':relayhost' => $relayhost, - ':username' => $username - )); + try { + $stmt = $pdo->prepare("UPDATE `mailbox` SET + `active` = :active, + `name`= :name, + `quota` = :quota_b, + `attributes` = JSON_SET(`attributes`, '$.force_pw_update', :force_pw_update), + `attributes` = JSON_SET(`attributes`, '$.sogo_access', :sogo_access), + `attributes` = JSON_SET(`attributes`, '$.imap_access', :imap_access), + `attributes` = JSON_SET(`attributes`, '$.sieve_access', :sieve_access), + `attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access), + `attributes` = JSON_SET(`attributes`, '$.relayhost', :relayhost), + `attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access), + `attributes` = JSON_SET(`attributes`, '$.recovery_email', :recovery_email) + WHERE `username` = :username"); + $stmt->execute(array( + ':active' => $active, + ':name' => $name, + ':quota_b' => $quota_b, + ':force_pw_update' => $force_pw_update, + ':sogo_access' => $sogo_access, + ':imap_access' => $imap_access, + ':pop3_access' => $pop3_access, + ':sieve_access' => $sieve_access, + ':smtp_access' => $smtp_access, + ':recovery_email' => $pw_recovery_email, + ':relayhost' => $relayhost, + ':username' => $username + )); + } + catch (PDOException $e) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => $e->getMessage() + ); + return false; + } // save tags foreach($tags as $index => $tag){ if (empty($tag)) continue; @@ -3263,6 +3281,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0; $attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0; $attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0; + $attr['acl_pw_reset'] = (in_array('pw_reset', $_data['acl'])) ? 1 : 0; } else { foreach ($is_now as $key => $value){ $attr[$key] = $is_now[$key]; @@ -3438,30 +3457,54 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $footers['plain'] = isset($_data['plain']) ? $_data['plain'] : ''; $footers['skip_replies'] = isset($_data['skip_replies']) ? (int)$_data['skip_replies'] : 0; $footers['mbox_exclude'] = array(); - if (isset($_data["mbox_exclude"])){ - if (!is_array($_data["mbox_exclude"])) { - $_data["mbox_exclude"] = array($_data["mbox_exclude"]); + $footers['alias_domain_exclude'] = array(); + if (isset($_data["exclude"])){ + if (!is_array($_data["exclude"])) { + $_data["exclude"] = array($_data["exclude"]); } - foreach ($_data["mbox_exclude"] as $mailbox) { - if (!filter_var($mailbox, FILTER_VALIDATE_EMAIL)) { + foreach ($_data["exclude"] as $exclude) { + if (filter_var($exclude, FILTER_VALIDATE_EMAIL)) { + $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `address` = :address + UNION + SELECT `username` FROM `mailbox` WHERE `username` = :username"); + $stmt->execute(array( + ':address' => $exclude, + ':username' => $exclude, + )); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if(!$row){ + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('username_invalid', $exclude) + ); + continue; + } + array_push($footers['mbox_exclude'], $exclude); + } + elseif (is_valid_domain_name($exclude)) { + $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `alias_domain` = :alias_domain"); + $stmt->execute(array( + ':alias_domain' => $exclude, + )); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if(!$row){ + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('username_invalid', $exclude) + ); + continue; + } + array_push($footers['alias_domain_exclude'], $exclude); + } + else { $_SESSION['return'][] = array( 'type' => 'danger', 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), - 'msg' => array('username_invalid', $mailbox) + 'msg' => array('username_invalid', $exclude) ); - continue; } - $is_now = mailbox('get', 'mailbox_details', $mailbox); - if(empty($is_now)){ - $_SESSION['return'][] = array( - 'type' => 'danger', - 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), - 'msg' => array('username_invalid', $mailbox) - ); - continue; - } - - array_push($footers['mbox_exclude'], $mailbox); } } foreach ($domains as $domain) { @@ -3486,12 +3529,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { try { $stmt = $pdo->prepare("DELETE FROM `domain_wide_footer` WHERE `domain`= :domain"); $stmt->execute(array(':domain' => $domain)); - $stmt = $pdo->prepare("INSERT INTO `domain_wide_footer` (`domain`, `html`, `plain`, `mbox_exclude`, `skip_replies`) VALUES (:domain, :html, :plain, :mbox_exclude, :skip_replies)"); + $stmt = $pdo->prepare("INSERT INTO `domain_wide_footer` (`domain`, `html`, `plain`, `mbox_exclude`, `alias_domain_exclude`, `skip_replies`) VALUES (:domain, :html, :plain, :mbox_exclude, :alias_domain_exclude, :skip_replies)"); $stmt->execute(array( ':domain' => $domain, ':html' => $footers['html'], ':plain' => $footers['plain'], ':mbox_exclude' => json_encode($footers['mbox_exclude']), + ':alias_domain_exclude' => json_encode($footers['alias_domain_exclude']), ':skip_replies' => $footers['skip_replies'], )); } @@ -4316,6 +4360,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $domaindata['mboxes_in_domain'] = $MailboxDataDomain['count']; $domaindata['mboxes_left'] = $row['mailboxes'] - $MailboxDataDomain['count']; $domaindata['domain_name'] = $row['domain']; + $domaindata['domain_h_name'] = idn_to_utf8($row['domain']); $domaindata['description'] = $row['description']; $domaindata['max_num_aliases_for_domain'] = $row['aliases']; $domaindata['max_num_mboxes_for_domain'] = $row['mailboxes']; @@ -4648,7 +4693,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { } try { - $stmt = $pdo->prepare("SELECT `html`, `plain`, `mbox_exclude`, `skip_replies` FROM `domain_wide_footer` + $stmt = $pdo->prepare("SELECT `html`, `plain`, `mbox_exclude`, `alias_domain_exclude`, `skip_replies` FROM `domain_wide_footer` WHERE `domain` = :domain"); $stmt->execute(array( ':domain' => $domain @@ -5186,7 +5231,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { 'msg' => 'Could not move maildir to garbage collector: variables local_part and/or domain empty' ); } - if (strtolower(getenv('SKIP_SOLR')) == 'n') { + if (strtolower(getenv('SKIP_SOLR')) == 'n' && strtolower(getenv('FLATCURVE_EXPERIMENTAL')) != 'y') { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, 'http://solr:8983/solr/dovecot-fts/update?commit=true'); curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: text/xml')); diff --git a/data/web/inc/functions.rspamd.inc.php b/data/web/inc/functions.rspamd.inc.php index fd1c5bd6..c2444d99 100644 --- a/data/web/inc/functions.rspamd.inc.php +++ b/data/web/inc/functions.rspamd.inc.php @@ -143,17 +143,26 @@ function rspamd_maps($_action, $_data = null) { return false; } $maps = (array)$_data['map']; + $valid_maps = array(); foreach ($maps as $map) { + $is_valid = false; foreach ($RSPAMD_MAPS as $rspamd_map_type) { - if (!in_array($map, $rspamd_map_type)) { - $_SESSION['return'][] = array( - 'type' => 'danger', - 'log' => array(__FUNCTION__, $_action, '-'), - 'msg' => array('global_map_invalid', $map) - ); - continue; + if (in_array($map, $rspamd_map_type)) { + $is_valid = true; + break; } } + if ($is_valid) { + array_push($valid_maps, $map); + } else { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, '-'), + 'msg' => array('global_map_invalid', $map) + ); + } + } + foreach ($valid_maps as $map) { try { if (file_exists('/rspamd_custom_maps/' . $map)) { $map_content = trim($_data['rspamd_map_data']); diff --git a/data/web/inc/header.inc.php b/data/web/inc/header.inc.php index 9afc288d..5fe25bef 100644 --- a/data/web/inc/header.inc.php +++ b/data/web/inc/header.inc.php @@ -49,7 +49,6 @@ $globalVariables = [ 'app_links' => customize('get', 'app_links'), 'is_root_uri' => (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == '/'), 'uri' => $_SERVER['REQUEST_URI'], - 'last_login' => last_login('get', $_SESSION['mailcow_cc_username'], 7, 0)['ui']['time'] ]; foreach ($globalVariables as $globalVariableName => $globalVariableValue) { diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php index 6fec0c2f..8c4951d5 100644 --- a/data/web/inc/init_db.inc.php +++ b/data/web/inc/init_db.inc.php @@ -3,7 +3,7 @@ function init_db_schema() { try { global $pdo; - $db_version = "08012024_1442"; + $db_version = "29072024_1000"; $stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); @@ -273,6 +273,7 @@ function init_db_schema() { "html" => "LONGTEXT", "plain" => "LONGTEXT", "mbox_exclude" => "JSON NOT NULL DEFAULT ('[]')", + "alias_domain_exclude" => "JSON NOT NULL DEFAULT ('[]')", "skip_replies" => "TINYINT(1) NOT NULL DEFAULT '0'" ), "keys" => array( @@ -482,6 +483,7 @@ function init_db_schema() { "quarantine_notification" => "TINYINT(1) NOT NULL DEFAULT '1'", "quarantine_category" => "TINYINT(1) NOT NULL DEFAULT '1'", "app_passwds" => "TINYINT(1) NOT NULL DEFAULT '1'", + "pw_reset" => "TINYINT(1) NOT NULL DEFAULT '1'", ), "keys" => array( "primary" => array( @@ -693,6 +695,19 @@ function init_db_schema() { ), "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC" ), + "reset_password" => array( + "cols" => array( + "username" => "VARCHAR(255) NOT NULL", + "token" => "VARCHAR(255) NOT NULL", + "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)", + ), + "keys" => array( + "primary" => array( + "" => array("token", "created") + ), + ), + "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC" + ), "imapsync" => array( "cols" => array( "id" => "INT NOT NULL AUTO_INCREMENT", @@ -978,6 +993,18 @@ function init_db_schema() { ), "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC" ), + "sogo_admin" => array( + "cols" => array( + "c_key" => "VARCHAR(255) NOT NULL DEFAULT ''", + "c_content" => "mediumtext NOT NULL", + ), + "keys" => array( + "primary" => array( + "" => array("c_key") + ) + ), + "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC" + ), "pushover" => array( "cols" => array( "username" => "VARCHAR(255) NOT NULL", diff --git a/data/web/inc/lib/sieve/extensions/enotify.xml b/data/web/inc/lib/sieve/extensions/enotify.xml new file mode 100644 index 00000000..b4686a33 --- /dev/null +++ b/data/web/inc/lib/sieve/extensions/enotify.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/data/web/inc/lib/sieve/extensions/mime.xml b/data/web/inc/lib/sieve/extensions/mime.xml new file mode 100644 index 00000000..d7e200f0 --- /dev/null +++ b/data/web/inc/lib/sieve/extensions/mime.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/data/web/inc/presets/sieve/sieve_1.yml b/data/web/inc/presets/sieve/sieve_1.yml index e7fa8c84..45e0eb46 100644 --- a/data/web/inc/presets/sieve/sieve_1.yml +++ b/data/web/inc/presets/sieve/sieve_1.yml @@ -1,7 +1,7 @@ headline: lang.sieve_preset_1 content: | require ["reject","body","regex"]; - if anyof (body :raw :regex ["filename=.*\.doc","filename=.*\.exe","filename=.*\.moo"]) { + if anyof (body :raw :regex ["filename=\".*\\.(doc|exe|moo)\""]) { reject text: doc, exe and moo are dangerous file extensions. Why would you do that? I am a sad cow. diff --git a/data/web/inc/triggers.inc.php b/data/web/inc/triggers.inc.php index 6922429b..5c625e41 100644 --- a/data/web/inc/triggers.inc.php +++ b/data/web/inc/triggers.inc.php @@ -10,16 +10,54 @@ if (!empty($_GET['sso_token'])) { } } +if (isset($_POST["pw_reset_request"]) && !empty($_POST['username'])) { + reset_password("issue", $_POST['username']); + header("Location: /"); + exit; +} +if (isset($_POST["pw_reset"])) { + $username = reset_password("check", $_POST['token']); + $reset_result = reset_password("reset", array( + 'new_password' => $_POST['new_password'], + 'new_password2' => $_POST['new_password2'], + 'token' => $_POST['token'], + 'username' => $username, + 'check_tfa' => True + )); + + if ($reset_result){ + header("Location: /"); + exit; + } +} if (isset($_POST["verify_tfa_login"])) { if (verify_tfa_login($_SESSION['pending_mailcow_cc_username'], $_POST)) { - $_SESSION['mailcow_cc_username'] = $_SESSION['pending_mailcow_cc_username']; - $_SESSION['mailcow_cc_role'] = $_SESSION['pending_mailcow_cc_role']; - unset($_SESSION['pending_mailcow_cc_username']); - unset($_SESSION['pending_mailcow_cc_role']); - unset($_SESSION['pending_tfa_methods']); + if (isset($_SESSION['pending_mailcow_cc_username']) && isset($_SESSION['pending_pw_reset_token']) && isset($_SESSION['pending_pw_new_password'])) { + reset_password("reset", array( + 'new_password' => $_SESSION['pending_pw_new_password'], + 'new_password2' => $_SESSION['pending_pw_new_password'], + 'token' => $_SESSION['pending_pw_reset_token'], + 'username' => $_SESSION['pending_mailcow_cc_username'] + )); + unset($_SESSION['pending_pw_reset_token']); + unset($_SESSION['pending_pw_new_password']); + unset($_SESSION['pending_mailcow_cc_username']); + unset($_SESSION['pending_tfa_methods']); - header("Location: /user"); + header("Location: /"); + exit; + } else { + $_SESSION['mailcow_cc_username'] = $_SESSION['pending_mailcow_cc_username']; + $_SESSION['mailcow_cc_role'] = $_SESSION['pending_mailcow_cc_role']; + unset($_SESSION['pending_mailcow_cc_username']); + unset($_SESSION['pending_mailcow_cc_role']); + unset($_SESSION['pending_tfa_methods']); + + header("Location: /user"); + } } else { + unset($_SESSION['pending_pw_reset_token']); + unset($_SESSION['pending_pw_new_password']); unset($_SESSION['pending_mailcow_cc_username']); unset($_SESSION['pending_mailcow_cc_role']); unset($_SESSION['pending_tfa_methods']); @@ -27,11 +65,13 @@ if (isset($_POST["verify_tfa_login"])) { } if (isset($_GET["cancel_tfa_login"])) { - unset($_SESSION['pending_mailcow_cc_username']); - unset($_SESSION['pending_mailcow_cc_role']); - unset($_SESSION['pending_tfa_methods']); + unset($_SESSION['pending_pw_reset_token']); + unset($_SESSION['pending_pw_new_password']); + unset($_SESSION['pending_mailcow_cc_username']); + unset($_SESSION['pending_mailcow_cc_role']); + unset($_SESSION['pending_tfa_methods']); - header("Location: /"); + header("Location: /"); } if (isset($_POST["quick_release"])) { diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php index afc801e4..d3165b8a 100644 --- a/data/web/inc/vars.inc.php +++ b/data/web/inc/vars.inc.php @@ -95,6 +95,8 @@ $AVAILABLE_LANGUAGES = array( 'it-it' => 'Italiano (Italian)', 'ko-kr' => '한국어 (Korean)', 'lv-lv' => 'latviešu (Latvian)', + 'lt-lt' => 'Lietuvių (Lithuanian)', + 'nb-no' => 'Norsk (Norwegian)', 'nl-nl' => 'Nederlands (Dutch)', 'pl-pl' => 'Język Polski (Polish)', 'pt-br' => 'Português brasileiro (Brazilian Portuguese)', @@ -208,6 +210,12 @@ $MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format'] = 'maildir:'; // Show last IMAP and POP3 logins $SHOW_LAST_LOGIN = true; +// Maximum number of password reset tokens that can be generated at once per user +$PW_RESET_TOKEN_LIMIT = 3; + +// Maximum time in minutes a password reset token is valid +$PW_RESET_TOKEN_LIFETIME = 15; + // UV flag handling in FIDO2/WebAuthn - defaults to false to allow iOS logins // true = required // false = preferred diff --git a/data/web/js/site/admin.js b/data/web/js/site/admin.js index 80da6416..a2c7954d 100644 --- a/data/web/js/site/admin.js +++ b/data/web/js/site/admin.js @@ -397,7 +397,10 @@ jQuery(function($){ { title: lang.host, data: 'hostname', - defaultContent: '' + defaultContent: '', + render: function (data, type) { + return escapeHtml(data); + } }, { title: lang.username, diff --git a/data/web/js/site/debug.js b/data/web/js/site/debug.js index 512d9551..3c51c194 100644 --- a/data/web/js/site/debug.js +++ b/data/web/js/site/debug.js @@ -325,7 +325,10 @@ jQuery(function($){ title: 'URI', data: 'uri', defaultContent: '', - className: 'dtr-col-md dtr-break-all' + className: 'dtr-col-md dtr-break-all', + render: function (data, type) { + return escapeHtml(data); + } }, { title: 'Method', @@ -1294,13 +1297,7 @@ function update_stats(timeout=5){ $("#host_cpu_usage").text(parseInt(data.cpu.usage).toString() + "%"); $("#host_memory_total").text((data.memory.total / (1024 ** 3)).toFixed(2).toString() + "GB"); $("#host_memory_usage").text(parseInt(data.memory.usage).toString() + "%"); - if (data.architecture == "aarch64"){ - $("#host_architecture").html('' + data.architecture + ' ⚠️'); - } - else { - $("#host_architecture").html(data.architecture); - } - + $("#host_architecture").html(data.architecture); // update cpu and mem chart var cpu_chart = Chart.getChart("host_cpu_chart"); var mem_chart = Chart.getChart("host_mem_chart"); diff --git a/data/web/js/site/mailbox.js b/data/web/js/site/mailbox.js index cc316b71..51dbcf43 100644 --- a/data/web/js/site/mailbox.js +++ b/data/web/js/site/mailbox.js @@ -380,6 +380,9 @@ $(document).ready(function() { if (template.acl_app_passwds == 1){ acl.push("app_passwds"); } + if (template.acl_pw_reset == 1){ + acl.push("pw_reset"); + } $('#user_acl').selectpicker('val', acl); $('#rl_value').val(template.rl_value); @@ -451,6 +454,10 @@ jQuery(function($){ dataSrc: function(json){ $.each(json.data, function(i, item) { item.domain_name = escapeHtml(item.domain_name); + item.domain_h_name = escapeHtml(item.domain_h_name); + if (item.domain_name != item.domain_h_name){ + item.domain_h_name = item.domain_h_name + '' + item.domain_name + ''; + } item.aliases = item.aliases_in_domain + " / " + item.max_num_aliases_for_domain; item.mailboxes = item.mboxes_in_domain + " / " + item.max_num_mboxes_for_domain; @@ -489,11 +496,11 @@ jQuery(function($){ if (item.backupmx == 1) { if (item.relay_unknown_only == 1) { - item.domain_name = '
Relay Non-Local
' + item.domain_name; + item.domain_h_name = '
Relay Non-Local
' + item.domain_h_name; } else if (item.relay_all_recipients == 1) { - item.domain_name = '
Relay All
' + item.domain_name; + item.domain_h_name = '
Relay All
' + item.domain_h_name; } else { - item.domain_name = '
Relay
' + item.domain_name; + item.domain_h_name = '
Relay
' + item.domain_h_name; } } }); @@ -521,7 +528,7 @@ jQuery(function($){ }, { title: lang.domain, - data: 'domain_name', + data: 'domain_h_name', responsivePriority: 3, defaultContent: '' }, diff --git a/data/web/js/site/user.js b/data/web/js/site/user.js index 088321cd..59d65d8c 100644 --- a/data/web/js/site/user.js +++ b/data/web/js/site/user.js @@ -676,5 +676,5 @@ jQuery(function($){ onVisible("[id^=wl_policy_mailbox_table]", () => draw_wl_policy_mailbox_table()); onVisible("[id^=sync_job_table]", () => draw_sync_job_table()); onVisible("[id^=app_passwd_table]", () => draw_app_passwd_table()); - last_logins('get'); + onVisible("[id^=recent-logins]", () => last_logins('get')); }); diff --git a/data/web/json_api.php b/data/web/json_api.php index 28f8cac5..e14dd996 100644 --- a/data/web/json_api.php +++ b/data/web/json_api.php @@ -47,6 +47,12 @@ function api_log($_data) { } } +// Block requests not intended for direct API use by checking the 'Sec-Fetch-Dest' header. +if (isset($_SERVER['HTTP_SEC_FETCH_DEST']) && $_SERVER['HTTP_SEC_FETCH_DEST'] !== 'empty') { + header('HTTP/1.1 403 Forbidden'); + exit; +} + if (isset($_GET['query'])) { $query = explode('/', $_GET['query']); @@ -1967,7 +1973,6 @@ if (isset($_GET['query'])) { case "quota_notification_bcc": process_edit_return(quota_notification_bcc('edit', $attr)); break; - break; case "mailq": process_edit_return(mailq('edit', array_merge(array('qid' => $items), $attr))); break; @@ -2063,6 +2068,9 @@ if (isset($_GET['query'])) { case "cors": process_edit_return(cors('edit', $attr)); break; + case "reset-password-notification": + process_edit_return(reset_password('edit_notification', $attr)); + break; // return no route found if no case is matched default: http_response_code(404); diff --git a/data/web/lang/lang.cs-cz.json b/data/web/lang/lang.cs-cz.json index 2d0b1014..593f1cdc 100644 --- a/data/web/lang/lang.cs-cz.json +++ b/data/web/lang/lang.cs-cz.json @@ -547,7 +547,7 @@ "dns_records": "DNS záznamy", "dns_records_24hours": "Upozornění: Změnám v systému DNS může trvat až 24 hodin, než se zde správně zobrazí jejich aktuální stav. Můžete zde snadno zjistit, jak nastavit DNS záznamy a zda jsou všechny záznamy správně uloženy.", "dns_records_data": "Správný záznam", - "dns_records_docs": "Přečtěte si prosím dokumentaci.", + "dns_records_docs": "Přečtěte si prosím dokumentaci.", "dns_records_name": "Název", "dns_records_status": "Současný stav", "dns_records_type": "Typ", diff --git a/data/web/lang/lang.da-dk.json b/data/web/lang/lang.da-dk.json index 33629bbe..95db916e 100644 --- a/data/web/lang/lang.da-dk.json +++ b/data/web/lang/lang.da-dk.json @@ -459,7 +459,7 @@ "cname_from_a": "Værdi afledt af A / AAAA-post. Dette understøttes, så længe posten peger på den korrekte ressource.", "dns_records": "DNS-poster", "dns_records_24hours": "Bemærk, at ændringer, der foretages i DNS, kan tage op til 24 timer for at få deres aktuelle status korrekt reflekteret på denne side. Det er beregnet som en måde for dig let at se, hvordan du konfigurerer dine DNS-poster og kontrollere, om alle dine poster er korrekt gemt i DNS.", - "dns_records_docs": "Se også dokumentationen.", + "dns_records_docs": "Se også dokumentationen.", "dns_records_data": "Korrekte data", "dns_records_name": "Navn", "dns_records_status": "Nuværende tilstand", diff --git a/data/web/lang/lang.de-de.json b/data/web/lang/lang.de-de.json index ddadfac6..189774ee 100644 --- a/data/web/lang/lang.de-de.json +++ b/data/web/lang/lang.de-de.json @@ -14,6 +14,7 @@ "prohibited": "Untersagt durch Richtlinie", "protocol_access": "Ändern der erlaubten Protokolle", "pushover": "Pushover", + "pw_reset": "Verwalten der E-Mail zur Passwortwiederherstellung erlauben", "quarantine": "Quarantäne-Aktionen", "quarantine_attachments": "Anhänge aus Quarantäne", "quarantine_category": "Ändern der Quarantäne-Benachrichtigungskategorie", @@ -248,6 +249,11 @@ "password_policy_numbers": "Muss eine Ziffer enthalten", "password_policy_special_chars": "Muss Sonderzeichen enthalten", "password_repeat": "Passwort wiederholen", + "password_reset_info": "Wenn keine E-Mail zur Passwortwiederherstellung hinterlegt ist, kann diese Funktion nicht genutzt werden.", + "password_reset_settings": "Einstellungen zur Passwortwiederherstellung", + "password_reset_tmpl_html": "HTML Vorlage", + "password_reset_tmpl_text": "Text Vorlage", + "password_settings": "Passwort Einstellungen", "priority": "Gewichtung", "private_key": "Private Key", "quarantine": "Quarantäne", @@ -287,6 +293,8 @@ "remove_row": "Entfernen", "reset_default": "Zurücksetzen auf Standard", "reset_limit": "Hash entfernen", + "reset_password_vars": "{{link}} Der generierte Passwort-Reset-Link
{{username}} Die E-Mail-Adresse des Benutzers, der die Passwortzurücksetzung angefordert hat
{{username2}} Die E-Mail-Adresse zur Wiederherstellung
{{date}} Das Datum, an dem die Passwort-Reset-Anfrage gestellt wurde
{{token_lifetime}} Die Gültigkeitsdauer des Tokens in Minuten
{{hostname}} Der mailcow Hostname", + "restore_template": "Leer lassen, um Standard-Template wiederherzustellen.", "routing": "Routing", "rsetting_add_rule": "Regel hinzufügen", "rsetting_content": "Regelinhalt", @@ -407,6 +415,7 @@ "invalid_nexthop_authenticated": "Dieser Next Hop existiert bereits mit abweichenden Authentifizierungsdaten. Die bestehenden Authentifizierungsdaten dieses \"Next Hops\" müssen vorab angepasst werden.", "invalid_recipient_map_new": "Neuer Empfänger \"%s\" ist ungültig", "invalid_recipient_map_old": "Originaler Empfänger \"%s\" ist ungültig", + "invalid_reset_token": "Ungültiger Rücksetz-Token", "ip_list_empty": "Liste erlaubter IPs darf nicht leer sein", "is_alias": "%s lautet bereits eine Alias-Adresse", "is_alias_or_mailbox": "Eine Mailbox, ein Alias oder eine sich aus einer Alias-Domain ergebende Adresse mit dem Namen %s ist bereits vorhanden", @@ -436,6 +445,8 @@ "password_complexity": "Passwort entspricht nicht den Richtlinien", "password_empty": "Passwort darf nicht leer sein", "password_mismatch": "Passwort-Wiederholung stimmt nicht überein", + "password_reset_invalid_user": "Benutzer nicht gefunden oder keine E-Mail-Adresse zur Wiederherstellung eingerichtet", + "password_reset_na": "Die Passwortwiederherstellung ist momentan nicht verfügbar. Bitte wenden Sie sich an Ihren Administrator.", "policy_list_from_exists": "Ein Eintrag mit diesem Wert existiert bereits", "policy_list_from_invalid": "Eintrag hat ein ungültiges Format", "private_key_error": "Schlüsselfehler: %s", @@ -444,10 +455,12 @@ "pushover_token": "Pushover Token hat das falsche Format", "quota_not_0_not_numeric": "Speicherplatz muss numerisch und >= 0 sein", "recipient_map_entry_exists": "Eine Empfängerumschreibung für Objekt \"%s\" existiert bereits", + "recovery_email_failed": "E-Mail zur Wiederherstellung konnte nicht gesendet werden. Bitte wenden Sie sich an Ihren Administrator.", "redis_error": "Redis Fehler: %s", "relayhost_invalid": "Map-Eintrag %s ist ungültig", "release_send_failed": "Die Nachricht konnte nicht versendet werden: %s", "reset_f2b_regex": "Regex-Filter konnten nicht in vorgegebener Zeit zurückgesetzt werden, bitte erneut versuchen oder die Webseite neu laden.", + "reset_token_limit_exceeded": "Das Limit für Rücksetz-Tokens wurde überschritten. Bitte versuchen Sie es später erneut.", "resource_invalid": "Ressourcenname %s ist ungültig", "rl_timeframe": "Ratelimit-Zeitraum ist inkorrekt", "rspamd_ui_pw_length": "Rspamd UI-Passwort muss mindestens 6 Zeichen lang sein", @@ -467,6 +480,7 @@ "tls_policy_map_dest_invalid": "Ziel ist ungültig", "tls_policy_map_entry_exists": "Eine TLS-Richtlinie \"%s\" existiert bereits", "tls_policy_map_parameter_invalid": "Parameter ist ungültig", + "to_invalid": "Empfänger darf nicht leer sein", "totp_verification_failed": "TOTP-Verifizierung fehlgeschlagen", "transport_dest_exists": "Transport-Maps-Ziel \"%s\" existiert bereits", "webauthn_verification_failed": "WebAuthn-Verifizierung fehlgeschlagen: %s", @@ -556,7 +570,7 @@ "dns_records": "DNS-Einträge", "dns_records_24hours": "Bitte beachten Sie, dass es bis zu 24 Stunden dauern kann, bis Änderungen an Ihren DNS-Einträgen als aktueller Status auf dieser Seite dargestellt werden. Diese Seite ist nur als Hilfsmittel gedacht, um die korrekten Werte für DNS-Einträge anzuzeigen und zu überprüfen, ob die Daten im DNS hinterlegt sind.", "dns_records_data": "Korrekte Daten", - "dns_records_docs": "Die Online-Dokumentation enthält weitere Informationen zur DNS-Konfiguration.", + "dns_records_docs": "Die Online-Dokumentation enthält weitere Informationen zur DNS-Konfiguration.", "dns_records_name": "Name", "dns_records_status": "Aktueller Status", "dns_records_type": "Typ", @@ -613,6 +627,7 @@ "extended_sender_acl_info": "Der DKIM-Domainkey der externen Absenderdomain sollte in diesen Server importiert werden, falls vorhanden.
\r\n Wird SPF verwendet, muss diesem Server der Versand gestattet werden.
\r\n Wird eine Domain oder Alias-Domain zu diesem Server hinzugefügt, die sich mit der externen Absenderadresse überschneidet, wird der externe Absender hier entfernt.
\r\n Ein Eintrag @domain.tld erlaubt den Versand als *@domain.tld", "force_pw_update": "Erzwinge Passwortänderung bei nächstem Login", "force_pw_update_info": "Dem Benutzer wird lediglich der Zugang zur %s ermöglicht, App Passwörter funktionieren weiterhin.", + "footer_exclude": "von Fußzeile ausschließen", "full_name": "Voller Name", "gal": "Globales Adressbuch", "gal_info": "Das globale Adressbuch enthält alle Objekte einer Domain und kann durch keinen Benutzer geändert werden. Die Verfügbarkeitsinformation in SOGo ist nur bei eingeschaltetem globalen Adressbuch ersichtlich Zum Anwenden einer Änderung muss SOGo neugestartet werden.", @@ -631,13 +646,13 @@ "max_quota": "Max. Größe per Mailbox (MiB)", "maxage": "Maximales Alter in Tagen einer Nachricht, die kopiert werden soll
(0 = alle Nachrichten kopieren)", "maxbytespersecond": "Max. Übertragungsrate in Bytes/s (0 für unlimitiert)", - "mbox_exclude": "Mailboxen ausschließen", "mbox_rl_info": "Dieses Limit wird auf den SASL Loginnamen angewendet und betrifft daher alle Absenderadressen, die der eingeloggte Benutzer verwendet. Bei Mailbox Ratelimit überwiegt ein Domain-weites Ratelimit.", "mins_interval": "Intervall (min)", "multiple_bookings": "Mehrfaches Buchen", "nexthop": "Next Hop", "none_inherit": "Keine Auswahl / Erben", "password": "Passwort", + "password_recovery_email": "E-Mail zur Passwortwiederherstellung", "password_repeat": "Passwort wiederholen", "previous": "Vorherige Seite", "private_comment": "Privater Kommentar", @@ -741,12 +756,19 @@ "session_expires": "Die Sitzung wird in etwa 15 Sekunden beendet." }, "login": { + "back_to_mailcow": "Zurück zu mailcow", "delayed": "Login wurde zur Sicherheit um %s Sekunde/n verzögert.", "fido2_webauthn": "FIDO2/WebAuthn Login", + "forgot_password": "> Passwort vergessen?", + "invalid_pass_reset_token": "Der Rücksetz-Token für das Passwort ist ungültig oder abgelaufen.
Bitte fordern Sie einen neuen Link zur Passwortwiederherstellung an.", "login": "Anmelden", "mobileconfig_info": "Bitte als Mailbox-Benutzer einloggen, um das Verbindungsprofil herunterzuladen.", + "new_password": "Neues Passwort", + "new_password_confirm": "Neues Passwort bestätigen", "other_logins": "Key Login", "password": "Passwort", + "reset_password": "Passwort zurücksetzen", + "request_reset_password": "Passwortänderung anfordern", "username": "Benutzername" }, "mailbox": { @@ -1065,11 +1087,13 @@ "nginx_reloaded": "Nginx wurde neu geladen", "object_modified": "Änderungen an Objekt %s wurden gespeichert", "password_policy_saved": "Passwortrichtlinie wurde erfolgreich gespeichert", + "password_changed_success": "Das Passwort wurde erfolgreich geändert", "pushover_settings_edited": "Pushover-Konfiguration gespeichert, bitte den Zugang im Anschluss verifizieren.", "qlearn_spam": "Nachricht-ID %s wurde als Spam gelernt und gelöscht", "queue_command_success": "Queue-Aufgabe erfolgreich ausgeführt", "recipient_map_entry_deleted": "Empfängerumschreibung mit der ID %s wurde gelöscht", "recipient_map_entry_saved": "Empfängerumschreibung für Objekt \"%s\" wurde gespeichert", + "recovery_email_sent": "Wiederherstellungs-E-Mail an %s gesendet", "relayhost_added": "Map-Eintrag %s wurde hinzugefügt", "relayhost_removed": "Map-Eintrag %s wurde entfernt", "reset_main_logo": "Standardgrafik wurde wiederhergestellt", @@ -1202,6 +1226,7 @@ "password": "Passwort", "password_now": "Aktuelles Passwort (Änderungen bestätigen)", "password_repeat": "Passwort (Wiederholung)", + "password_reset_info": "Wenn keine E-Mail zur Passwortwiederherstellung hinterlegt ist, kann diese Funktion nicht genutzt werden.", "pushover_evaluate_x_prio": "Hohe Priorität eskalieren [X-Priority: 1]", "pushover_info": "Push-Benachrichtungen werden angewendet auf alle nicht-Spam Nachrichten zugestellt an %s, einschließlich Alias-Adressen (shared, non-shared, tagged).", "pushover_only_x_prio": "Nur Mail mit hoher Priorität berücksichtigen [X-Priority: 1]", @@ -1211,6 +1236,7 @@ "pushover_title": "Notification Titel", "pushover_vars": "Wenn kein Sender-Filter definiert ist, werden alle E-Mails berücksichtigt.
Die direkte Absenderprüfung und reguläre Ausdrücke werden unabhängig voneinander geprüft, sie hängen nicht voneinander ab und werden der Reihe nach ausgeführt.
Verwendbare Variablen für Titel und Text (Datenschutzrichtlinien beachten)", "pushover_verify": "Verbindung verifizieren", + "pw_recovery_email": "E-Mail zur Passwortwiederherstellung", "q_add_header": "Junk-Ordner", "q_all": "Alle Kategorien", "q_reject": "Abgelehnt", diff --git a/data/web/lang/lang.en-gb.json b/data/web/lang/lang.en-gb.json index ec97d0ae..60044180 100644 --- a/data/web/lang/lang.en-gb.json +++ b/data/web/lang/lang.en-gb.json @@ -14,6 +14,7 @@ "prohibited": "Prohibited by ACL", "protocol_access": "Change protocol access", "pushover": "Pushover", + "pw_reset": "Allow to reset mailcow user password", "quarantine": "Quarantine actions", "quarantine_attachments": "Quarantine attachments", "quarantine_category": "Change quarantine notification category", @@ -256,6 +257,11 @@ "password_policy_numbers": "Must contain at least one number", "password_policy_special_chars": "Must contain special characters", "password_repeat": "Confirmation password (repeat)", + "password_reset_info": "If no recovery email is provided, this function cannot be used.", + "password_reset_settings": "Password Recovery Settings", + "password_reset_tmpl_html": "HTML Template", + "password_reset_tmpl_text": "Text Template", + "password_settings": "Password Settings", "priority": "Priority", "private_key": "Private key", "quarantine": "Quarantine", @@ -296,6 +302,8 @@ "remove_row": "Remove row", "reset_default": "Reset to default", "reset_limit": "Remove hash", + "reset_password_vars": "{{link}} The generated password reset link
{{username}} The mailbox name of the user who requested the password reset
{{username2}} The recovery mailbox name
{{date}} The date the password reset request was made
{{token_lifetime}} The token lifetime in minutes
{{hostname}} The mailcow hostname", + "restore_template": "Leave empty to restore default template.", "routing": "Routing", "rsetting_add_rule": "Add rule", "rsetting_content": "Rule content", @@ -407,6 +415,7 @@ "invalid_nexthop_authenticated": "Next hop exists with different credentials, please update the existing credentials for this next hop first.", "invalid_recipient_map_new": "Invalid new recipient specified: %s", "invalid_recipient_map_old": "Invalid original recipient specified: %s", + "invalid_reset_token": "Invalid reset token", "ip_list_empty": "List of allowed IPs cannot be empty", "is_alias": "%s is already known as an alias address", "is_alias_or_mailbox": "%s is already known as an alias, a mailbox or an alias address expanded from an alias domain.", @@ -436,6 +445,8 @@ "password_complexity": "Password does not meet the policy", "password_empty": "Password must not be empty", "password_mismatch": "Confirmation password does not match", + "password_reset_invalid_user": "Mailbox not found or no recovery email is set", + "password_reset_na": "The password recovery is currently unavailable. Please contact your administrator.", "policy_list_from_exists": "A record with given name exists", "policy_list_from_invalid": "Record has invalid format", "private_key_error": "Private key error: %s", @@ -444,10 +455,12 @@ "pushover_token": "Pushover token has a wrong format", "quota_not_0_not_numeric": "Quota must be numeric and >= 0", "recipient_map_entry_exists": "A Recipient map entry \"%s\" exists", + "recovery_email_failed": "Could not send a recovery email. Please contact your administrator.", "redis_error": "Redis error: %s", "relayhost_invalid": "Map entry %s is invalid", "release_send_failed": "Message could not be released: %s", "reset_f2b_regex": "Regex filter could not be reset in time, please try again or wait a few more seconds and reload the website.", + "reset_token_limit_exceeded": "Reset token limit has been exceeded. Please try again later.", "resource_invalid": "Resource name %s is invalid", "rl_timeframe": "Rate limit time frame is incorrect", "rspamd_ui_pw_length": "Rspamd UI password should be at least 6 chars long", @@ -470,6 +483,7 @@ "tls_policy_map_dest_invalid": "Policy destination is invalid", "tls_policy_map_entry_exists": "A TLS policy map entry \"%s\" exists", "tls_policy_map_parameter_invalid": "Policy parameter is invalid", + "to_invalid": "Recipient must not be empty", "totp_verification_failed": "TOTP verification failed", "transport_dest_exists": "Transport destination \"%s\" exists", "webauthn_verification_failed": "WebAuthn verification failed: %s", @@ -556,7 +570,7 @@ "dns_records": "DNS Records", "dns_records_24hours": "Please note that changes made to DNS may take up to 24 hours to correctly have their current state reflected on this page. It is intended as a way for you to easily see how to configure your DNS records and to check whether all your records are correctly stored in DNS.", "dns_records_data": "Correct Data", - "dns_records_docs": "Please also consult the documentation.", + "dns_records_docs": "Please also consult the documentation.", "dns_records_name": "Name", "dns_records_status": "Current State", "dns_records_type": "Type", @@ -613,6 +627,7 @@ "extended_sender_acl_info": "A DKIM domain key should be imported, if available.
\r\n Remember to add this server to the corresponding SPF TXT record.
\r\n Whenever a domain or alias domain is added to this server, that overlaps with an external address, the external address is removed.
\r\n Use @domain.tld to allow to send as *@domain.tld.", "force_pw_update": "Force password update at next login", "force_pw_update_info": "This user will only be able to login to %s. App passwords remain useable.", + "footer_exclude": "Exclude from footer", "full_name": "Full name", "gal": "Global Address List", "gal_info": "The GAL contains all objects of a domain and cannot be edited by any user. Free/busy information in SOGo is missing, if disabled! Restart SOGo to apply changes.", @@ -631,13 +646,13 @@ "max_quota": "Max. quota per mailbox (MiB)", "maxage": "Maximum age of messages in days that will be polled from remote
(0 = ignore age)", "maxbytespersecond": "Max. bytes per second
(0 = unlimited)", - "mbox_exclude": "Exclude mailboxes", "mbox_rl_info": "This rate limit is applied on the SASL login name, it matches any \"from\" address used by the logged-in user. A mailbox rate limit overrides a domain-wide rate limit.", "mins_interval": "Interval (min)", "multiple_bookings": "Multiple bookings", "none_inherit": "None / Inherit", "nexthop": "Next hop", "password": "Password", + "password_recovery_email": "Password recovery email", "password_repeat": "Confirmation password (repeat)", "previous": "Previous page", "private_comment": "Private comment", @@ -741,12 +756,19 @@ "session_expires": "Your session will expire in about 15 seconds" }, "login": { + "back_to_mailcow": "Back to mailcow", "delayed": "Login was delayed by %s seconds.", "fido2_webauthn": "FIDO2/WebAuthn Login", + "forgot_password": "> Forgot Password?", + "invalid_pass_reset_token": "The reset password token is invalid or has expired.
Please request a new password reset link.", "login": "Login", "mobileconfig_info": "Please login as mailbox user to download the requested Apple connection profile.", + "new_password": "New Password", + "new_password_confirm": "Confirm new password", "other_logins": "Key login", "password": "Password", + "reset_password": "Reset Password", + "request_reset_password": "Request password change", "username": "Username" }, "mailbox": { @@ -1072,11 +1094,13 @@ "nginx_reloaded": "Nginx was reloaded", "object_modified": "Changes to object %s have been saved", "password_policy_saved": "Password policy was saved successfully", + "password_changed_success": "Password was successfully changed", "pushover_settings_edited": "Pushover settings successfully set, please verify credentials.", "qlearn_spam": "Message ID %s was learned as spam and deleted", "queue_command_success": "Queue command completed successfully", "recipient_map_entry_deleted": "Recipient map ID %s has been deleted", "recipient_map_entry_saved": "Recipient map entry \"%s\" has been saved", + "recovery_email_sent": "Recovery email sent to %s", "relayhost_added": "Map entry %s has been added", "relayhost_removed": "Map entry %s has been removed", "reset_main_logo": "Reset to default logo", @@ -1210,6 +1234,7 @@ "password": "Password", "password_now": "Current password (confirm changes)", "password_repeat": "Password (repeat)", + "password_reset_info": "If no email for password recovery is provided, this function cannot be used.", "pushover_evaluate_x_prio": "Escalate high priority mail [X-Priority: 1]", "pushover_info": "Push notification settings will apply to all clean (non-spam) mail delivered to %s including aliases (shared, non-shared, tagged).", "pushover_only_x_prio": "Only consider high priority mail [X-Priority: 1]", @@ -1220,6 +1245,7 @@ "pushover_sound": "Sound", "pushover_vars": "When no sender filter is defined, all mails will be considered.
Regex filters as well as exact sender checks can be defined individually and will be considered sequentially. They do not depend on each other.
Useable variables for text and title (please take note of data protection policies)", "pushover_verify": "Verify credentials", + "pw_recovery_email": "Password recovery email", "q_add_header": "Junk folder", "q_all": "All categories", "q_reject": "Rejected", diff --git a/data/web/lang/lang.es-es.json b/data/web/lang/lang.es-es.json index 78580ccc..8a8c0527 100644 --- a/data/web/lang/lang.es-es.json +++ b/data/web/lang/lang.es-es.json @@ -22,7 +22,9 @@ "app_passwds": "Gestionar las contraseñas de aplicaciones", "domain_desc": "Cambiar descripción del dominio", "protocol_access": "Cambiar protocolo de acceso", - "quarantine_category": "Cambiar categoría de las notificaciones de cuarentena" + "quarantine_category": "Cambiar categoría de las notificaciones de cuarentena", + "domain_relayhost": "Cambiar relayhost por un dominio", + "extend_sender_acl": "Permitir extender la ACL del remitente por direcciones externas" }, "add": { "activate_filter_warn": "Todos los demás filtros se desactivarán cuando este filtro se active.", diff --git a/data/web/lang/lang.fr-fr.json b/data/web/lang/lang.fr-fr.json index 96e1aef7..aed9ec56 100644 --- a/data/web/lang/lang.fr-fr.json +++ b/data/web/lang/lang.fr-fr.json @@ -25,7 +25,7 @@ "spam_score": "Score SPAM", "syncjobs": "Tâches de synchronisation", "tls_policy": "Politique TLS", - "unlimited_quota": "Quota illimité pour les boites de courriel", + "unlimited_quota": "Quota illimité pour les boîtes de réception", "domain_desc": "Modifier la description du domaine", "domain_relayhost": "Changer le relais pour un domaine", "mailbox_relayhost": "Changer le relais d’une boîte de réception" @@ -52,7 +52,7 @@ "delete2duplicates": "Supprimer les doubles à destination", "description": "Description", "destination": "Destination", - "disable_login": "Désactiver l'authentification (les mails entrants resteront acceptés)", + "disable_login": "Désactiver l'authentification (les courriels entrants resteront acceptés)", "domain": "domaine", "domain_matches_hostname": "Le domaine %s correspond à la machine (hostname)", "domain_quota_m": "Quota total du domaine (Mo)", @@ -68,11 +68,11 @@ "hostname": "Nom d'hôte", "inactive": "Inactif", "kind": "Type", - "mailbox_quota_def": "Quota boîte mail par défaut", - "mailbox_quota_m": "Quota max par boîte (Mo)", + "mailbox_quota_def": "Quota boîte de réception par défaut", + "mailbox_quota_m": "Quota max par boîte de réception (Mo)", "mailbox_username": "Identifiant (partie gauche d'une adresse de courriel)", "max_aliases": "Nombre maximal d'alias", - "max_mailboxes": "Nombre maximal de boîtes", + "max_mailboxes": "Nombre maximal de boîtes de réception", "mins_interval": "Période de relève (minutes)", "multiple_bookings": "Inscriptions multiples", "nexthop": "Suivant", @@ -84,10 +84,10 @@ "public_comment": "Commentaire public", "quota_mb": "Quota (Mo)", "relay_all": "Relayer tous les destinataires", - "relay_all_info": "↪ Si vous choissisez de ne pas relayer tous les destinataires, vous devez ajouter une boîte (\"aveugle\") pour chaque destinataire simple qui doit être relayé.", + "relay_all_info": "↪ Si vous choissisez de ne pas relayer tous les destinataires, vous devez ajouter une boîte de réception (\"aveugle\") pour chaque destinataire simple qui doit être relayé.", "relay_domain": "Relayer ce domaine", "relay_transport_info": "
Info
Vous pouvez définir des cartes de transport vers une destination personnalisée pour ce domaine. sinon, une recherche MX sera effectuée.", - "relay_unknown_only": "Relayer uniquement les boîtes inexistantes. Les boîtes existantes seront livrées localement.", + "relay_unknown_only": "Relayer uniquement les boîtes de réception inexistantes. Les boîtes de réception existantes seront livrées localement.", "relayhost_wrapped_tls_info": "Veuillez ne pas utiliser des ports TLS wrappés (généralement utilisés sur le port 465).
\r\nUtilisez n'importe quel port non encapsulé et lancez STARTTLS. Une politique TLS pour appliquer TLS peut être créée dans \"Cartes de politique TLS\".", "select": "Veuillez sélectionner…", "select_domain": "Sélectionner d'abord un domaine", @@ -96,7 +96,7 @@ "skipcrossduplicates": "Ignorer les messages en double dans les dossiers (premier arrivé, premier servi)", "subscribeall": "S'abonner à tous les dossiers", "syncjob": "Ajouter une tâche de synchronisation", - "syncjob_hint": "Sachez que les mots de passe seront sauvegardés en clair !", + "syncjob_hint": "Sachez que les mots de passe seront enregistrés en clair !", "target_address": "Aller à l'adresse", "target_address_info": "Adresse(s) de courriel complète(s) (séparées par des virgules).", "target_domain": "Domaine cible", @@ -105,9 +105,10 @@ "username": "Nom d'utilisateur", "validate": "Valider", "validation_success": "Validation réussie", - "bcc_dest_format": "La destination Cci doit être une seule adresse e-mail valide.
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 de courriel valide.
Si vous avez besoin d'envoyer une copie à plusieurs adresses, créez un alias et utilisez-le ici.", "tags": "Etiquettes", - "app_passwd_protocols": "Protocoles autorisés pour le mot de passe de l'application" + "app_passwd_protocols": "Protocoles autorisés pour le mot de passe de l'application", + "dry": "Simuler la synchronisation" }, "admin": { "access": "Accès", @@ -169,7 +170,7 @@ "domain_s": "Domaine(s)", "duplicate": "Dupliquer", "duplicate_dkim": "Dupliquer l'enregistrement DKIM", - "edit": "Editer", + "edit": "Éditer", "empty": "Aucun résultat", "excludes": "Exclure ces destinataires", "f2b_ban_time": "Durée du bannissement (s)", @@ -193,7 +194,7 @@ "generate": "générer", "guid": "GUID - Identifiant de l'instance", "guid_and_license": "GUID & Licence", - "hash_remove_info": "La suppression d'un hachage ratelimit (s'il existe toujours) réinitialisera complètement son compteur.
\r\n Chaque hachage est indiqué par une couleur individuelle.", + "hash_remove_info": "La suppression d'un hachage limite d'envoi (s'il existe toujours) réinitialisera complètement son compteur.
\n Chaque hachage est indiqué par une couleur individuelle.", "help_text": "Remplacer le texte d'aide sous le masque de connexion (HTML autorisé)", "host": "Hôte", "html": "HTML", @@ -202,14 +203,14 @@ "in_use_by": "Utilisé par", "inactive": "Inactif", "include_exclude": "Inclure/Exclure", - "include_exclude_info": "Par défaut - sans sélection - toutes les boîtes sont adressées", + "include_exclude_info": "Par défaut - sans sélection - toutes les boîte de réception sont adressées", "includes": "Inclure ces destinataires", "last_applied": "Dernière application", "license_info": "Une licence n’est pas requise, mais contribue au développement.
Enregistrer votre GUID ici or acheter le support pour votre intallation Mailcow.", "link": "Lien", "loading": "Veuillez patienter…", "logo_info": "Votre image sera redimensionnée à une hauteur de 40 pixels pour la barre de navigation du haut et à un maximum de 250 pixels en largeur pour la page d'accueil. Un graphique extensible est fortement recommandé.", - "lookup_mx": "Faire correspondre la destination à MX (.outlook.com pour acheminer tous les messages ciblés vers un MX * .outlook.com sur ce tronçon)", + "lookup_mx": "Faire correspondre la destination à MX (.*\\.google\\.com pour acheminer tous les messages ciblés vers un MX se terminant par google.com sur ce tronçon)", "main_name": "\"mailcow UI\" nom", "merged_vars_hint": "Les lignes grisées ont été importées depuis vars.(local.)inc.php et ne peuvent pas être modifiées.", "message": "Message", @@ -221,7 +222,7 @@ "no_record": "Aucun enregistrement", "oauth2_client_id": "Client ID", "oauth2_client_secret": "Secret client", - "oauth2_info": "L'implémentation OAuth2 prend en charge le type d'autorisation \"Authorization Code\" et émet des jetons d'actualisation.
\nLe serveur émet également automatiquement de nouveaux jetons d'actualisation, après qu'un jeton d'actualisation a été utilisé.

\n→ La portée par défaut est profile. Seuls les utilisateurs d'une boîte peuvent être authentifiés par rapport à OAuth2. Si le paramètre scope est omis, il revient au profile.
\n→ Le paramètre state doit être envoyé par le client dans le cadre de la demande d'autorisation.

\nChemins d'accès aux requêtes vers l'API OAuth
\n
    \n
  • Point de terminaison d'autorisation : /oauth/authorize
  • \n
  • Point de terminaison du jeton : /oauth/token
  • \n
  • Page de ressource : /oauth/profile
  • \n
\nLa régénération du secret client ne fera pas expirer les codes d'autorisation existants, mais ils ne pourront pas renouveler leur jeton.

\nLa révocation des jetons clients entraînera la fin immédiate de toutes les sessions actives. Tous les clients doivent se ré-authentifier.", + "oauth2_info": "L'implémentation OAuth2 prend en charge le type d'autorisation \"Authorization Code\" et émet des jetons d'actualisation.
\nLe serveur émet également automatiquement de nouveaux jetons d'actualisation, après qu'un jeton d'actualisation a été utilisé.

\n→ La portée par défaut est profile. Seuls les utilisateurs d'une boîte de réception peuvent être authentifiés par rapport à OAuth2. Si le paramètre scope est omis, il revient au profile.
\n→ Le paramètre state doit être envoyé par le client dans le cadre de la demande d'autorisation.

\nChemins d'accès aux requêtes vers l'API OAuth
\n
    \n
  • Point de terminaison d'autorisation : /oauth/authorize
  • \n
  • Point de terminaison du jeton : /oauth/token
  • \n
  • Page de ressource : /oauth/profile
  • \n
\nLa régénération du secret client ne fera pas expirer les codes d'autorisation existants, mais ils ne pourront pas renouveler leur jeton.

\nLa révocation des jetons clients entraînera la fin immédiate de toutes les sessions actives. Tous les clients doivent se ré-authentifier.", "oauth2_redirect_uri": "URI de redirection", "oauth2_renew_secret": "Générer un nouveau secret client", "oauth2_revoke_tokens": "Révoquer tous les jetons", @@ -236,24 +237,24 @@ "quarantine_max_age": "Âge maximun en jour(s)
La valeur doit être égale ou supérieure à 1 jour.", "quarantine_max_size": "Taille maximum en Mo (les éléments plus grands sont mis au rebut):
0 ne signifie pas illimité.", "quarantine_max_score": "Ignorer la notification si le score de spam est au dessus de cette valeur :
Par défaut : 9999.0", - "quarantine_notification_html": "Modèle de courriel de notification:
Laisser vide pour restaurer le modèle par défaut.", - "quarantine_notification_sender": "Notification par e-mail de l’expéditeur", + "quarantine_notification_html": "Modèle de courriel de notification :
Laisser vide pour restaurer le modèle par défaut.", + "quarantine_notification_sender": "Notification par courriel de l’expéditeur", "quarantine_notification_subject": "Objet du courriel de notification", "quarantine_redirect": "Rediriger toutes les notifications vers ce destinataire:
Laisser vide pour désactiver. Courrier non signé et non coché. Doit être livré en interne seulement.", "quarantine_release_format": "Format des éléments diffusés", "quarantine_release_format_att": "En pièce jointe", "quarantine_release_format_raw": "Original non modifié", - "quarantine_retention_size": "Rétentions par boîte:
0 indique inactive.", - "quota_notification_html": "Modèle de courriel de notification:
Laisser vide pour restaurer le modèle par défaut.", - "quota_notification_sender": "Notification par e-mail de l’expéditeur", + "quarantine_retention_size": "Rétentions par boîte de réception:
0 indique inactive.", + "quota_notification_html": "Modèle de courriel de notification :
Laisser vide pour restaurer le modèle par défaut.", + "quota_notification_sender": "Notification par courriel de l’expéditeur", "quota_notification_subject": "Objet du courriel de notification", "quota_notifications": "Notifications de quotas", "quota_notifications_info": "Les notications de quota sont envoyées aux utilisateurs une fois lors du passage à 80 % et une fois lors du passage à 95 % d’utilisation.", - "quota_notifications_vars": "{{percent}} égale le quota actuel de l’utilisateur
{{username}} est le nom de la boîte", + "quota_notifications_vars": "{{percent}} égale le quota actuel de l’utilisateur
{{username}} est le nom de la boîte de réception", "r_active": "Restrictions actives", "r_inactive": "Restrictions inactives", "r_info": "Les éléments grisés/désactivés sur la liste des restrictions actives ne sont pas considérés comme des restrictions valides pour Mailcow et ne peuvent pas être déplacés. Des restrictions inconnues seront établies par ordre d’apparition de toute façon.
Vous pouvez ajouter de nouveaux éléments dans le code inc/vars.local.inc.php pour pouvoir les basculer.", - "rate_name": "Nom du taux", + "rate_name": "Nom de la limite", "recipients": "Destinataires", "refresh": "Rafraîchir", "regen_api_key": "Regénérer la clé API", @@ -273,9 +274,9 @@ "rsetting_no_selection": "Veuillez sélectionner une règle", "rsetting_none": "Pas de règles disponibles", "rsettings_insert_preset": "Insérer un exemple de préréglage \"%s\"", - "rsettings_preset_1": "Désactiver tout sauf DKIM et la limite tarifaire pour les utilisateurs authentifiés", + "rsettings_preset_1": "Désactiver tout sauf DKIM et la limite d'envoi pour les utilisateurs authentifiés", "rsettings_preset_2": "Les postmasters veulent du spam", - "rsettings_preset_3": "Autoriser uniquement des expéditeurs particuliers pour une boîte (c.-à-d. utilisation comme boîte interne seulement)", + "rsettings_preset_3": "Autoriser uniquement des expéditeurs particuliers pour une boîte de réception (c.-à-d. utilisation comme boîte de réception interne seulement)", "rspamd_com_settings": "Un nom de paramètre sera généré automatiquement, voir l’exemple de préréglages ci-dessous. Pour plus de détails voir : Docs Rspamd", "rspamd_global_filters": "Cartes des filtres globaux", "rspamd_global_filters_agree": "Je serai prudent !", @@ -311,7 +312,7 @@ "ui_header_announcement_type_warning": "Important", "ui_header_announcement_type_danger": "Très important", "ui_texts": "Textes et étiquettes de l'interface utilisateur", - "unban_pending": "unban en attente", + "unban_pending": "Débanissement en attente", "unchanged_if_empty": "Si non modifié, laisser en blanc", "upload": "Charger", "username": "Nom d'utilisateur", @@ -330,7 +331,19 @@ "logo_normal_label": "Normal", "logo_dark_label": "Inversé pour le mode sombre", "allowed_methods": "Access-Control-Allow-Methods", - "allowed_origins": "Access-Control-Allow-Origin" + "allowed_origins": "Access-Control-Allow-Origin", + "copy_to_clipboard": "Texte copié dans le presse-papier !", + "password_policy_special_chars": "Doit contenir des caractères spéciaux", + "rsettings_preset_4": "Désactiver Rspamd pour un domaine", + "oauth2_apps": "Applications OAuth2", + "password_length": "Longueur des mots de passe", + "password_policy_chars": "Doit contenir au moins une lettre", + "password_policy_length": "La longueur minimale du mot de passe est de %d", + "f2b_manage_external_info": "Fail2ban maintiendra la liste de bannissement, mais ne définira pas activement de règles pour bloquer le trafic. Utilisez la liste de bannissement générée ci-dessous pour bloquer le trafic de manière externe.", + "f2b_manage_external": "Gérer Fail2Ban en externe", + "transport_test_rcpt_info": "• ; Utilisez null@hosted.mailcow.de pour tester le relais vers une destination étrangère.", + "relay_rcpt": "Adresse \"À :\"", + "is_mx_based": "Basé sur MX" }, "danger": { "access_denied": "Accès refusé ou données de formulaire non valides", @@ -344,9 +357,9 @@ "app_passwd_id_invalid": "Le mot de passe ID %s de l'application est non valide", "bcc_empty": "La destination BCC destination ne peut pas être vide", "bcc_exists": "Une carte de transport BCC %s existe pour le type %s", - "bcc_must_be_email": "Le destination BCC %s n'est pas une adresse mail valide", + "bcc_must_be_email": "La destination BCC %s n'est pas une adresse de courriel valide", "comment_too_long": "Le commentaire est trop long, 160 caractère max sont permis", - "defquota_empty": "Le quota par défaut par boîte ne doit pas être 0.", + "defquota_empty": "Le quota par défaut par boîte de réception doit pas être 0.", "description_invalid": "La description des ressources pour %s est non valide", "dkim_domain_or_sel_exists": "Une clé DKIM pour \"%s\" existe et ne sera pas écrasée", "dkim_domain_or_sel_invalid": "Domaine ou sélection DKIM non valide : %s", @@ -381,22 +394,22 @@ "invalid_recipient_map_old": "Destinataire original spécifié non valide : %s", "ip_list_empty": "La liste des adresses IP autorisées ne peut pas être vide", "is_alias": "%s est déjà connu comme une adresse alias", - "is_alias_or_mailbox": "%s est déjà connu comme un alias, une boîte ou une adresse alias développée à partir d’un domaine alias.", + "is_alias_or_mailbox": "%s est déjà connu comme un alias, une boîte de réception ou une adresse alias développée à partir d’un domaine alias.", "is_spam_alias": "%s est déjà connu comme une adresse alias temporaire (alias d'adresse spam)", "last_key": "La dernière clé ne peut pas être supprimée, veuillez désactiver TFA à la place.", "login_failed": "La connexion a échoué", "mailbox_defquota_exceeds_mailbox_maxquota": "Le quota par défaut dépasse la limite maximale du quota", - "mailbox_invalid": "Le nom de la boîte n'est pas valide", + "mailbox_invalid": "Le nom de la boîte de réception n'est pas valide", "mailbox_quota_exceeded": "Le quota dépasse la limite du domaine (max. %d Mo)", - "mailbox_quota_exceeds_domain_quota": "Le quota maximum dépasse la limite du quota de domaine", + "mailbox_quota_exceeds_domain_quota": "Le quota maximal dépasse la limite du quota de domaine", "mailbox_quota_left_exceeded": "Espace libre insuffisant (espace libre : %d Mio)", - "mailboxes_in_use": "Le max. des boîtes doit être supérieur ou égal à %d", + "mailboxes_in_use": "Le max. des boîtes de réception doit être supérieur ou égal à %d", "malformed_username": "Nom d’utilisateur malformé", "map_content_empty": "Le contenu de la carte ne peut pas être vide", "max_alias_exceeded": "Le nombre max. d'aliases est dépassé", - "max_mailbox_exceeded": "Le nombre max. de boîte est dépassé (%d of %d)", - "max_quota_in_use": "Le quota de la boîte doit être supérieur ou égal à %d Mo", - "maxquota_empty": "Le quota maximum par boîte ne doit pas être de 0.", + "max_mailbox_exceeded": "Le nombre max. de boîte de réception est dépassé (%d of %d)", + "max_quota_in_use": "Le quota de la boîte de réception doit être supérieur ou égal à %d Mo", + "maxquota_empty": "Le quota maximum par boîte de réception ne doit pas être de 0.", "mysql_error": "Erreur MySQL : %s", "nginx_reload_failed": "Le rechargement de Nginx a échoué : %s", "network_host_invalid": "Réseau ou hôte non valide : %s", @@ -421,15 +434,15 @@ "release_send_failed": "Le message n’a pas pu être diffusé : %s", "reset_f2b_regex": "Le filtre regex n'a pas pu être réinitialisé à temps, veuillez réessayer ou attendre quelques secondes de plus et recharger le site web.", "resource_invalid": "Le nom de la resource %s n'est pas valide", - "rl_timeframe": "Le délai limite du taux est incorrect", - "rspamd_ui_pw_length": "Le mot de passe de l'interface Rspamd doit être de 6 caratères au minimum", + "rl_timeframe": "Le délai de la limite d'envoi est incorrect", + "rspamd_ui_pw_length": "Le mot de passe de l'interface Rspamd doit être de 6 caractères au minimum", "script_empty": "Le script ne peut pas être vide", "sender_acl_invalid": "La valeur ACL de l’expéditeur %s est invalide", - "set_acl_failed": "Impossible de définir ACL", + "set_acl_failed": "Impossible de définir l'ACL", "settings_map_invalid": "La carte des paramètres %s est invalide", "sieve_error": "Erreur d'analyse syntaxique Sieve : %s", "spam_learn_error": "Erreur d'apprentissage du spam : %s", - "subject_empty": "Le sujet ne peut^pas être vide", + "subject_empty": "Le sujet ne peut pas être vide", "target_domain_invalid": "Le domaine cible %s n'est pas valide", "targetd_not_found": "Le domaine cible %s est introuvable", "targetd_relay_domain": "Le domaine cible %s est un domaine de relais", @@ -441,7 +454,7 @@ "tls_policy_map_parameter_invalid": "Le paramètre Policy est invalide", "totp_verification_failed": "Echec de la vérification TOTP", "transport_dest_exists": "La destination de transport \"%s\" existe", - "webauthn_verification_failed": "Echec de la vérification WebAuthn : %s", + "webauthn_verification_failed": "Échec de la vérification WebAuthn : %s", "fido2_verification_failed": "La vérification FIDO2 a échoué : %s", "unknown": "Une erreur inconnue est survenue", "unknown_tfa_method": "Methode TFA inconnue", @@ -450,11 +463,18 @@ "validity_missing": "Veuillez attribuer une période de validité", "value_missing": "Veuillez fournir toutes les valeurs", "yotp_verification_failed": "La vérification Yubico OTP a échoué : %s", - "webauthn_authenticator_failed": "L'authentificateur selectionné est introuvable", + "webauthn_authenticator_failed": "L'authentificateur sélectionné 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" + "template_exists": "Le modèle %s existe déjà", + "template_id_invalid": "Le numéro de modèle %s est invalide", + "template_name_invalid": "Le nom du modèle est invalide", + "img_dimensions_exceeded": "L'image dépasse les dimensions maximales", + "img_size_exceeded": "L'image dépasse la taille maximale de fichier", + "webauthn_publickey_failed": "Aucune clé publique n'a été stockée pour l'authentificateur sélectionné.", + "cors_invalid_method": "Allow-Method specifiée invalide", + "cors_invalid_origin": "Allow-Origin spécifiée invalide", + "extended_sender_acl_denied": "ACL manquante pour définir les adresses des expéditeurs externes", + "webauthn_username_failed": "L'authentificateur sélectionné appartient à un autre compte" }, "debug": { "chart_this_server": "Graphique (ce serveur)", @@ -464,7 +484,7 @@ "history_all_servers": "Historique (tous les serveurs)", "in_memory_logs": "Logs En-mémoire", "jvm_memory_solr": "Utilisation mémoire JVM", - "log_info": "

Les logs En-mémoire Mailcow sont collectés dans des listes Redis et découpées en LOG_LINES (%d) chaque minute pour réduire la charge.\r\n
Les logs En-mémoire ne sont pas destinés à être persistants. Toutes les applications qui se connectent en mémoire, se connectent également au démon Docker et donc au pilote de journalisation par défaut.\r\n
Le type de journal en mémoire doit être utilisé pour déboguer les problèmes mineurs avec les conteneurs.

\r\n

Les logs externes sont collectés via l'API de l'application concernée.

\r\n

Les journaux statiques sont principalement des journaux d’activité, qui ne sont pas enregistrés dans Dockerd, mais qui doivent toujours être persistants (sauf pour les logs API).

", + "log_info": "

Les logs En-mémoire Mailcow sont collectés dans des listes Redis et découpées en LOG_LINES (%d) chaque minute pour réduire la charge.\n
Les logs En-mémoire ne sont pas destinés à être persistants. Toutes les applications qui se connectent en mémoire, se connectent également au démon Docker, et donc au pilote de journalisation par défaut.\n
Le type de journal en mémoire doit être utilisé pour déboguer les problèmes mineurs avec les conteneurs.

\n

Les logs externes sont collectés via l'API de l'application concernée.

\n

Les journaux statiques sont principalement des journaux d’activité, qui ne sont pas enregistrés dans Dockerd, mais qui doivent toujours être persistants (sauf pour les logs API).

", "logs": "Logs", "restart_container": "Redémarrer", "solr_dead": "Solr est en cours de démarrage, désactivé ou mort.", @@ -477,23 +497,29 @@ "uptime": "Disponibilité", "started_on": "Démarré à", "static_logs": "Logs statiques", - "system_containers": "Système & Conteneurs" + "system_containers": "Système & Conteneurs", + "timezone": "Fuseau horaire", + "username": "Nom d'utilisateur", + "wip": "En cours de réalisation", + "architecture": "Architecture", + "cores": "Cœurs", + "current_time": "Heure du système" }, "diagnostics": { "cname_from_a": "Valeur dérivée de l’enregistrement A/AAAA. Ceci est supporté tant que l’enregistrement indique la bonne ressource.", "dns_records": "Enregistrements DNS", "dns_records_24hours": "Veuillez noter que les modifications apportées au DNS peuvent prendre jusqu’à 24 heures pour que leurs états actuels soient correctement reflétés sur cette page. Il est conçu comme un moyen pour vous de voir facilement comment configurer vos enregistrements DNS et de vérifier si tous vos enregistrements sont correctement stockés dans les DNS.", - "dns_records_docs": "Veuillez également consulter la documentation.", + "dns_records_docs": "Veuillez également consulter la documentation.", "dns_records_data": "Données correcte", "dns_records_name": "Nom", - "dns_records_status": "Etat courant", + "dns_records_status": "État courant", "dns_records_type": "Type", "optional": "Cet enregistrement est optionel." }, "edit": { "active": "Actif", "advanced_settings": "Réglages avancés", - "alias": "Editer les alias", + "alias": "Éditer les alias", "allow_from_smtp": "Restreindre l'utilisation de SMTP à ces adresses IP", "allow_from_smtp_info": "Laissez vide pour autoriser tous les expéditeurs.
Adresses IPv4/IPv6 et réseaux.", "allowed_protocols": "Protocoles autorisés", @@ -501,7 +527,7 @@ "app_passwd": "Mot de passe de l'application", "automap": "Essayer d’automatiser les dossiers (\"Sent items\", \"Sent\" => \"Sent\" etc.)", "backup_mx_options": "Options Backup MX", - "bcc_dest_format": "La destination BCC doit être une seule adresse e-mail valide.", + "bcc_dest_format": "La destination BCC doit être une seule adresse de courriel valide.", "client_id": "ID client", "client_secret": "Secret client", "comment_info": "Un commentaire privé n’est pas visible pour l’utilisateur, tandis qu’un commentaire public est affiché comme infobulle lorsque vous le placez dans un aperçu des utilisateurs", @@ -511,13 +537,13 @@ "delete_ays": "Veuillez confirmer le processus de suppression.", "description": "Description", "disable_login": "Refuser l’ouverture de session (le courrier entrant est toujours accepté)", - "domain": "Edition du domaine", - "domain_admin": "Edition de l'administrateur du domaine", + "domain": "Édition du domaine", + "domain_admin": "Édition de l'administrateur du domaine", "domain_quota": "Quota du domaine", "domains": "Domaines", "dont_check_sender_acl": "Désactiver la vérification de l’expéditeur pour le domaine %s (+ alias de domaines)", - "edit_alias_domain": "Edition des alias de domaine", - "encryption": "Cryptage", + "edit_alias_domain": "Édition des alias de domaine", + "encryption": "Chiffrement", "exclude": "Exclure des objets (regex)", "extended_sender_acl": "Adresses de l’expéditeur externe", "extended_sender_acl_info": "Une clé de domaine DKIM doit être importée, si disponible.
\r\n N’oubliez pas d’ajouter ce serveur à l’enregistrement TXT SPF correspondant.
\r\n Chaque fois qu’un domaine ou un alias de domaine est ajouté à ce serveur, et qui chevauche une adresse externe, l’adresse externe est supprimée.
\r\n Utiliser @domain.tld pour permettre l'envoi comme *@domain.tld.", @@ -532,14 +558,14 @@ "inactive": "Inactif", "kind": "Type", "last_modified": "Dernière modification", - "mailbox": "Edition de la boîte mail", - "mailbox_quota_def": "Quota par défaut de la boîte", + "mailbox": "Édition de la boîte de réception", + "mailbox_quota_def": "Quota par défaut de la boîte de réception", "max_aliases": "Nombre max. d'alias", - "max_mailboxes": "Nombre max. de boîtes possibles", - "max_quota": "Quota max. par boîte mail (Mo)", + "max_mailboxes": "Nombre max. de boîte de réception possibles", + "max_quota": "Quota max. par boîte de réception (Mo)", "maxage": "Âge maximal en jours des messages qui seront consultés à distance
(0 = ignorer la durée)", "maxbytespersecond": "Octets max. par seconde
(0 = pas de limite)", - "mbox_rl_info": "Cette limite de taux est appliquée au nom de connexion SASL, elle correspond à toute adresse \"from\" utilisée par l’utilisateur connecté. Une limite tarifaire pour les boîtes remplace une limite tarifaire pour l’ensemble du domaine.", + "mbox_rl_info": "Cette limite d'envoi est appliquée au nom de connexion SASL, elle correspond à toute adresse \"from\" utilisée par l’utilisateur connecté. Une limite d'envoi pour les boîtes de réception remplace une limite d'envoi pour l’ensemble du domaine.", "mins_interval": "Intervalle (min)", "multiple_bookings": "Réservations multiples", "nexthop": "Saut suivant", @@ -549,22 +575,22 @@ "private_comment": "Commentaire privé", "public_comment": "Commentaire public", "pushover_evaluate_x_prio": "Acheminement du courrier hautement prioritaire [X-Priority: 1]", - "pushover_info": "Les paramètres de notification push s’appliqueront à tout le courrier propre (non spam) livré à %s y compris les alias (partagés, non partagés, étiquetés).", + "pushover_info": "Les paramètres de notification push s’appliqueront à tout le courrier propre (non-spam) livré à %s y compris les alias (partagés, non partagés, étiquetés).", "pushover_only_x_prio": "Ne tenir compte que du courrier hautement prioritaire [X-Priority: 1]", - "pushover_sender_array": "Ne tenir compte que des adresses électroniques suivantes de l’expéditeur : (séparées par des virgules)", + "pushover_sender_array": "Ne tenir compte que des adresses de courriel suivantes de l’expéditeur : (séparées par des virgules)", "pushover_sender_regex": "Tenir compte de l’expéditeur regex suivant", "pushover_text": "Texte de la notification", "pushover_title": "Titre de la notification", "pushover_vars": "Lorsque aucun filtre d’expéditeur n’est défini, tous les messages seront considérés.
Les filtres Regex ainsi que les vérifications exactes de l’expéditeur peuvent être définis individuellement et seront considérés de façon séquentielle. Ils ne dépendent pas les uns des autres.
Variables utilisables pour le texte et le titre (veuillez prendre note des politiques de protection des données)", - "pushover_verify": "Vérifier les justificatifs", + "pushover_verify": "Vérifier les informations d'identification", "quota_mb": "Quota (Mo)", - "ratelimit": "Limite de taux", - "redirect_uri": "Redirection/rappel URL", + "ratelimit": "Limite d'envoi", + "redirect_uri": "URL de redirection/callback", "relay_all": "Relayer tous les destinataires", - "relay_all_info": "↪ Si vous ne choissisez pas de relayer tous les destinataires, vous devrez ajouter une boîte (\"aveugle\") pour chaque destinataire qui devrait être relayé.", + "relay_all_info": "↪ Si vous ne choisissez pas de relayer tous les destinataires, vous devrez ajouter une boîte de réception (\"aveugle\") pour chaque destinataire qui devrait être relayé.", "relay_domain": "Relayer ce domaine", "relay_transport_info": "
Info
Vous pouvez définir des cartes de transport vers une destination personnalisée pour ce domaine. Si elle n’est pas configurée, une recherche MX sera effectuée.", - "relay_unknown_only": "Relais des boîtes non existantes seulement. Les boîtes existantes seront livrées localement..", + "relay_unknown_only": "Relais des boîtes de réception non existantes seulement. Les boîtes de réception existantes seront livrées localement.", "relayhost": "Transports dépendant de l’expéditeur", "remove": "Enlever", "resource": "Ressource", @@ -572,12 +598,12 @@ "scope": "Portée", "sender_acl": "Permettre d’envoyer comme", "sender_acl_disabled": "Le contrôle de l’expéditeur est désactivé", - "sender_acl_info": "Si l’utilisateur de la boîte A est autorisé à envoyer en tant qu’utilisateur de la boîte B, l’adresse de l’expéditeur n’est pas automatiquement affichée comme sélectionnable du champ \"from\" dans SOGo.
\r\n L’utilisateur B de la boîte doit créer une délégation dans Sogo pour permettre à l’utilisateur A de la boîte de sélectionner son adresse comme expéditeur. Pour déléguer une boîte dans Sogo, utilisez le menu (trois points) à droite du nom de votre boîte dans le coin supérieur gauche dans la vue de courrier. Ce comportement ne s’applique pas aux adresses alias.", + "sender_acl_info": "Si l’utilisateur de la boîte de réception A est autorisé à envoyer en tant qu’utilisateur de la boîte de réception B, l’adresse de l’expéditeur n’est pas automatiquement affichée comme sélectionnable du champ \"de\" dans SOGo.
\n L’utilisateur B de la boîte de réception doit créer une délégation dans Sogo pour permettre à l’utilisateur A de la boîte de réception de sélectionner son adresse comme expéditeur. Pour déléguer une boîte de réception dans Sogo, utilisez le menu (trois points) à droite du nom de votre boîte dans le coin supérieur gauche dans la vue de courrier. Ce comportement ne s’applique pas aux adresses alias.", "sieve_desc": "Description courte", "sieve_type": "Type de filtre", "skipcrossduplicates": "Ignorer les messages en double dans les dossiers (premier arrivé, premier servi)", "sogo_visible": "Alias visible dans SOGo", - "sogo_visible_info": "Cette option affecte uniquement les objets qui peuvent être affichés dans SOGo (adresses alias partagées ou non partagées pointant vers au moins une boîte mail locale). Si caché, un alias n’apparaîtra pas comme expéditeur sélectionnable dans SOGo.", + "sogo_visible_info": "Cette option affecte uniquement les objets qui peuvent être affichés dans SOGo (adresses alias partagées ou non partagées pointant vers au moins une boîte de réception locale). Si caché, un alias n’apparaîtra pas comme expéditeur sélectionnable dans SOGo.", "spam_alias": "Créer ou modifier des adresses alias limitées dans le temps", "spam_filter": "Filtre spam", "spam_policy": "Ajouter ou supprimer des éléments à la liste blanche/noire", @@ -588,12 +614,35 @@ "target_domain": "Domaine cible", "timeout1": "Délai de connexion à l’hôte distant", "timeout2": "Délai de connexion à l’hôte local", - "title": "Editer l'objet", + "title": "Éditer l'objet", "unchanged_if_empty": "Si non modifié, laisser en blanc", "username": "Nom d'utilisateur", - "validate_save": "Valider et sauver", + "validate_save": "Valider et enregistrer", "lookup_mx": "La destination est une expression régulière qui doit correspondre avec le nom du MX (.*\\.google\\.com 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 de réception et aux alias directs, remplace le relayhost du domaine.", + "acl": "ACL (Permission)", + "footer_exclude": "Exclure du pied de page", + "custom_attributes": "Attributs personnalisés", + "domain_footer_info_vars": { + "from_addr": "{= from_addr =} - Partie de l'enveloppe relative à l'adresse de provenance", + "from_domain": "{= from_domain =} - Partie de l'enveloppe provenant du domaine", + "custom": "{= foo =} - Si la boîte de réception possède l'attribut personnalisé \"foo\" avec la valeur \"bar\", elle renvoie \"bar\"", + "auth_user": "{= auth_user =} - Nom d'utilisateur authentifié spécifié par un MTA", + "from_user": "{= from_user =} -La partie utilisateur de l'enveloppe, par exemple, pour \"moo@mailcow.tld\", renvoie \"moo\"", + "from_name": "{= from_name =} - À partir du nom de l'enveloppe, par exemple, pour \"Mailcow <moo@mailcow.tld> ;\" on obtient \"Mailcow\"" + }, + "domain_footer_skip_replies": "Ignorer le pied de page des courriels de réponse", + "domain_footer": "Pied de page du domaine", + "domain_footer_html": "Pied de page HTML", + "domain_footer_info": "Les pieds de page du domaine sont ajoutés à tous les courriels sortants associés à une adresse au sein de ce domaine.
Les variables suivantes peuvent être utilisées pour le pied de page :", + "domain_footer_plain": "Pied de page", + "app_passwd_protocols": "Protocoles autorisés pour le mot de passe d'application", + "created_on": "Créé le", + "none_inherit": "Aucun / Héritage", + "quota_warning_bcc": "Avertissement sur les quotas BCC", + "quota_warning_bcc_info": "Les avertissements seront envoyés en copies séparées aux destinataires suivants. Le sujet sera précédé du nom d'utilisateur correspondant entre parenthèses, par exemple : Avertissement sur les quotas (user@example.com).", + "sogo_access_info": "L'authentification unique à partir de l'interface de messagerie reste opérationnelle. Ce paramètre n'affecte pas l'accès à tous les autres services et ne supprime ni ne modifie le profil SOGo existant d'un utilisateur.", + "admin": "Modifier l'administrateur" }, "footer": { "cancel": "Annuler", @@ -604,15 +653,16 @@ "hibp_ok": "Aucune correspondance trouvée.", "loading": "Veuillez patienter…", "restart_container": "Redémarrer le conteneur", - "restart_container_info": "Important: Un redémarrage en douceur peut prendre un certain temps, veuillez attendre qu’il soit terminé.", + "restart_container_info": "Important : Un redémarrage en douceur peut prendre un certain temps, veuillez attendre qu’il soit terminé.", "restart_now": "Redémarrer maintenant", - "restarting_container": "Redémarrage du conteneur, cela peut prendre un certain temps" + "restarting_container": "Redémarrage du conteneur, cela peut prendre un certain temps", + "nothing_selected": "Rien n'est sélectionné" }, "header": { "administration": "Configuration & détails", "apps": "Applications", "debug": "Information Système", - "email": "E-Mail", + "email": "Courriel", "mailcow_config": "Configuration", "quarantine": "Quarantaine", "restart_netfilter": "Redémarrer Netfilter", @@ -628,7 +678,7 @@ "delayed": "La connexion a été retardée de %s secondes.", "fido2_webauthn": "FIDO2/WebAuthn Login", "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 de réception pour télécharger le profil de connexion Apple demandé.", "other_logins": "Clé d'authentification", "password": "Mot de passe", "username": "Nom d'utilisateur" @@ -636,7 +686,7 @@ "mailbox": { "action": "Action", "activate": "Activer", - "active": "Active", + "active": "Actif", "add": "Ajouter", "add_alias": "Ajouter un alias", "add_bcc_entry": "Ajouter une carte BCC", @@ -644,19 +694,19 @@ "add_domain_alias": "Ajouter un alias de domaine", "add_domain_record_first": "Veuillez d’abord ajouter un domaine", "add_filter": "Ajouter un filtre", - "add_mailbox": "Ajouter une boîte", + "add_mailbox": "Ajouter une boîte de réception", "add_recipient_map_entry": "Ajouter la carte du destinataire", "add_resource": "Ajouter une ressource", "add_tls_policy_map": "Ajouter la carte de la politique des TLS", "address_rewriting": "Réécriture de l’adresse", "alias": "Alias", - "alias_domain_alias_hint": "Les alias ne sont pas appliqués automatiquement sur les alias de domaine. Un alias d'adresse my-alias@domain ne couvre pas l'adresse my-alias@alias-domain (où \"alias-domain\" est un alias imaginaire pour \"domain\").
Veuillez utiliser un filtre à tamis pour rediriger le courrier vers une boîte externe (voir l'onglet \"Filtres\" ou utilisez SOGo -> Forwarder).", + "alias_domain_alias_hint": "Les alias ne sont pas appliqués automatiquement sur les alias de domaine. Un alias d'adresse my-alias@domain ne couvre pas l'adresse my-alias@alias-domain (où \"alias-domain\" est un alias imaginaire pour \"domain\").
Veuillez utiliser un filtre à tamis pour rediriger le courrier vers une boîte de réception externe (voir l'onglet « Filtres » ou utilisez SOGo → Transférer).", "alias_domain_backupmx": "Alias de domaine inactif pour le domaine relais", "aliases": "Aliases", "allow_from_smtp": "Restreindre l'utilisation de SMTP à ces adresses IP", "allow_from_smtp_info": "Laissez vide pour autoriser tous les expéditeurs.
Adresses IPv4/IPv6 et réseaux.", "allowed_protocols": "Protocoles autorisés", - "backup_mx": "Sauvegarde MX", + "backup_mx": "Domaine de relais", "bcc": "BCC", "bcc_destination": "Destination BCC", "bcc_destinations": "Destinations BCC", @@ -672,9 +722,9 @@ "bcc_type": "Type de BCC", "booking_null": "Toujours montrer comme libre", "booking_0_short": "Toujours libre", - "booking_custom": "Limite rigide à un nombre de réservations personnalisé", - "booking_custom_short": "Limite rigide", - "booking_ltnull": "Illimité, mais afficher aussi occupé lorsque réservé", + "booking_custom": "Limitation stricte à un nombre personnalisé de réservations", + "booking_custom_short": "Limite stricte", + "booking_ltnull": "Illimité, mais indiqué comme occupé lors de la réservation", "booking_lt0_short": "Limite souple", "daily": "Quotidiennement", "deactivate": "Désactiver", @@ -689,33 +739,33 @@ "domain_quota": "Quota", "domain_quota_total": "Quota total du domaine", "domains": "Domaines", - "edit": "Editer", - "empty": "Pas de résulats", + "edit": "Éditer", + "empty": "Pas de résultats", "enable_x": "Activer", - "excludes": "Exclut", - "filter_table": "Table de filtre", + "excludes": "Exclus", + "filter_table": "Table de filtrage", "filters": "Filtres", "fname": "Nom complet", "force_pw_update": "Forcer la mise à jour du mot de passe à la prochaine ouverture de session", "gal": "Carnet d'Adresses Global (GAL)", - "hourly": "Horaire", + "hourly": "Toutes les heures", "in_use": "Utilisé (%)", "inactive": "Inactif", "insert_preset": "Insérer un exemple de préréglage \"%s\"", "kind": "Type", "last_mail_login": "Dernière connexion mail", "last_modified": "Dernière modification", - "last_run": "Dernière éxécution", + "last_run": "Dernière exécution", "last_run_reset": "Calendrier suivant", - "mailbox": "Mailbox", - "mailbox_defquota": "Taille de boîte par défaut", - "mailbox_quota": "Taille max. d’une boîte", - "mailboxes": "Boîtes mail", + "mailbox": "Boîte de réception", + "mailbox_defquota": "Taille de boîte de réception par défaut", + "mailbox_quota": "Taille max. d’une boîte de réception", + "mailboxes": "Boîtes de réception", "mailbox_defaults": "Paramètres par défaut", - "mailbox_defaults_info": "Définir les paramètres par défaut pour les nouvelles boîtes aux lettres.", + "mailbox_defaults_info": "Définir les paramètres par défaut pour les nouvelles boîtes de réception.", "max_aliases": "Nombre maximal d'alias", - "max_mailboxes": "Nombre maximal de boîtes", - "max_quota": "Quota max. par boîte mail", + "max_mailboxes": "Nombre maximal de boîte de réception", + "max_quota": "Quota max. par boîte de réception", "mins_interval": "Intervalle (min)", "msg_num": "Message #", "multiple_bookings": "Réservations multiples", @@ -726,18 +776,18 @@ "owner": "Propriétaire", "private_comment": "Commentaire privé", "public_comment": "Commentaire public", - "q_add_header": "Courriers indésirables", - "q_all": " quand déplacé dans le dossier spam ou rejeté", - "q_reject": "Rejecté", + "q_add_header": "lorsqu'il est déplacé dans le dossier Indésirables", + "q_all": " quand déplacé dans le dossier indésirables ou rejeté", + "q_reject": "en cas de refus", "quarantine_notification": "Avis de quarantaine", "quarantine_category": "Catégorie de la notification de quarantaine", "quick_actions": "Actions", "recipient_map": "Carte du destinataire", "recipient_map_info": "Les cartes des destinataires sont utilisées pour remplacer l’adresse de destination d’un message avant sa livraison.", "recipient_map_new": "Nouveau destinataire", - "recipient_map_new_info": "La destination de la carte du destinataire doit être une adresse électronique valide.", + "recipient_map_new_info": "La destination de la carte du destinataire doit être une adresse de courriel valide.", "recipient_map_old": "Destinataire original", - "recipient_map_old_info": "Une carte de destination originale doit être une adresse e-mail valide ou un nom de domaine.", + "recipient_map_old_info": "Une carte de destination originale doit être une adresse de courriel valide ou un nom de domaine.", "recipient_maps": "Cartes des bénéficiaires", "relay_all": "Relayer tous les destinataires", "remove": "Supprimer", @@ -745,16 +795,16 @@ "running": "En fonctionnement", "set_postfilter": "Marquer comme postfiltre", "set_prefilter": "Marquer comme préfiltre", - "sieve_info": "Vous pouvez stocker plusieurs filtres par utilisateur, mais un seul préfiltre et un seul postfiltre peuvent être actifs en même temps.
\r\nChaque filtre sera traité dans l’ordre décrit. Ni un script \"rejeter\" ni un \"garder\" n’arrêtera le traitement des autres scripts. Les modifications apportées aux scripts de tamis globaux déclencheront un redémarrage de Dovecot.

Préfiltre de tamis global → Préfiltre → Scripts utilisateur → Postfiltre → Postfiltre du tamis global", + "sieve_info": "Vous pouvez stocker plusieurs filtres par utilisateur, mais un seul préfiltre et un seul postfiltre peuvent être actifs simultanément.
\nChaque filtre sera traité dans l’ordre décrit. Ni un script « rejeter » ni un « garder » n’arrêtera le traitement des autres scripts. Les modifications apportées aux scripts de tamis globaux déclencheront un redémarrage de Dovecot.

Préfiltre de tamis global → Préfiltre → Scripts utilisateur → Postfiltre → Postfiltre du tamis global", "sieve_preset_1": "Jeter le courrier avec les types de fichiers dangereux probables", - "sieve_preset_2": "Toujours marquer l’e-mail d’un expéditeur spécifique comme vu", - "sieve_preset_3": "Jeter en silence, arrêter tout traitement supplémentaire du tamis", - "sieve_preset_4": "Fichier dans INBOX, éviter le traitement ultérieur par filtres à tamis", + "sieve_preset_2": "Toujours marquer l'adresse de courriel d’un expéditeur spécifique comme vu", + "sieve_preset_3": "Jeter en silence, arrêter tout traitement supplémentaire par filtre sieve", + "sieve_preset_4": "Fichier dans INBOX, éviter le traitement ultérieur par filtres sieve", "sieve_preset_5": "Répondeur auto (vacances)", "sieve_preset_6": "Rejeter le courrier avec réponse", "sieve_preset_7": "Rediriger et garder/déposer", - "sieve_preset_8": "Supprimer le message envoyé à une adresse alias dont fait partie l’expéditeur", - "sieve_preset_header": "Voir les exemples de préréglages ci-dessous. Pour plus de détails voir Wikipedia.", + "sieve_preset_8": "Rediriger les courriels d'un expéditeur spécifique, les marquer comme lus et les classer dans des sous-dossiers.", + "sieve_preset_header": "Voir les exemples de préréglages ci-dessous. Pour plus de détails, voir Wikipédia.", "sogo_visible": "Alias visible dans SOGo", "sogo_visible_n": "Masquer alias dans SOGo", "sogo_visible_y": "Afficher alias dans SOGo", @@ -775,19 +825,29 @@ "tls_map_policy": "Politique", "tls_policy_maps": "Cartes des politiques des TLS", "tls_policy_maps_info": "Cette carte de politique remplace les règles de transport TLS sortantes indépendamment des paramètres de politique TLS des utilisateurs.
\r\n Veuillez vérifier la doc \"smtp_tls_policy_maps\" pour plus d'informations.", - "tls_policy_maps_enforced_tls": "Ces politiques remplaceront également le comportement des utilisateurs de boîtes qui appliquent les connexions TLS sortantes. Si aucune politique n’existe ci-dessous, ces utilisateurs appliqueront les valeurs par défaut spécifiées comme smtp_tls_mandatory_protocols et smtp_tls_mandatory_ciphers.", + "tls_policy_maps_enforced_tls": "Ces politiques remplaceront également le comportement des utilisateurs de boîtes de réception qui appliquent les connexions TLS sortantes. Si aucune politique n’existe ci-dessous, ces utilisateurs appliqueront les valeurs par défaut spécifiées comme smtp_tls_mandatory_protocols et smtp_tls_mandatory_ciphers.", "tls_policy_maps_long": "Contournement de la carte de politique TLS sortante", "toggle_all": "Tout basculer", "username": "Nom d'utilisateur", "waiting": "En attente", "weekly": "Hebdomadaire", - "yes": "✓" + "yes": "✓", + "add_alias_expand": "Étendre l'alias aux alias de domaine", + "catch_all": "Catch-All", + "created_on": "Créé le", + "goto_ham": "Apprendre comme ham", + "goto_spam": "Apprendre comme pourriel", + "last_pw_change": "Dernier changement de mot de passe", + "mailbox_templates": "Modèle de boîte de réception", + "relay_unknown": "Relayer les boîtes de réception inconnues", + "all_domains": "Tous les domaines", + "syncjob_EXIT_OVERQUOTA": "Quota dépassé de la boîte de réception cible" }, "oauth2": { - "access_denied": "Veuillez vous connecter en tant que propriétaire de la boîte pour accorder l’accès via Oauth2.", + "access_denied": "Veuillez vous connecter en tant que propriétaire de la boîte de réception pour accorder l’accès via Oauth2.", "authorize_app": "Autoriser l'application", "deny": "Refuser", - "permit": "Autorise l'application", + "permit": "Autoriser l'application", "profile": "Profil", "profile_desc": "Afficher les informations personnelles : nom d’utilisateur, nom complet, créé, modifié, actif", "scope_ask_permission": "Une application demande les permissions suivantes" @@ -800,8 +860,8 @@ "confirm_delete": "Confirmer la suppression de cet élément.", "danger": "Danger", "deliver_inbox": "Envoyer dans la boîte de reception", - "disabled_by_config": "La configuration actuelle du système désactive la fonctionnalité de quarantaine. Veuillez définir \"retentions par boîte\" et une \"taille maximum\" pour les éléments en quarantaine.", - "settings_info": "Quantité maximum d'éléments à mettre en quarantaine : %s
Taille maximale des e-mails : %s MiB", + "disabled_by_config": "La configuration actuelle du système désactive la fonctionnalité de quarantaine. Veuillez définir « retentions par boîte » et une « taille maximale » pour les éléments en quarantaine.", + "settings_info": "Quantité maximale d'éléments à mettre en quarantaine : %s
Taille maximale des courriels : %s MiB", "download_eml": "Télécharger (.eml)", "empty": "Pas de résultat", "high_danger": "Haut", @@ -814,7 +874,7 @@ "notified": "Notifié", "qhandler_success": "Demande envoyée avec succès au système. Vous pouvez maintenant fermer la fenêtre.", "qid": "Rspamd QID", - "qinfo": "Le système de quarantaine enregistrera le courrier rejeté dans la base de données (l'expéditeur n'aura pas l'impression d'un courrier remis) ainsi que le courrier, qui est remis sous forme de copie dans le dossier indésirable d'une boîte aux lettres.\r\n
\"Apprendre comme spam et supprimer\" apprendra un message comme spam via le théorème Bayesianet calculera également des hachages flous pour refuser des messages similaires à l'avenir.\r\n
Veuillez noter que l'apprentissage de plusieurs messages peut prendre du temps, selon votre système.
Les éléments figurant sur la liste noire sont exclus de la quarantaine.", + "qinfo": "Le système de quarantaine enregistrera le courrier rejeté dans la base de données (l'expéditeur n'aura pas l'impression d'un courrier remis) ainsi que le courrier, remis sous forme de copie dans le dossier indésirable d'une boîte de réception.\n
« Apprendre comme spam et supprimer » apprendra un message comme spam via le théorème Bayésien calculera également des hachages flous pour refuser des messages similaires à l'avenir.\n
Veuillez noter que l'apprentissage de plusieurs messages peut prendre du temps, selon votre système.
Les éléments figurant sur la liste noire sont exclus de la quarantaine.", "qitem": "Élément de quarantaine", "quarantine": "Quarantaine", "quick_actions": "Actions", @@ -846,26 +906,34 @@ "toggle_all": "Tout basculer" }, "queue": { - "queue_manager": "Gestion de la file d'attente" + "queue_manager": "Gestion de la file d'attente", + "hold_mail": "Garder", + "legend": "Fonctions d'action de la file d'attente du courrier :", + "info": "La file d'attente contient tous les courriels en attente de livraison. Si un courriel reste longtemps dans la file d'attente, il est automatiquement supprimé par le système.
Le message d'erreur du courriel concerné indique pourquoi le courriel n'a pas pu être distribué.", + "deliver_mail_legend": "Tentatives de réexpédition des courriers sélectionnés.", + "hold_mail_legend": "Met en attente les courriers sélectionnés. (Empêche les tentatives de distribution ultérieures)", + "unban": "file d'attente d'unban", + "unhold_mail": "Libérer", + "unhold_mail_legend": "Libère les courriers sélectionnés pour la distribution. (Nécessite une mise en attente préalable)" }, "start": { "help": "Afficher/masquer le panneau d’aide", - "imap_smtp_server_auth_info": "Veuillez utiliser votre adresse e-mail complète et le mécanisme d’authentification PLAIN.
\r\nVos données de connexion seront cryptées par le cryptage obligatoire côté serveur.", - "mailcow_apps_detail": "Utiliser une application mailcow pour accéder à vos messages, calendrier, contacts et plus.", - "mailcow_panel_detail": "Les administrateurs de domaines peuvent créer, modifier or supprimer des boîtes et alias, changer de domaines et lire de plus amples renseignements sur les domaines qui leurs sont attribués.
\r\nLes utilisateurs de boîtes sont en mesure de créer des alias limités dans le temps (alias spam), de modifier leurs mots de passe et les paramètres du filtre anti-spam." + "imap_smtp_server_auth_info": "Veuillez utiliser votre adresse courriel complète et le mécanisme d’authentification PLAIN.
\nVos données de connexion seront cryptées par le cryptage obligatoire côté serveur.", + "mailcow_apps_detail": "Utiliser une application mailcow pour accéder à vos messages, vos calendriers, vos contacts et plus.", + "mailcow_panel_detail": "Les administrateurs de domaines peuvent créer, modifier, ou supprimer des boîtes de réception et alias, changer de domaines et lire de plus amples renseignements sur les domaines qui leur sont attribués.
\nLes utilisateurs de boîtes de réception sont en mesure de créer des alias limités dans le temps (alias spam), de modifier leurs mots de passe et les paramètres du filtre anti-spam." }, "success": { - "acl_saved": "ACL (Access Control List) pour l'objet %s sauvé", - "admin_added": "Administrateur %s a été ajoutées", + "acl_saved": "ACL (Access Control List) pour l'objet %s enregistré", + "admin_added": "Administrateur %s a été ajouté", "admin_api_modified": "Les modifications apportées à l’API ont été enregistrées", "admin_modified": "Les modifications apportées à l’administrateur ont été enregistrées", "admin_removed": "Administrateur %s a été effacé", "alias_added": "L'adresse alias %s (%d) a été ajoutée", "alias_domain_removed": "L'alias de domaine %s a été effacé", - "alias_modified": "Le changement de l'adresse alias %s a été sauvegardée", + "alias_modified": "Le changement de l'adresse alias %s a été enregistré", "alias_removed": "L'alias %s a été effacé", "aliasd_added": "Alias de domaine %s ajouté", - "aliasd_modified": "Les changements de l'alias de domaine %s ont été sauvegardés", + "aliasd_modified": "Les changements de l'alias de domaine %s ont été enregistrés", "app_links": "Modifications enregistrées dans les liens d’application", "app_passwd_added": "Ajout d’un nouveau mot de passe d’application", "app_passwd_removed": "Suppression de l’identifiant du mot de passe de l’application %s", @@ -877,14 +945,14 @@ "delete_filters": "Filtres supprimés : %s", "deleted_syncjob": "ID du travail de synchronisation supprimé : %s", "deleted_syncjobs": "Travail de synchronisation supprimé : %s", - "dkim_added": "La clé DKIM %s a été sauvegardée", - "dkim_duplicated": "La clé DKIM pour e domaine %s a été copiée vers %s", + "dkim_added": "La clé DKIM %s a été enregistrée", + "dkim_duplicated": "La clé DKIM pour le domaine %s a été copiée vers %s", "dkim_removed": "La clé DKIM %s a été supprimée", "domain_added": "Domaine ajouté %s", "domain_admin_added": "L'administrateur de domaine %s a été ajouté", - "domain_admin_modified": "Les modifications de l'administrateur de domaine %s ont été sauvées", + "domain_admin_modified": "Les modifications de l'administrateur de domaine %s ont été enregistrées", "domain_admin_removed": "L'administrateur de domaine %s a été supprimé", - "domain_modified": "Les modification du domaine %s ont été sauvées", + "domain_modified": "Les modifications du domaine %s ont été enregistrées", "domain_removed": "Le domaine %s a été supprimé", "dovecot_restart_success": "Dovecot a été relancé avec succès", "eas_reset": "Les périphériques Activesync pour l’utilisateur %s ont été réinitialisés", @@ -900,40 +968,47 @@ "learned_ham": "ID %s acquis avec succès comme ham", "license_modified": "Les modifications apportées à la licence ont été enregistrées", "logged_in_as": "Connecté en tant que %s", - "mailbox_added": "La boîte mail %s a été ajoutée", - "mailbox_modified": "Les modifications de la boîte %s ont été sauvées", - "mailbox_removed": "La boîte %s a été supprimée", + "mailbox_added": "La boîte de réception %s a été ajoutée", + "mailbox_modified": "Les modifications de la boîte de réception %s ont été enregistrées", + "mailbox_removed": "La boîte de réception %s a été supprimée", "nginx_reloaded": "Nginx a été rechargé", - "object_modified": "Les changements de %s ont été sauvés", + "object_modified": "Les changements de %s ont été enregistrés", "pushover_settings_edited": "Paramètres Pushover réglés avec succès, veuillez vérifier les informations d’identification.", "qlearn_spam": "Le message ID %s a été appris comme spam et supprimé", "queue_command_success": "Queue de commande terminée avec succès", "recipient_map_entry_deleted": "La carte du destinataire ID %s a été effacée", - "recipient_map_entry_saved": "L'entrée de la carte du bénéficiaire \"%s\" a été sauvée", + "recipient_map_entry_saved": "L'entrée de la carte du bénéficiaire \"%s\" a été enregistrée", "relayhost_added": "L'entrée de la carte %s a été ajoutée", "relayhost_removed": "L'entrée de la carte %s a été supprimée", "reset_main_logo": "Réinitialisation du logo par défaut", "resource_added": "La ressource %s a été ajoutée", - "resource_modified": "Les modifications apportées à la boîte %s ont été enregistrées", + "resource_modified": "Les modifications apportées à la boîte de réception %s ont été enregistrées", "resource_removed": "La ressource %s a été supprimée", - "rl_saved": "Limite de taux pour l’objet %s enregistrée", + "rl_saved": "Limite d'envoi pour l’objet %s enregistrée", "rspamd_ui_pw_set": "Mot de passe de l'interface Rspamd sauvegardé avec succès", "saved_settings": "Paramètres enregistrés", "settings_map_added": "Ajout de l’entrée de la carte des paramètres", "settings_map_removed": "Suppression de la carte des paramètres ID %s", "sogo_profile_reset": "Le profil SOGo profile pour l'utilisateur %s est remis à zéro", - "tls_policy_map_entry_deleted": "La carte de stratégie TLS ID %s a été supprimé", - "tls_policy_map_entry_saved": "La carte de stratégie TLS ID \"%s\" a été sauvée", + "tls_policy_map_entry_deleted": "La carte de stratégie TLS ID %s a été supprimée", + "tls_policy_map_entry_saved": "La carte de stratégie TLS ID \"%s\" a été enregistrée", "ui_texts": "Enregistrement des modifications apportées aux textes de l’interface utilisateur", "upload_success": "Fichier téléchargé avec succès", "verified_totp_login": "Authentification TOTP vérifiée", "verified_webauthn_login": "Authentification WebAuthn vérifiée", "verified_fido2_login": "Authentification FIDO2 vérifiée", - "verified_yotp_login": "Authentification Yubico OTP vérifiée" + "verified_yotp_login": "Authentification Yubico OTP vérifiée", + "cors_headers_edited": "Les paramètres CORS ont été enregistrés", + "domain_footer_modified": "Les modifications apportées au pied de page du domaine %s ont été enregistrées", + "f2b_banlist_refreshed": "L'ID de la liste de ban a été actualisé avec succès.", + "template_added": "Modèles ajoutés %s", + "template_removed": "Le modèle ayant l'ID %s a été supprimé", + "domain_add_dkim_available": "A DKIM key did already exist", + "ip_check_opt_in_modified": "Le contrôle de l'IP a été enregistré avec succès" }, "tfa": { - "api_register": "%s utilise l'API Yubico Cloud. Veuillez obtenir une clé API pour votre clé here", - "confirm": "confirmer", + "api_register": "%s utilise l'API Yubico Cloud. Veuillez obtenir une clé API pour votre clé ici", + "confirm": "Confirmer", "confirm_totp_token": "Veuillez confirmer vos modifications en saisissant le jeton généré", "delete_tfa": "Désactiver TFA", "disable_tfa": "Désactiver TFA jusqu’à la prochaine ouverture de session réussie", @@ -954,21 +1029,25 @@ "webauthn": "Authentification WebAuthn", "waiting_usb_auth": "En attente d’un périphérique USB…

S’il vous plaît appuyez maintenant sur le bouton de votre périphérique USB WebAuthn.", "waiting_usb_register": "En attente d’un périphérique USB…

Veuillez entrer votre mot de passe ci-dessus et confirmer votre inscription WebAuthn en appuyant sur le bouton de votre périphérique USB WebAuthn.", - "yubi_otp": "Authentification OTP Yubico" + "yubi_otp": "Authentification OTP Yubico", + "authenticators": "Authentificateurs", + "u2f_deprecated_important": "Veuillez enregistrer votre clé dans le panneau d'administration avec la nouvelle méthode WebAuthn.", + "u2f_deprecated": "Il semble que votre clé ait été enregistrée à l'aide de la méthode U2F obsolète. Nous allons désactiver l'authentification à deux facteurs pour vous et supprimer votre clé." }, "fido2": { "set_fn": "Définir un nom", "fn": "Nom", - "rename": "renommer", + "rename": "Renommer", "confirm": "Confirmer", - "register_status": "Etat de l'enregistrement", + "register_status": "État de l'enregistrement", "known_ids": "Identifiant(s) connu(s)", "none": "Désactivé", "set_fido2": "Enregistrer un nouvel appareil FIDO2", "start_fido2_validation": "Tester la validation FIDO2", "fido2_auth": "Se connecter avec FIDO2", "fido2_success": "L'appareil est enregistré avec succès", - "fido2_validation_failed": "La validation a échoué" + "fido2_validation_failed": "La validation a échoué", + "set_fido2_touchid": "Enregistrer Touch ID sur Apple M1" }, "user": { "action": "Action", @@ -985,9 +1064,9 @@ "alias_valid_until": "Valide jusque", "aliases_also_send_as": "Aussi autorisé à envoyer en tant qu’utilisateur", "aliases_send_as_all": "Ne pas vérifier l’accès de l’expéditeur pour les domaines suivants et leurs alias", - "app_hint": "Les mots de passe d’application sont des mots de passe alternatifs pour votre connexion IMAP, SMTP, Caldav, Carddav et EAS. Le nom d’utilisateur reste inchangé.
SOGo n'est pas disponible au travers de mots de passe.", + "app_hint": "Les mots de passe d’application sont des mots de passe alternatifs pour votre connexion IMAP, SMTP, Caldav, Carddav et EAS. Le nom d’utilisateur reste inchangé.
SOGo n'est pas disponible au travers des mots de passe d'application.", "app_name": "Nom d'application", - "app_passwds": "Mots de passe de l'application", + "app_passwds": "Mots de passe d'applications", "apple_connection_profile": "Profil de connexion Apple", "apple_connection_profile_complete": "Ce profil de connexion inclut les paramètres IMAP et SMTP ainsi que les chemins Caldav (calendriers) et Carddav (contacts) pour un appareil Apple.", "apple_connection_profile_mailonly": "Ce profil de connexion inclut les paramètres de configuration IMAP et SMTP pour un périphérique Apple.", @@ -1000,14 +1079,14 @@ "delete_ays": "Veuillez confirmer le processus de suppression.", "direct_aliases": "Adresses alias directes", "direct_aliases_desc": "Les adresses d’alias directes sont affectées par le filtre anti-spam et les paramètres de politique TLS.", - "eas_reset": "Réinitialiser le cache de l’appareil Activesync", - "eas_reset_help": "Dans de nombreux cas, une réinitialisation du cache de l’appareil aidera à récupérer un profil Activesync cassé.
Attention : Tous les éléments seront à nouveau téléchargés !", + "eas_reset": "Réinitialiser le cache de l’appareil ActiveSync", + "eas_reset_help": "Dans de nombreux cas, une réinitialisation du cache de l’appareil aidera à récupérer un profil ActiveSync cassé.
Attention : Tous les éléments seront de nouveau téléchargés !", "eas_reset_now": "Réinitialiser maintenant", "edit": "Éditer", - "email": "E-mail", - "email_and_dav": "E-mail, calendriers et contacts", - "encryption": "Cryptage", - "excludes": "Exclut", + "email": "Courriel", + "email_and_dav": "Courriel, calendriers et contacts", + "encryption": "Chiffrement", + "excludes": "Exclus", "expire_in": "Expire dans", "force_pw_update": "Vous devez définir un nouveau mot de passe pour pouvoir accéder aux services liés aux logiciels de groupe.", "generate": "générer", @@ -1020,7 +1099,7 @@ "last_mail_login": "Dernière connexion mail", "last_run": "Dernière exécution", "loading": "Chargement…", - "mailbox_details": "Détails de la boîte", + "mailbox_details": "Détails", "messages": "messages", "never": "jamais", "new_password": "Nouveau mot de passe", @@ -1034,27 +1113,27 @@ "pushover_evaluate_x_prio": "Acheminement du courrier hautement prioritaire [X-Priority: 1]", "pushover_info": "Les paramètres de notification push s’appliqueront à tout le courrier propre (non spam) livré à %s y compris les alias (partagés, non partagés, étiquetés).", "pushover_only_x_prio": "Ne tenir compte que du courrier hautement prioritaire [X-Priority: 1]", - "pushover_sender_array": "Tenez compte des adresses courriel suivantes de l’expéditeur : (comma-separated)", + "pushover_sender_array": "Tenir compte des adresses de courriel suivantes de l’expéditeur : (comma-separated)", "pushover_sender_regex": "Apparier les expéditeurs par le regex suivant", "pushover_text": "Texte de notification", "pushover_title": "Titre de la notification", - "pushover_vars": "Lorsqu’aucun filtre d’expéditeur n’est défini, tous les messages seront considérés.
Les filtres Regex ainsi que les vérifications exactes de l’expéditeur peuvent être définis individuellement et seront considérés de façon séquentielle. Ils ne dépendent pas les uns des autres.
Variables utilisables pour le texte et le titre (veuillez prendre note des politiques de protection des données)", - "pushover_verify": "Vérifier les justificatifs", + "pushover_vars": "Lorsque aucun filtre d’expéditeur n’est défini, tous les messages seront considérés.
Les filtres Regex ainsi que les vérifications exactes de l’expéditeur peuvent être définis individuellement et seront considérés de façon séquentielle. Ils ne dépendent pas les uns des autres.
Variables utilisables pour le texte et le titre (veuillez prendre note des politiques de protection des données)", + "pushover_verify": "Vérifier les identifiants", "q_add_header": "Courrier indésirable", "q_all": "Toutes les catégories", "q_reject": "Rejeté", "quarantine_notification": "Avis de quarantaine", "quarantine_category": "Catégorie de la notification de quarantaine", - "quarantine_notification_info": "Une fois qu’un avis a été envoyé, les articles seront marqués comme \"notified\" et aucune autre notification ne sera envoyée pour ce point particulier.", - "quarantine_category_info": "La catégorie de notification \"Rejeté\" inclut le courrier qui a été rejeté, tandis que \"Dossier indésirable\" informera un utilisateur des e-mails qui ont été placés dans le dossier indésirable.", + "quarantine_notification_info": "Une fois qu’un avis a été envoyé, les articles seront marqués comme « notifiés » et aucune autre notification ne sera envoyée pour ce point particulier.", + "quarantine_category_info": "La catégorie de notification « Rejeté » inclut le courrier rejeté, tandis que « Dossier indésirable » informera un utilisateur des courriels placés dans le dossier indésirable.", "remove": "Enlever", - "running": "En fonction", - "save": "Sauvegarder les changements", - "save_changes": "Sauvegarder les changements", + "running": "En fonctionnement", + "save": "Enregistrer les changements", + "save_changes": "Enregistrer les changements", "sender_acl_disabled": "Le contrôle de l’expéditeur est désactivé", "shared_aliases": "Adresses alias partagées", "shared_aliases_desc": "Les alias partagés ne sont pas affectés par les paramètres spécifiques à l’utilisateur tels que le filtre anti-spam ou la politique de chiffrement. Les filtres anti-spam correspondants ne peuvent être effectués que par un administrateur en tant que politique de domaine.", - "show_sieve_filters": "Afficher le filtre de tamis actif de l’utilisateur", + "show_sieve_filters": "Afficher le filtre sieve actif de l’utilisateur", "sogo_profile_reset": "Remise à zéro du profil SOGo", "sogo_profile_reset_help": "Ceci détruira un profil Sogo des utilisateurs et supprimera toutes les données de contact et de calendrier irrécupérables.", "sogo_profile_reset_now": "Remise à zéro du profil maintenant", @@ -1063,10 +1142,10 @@ "spamfilter": "Filtre de spam", "spamfilter_behavior": "Note", "spamfilter_bl": "Liste noire (BlackList)", - "spamfilter_bl_desc": "Les adresses de courriel sur la liste noire de always (toujours) peuvent être classées comme des pourriels et rejetées. Des caractères génériques peuvent être utilisés. Un filtre n’est appliqué qu’aux alias directs (alias avec une seule boîte cible), à l’exclusion des alias tous azimuts et d’une boîte elle-même.", + "spamfilter_bl_desc": "Les adresses de courriel sur la liste noire de toujours peuvent être classées comme des pourriels et rejetées. Des caractères génériques peuvent être utilisés. Un filtre n’est appliqué qu’aux alias directs (alias avec une seule boîte de réception cible), à l’exclusion des alias tous azimuts et d’une boîte de réception elle-même.", "spamfilter_default_score": "Valeurs par défaut", "spamfilter_green": "Vert : ce message n'est pas un spam", - "spamfilter_hint": "La première valeur indique un \"faible score de spam\", la seconde représente un \"haut score de spam\".", + "spamfilter_hint": "La première valeur indique un « faible score de spam », la seconde représente un « haut score de spam ».", "spamfilter_red": "Rouge : Ce message est un spam et sera rejeté par le serveur", "spamfilter_table_action": "Action", "spamfilter_table_add": "Ajouter un élément", @@ -1075,13 +1154,13 @@ "spamfilter_table_remove": "supprimer", "spamfilter_table_rule": "Règle", "spamfilter_wl": "Liste blanche (WhiteList)", - "spamfilter_wl_desc": "La liste blanche est programmé pour ne jamais classer comme spam les adresses e-mail qu'elle contient. Des caractères génériques peuvent être utilisés. Un filtre n’est appliqué qu’aux alias directs (alias avec une seule boîte cible), à l’exclusion des alias catch-all et d’une boîte mail.", + "spamfilter_wl_desc": "La liste blanche est programmée pour ne jamais classer comme spam les adresses de courriel qu'elle contient. Des caractères génériques peuvent être utilisés. Un filtre n’est appliqué qu’aux alias directs (alias avec une seule boîte de réception cible), à l’exclusion des alias catch-all et d’une boîte de réception.", "spamfilter_yellow": "Jaune : ce message est peut être un spam, il sera étiqueté comme spam et déplacé vers votre dossier Pourriel", "status": "Statut", "sync_jobs": "Jobs de synchronisation", "tag_handling": "Régler la manipulation du courrier étiqueté", - "tag_help_example": "Exemple pour une adresse e-mail étiquetée : me+Facebook@example.org", - "tag_help_explain": "Dans un sous-dossier : un nouveau sous-dossier nommé selon l'étiquette sera créé sous INBOX (\"INBOX/Facebook\").
\nDans le sujet : le nom des balises sera ajouté au début du sujet du mail, exemple : \"[Facebook] My News\".", + "tag_help_example": "Exemple pour une adresse de courriel étiquetée : me+Facebook@example.org", + "tag_help_explain": "Dans un sous-dossier : un nouveau sous-dossier nommé selon l'étiquette sera créé sous INBOX (\"INBOX/Facebook\").
\nDans le sujet : le nom des balises sera ajouté au début du sujet de l'e-mail, exemple : \"[Facebook] My News\".", "tag_in_none": "Ne rien faire", "tag_in_subfolder": "Dans un sous dossier", "tag_in_subject": "Dans le sujet", @@ -1090,7 +1169,7 @@ "tls_enforce_in": "Appliquer le TLS entrant", "tls_enforce_out": "Appliquer le TLS sortant", "tls_policy": "Politique de chiffrement", - "tls_policy_warning": "Attention: Si vous décidez d’appliquer le transfert de courrier chiffré, vous risquez de perdre des courriels.
Les messages qui ne satisfont pas à la politique seront renvoyés avec une erreur grave par le système de messagerie.
Cette option s’applique à votre adresse courriel principale (login name), toutes les adresses dérivées de domaines alias ainsi que les adresses alias avec cette seule boîte comme cible.", + "tls_policy_warning": "Attention : Si vous décidez d’appliquer le transfert de courrier chiffré, vous risquez de perdre des courriels.
Les messages qui ne satisfont pas à la politique seront renvoyés avec une erreur grave par le système de messagerie.
Cette option s’applique à votre adresse courriel principale (login name), toutes les adresses dérivées de domaines alias ainsi que les adresses alias avec cette seule boîte de réception comme cible.", "user_settings": "Paramètres utilisateur", "username": "Nom d'utilisateur", "verify": "Vérification", @@ -1101,7 +1180,29 @@ "months": "mois", "year": "année", "years": "années", - "with_app_password": "avec le mot de passe de l'application" + "with_app_password": "avec le mot de passe de l'application", + "apple_connection_profile_with_app_password": "Un nouveau mot de passe est généré et ajouté au profil, de sorte qu'aucun mot de passe ne doit être saisi lors de la configuration de votre appareil. Ne partagez pas le fichier car il vous donne un accès complet à votre boîte de réception.", + "attribute": "Attribut", + "direct_protocol_access": "Cet utilisateur de la boîte aux lettres dispose d'un accès externe direct aux protocoles et applications suivants. Votre administrateur contrôle ce paramètre. Il est possible de créer des mots de passe d'application pour accorder l'accès à des protocoles et des applications individuels.
Le bouton « Connexion au webmail » permet une connexion unique à SOGo et est toujours disponible.", + "open_webmail_sso": "Connexion au webmail", + "recent_successful_connections": "Voir les connexions réussies", + "syncjob_EXIT_TLS_FAILURE": "Problème de connexion chiffrée", + "syncjob_EXIT_AUTHENTICATION_FAILURE": "Problème d'authentification", + "syncjob_EXIT_OVERQUOTA": "La boîte de réception cible a dépassé le quota", + "login_history": "Historique des connexions", + "change_password_hint_app_passwords": "Votre compte a %d mots de passe d'application qui ne seront pas modifiés. Pour les gérer, allez dans l'onglet Mots de passe de l'application.", + "clear_recent_successful_connections": "Vider l'historique des connexions réussies", + "created_on": "Créé le", + "last_ui_login": "Dernière connexion sur l'interface", + "syncjob_check_log": "Vérifier le journal", + "syncjob_last_run_result": "Résultat du dernier lancement", + "syncjob_EX_OK": "Succès", + "syncjob_EXIT_CONNECTION_FAILURE": "Problème de connexion", + "syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Impossible de se connecter au serveur distant", + "syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Nom d'utilisateur ou mot de passe incorrect", + "value": "Valeur", + "allowed_protocols": "Protocoles autorisés", + "mailbox": "Boîte de réception" }, "warning": { "cannot_delete_self": "Impossible de supprimer l’utilisateur connecté", @@ -1110,9 +1211,32 @@ "fuzzy_learn_error": "Erreur d’apprentissage du hachage flou: %s", "hash_not_found": "Hachage non trouvé ou déjà supprimé", "ip_invalid": "IP non valide ignorée : %s", - "no_active_admin": "Impossible de désactiver le dernier administrateur active", - "quota_exceeded_scope": "Dépassement du quota de domaine : Seules des boîtes illimitées peuvent être créées dans ce domaine.", + "no_active_admin": "Impossible de désactiver le dernier administrateur actif", + "quota_exceeded_scope": "Dépassement du quota de domaine : Seules des boîtes de réception illimitées peuvent être créées dans ce domaine.", "session_token": "Jeton de formulaire invalide : Jeton différent", - "session_ua": "Jeton de formulaire invalide : erreur de validation User-Agent" + "session_ua": "Jeton de formulaire invalide : erreur de validation User-Agent", + "is_not_primary_alias": "Alias non primaire ignoré %s" + }, + "datatables": { + "decimal": ".", + "expand_all": "Tout déplier", + "thousands": ",", + "paginate": { + "first": "Premier", + "last": "Dernier" + }, + "aria": { + "sortAscending": ": activer pour trier les colonnes en ordre croissant", + "sortDescending": ": activer pour trier les colonnes en ordre décroissant" + }, + "infoEmpty": "Affichage de 0 à 0 de 0 entrées", + "infoFiltered": "(filtré à partir de _MAX_ entrées totales)", + "lengthMenu": "Afficher les entrées _MENU_", + "loadingRecords": "Chargement…", + "processing": "Veuillez patienter…", + "collapse_all": "Tout réduire" + }, + "ratelimit": { + "disabled": "Désactivé" } } diff --git a/data/web/lang/lang.hu-hu.json b/data/web/lang/lang.hu-hu.json index 1c798bd9..e9762ff5 100644 --- a/data/web/lang/lang.hu-hu.json +++ b/data/web/lang/lang.hu-hu.json @@ -22,7 +22,114 @@ "activate_api": "API aktiválása", "activate_send": "Küldés gomb aktiválása", "add": "Hozzáad", - "active": "Aktív" + "active": "Aktív", + "api_info": "Az API még fejlesztés alatt áll. A dokumentáció megtalálható a /api alatt", + "allowed_methods": "Hozzáférés-Szabályozás-Engedélyezési-Módszerek", + "logo_normal_label": "Normál", + "logo_dark_label": "Sötét üzemmódhoz invertálva", + "f2b_regex_info": "Figyelembe vett naplók: SOGo, Postfix, Dovecot, PHP-FPM.", + "f2b_retry_window": "Újrapróbálkozási ablak (s) a maximális próbálkozásokhoz", + "f2b_whitelist": "Fehérlistás hálózatok/hostok", + "filter_table": "Szűrő táblázat", + "forwarding_hosts": "Továbbító hostok", + "forwarding_hosts_add_hint": "Megadhat IPv4/IPv6 címeket, hálózatokat CIDR jelölésben, állomásneveket (amelyek IP-címekre lesznek feloldva) vagy tartományneveket (amelyek IP-címekre lesznek feloldva az SPF rekordok vagy ezek hiányában az MX rekordok lekérdezésével).", + "from": "A címről", + "copy_to_clipboard": "Szöveg másolva a vágólapra!", + "f2b_manage_external": "A Fail2Ban külső kezelése", + "f2b_manage_external_info": "A Fail2ban továbbra is karbantartja a tiltólistát, de nem állít be aktívan szabályokat a forgalom blokkolására. Használja az alábbi generált tiltólistát a forgalom külső blokkolásához.", + "f2b_max_ban_time": "Maximális tiltási idő (s)", + "f2b_netban_ipv4": "IPv4 alhálózat mérete, amelyre tilalmat kell alkalmazni (8-32)", + "f2b_netban_ipv6": "IPv6 alhálózat mérete, amelyre tilalmat kell alkalmazni (8-128)", + "f2b_parameters": "Fail2ban paraméterek", + "forwarding_hosts_hint": "A bejövő üzeneteket feltétel nélkül elfogadják az itt felsorolt összes állomásról. Ezeket az állomáshelyeket nem ellenőrzik a DNSBL-ek alapján, és nem vetik alá a szürkelistázásnak. A tőlük érkező spameket a rendszer soha nem utasítja el, de opcionálisan a Junk mappába iktathatja őket. Leggyakrabban olyan levelezőszerverek megadására használjuk, amelyeken olyan szabályt állítottunk be, amely a bejövő e-maileket a mailcow-kiszolgálóra továbbítja.", + "guid_and_license": "GUID & Licenc", + "help_text": "Súgó szöveg felülírása a bejelentkezési maszk alatt (HTML engedélyezett)", + "html": "HTML", + "import": "Import", + "ip_check": "IP ellenőrzés", + "ip_check_disabled": "Az IP-ellenőrzés le van tiltva. Bekapcsolhatja a következő menüpont alatt
Rendszer > Beállítások > Opciók > Személyreszabás", + "is_mx_based": "MX alapú", + "last_applied": "Utoljára alkalmazott", + "link": "Link", + "loading": "Kérjük, várj...", + "login_time": "Bejelentkezési idő", + "f2b_list_info": "Egy feketelistán szereplő állomás vagy hálózat mindig nagyobb súlyú, mint egy fehérlistás entitás. A lista frissítései néhány másodpercig tartanak.", + "f2b_ban_time_increment": "A tiltási idő minden egyes tiltással növekszik", + "additional_rows": " - további sorokat adtak hozzá", + "admin": "Adminisztrátor", + "admin_details": "Rendszergazda adatok szerkesztése", + "admin_domains": "Domain hozzárendelések", + "f2b_max_attempts": "Max. próbálkozások", + "generate": "generálni", + "admins": "Adminisztrátorok", + "admins_ldap": "LDAP rendszergazdák", + "allowed_origins": "Hozzáférés-Szabályozás-Engedélyezési-Származás", + "api_allow_from": "API-hozzáférés engedélyezése ezekről az IP/CIDR hálózati jelölésekről", + "api_key": "API-kulcs", + "api_read_only": "Csak olvasható hozzáférés", + "api_read_write": "Olvasás-írás hozzáférés", + "api_skip_ip_check": "IP-ellenőrzés kihagyása az API esetében", + "cors_settings": "CORS beállítások", + "guid": "GUID - egyedi példányazonosító", + "dkim_to": "A címre", + "dkim_to_title": "Céltartomány(ok) - felülírásra kerül", + "domain": "Domain", + "domain_admin": "Domain adminisztrátor", + "domain_admins": "Domain adminisztrátorok", + "domain_s": "Domain(ek)", + "duplicate": "Duplikátum", + "duplicate_dkim": "Duplikált DKIM bejegyzés", + "edit": "Szerkesztés", + "empty": "Nincs eredmény", + "excludes": "Kizárja ezeket a kedvezményezetteket", + "f2b_ban_time": "Tilalmi idő (s)", + "f2b_blacklist": "Feketelistás hálózatok/hostok", + "f2b_filter": "Regex szűrők", + "logo_info": "A képed 40px magasságúra lesz méretezve a felső navigációs sávhoz és max. 250px szélességűre a kezdőlaphoz. A skálázható grafika használata erősen ajánlott.", + "dkim_add_key": "ARC/DKIM kulcs hozzáadása", + "dkim_domains_selector": "Válogató", + "dkim_domains_wo_keys": "A hiányzó kulcsokkal rendelkező tartományok kiválasztása", + "dkim_from": "A címről", + "dkim_from_title": "Forrás tartomány, ahonnan az adatokat másolni kell", + "dkim_key_length": "DKIM kulcs hossza (bit)", + "dkim_key_missing": "Kulcs hiányzik", + "import_private_key": "Privát kulcs importálása", + "in_use_by": "Használja a", + "inactive": "Inaktív", + "include_exclude": "Beleértve/Kivéve", + "include_exclude_info": "Alapértelmezés szerint - kiválasztás nélkül - minden postafiók címzésre kerül.", + "includes": "Vegye fel ezeket a címzetteket", + "add_row": "Sor hozzáadása", + "host": "Host", + "active_rspamd_settings_map": "Aktív beállítások térképe", + "add_admin": "Adminisztrátor hozzáadása", + "add_forwarding_host": "Továbbító állomás hozzáadása", + "add_relayhost": "Feladófüggő szállítás hozzáadása", + "add_relayhost_hint": "Felhívjuk figyelmed, hogy ha vannak hitelesítési adatok, azok egyszerű szövegként kerülnek tárolásra.", + "add_settings_rule": "Beállítási szabály hozzáadása", + "add_transport": "Szállítás hozzáadása", + "add_transports_hint": "Felhívjuk figyelmed, hogy ha vannak hitelesítési adatok, azok egyszerű szövegként kerülnek tárolásra.", + "advanced_settings": "Speciális beállítások", + "change_logo": "Logó módosítása", + "dkim_key_unused": "Nem használt kulcs", + "add_domain_admin": "Tartományi rendszergazda hozzáadása", + "dkim_key_valid": "Érvényes kulcs", + "dkim_keys": "ARC/DKIM kulcsok", + "dkim_overwrite_key": "A meglévő DKIM kulcs felülírása", + "dkim_private_key": "Privát kulcs", + "app_links": "App linkek", + "app_name": "Alkalmazás neve", + "arrival_time": "Érkezési idő (szerveridő)", + "authed_user": "Azonosított felhasználó", + "ays": "Biztos, hogy folytatni akarod?", + "ban_list_info": "A tiltott IP-címek listáját lásd alább: hálózat (fennmaradó tiltási idő) - [akciók].
A tiltás feloldására várakozó IP-ket néhány másodpercen belül eltávolítjuk az aktív tiltási listáról.
A piros címkék a feketelistán szereplő aktív állandó tiltásokat jelzik.", + "configuration": "Konfiguráció", + "convert_html_to_text": "HTML átalakítása egyszerű szöveggé", + "credentials_transport_warning": "Figyelmeztetés: Egy új közlekedési térképbejegyzés hozzáadása frissíti a hitelesítő adatokat minden olyan bejegyzéshez, amelynek a következő ugrás oszlopa megegyezik.", + "customize": "Testreszabás", + "destination": "Célállomás", + "customer_id": "Ügyfél azonosító", + "apps_name": "\"mailcow Apps\" név" }, "edit": { "active": "Aktív", @@ -57,7 +164,7 @@ "header": { "administration": "Beállítások és részletek", "apps": "Appok", - "debug": "Rendszer információ", + "debug": "Információ", "email": "E-Mail", "mailcow_config": "Beállítások", "quarantine": "Karantén", @@ -399,13 +506,89 @@ "protocol_access": "Protokoll-hozzáférés módosítása", "quarantine_attachments": "Karantén mellékletek", "quarantine_category": "Karantén értesítési kategória módosítása", - "quarantine_notification": "Karantén értesítések módosítása" + "quarantine_notification": "Karantén értesítések módosítása", + "eas_reset": "EAS-eszközök alaphelyzetbe állítása", + "extend_sender_acl": "Küldő ACL külső címekkel való bővítésének engedélyezése", + "mailbox_relayhost": "Relayhost módosítása egy postafiókhoz", + "prohibited": "ACL által tiltott", + "pushover": "Pushover", + "ratelimit": "Mérték határ", + "recipient_maps": "Címzett térképek", + "smtp_ip_access": "Az SMTP engedélyezett állomásainak módosítása", + "sogo_profile_reset": "SOGo profil visszaállítása", + "spam_alias": "Ideiglenes álnevek", + "spam_policy": "Fekete/Fehér lista", + "spam_score": "Spam pontszám", + "syncjobs": "Szinkronizálási feladatok", + "tls_policy": "TLS szabályzat", + "unlimited_quota": "Korlátlan kvóta a postafiókok számára", + "sogo_access": "A SOGo-hozzáférés kezelésének lehetővé tétele" }, "diagnostics": { "dns_records": "DNS bejegyzések" }, "add": { "username": "Felhasználónév", - "validation_success": "Sikeres ellenőrzés" + "validation_success": "Sikeres ellenőrzés", + "mailbox_quota_def": "Alapértelmezett postafiók kvóta", + "password_repeat": "Megerősítő jelszó (ismétlés)", + "post_domain_add": "A \"sogo-mailcow\" SOGo konténert újra kell indítani egy új tartomány hozzáadása után!

Kiegészítésképpen a tartományok DNS-konfigurációját is felül kell vizsgálni. A DNS-konfiguráció jóváhagyása után indítsa újra az \"acme-mailcow\"-t, hogy automatikusan generáljon tanúsítványokat az új tartományhoz (autoconfig.<domain>, autodiscover.<domain>).
Ez a lépés opcionális, és 24 óránként megismétlődik.", + "dry": "Szinkronizálás szimulálása", + "inactive": "Inaktív", + "kind": "Kedves", + "mailbox_quota_m": "Maximális kvóta postafiókonként (MiB)", + "mailbox_username": "Felhasználónév (az e-mail cím bal oldali része)", + "max_aliases": "Max. lehetséges álnevek", + "max_mailboxes": "Max. lehetséges postafiókok", + "mins_interval": "A lekérdezési időköz (perc)", + "password": "Jelszó", + "port": "Port", + "public_comment": "Nyilvános megjegyzés", + "target_domain": "Céltartomány", + "timeout1": "Időtúllépés a távoli állomáshoz való csatlakozáskor", + "timeout2": "Időtúllépés a helyi állomáshoz való csatlakozáskor", + "validate": "Érvényesítsd", + "description": "Leírás", + "destination": "Célállomás", + "disable_login": "Bejelentkezés letiltása (a bejövő leveleket továbbra is elfogadja)", + "domain_matches_hostname": "Domain %s megegyezik a hostnévvel", + "domain_quota_m": "Teljes tartományi kvóta (MiB)", + "enc_method": "Titkosítási módszer", + "exclude": "Objektumok kizárása (regex)", + "full_name": "Teljes név", + "gal": "Globális címlista", + "goto_ham": "Tanulj sonkaként", + "goto_null": "Leveleket csendben eldobni", + "goto_spam": "Tanuld spamként", + "syncjob_hint": "Ne feledje, hogy a jelszavakat egyszerű szöveges formában kell elmenteni!", + "target_address": "Továbbítási címek", + "target_address_info": "Teljes e-mail cím(ek) (vesszővel elválasztva).", + "bcc_dest_format": "A BCC-célpontnak egyetlen érvényes e-mail címnek kell lennie.
Ha több címre kell másolatot küldenie, hozzon létre egy aliast, és használja azt.", + "comment_info": "A privát megjegyzés nem látható a felhasználó számára, míg a nyilvános megjegyzés tooltip-ként jelenik meg, amikor a felhasználó áttekintésében a megjegyzésre mutat.", + "custom_params": "Egyéni paraméterek", + "gal_info": "A GAL tartalmazza a tartomány összes objektumát, és egyetlen felhasználó sem szerkesztheti. A SOGo-ban a Szabad/Elfoglalt információ hiányzik, ha ki van kapcsolva! Indítsa újra a SOGo-t a változások alkalmazásához.", + "hostname": "Házigazda", + "backup_mx_options": "Továbbítási opciók", + "custom_params_hint": "Megfelelő: --param=xy, Rossz: --param xy", + "delete1": "Törlés a forrásból, ha befejeződött", + "delete2": "A forráson kívüli üzenetek törlése a célállomáson", + "delete2duplicates": "Duplikáltak törlése a célállomáson", + "domain": "Domain", + "nexthop": "Következő hop", + "tags": "Címkék", + "app_password": "Alkalmazás jelszó hozzáadása", + "private_comment": "Privát megjegyzés", + "alias_address_info": "Teljes e-mail cím(ek) vagy @example.com, egy domainhez tartozó összes üzenetet elfogásához (vesszővel elválasztva). csak mailcow tartományok.", + "generate": "generál", + "activate_filter_warn": "Az összes többi szűrő deaktiválódik, ha az aktív opció be van jelölve.", + "active": "Aktív", + "add": "Hozzáad", + "add_domain_only": "Csak domain hozzáadása", + "add_domain_restart": "Domain hozzáadása és a SOGo újraindítása", + "alias_address": "Alias cím(ek)", + "alias_domain": "Alias domain", + "alias_domain_info": "Csak érvényes tartománynevek (vesszővel elválasztva).", + "app_name": "Alkalmazás neve", + "app_passwd_protocols": "Engedélyezett protokollok az alkalmazás jelszavához" } } diff --git a/data/web/lang/lang.it-it.json b/data/web/lang/lang.it-it.json index 6783dfed..f6527840 100644 --- a/data/web/lang/lang.it-it.json +++ b/data/web/lang/lang.it-it.json @@ -107,7 +107,8 @@ "validation_success": "Convalidato con successo", "bcc_dest_format": "Il destinatario in copia nascosta deve essere un singolo indirizzo email.
Se si vuole spedire una copia del messaggio a più destinatari, bisogna creare un alias ed utilizzarlo per questa opzione.", "app_passwd_protocols": "Protocolli consentiti per la password dell'app", - "tags": "Tag" + "tags": "Tag", + "dry": "Simula sincronizzazione" }, "admin": { "access": "Accedi", @@ -339,7 +340,8 @@ "oauth2_add_client": "Aggiungere il client OAuth2", "rsettings_preset_4": "Disattivare Rspamd per un dominio", "options": "Opzioni", - "cors_settings": "Impostazioni CORS" + "cors_settings": "Impostazioni CORS", + "copy_to_clipboard": "Testo copiato negli appunti!" }, "danger": { "access_denied": "Accesso negato o form di login non corretto", @@ -462,7 +464,9 @@ "demo_mode_enabled": "La modalità demo è abilitata", "template_name_invalid": "Nome template non valido", "template_exists": "Il template %s esiste già", - "template_id_invalid": "Il template con ID %s non è valido" + "template_id_invalid": "Il template con ID %s non è valido", + "img_dimensions_exceeded": "L'immagine supera la dimensione massima consentita", + "img_size_exceeded": "L'immagine supera la dimensione massima del file" }, "debug": { "chart_this_server": "Grafico (questo server)", @@ -506,7 +510,7 @@ "dns_records": "Record DNS", "dns_records_24hours": "Tieni presente che le modifiche apportate ai record DNS potrebbero richiedere fino a 24 ore per poter essere visualizzate correttamente in questa pagina. Tutto ciò è da intendersi come un modo per voi di vedere come configurare i record DNS e per controllare se tutti i record DNS sono stati inseriti correttamente.", "dns_records_data": "Dati corretti", - "dns_records_docs": "Si prega di consultare anche la documentazione.", + "dns_records_docs": "Si prega di consultare anche la documentazione.", "dns_records_name": "Nome", "dns_records_status": "Stato attuale", "dns_records_type": "Tipo", @@ -626,7 +630,9 @@ "acl": "ACL (autorizzazione)", "app_passwd_protocols": "Protocolli consentiti per la password dell'app", "last_modified": "Ultima modifica", - "pushover_sound": "Suono" + "pushover_sound": "Suono", + "custom_attributes": "Attributi personalizzati", + "domain_footer_skip_replies": "Ignora il piè di pagina nelle e-mail di risposta" }, "fido2": { "confirm": "Conferma", @@ -1021,7 +1027,8 @@ "domain_add_dkim_available": "Esisteva già una chiave DKIM", "template_added": "Aggiunto template %s", "template_modified": "Le modifiche al template %s sono state salvate", - "template_removed": "Il template con ID %s è stato cancellato" + "template_removed": "Il template con ID %s è stato cancellato", + "f2b_banlist_refreshed": "L'ID della lista blocchi è stato aggiornato con successo." }, "tfa": { "api_register": "%s usa le API Yubico Cloud. Richiedi una chiave API qui", @@ -1048,7 +1055,8 @@ "yubi_otp": "Autenticazione Yubico OTP", "tfa_token_invalid": "Token TFA non valido", "u2f_deprecated": "Sembra che la tua chiave sia stata registrata utilizzando il metodo U2F deprecato. Disattiveremo Two-Factor-Authenticaiton per te e cancelleremo la tua chiave.", - "u2f_deprecated_important": "Registra la tua chiave nel pannello di amministrazione con il nuovo metodo WebAuthn." + "u2f_deprecated_important": "Registra la tua chiave nel pannello di amministrazione con il nuovo metodo WebAuthn.", + "authenticators": "Autenticatori" }, "user": { "action": "Azione", @@ -1210,7 +1218,9 @@ "syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Nome utente o password errati", "with_app_password": "con password dell'app", "direct_protocol_access": "Questo utente della mailbox ha accesso diretto ed esterno ai seguenti protocolli e applicazioni. Questa impostazione è controllata dal tuo amministratore. Le password delle applicazioni possono essere create per garantire l'accesso ai singoli protocolli e applicazioni.
Il pulsante \"Accedi alla webmail\" fornisce un singolo accesso a SOGo ed è sempre disponibile.", - "pushover_sound": "Suono" + "pushover_sound": "Suono", + "attribute": "Attributo", + "value": "Valore" }, "warning": { "cannot_delete_self": "Cannot delete logged in user", diff --git a/data/web/lang/lang.lt-lt.json b/data/web/lang/lang.lt-lt.json new file mode 100644 index 00000000..f5413b1a --- /dev/null +++ b/data/web/lang/lang.lt-lt.json @@ -0,0 +1,354 @@ +{ + "acl": { + "app_passwds": "Tvarkyti programėlių slaptažodžius", + "bcc_maps": "BCC žemėlapiai", + "domain_desc": "Keisti domeno aprašymą", + "eas_reset": "Išvalyti EAS įrenginius", + "filters": "Filtrai", + "login_as": "Prisijungti kaip elektroninio pašto naudotojas", + "protocol_access": "Keisti protokolų prieigą", + "quarantine": "Karantino valdymas", + "quarantine_category": "Keisti karantino pranešimo katrgoriją", + "quarantine_notification": "Keisti karantino pranešimus", + "ratelimit": "Prieigos limitas", + "recipient_maps": "Gavėjų sąsajos", + "smtp_ip_access": "Pakeisti prieinamuosius SMTP serverius", + "sogo_access": "Leisti SOGo prieigos valdymą", + "spam_policy": "Juodasis/Baltasis sąrašas", + "spam_score": "Šlamsto balas", + "tls_policy": "TLS politika", + "unlimited_quota": "Neribota elektroninio pašto dėžudžių kvota", + "quarantine_attachments": "Karantino priedai", + "sogo_profile_reset": "Nustatyti SOGo profilį iš naujo", + "alias_domains": "Pridėti pakaitinius domenus", + "delimiter_action": "Delimitatoriaus veiksmas", + "domain_relayhost": "Pakeisti peradresavimo serverį domenui", + "extend_sender_acl": "Leisti išplėsti siuntėjo ACL išoriniais adresais", + "mailbox_relayhost": "Pakeisti siuntimo serverį pašto dėžutei", + "prohibited": "Draudžiama pagal ACL", + "spam_alias": "Laikini slapyvardžiai", + "syncjobs": "Sinchronizuoti darbus" + }, + "add": { + "active": "Aktyvus", + "add": "Pridėti", + "add_domain_only": "Pridėti tik domeną", + "add_domain_restart": "Pridėti domeną ir paleisti SOGo iš naujo", + "alias_domain_info": "Tik tinkami domenų vardai (išskirta kableliais).", + "app_name": "Programėlės pavadinimas", + "app_password": "Pridėti programėlės slaptažodį", + "app_passwd_protocols": "Prieinamieji programėlės slaptažodžio protokolai", + "custom_params": "Pasirinktiniai parametrai", + "delete1": "Ištrinti iš šaltinio, kai baigta", + "activate_filter_warn": "Visi kiti filtrai bus deaktivuoti, kai „aktyvus“ yra pražymėtas.", + "custom_params_hint": "Teisingai: --param=xy, neteisingai: --param xy", + "description": "Aprašymas", + "destination": "Gavėjas", + "domain": "Domenas", + "domain_quota_m": "Viso domeno kvota (MiB)", + "dry": "Simuliuoti sinchronizaciją", + "enc_method": "Šifravimo metodas", + "full_name": "Prilnas vardas", + "generate": "generuoti", + "goto_null": "Tyliai atmesti žinutes", + "goto_spam": "Išmokti kaip šlamštas", + "password": "Slaptažodis", + "select": "Pasirinkite...", + "select_domain": "Prima, pasirinkite domeną", + "sieve_desc": "Trumpas aprašymas", + "sieve_type": "Filtro tipas", + "mailbox_quota_def": "Numatytoji elelktroninio pašto dėžutės kvota", + "password_repeat": "Slaptažodžio patvirtininas (pakartoti)", + "disable_login": "Uždrausti prisijungimą (ateinančios žinutės vistiek bus gaunamos)", + "inactive": "Neaktyvus", + "alias_address": "Pakaitiniai/is adresai/as", + "alias_address_info": "Pilnas el. pašto adresas (-ai) arba @example.com, kad gautumėte visus pranešimus iš domeno (atskirtus kableliais). Tik \"mailcow\" domenai.", + "alias_domain": "Pakaitinis domenas", + "automap": "Stenktis automatiškai susieti aplankus (\"Išsiųsti\", \"Išsiųsti\" => \"išsiųsti\" ir tt.)", + "backup_mx_options": "Perdavimo nustatymai", + "bcc_dest_format": "BCC gavimo adresas turi būti vienas galiojantis el. pašto adresas.
Jei turite siųsti kopiją į kelis adresus, sukurkite slapyvardį ir naudokite jį čia.", + "delete2": "Ištrinti žinutes gavimo vietoje, kurios nėra šaltinyje.", + "delete2duplicates": "Ištrinti dublikatus gavimo vietoje", + "domain_matches_hostname": "Domenas %s atitinka serverio vardą", + "exclude": "Išskirti objektus (regex)", + "gal": "Visuotinis adresų sąrašas", + "gal_info": "GAL (Global Address List) apima visus domeno objektus ir jų negali redaguoti joks vartotojas. SOGo trūksta laisvosios/užimtosios informacijos, jei tai išjungta! Perkraukite SOGo, kad pritaikytumėte pakeitimus." + }, + "admin": { + "access": "Prieiga", + "active": "Aktyvus", + "add": "Pridėti", + "add_admin": "Pridėti administratorių", + "add_domain_admin": "Pridėti domeno administratorių", + "add_settings_rule": "Pridėti nustatymų taisyklę", + "admin": "Administratorius", + "admins": "Administratoriai", + "admins_ldap": "LDAP administratoriai", + "api_key": "API prieigos raktas", + "copy_to_clipboard": "Tekstas nukopijuotas!", + "cors_settings": "CORS nustatymai", + "dkim_from": "Iš", + "dkim_key_length": "DKIM rakto ilgis (bitai)", + "dkim_key_valid": "Raktas tinkamas", + "dkim_keys": "ARC/DKIM raktai", + "dkim_private_key": "Slaptasis raktas", + "dkim_to": "Į", + "domain": "Domenas", + "domain_admin": "Domeno administratorius", + "domain_admins": "Doneno administratoriai", + "domain_s": "Domenas/ai", + "duplicate": "Dublikatas", + "duplicate_dkim": "Dublikuotas DKIM įrašas", + "edit": "Redaguoti", + "empty": "Jokių rezultatų", + "f2b_filter": "Regex filtrai", + "filter_table": "Filtrų lentelė", + "from": "Nuo", + "generate": "generuoti", + "html": "HTML", + "import": "Importuoti", + "inactive": "Neaktyvus", + "message": "Žinutė", + "message_size": "Žinutės dydis", + "nexthop": "Kitas šuolis", + "no": "✕", + "no_record": "Nėra įrašo", + "oauth2_apps": "OAuth2 Programėlės", + "oauth2_add_client": "Pridėti OAuth2 klientą", + "oauth2_client_id": "Kliento ID", + "optional": "pasirinktinas", + "options": "Nustatymai", + "password": "Slaptažodis", + "password_length": "Slaptažodžio ilgis", + "password_policy_chars": "Privalo turėti bent vieną numerį ar skaičių", + "password_policy_length": "Mažiausias slaptažodžio ilgis - %d", + "password_policy_numbers": "Privalo turėti bent vieną skaičių", + "password_policy_special_chars": "Privalo turėti specialiųjų ženklų", + "password_repeat": "Slaptažodžio patvirtinimas (pakartoti)", + "quarantine": "Karantinas", + "quarantine_notification_sender": "Pranešimų e-pašto siuntėjas", + "quarantine_release_format_att": "Kaip priedą", + "quarantine_release_format_raw": "Nepakeitas originalas", + "quota_notifications": "Kvotos pranešimai", + "r_active": "Aktyvūs apribojimai", + "r_inactive": "Neaktyvus apribojimai", + "refresh": "Perkrauti", + "regen_api_key": "Regeneruoti API raktą", + "relay_rcpt": "„Kam:“ adresas", + "relay_run": "Paleisti testą", + "remove": "Ištrinti", + "rsetting_add_rule": "Pridėti taisyklę", + "rsetting_desc": "Trumpas aprašymas", + "rspamd_global_filters_agree": "Aš busiu atsargus/i!", + "save": "Išsaugoti pakeitimus", + "search_domain_da": "Ieškoti domenus", + "send": "Siųsti", + "sender": "Siuntėjas", + "source": "Šaltinis", + "spamfilter": "Šlamšto filtras", + "text": "Tekstas", + "time": "Laikas", + "to_top": "Atgal į viršų", + "ui_header_announcement_content": "Tekstas (HTML leistina)", + "ui_header_announcement_select": "Pasirinkite pranešimo tipą", + "ui_header_announcement_type": "Tipas", + "ui_header_announcement_type_danger": "Labai svarbus", + "ui_header_announcement_type_info": "Info", + "upload": "Įkelti", + "username": "Naudotojo vardas", + "verify": "Patikrinti", + "yes": "✓", + "customer_id": "Kliento ID", + "f2b_parameters": "„Fail2Ban“ parametrai", + "import_private_key": "Importuoti slaptąjį raktą", + "action": "Veiksmas", + "convert_html_to_text": "Konvertuoti HTML į paprastą tekstą", + "oauth2_renew_secret": "Geberuoti naują kliento slapuką", + "private_key": "Slaptasis raktas", + "sal_level": "Moo lygis", + "ui_header_announcement_type_warning": "Svarbus", + "admin_details": "Redaguoti administratoriaus duomenis", + "login_time": "Prisijungino laikas", + "ui_header_announcement": "Pranešimai", + "dkim_overwrite_key": "Perrašyti egzistuojantį DKIK raktą", + "f2b_whitelist": "Tinklai baltajama sąraše", + "f2b_blacklist": "Tinklai juodajame saraše", + "loading": "Prašau palaukite...", + "password_policy_lowerupper": "Privalo turėti mažuosius ir didžiuosius ženklus/raides", + "relay_from": "„Nuo:“ adresas" + }, + "danger": { + "demo_mode_enabled": "Demo Režimas įjungtas", + "description_invalid": "Resurso %s aprašymas yra netinkamas", + "domain_exists": "Domenas %s jau egzistuoja", + "domain_invalid": "Domeno vardas tuščias arba netinkamas", + "domain_not_found": "Domenas %s nerastas", + "domain_quota_m_in_use": "Domeno kvota turi būti daygiau arba lygiai %s MiB", + "file_open_error": "Failas negali būti atidarytas įrašymui", + "filter_type": "Netinkamas filtro tipas", + "invalid_mime_type": "Netinkamas MIME tipas", + "login_failed": "Prisijungimas nepavyko", + "mailbox_defquota_exceeds_mailbox_maxquota": "Numatytoji kvota didesnė nei maksimalus kvotos limitas", + "mysql_error": "MySQL problema: %s", + "img_invalid": "Negalimas nuotraukos patikrinimas", + "mailbox_quota_left_exceeded": "Per mažai vietos diske (liko %d MiB)", + "comment_too_long": "Komentaeas per ilgas, maksimalus leistinas simbolių skaičius yra 160", + "nginx_reload_failed": "Nginx perkrovimas nepavyko: %s", + "invalid_filter_type": "Netinkamas filtro tipas" + }, + "edit": { + "validate_save": "Patikrinti ir išsaugoti", + "unchanged_if_empty": "Jei nepakeista, palikite tuščią", + "username": "Naudotojo vardas" + }, + "fido2": { + "confirm": "Patvirtinti", + "fido2_success": "Įrenginys sėkmingai užregistruotas", + "fido2_validation_failed": "Patikrinimas nepavyko", + "fn": "Draugiškasis vardas", + "known_ids": "Žinomi ID", + "none": "Neįgalintas", + "register_status": "Registracijos statusas", + "rename": "Pervadyti", + "set_fido2_touchid": "Registruokite Touch ID su Apple M1", + "set_fn": "Nustatyti draugiškąjį vardą", + "start_fido2_validation": "Pradėti FIDO2 patikrinimą", + "fido2_auth": "Prisijungti su FIDO2", + "set_fido2": "Registruoti FIDO2 įrengenį" + }, + "footer": { + "cancel": "Atšaukti", + "confirm_delete": "Patvirtinti trynimą", + "delete_now": "Ištrinti dabar", + "hibp_check": "Patikrinti naudodami haveibeenpwned.com", + "hibp_nok": "Atitikta! Tai yra galimai pavojingas slaptažodis!", + "hibp_ok": "Nerasta jokių atitikmenų.", + "loading": "Prašome palaukti...", + "nothing_selected": "Niekas nepasirinkta", + "restart_container": "Paleiskite konteinerį iš naujo", + "restart_now": "Perkrauti dabar", + "restarting_container": "Perkraunamas konteineris, tai gali užtrukti.", + "delete_these_items": "Prašome patvirtinti savo pakeitimus šiam objekto ID", + "restart_container_info": "Svarbu: Sklandus paleidimas iš naujo gali užtrukti, prašome palaukti, kol jis baigsis." + }, + "header": { + "administration": "Konfigūracija ir detalės", + "apps": "Programėlės", + "debug": "Informacija", + "email": "El. paštas", + "mailcow_system": "Sistema", + "mailcow_config": "Konfiguracija", + "quarantine": "Karantinas", + "restart_netfilter": "Paleisti „netfilter“ iš naujo", + "restart_sogo": "Paleisti SOGo iš naujo", + "user_settings": "Naudotojo Nustatymai" + }, + "info": { + "no_action": "Nėra taikomų veiksmų", + "session_expires": "Jūsų sesija pasibaigs už maždaug 15 sekundžių.", + "awaiting_tfa_confirmation": "Laukiama DFA patvirtinimo" + }, + "login": { + "fido2_webauthn": "FIDO2/WebAuthn Prisijungimas", + "login": "Prisijungti", + "other_logins": "Prisijungimas raktu", + "password": "Slaptažodis", + "username": "Naudotojo vardas", + "mobileconfig_info": "Prašome prisijungti kaip pašto dėžutės vartotojui, kad galėtumėte atsisiųsti pageidaujamą „Apple“ ryšio profilį." + }, + "mailbox": { + "action": "Veiksmas", + "activate": "Aktivuoti", + "active": "Aktyvus", + "add": "Pridėti", + "add_alias": "Pridėti pseudonimą", + "add_alias_expand": "Išplėsti pseudonimą per pseudonimų domenus", + "add_bcc_entry": "Pridėti BCC žemėlapį", + "add_domain": "Pridėti domeną", + "add_domain_alias": "Pridėti pakaitinį domeną", + "add_domain_record_first": "Prašome pridėti domeną pirmiausia", + "add_filter": "Pridėti filtrą", + "add_mailbox": "Pridėti pašto dėžutę", + "add_recipient_map_entry": "Pridėti gavėjų žemėlapį", + "add_resource": "Pridėti resursą", + "add_template": "Pridėti Šabloną", + "add_tls_policy_map": "Pridėti TLS politikos schemą", + "address_rewriting": "Adresų perrašymas", + "alias": "Slapyvardis", + "alias_domain_backupmx": "Pakaitinis domenas nėra aktyvuotas peradresavimo domenui", + "all_domains": "Visi Domenai", + "allow_from_smtp_info": "Palikite tuščią, norėdami leisti visiems siuntėjams.
IPv4/IPv6 adresai ir tinklai.", + "backup_mx": "Peradresavimo domenas", + "bcc": "BCC", + "bcc_destination": "BCC gavimo vieta", + "bcc_destinations": "BCC gavimo vieta", + "bcc_local_dest": "Vietinė gavimo vieta", + "bcc_map": "BCC žemėlapis", + "bcc_map_type": "BCC tipas", + "bcc_maps": "BCC žemėlapiai", + "bcc_type": "BCC tipas", + "booking_null": "Visada rodyti kaip laisvą", + "booking_0_short": "Visada laisvas", + "booking_custom": "Nekintamasis apribojimas pagal individualią užsakymų sumą", + "booking_custom_short": "Nekintamasis ribojimas", + "booking_ltnull": "Neribotas, bet rodyti kaip užimtas, kai užrezervuota", + "booking_lt0_short": "Kintamasis apribojimas", + "catch_all": "Viską sugriebiantis", + "daily": "Kasdien", + "description": "Aprašymas", + "disable_login": "Uždrausti prisijungimą (gaunami el. laiškai vis dar priimami)", + "disable_x": "Išjungti", + "dkim_key_length": "DKIM rakto ilgis (bitai)", + "domain": "Domenas", + "domain_aliases": "Pakaitomieji domenai", + "domain_templates": "Domenų Šablonai", + "domain_quota": "Kvota", + "domain_quota_total": "Bendroji domeno kvota", + "domains": "Domenai", + "edit": "Redaguoti", + "filters": "Filtrai", + "fname": "Pilnas vardas", + "gal": "Visuotinis adresų sąrašas", + "goto_spam": "Išmokti kaip šlamštas", + "hourly": "Kas valandą", + "in_use": "Naudojimas (%)", + "inactive": "Neaktyvus", + "allowed_protocols": "Leidžiami protokolai tiesioginiam vartotojo prieigai (neturi įtakos programėlių slaptažodžių protokolams)", + "goto_ham": "Išmokti kaip ham", + "aliases": "Pseudonimai", + "allow_from_smtp": "Leiskite tik šiems IP naudotis SMTP", + "alias_domain_alias_hint": "Pseudonimai nėra taikomi domeno pseudonimams automatiškai. Pseudonimo adresas my-alias@domain neapima adreso my-alias@alias-domain (kur \"alias-domain\" yra įsivaizduojamas \"domain\" pseudonimas).
Prašome naudoti sieve filtrą, kad nukreiptumėte laiškus į išorinę pašto dėžutę (žr. skirtuką \"Filtrai\" arba naudokite SOGo -> Peradresavimas). Naudokite \"Išplėsti pseudonimus per pseudonimų sritis\" kad automatiškai pridėti trūkstamus pseudonimus.", + "deactivate": "Deaktivuoti", + "domain_admins": "Domeno administratoriai", + "enable_x": "Įjungti", + "last_run_reset": "Suplanuoti kitą", + "mailbox": "Pašto dėžutė", + "mailbox_defaults": "Numatytieji nustatymai", + "mailbox_defaults_info": "Nustatyti numatytuosius nustatymus naujoms pašto dėžutėms.", + "mailbox_defquota": "Numatytasis pašto dėžutės dydis", + "mailbox_templates": "Pašto dėžučių šablonai", + "mailbox_quota": "Maks. pašto dėžutės dydis", + "mailboxes": "Pašto dėžutės", + "max_aliases": "Maks. slapyvardžiai", + "max_mailboxes": "Maks. galimų pašto dėžučių", + "max_quota": "Maks. kvota kiekvienai pašto dėžutei", + "mins_interval": "Intervalas (min)", + "msg_num": "Žinutė #" + }, + "quarantine": { + "atts": "Priedaj", + "check_hash": "Ieškoti failo Hash'o @ VT", + "confirm": "Patvirtinti", + "confirm_delete": "Patvirtinti šio elemento trynimą", + "danger": "Pavojus" + }, + "success": { + "domain_admin_added": "Pridėtas domeno administractorius %s", + "domain_admin_removed": "Domeno administratorius %s ištrintas", + "domain_modified": "Domeno %s pakitimai išsaugoti", + "domain_removed": "Domenas %s ištrintas", + "dovecot_restart_success": "„Doveccot“ perkrautas", + "domain_added": "Pridėtas domenas %s", + "domain_admin_modified": "Pakeitimai domeno adminustratoriui %s išsaugoti" + } +} diff --git a/data/web/lang/lang.lv-lv.json b/data/web/lang/lang.lv-lv.json index 962b9000..5f486d90 100644 --- a/data/web/lang/lang.lv-lv.json +++ b/data/web/lang/lang.lv-lv.json @@ -4,7 +4,19 @@ "filters": "Filtri", "recipient_maps": "Saņēmēja kartes", "syncjobs": "Sinhronizācijas uzdevumi", - "spam_score": "Mēstules novērtējums" + "spam_score": "Mēstules novērtējums", + "alias_domains": "Pievienot aizstājdomēnus", + "spam_alias": "Pagaidu aizstājvārdi", + "app_passwds": "Lietotņu paroļu pārvaldība", + "delimiter_action": "Atdalītāja darbība", + "domain_desc": "Mainīt domēna aprakstu", + "domain_relayhost": "Mainīt domēna relayhost", + "eas_reset": "EAS ierīču atiestatīšana", + "extend_sender_acl": "Ļauj paplašināt sūtītāja ACL ar ārējām adresēm", + "login_as": "Pieteikšanās kā pastkastes lietotājam", + "mailbox_relayhost": "Pasta kastītes relayhost maiņa", + "prohibited": "Aizliegts ar ACL", + "protocol_access": "Protokola piekļuves maiņa" }, "add": { "activate_filter_warn": "Visi pārējie filtri tiks deaktivizēti, kad aktīvs ir atzīmēts.", @@ -12,9 +24,9 @@ "add": "Pievienot", "add_domain_only": "Tikai pievienot domēnu", "add_domain_restart": "Pievienot domēnu un restartēt SOGo", - "alias_address": "Alias addrese/s", + "alias_address": "Aizstājaddrese/s", "alias_address_info": "Pilna epasta addrese/s vai @piemērs.com, lai notvertu visas domēna ziņas (komatu atdalītas). tikai mailcow domēni.", - "alias_domain": "Alias domēni", + "alias_domain": "Aizstājdomēni", "alias_domain_info": "Tikai derīgi domēna vārdi (komatu atdalīti).", "automap": "Mēģiniet automatizēt mapes (\"Nosūtītie vienumi\", \"Nosūtītie\" => \"Nosūtītie\" etc.)", "backup_mx_options": "Dublējuma MX iespējas", @@ -23,7 +35,7 @@ "delete2duplicates": "Dzēst dublikātus galamērķī", "description": "Apraksts", "domain": "Domēns", - "domain_quota_m": "Kopējā domēna kvota (MiB)", + "domain_quota_m": "Kopējā domēna kvota (MiB)", "enc_method": "Šifrēšanas metode", "exclude": "Izslēgt objektus (regex)", "full_name": "Pilns vārds", @@ -32,17 +44,17 @@ "kind": "Veids", "mailbox_quota_m": "Maks. kvota pastkastei (MiB)", "mailbox_username": "Lietotājvārds (kriesā daļa no epasta adreses)", - "max_aliases": "Maks. iespejamās aliases", + "max_aliases": "Lielākais pieļaujamo aizstājvārdu skaits", "max_mailboxes": "Maks. iespējamās pastkastes", "mins_interval": "Aptauajs intervāls (minūtes)", "multiple_bookings": "Vairākas rezervācijas", "password": "Parole", "password_repeat": "Apstiprinājuma parole (atkārtot)", "port": "Ports", - "post_domain_add": "Jums būs nepieciešams atsāknēt SOGo servisa konteineru pēc jauna domēna pievienošanas!", + "post_domain_add": "SOGO konteineru \"sogo-mailcow\" ir nepieciešams pārsāknēt pēc jauna domēna pievienošanas.

Papildus vajadzētu pārskatīt domēnu DNS konfigurāciju. Tiklīdz DNS konfigurācija ir apstiprināta, jāpārsāknē \"acme-mailcow\", lai automātiski izveidotu sertifikātus jaunajam domēnam (autoconfig.<domain>, autodiscover.<domain>).
Šis solis ir izvēles un tiks atkārtots ik pēc 24 stundām.", "quota_mb": "Kvota (MiB)", "relay_all": "Pārsūtīt visus saņēmējus", - "relay_all_info": "Ja izvēlies nepārsūtīt visus saņēmējus, tad Tev būs nepieciešams pievienot (\"tukšu\") pastkasti katram saņēmējam, kas būtu jāpārsūta.", + "relay_all_info": "↪ Ja izvēlies nepārsūtīt visus saņēmējus, tad Tev būs nepieciešams pievienot (\"aklo\") pastkasti katram saņēmējam, kas būtu jāpārsūta.", "relay_domain": "Pārsūtīt šo domēnu", "select": "Lūdzu izvēlaties...", "select_domain": "Lūdzu sākumā izvēlaties domēnu", @@ -56,7 +68,8 @@ "target_domain": "Mērķa domēns", "username": "Lietotājvārds", "validate": "Apstiprināt", - "validation_success": "Apstiprināts veiksmīgi" + "validation_success": "Apstiprināts veiksmīgi", + "bcc_dest_format": "BCC galamērķim ir jābūt vienai derīgai e-pasta adresei.
Ja ir nepieciešams nosūtīt kopiju vairākām adresēm, jāizveido aizstājvārds un jāizmanto tas šeit." }, "admin": { "access": "Pieeja", @@ -93,14 +106,14 @@ "f2b_ban_time": "Aizlieguma laiks (s)", "f2b_max_attempts": "Maks. piegājieni", "f2b_netban_ipv4": "IPv4 apakštīkla izmērs, lai piemērotu aizliegumu uz (8-32)", - "f2b_netban_ipv6": "IPv6 apakštīkla izmērs, lai piemērotu aizliegumu uz (8-128)", + "f2b_netban_ipv6": "IPv6 apakštīkla izmērs, lai piemērotu aizliegumu uz (8-128)", "f2b_parameters": "Fail2ban parametri", "f2b_retry_window": "Atkārtošanas logs (s) priekš maks. piegājiena", "f2b_whitelist": "Baltā saraksta tīkls/hosts", "filter_table": "Filtru tabula", "forwarding_hosts": "Hostu pārsūtīšana", - "forwarding_hosts_add_hint": "Jūs varat norādīt IPv4/IPv6 addreses, tīklu iekš CIDR apzīmējuma, hosta nosaukumu (kas tiks atrisinātas IP adresēs), vai domēna vārdos (kas tiks atrisināts IP adresēs vaicājot SPF ierakstus vai, ja tādu nav, MX ierakstus).", - "forwarding_hosts_hint": "Ienākošie ziņojumi ir bez nosacījumiem pieņemti no visiem šeit norādītajiem hostiem. Pēc tam šie hosti netiek pārbaudīti pret DNSBL vai pakļauti Greylistei. No tiem saņemtās mēstules nekad netiek noraidītas, bet pēc izvēles tās var pārvietot mapē Nevēlamais. Visbiežāk to izmanto, lai precizētu pasta serverus, kuros ir iestatīts noteikums, kas pārsūta ienākošos e-pasta ziņojumus uz jūsu mailcow serveri.", + "forwarding_hosts_add_hint": "Var norādīt vai nu IPv4/IPv6 addreses, tīklu ar CIDR apzīmējumu, saimniekdatoru nosaukumus (kas tiks atrisināti IP adresēs) vai arī domēna vārdus (kas tiks atrisināti IP adresēs, vaicājot SPF ierakstus, vai, ja tādu nav, MX ierakstus).", + "forwarding_hosts_hint": "Ienākošie ziņojumi tiek bez nosacījumiem pieņemti no visiem šeit norādītajiem saimniekdatoriem. Tie tad netiek pārbaudīti pret DNSBL vai pakļauti ievietošanai pelēkajā sarakstā. No tiem saņemtās mēstules nekad netiek noraidītas, bet pēc izvēles tās var pārvietot mapē \"Nevēlams\". Visbiežāk to izmanto, lai norādītu pasta serverus, kuros ir uzstādīts nosacījums, kas pārsūta ienākošās e-pasta vēstules uz Tavu mailcow serveri.", "help_text": "Ignorēt palīdzības tekstu zem pieteikšanās maskas (HTML ir atļauta)", "host": "Hosts", "import": "Importēt", @@ -109,7 +122,7 @@ "inactive": "Neaktīvs", "link": "Saite", "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": "Tavs attēls augšējā pārvietošanās joslā tiks mērogots līdz 40 pikseļiem un ne vairāk par 250 pikseļiem platumā sākumlapā. Ļoti ieteicams izmantot mērogojamus attēlus.", "main_name": "\"mailcow UI\" nosaukums", "merged_vars_hint": "Pelēkās rindas tika apvienotas vars.(local.)inc.php un nevar tikt modificētas.", "no_new_rows": "Papildu rindas nav pieejamas", @@ -118,18 +131,18 @@ "password_repeat": "Apstiprināt paroli (atkārtot)", "private_key": "Privāta atslēga", "quarantine": "Karantīna", - "quarantine_exclude_domains": "Izslēgt domēnus un alias-domēnus:", - "quarantine_max_size": "Maks. izmērs MiB (lielāki vienumi ir atbrīvoti):", - "quarantine_retention_size": "Atlikumi pastkastēs:", + "quarantine_exclude_domains": "Neņemt vērā domēnus un aizstājdomēnus", + "quarantine_max_size": "Lielākais pieļaujamais izmērs MiB (lielāki vienumi tiek atmesti):
0 nenorāda neierobežotu.", + "quarantine_retention_size": "Paturējumi katrā pastkastē:
0 norāda, ka ir atspējoti.", "r_active": "Aktīvie ierobežojumi", "r_inactive": "Neaktīvie ierobežojumi", - "r_info": " Pelēki/atslēgti elementi aktīvo ierobežojumu sarakstā nav zināmi kā mailcow spēkā esoši ierobežojumi un tos nevar pārvietot. Jebkurā gadījumā nezināmi ierobežojumi tiks sakārtoti pēc pievienošanas.
Jūs varat pievienot jaunus elementus inc/vars.local.inc.php, lai varētu tos pārslēgt.", + "r_info": "Pelēkie/atspējotie vienumi spēkā esošo ierobežojumu sarakstā mailcow nav zināmi kā derīgi ierobežojumi, un tos nevar pārvietot. Nezināmi ierobežojumi jebkurā gadījumā parādīšanas secībā.
Jaunus vienumus var pievienot inc/vars.local.inc.php, lai varētu tos pārslēgt.", "recipients": "Adresāts", "refresh": "Atsvaidzināt", "regen_api_key": "Reģenerēt API atslēgu", "relay_from": "\"No:\" addrese", "relay_run": "Palaist testu", - "relayhosts_hint": "Definējiet relejhostus šeit, lai tos varētu izvēlēties domēna konfigurācijas logā.", + "relayhosts_hint": "Norādīt no sūtītāja atkarīgas piegādes, lai varētu tos atlasīt domēnu konfigurācijas uzvednē.
\n Piegādes pakalpojums vienmēr ir \"smtp\", tādējādi tiks mēģināts TLS, kad piedāvāts. Iekļautais TLS (SMTPS) netiek atbalstīts. Tiek ņemts vērā lietotāja atsevišķais izejošā TLS nosacījuma iestatījums.
\n Ietekmē atlasītos domēnus, tajā skaitā aizstājdomēnus.", "remove": "Noņemt", "remove_row": "Noņemt rindu", "reset_default": "Atiestatīt uz noklusējumu", @@ -148,16 +161,20 @@ "username": "Lietotājvārds", "generate": "izveidot", "message": "Ziņojums", - "last_applied": "Pēdējoreiz pielietots" + "last_applied": "Pēdējoreiz pielietots", + "f2b_regex_info": "Vērā ņemtie žurnāli: SOGO, Postfix, Dovecot, PHP-FPM.", + "sys_mails": "Sistēmas pasts", + "ip_check_disabled": "IP pārbaude ir atspējota. To var iespējot
Sistēma > Konfigurācija > iespējas > Pielāgot", + "rspamd_com_settings": "Iestatījuma nosaukums tiks izveidots automātiski. Lūgums zemāk skatīt priekšiestatījumu piemērus. Vairāk informācijas ir Rspamd dokumentācijā" }, "danger": { "access_denied": "Piekļuve liegta, vai nepareizi dati", - "alias_domain_invalid": "Alias domēns ir nepareizs", - "alias_empty": "Alias adrese nevar būt tukša", - "alias_goto_identical": "Alias un domēnvārds nevar būt identisks", - "alias_invalid": "Alias adrese nepareiza", - "aliasd_targetd_identical": "Alias domēns nevar būt vienāds ar mērķa domēnu", - "aliases_in_use": "Maks. aliases jabūt lielākām vai vienādām ar %d", + "alias_domain_invalid": "Aizstājdomēns %s ir nederīgs", + "alias_empty": "Aizstājadrese nedrīkst būt tukša", + "alias_goto_identical": "Aizstājvārds un mērķa adrese nedrīkst būt vienādi", + "alias_invalid": "Aizstājadrese %s ir nederīga", + "aliasd_targetd_identical": "Aizstājdomēns nedrīkst būt vienāds ar mērķa domēnu: %s", + "aliases_in_use": "Pieļaujamajam aizstājvārdu skaitam jābūt lielākam vai vienādam ar %d", "description_invalid": "Resursa apraksts ir nederīgs", "dkim_domain_or_sel_invalid": "DKIM domēns vai selektors nepareizs", "domain_exists": "Domēns %s jau pastāv", @@ -165,15 +182,15 @@ "domain_not_empty": "Nevar noņemt neaizpildītu domēnu", "domain_not_found": "Domēns %s nav atrasts", "domain_quota_m_in_use": "Domēna kvotai jābūt lielākai vai vienādai ar %s MiB", - "goto_empty": "Goto adrese nevar būt tukša", + "goto_empty": "Aizstājādresei jāsatur vismaz viena derīga mērķa adrese", "goto_invalid": "Goto adrese nepareiza", "imagick_exception": "Kļūda: Imagick izņēmums, lasot attēlu", "img_invalid": "Nevar apstiprināt attēla failu", "img_tmp_missing": "Nevar apstiprināt attēla failu: pagaidu failu nav atrasts", "invalid_mime_type": "Nederīgs mime tips", - "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_spam_alias": "%s ir jau zināms spam alias", + "is_alias": "%s jau ir zināma kā aizstājadrese", + "is_alias_or_mailbox": "%s jau ir zināms kā aizstājvārds, pastkaste vai aizstājadrese, kas ir izvērsta no aizstājdomēna.", + "is_spam_alias": "%s jau ir zināma kā pagaidu aizstājadrese (mēstuļu aizstājadrese)", "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", "mailbox_invalid": "Pastkastes vārds ir nederīgs", @@ -181,7 +198,7 @@ "mailbox_quota_exceeds_domain_quota": "Pastkastes izmērs pārsniedz maksimāli pieļaujamo", "mailbox_quota_left_exceeded": "Nav pietiekami daudz vietas (atlikusī vieta: %d MiB)", "mailboxes_in_use": "Maks. pastkastēm jābūt lielākām vai vienādām ar %d", - "max_alias_exceeded": "Visas aliases izmantotas", + "max_alias_exceeded": "Pārsniegts pieļaujamo aizstājvārdu skaits", "max_mailbox_exceeded": "Maksimālais pastkastšu skaits sasniegts (%d of %d)", "max_quota_in_use": "Pastkastes kvotai jābūt lielākai vai vienādai %d MiB", "maxquota_empty": "Maksimālais pieļaujamais izmērs nevar būt 0.", @@ -202,7 +219,7 @@ "validity_missing": "Lūdzu piešķiriet derīguma termiņu" }, "diagnostics": { - "cname_from_a": "Vērtība, kas iegūta no A/AAAA ieraksta. Tas tiek atbalstīts tik ilgi, kamēr ieraksts norāda pareizo resursu.", + "cname_from_a": "Vērtība, kas iegūta no A/AAAA ieraksta. Tas tiek atbalstīts tik ilgi, kamēr ieraksts norāda uz pareizo resursu.", "dns_records": "DNS Ieraksti", "dns_records_24hours": "Lūdzu ņemiet vērā, ka DNS izmaiņas var aizņemt laiku līdz 24 stundām, lai pareizi varētu atspoguļot izmaiņas šajā lapā. Tas ir paredzēts, lai jūs varētu viegli uzzināt, kā konfigurēt savus DNS ierakstus un pārbaudīt, vai visi jūsu ieraksti ir pareizi saglabāti DNS.", "dns_records_data": "Pareizi dati", @@ -213,7 +230,7 @@ }, "edit": { "active": "Aktīvs", - "alias": "Rediģēt alias", + "alias": "Labot aizstājvārdu", "automap": "Mēģiniet automatizēt mapes (\"Nosūtītie vienumi\", \"Nosūtītie\" => \"Nosūtītie\" utt.)", "backup_mx_options": "Dublēt MX iespējas", "delete1": "Dzēst no avota, kad pabeigts", @@ -224,8 +241,8 @@ "domain_admin": "Labot domēna administratoru", "domain_quota": "Domēna kvota", "domains": "Domēni", - "dont_check_sender_acl": "Atspējot domēna sūtītāju pārbaudi %s + alias domēni", - "edit_alias_domain": "Rediģēt alias domēnu", + "dont_check_sender_acl": "Atspējot sūtītāju pārbaudi domēnam %s (+ aizstājdomēni)", + "edit_alias_domain": "Labot aizstājdomēnu", "encryption": "Šifrēšana", "exclude": "Neiekļaut objektus (regex)", "force_pw_update": "Piespiedu paroles atjaunošana pie nākošās pieslēgšanās", @@ -235,7 +252,7 @@ "inactive": "Neaktīvs", "kind": "Veids", "mailbox": "Rediģēt pastkasti", - "max_aliases": "Maks. aliases", + "max_aliases": "Lielākais aizstājvārdu skaits", "max_mailboxes": "Maks. iespējamās pastkastes", "max_quota": "Maks. kvota uz pastkasti (MiB)", "maxage": "Maximum age of messages in days that will be polled from remote
(0 = ignore age)", @@ -247,7 +264,7 @@ "previous": "Iepriekšējā lapa", "quota_mb": "Kvota (MiB)", "relay_all": "Pārsūtīt visus adresātus", - "relay_all_info": "Ja tu izvēlies nepārsūtīt visus adresātus, tad tev vajadzēs pievienot (\"tukšu\") pastkasti katram saņēmējam, kas būtu jāpārsūta.", + "relay_all_info": "↪ Ja izvēlies nepārsūtīt visus adresātus, tad tev vajadzēs pievienot (\"aklo\") pastkasti katram saņēmējam, kas būtu jāpārsūta.", "relay_domain": "Pārsūtīt domēnu", "remove": "Noņemt", "resource": "Resurss", @@ -256,9 +273,9 @@ "sieve_desc": "Īss apraksts", "sieve_type": "Filtra tips", "skipcrossduplicates": "Izlaist dublētus ziņojumus pa mapēm (pirmais nāk, pirmais kalpo)", - "spam_alias": "Izveidot vai mainīt laika ierobežotas alias adreses", - "spam_policy": "Pievienot vai noņemt vienības baltajā-/melnajā sarakstā", - "spam_score": "Iestatīt pielāgotu surogātpastu", + "spam_alias": "Izveidot vai mainīt laika ierobežotas aizstājadreses", + "spam_policy": "Pievienot vai noņemt vienumus baltajā-/melnajā sarakstā", + "spam_score": "Iestatīt pielāgotu surogātpasta vērtējumu", "subfolder2": "Sinhronizēt galamērķa apakšmapē
(tukšs = neizmantot apakšmapi)", "syncjob": "Rediģēt sinhronizācijas darbu", "target_address": "Iet uz adresi/ēm (komatu atdalītas)", @@ -267,32 +284,41 @@ "unchanged_if_empty": "Ja neizmainīts atstājiet tukšu", "username": "Lietotājvārds", "validate_save": "Apstiprināt un saglabāt", - "last_modified": "Pēdējoreiz mainīts" + "last_modified": "Pēdējoreiz mainīts", + "domain_footer_skip_replies": "Neņemt vērā kājeni atbildes e-pastos", + "bcc_dest_format": "BCC galamērķim jābūt vienai derīgai e-pasta adresei.
Ja ir nepieciešams nosūtīt kopiju uz vairākām adresēm, jāizveido aizstājvārds, un tas ir jāizmanto šeit.", + "extended_sender_acl_info": "Vajadzētu ievietot DKIM domēna atslēgu, ja tā ir pieejama.
\n Jāatceras pievienot šo serveri attiecīgajam SPF TXT ierakstam.
\n Kad vien šim serverim tiek pievienots domēns vai aizstājdomēns, kas pārklājas ar ārēju adresi, ārējā adrese tiek noņemta.
\n Jāizmanto @domain.tld, lai ļautu nosūtīt kā *@domain.tld.", + "pushover_info": "Pašpiegādes paziņojumu iestatījumi tiks piemēroti visiem tīrajiem (ne surogātpasta) sūtījumiem, kas piegādāti %s, tostarp aizstājvārdiem (kopīgotiem, nekopīgotiem, ar birkām).", + "mailbox_relayhost_info": "Tiek piemērots tikai pastkastei un tiešajiem aizstājvārdiem, aizstāj domēna retranslācijas saimniekdatoru.", + "sender_acl_info": "Ja pastkastes lietotājam A ir ļauts sūtīt kā pastkastes lietotājam B, sūtītāja adrese SOGo netiek automātiski parādīta kā atlasāms lauks \"no\".
.\n Pastkastes lietotājam B SOGo ir jāizveido pilnvarojums, lai pastkastes lietotājs A varētu izvēlēties tā adresi kā sūtītāja. Lai SOGo pilnvarotu pastkasti, pasta skatā jāizmanto izvēlne (trīs punkti) pa labi no pastkastes nosaukuma augšējā kreisajā pusē. Šī darbība neattiecas uz aizstājadresēm.", + "sogo_visible": "Aizstājvārds ir redzams SOGo", + "sogo_visible_info": "Šī iespēja ietekmē tikai tos objektus, kurus var parādīt SOGo (koplietojamās vai nekoplietojamās aizstājadreses, kas norāda uz vismaz vienu vietējo pastkasti). Ja paslēpts, netiks parādīts SOGo kā atlasāms sūtītājs." }, "footer": { "cancel": "Atcelt", "confirm_delete": "Apstiprināt dzēšanu", "delete_now": "Dzēst tagad", - "delete_these_items": "Lūdzu apstipriniet darbīku šiem abjektiem:", + "delete_these_items": "Lūgums apstiprināt izmaiņas šim objekta Id", "loading": "Lūdzu uzgaidiet...", "restart_container": "Restartēt konteineri", "restart_container_info": "Important: Piespiedu restartēšana var aizņemt ilgu laiku, lūdzu uzgaidiet.", - "restart_now": "Restartēt " + "restart_now": "Pārsāknēt tagad" }, "header": { - "administration": "Administrēšana", - "debug": "Atkļūdošana", - "email": "E-Mail", - "mailcow_config": "Configurācija", + "administration": "Konfigurācija un informācija", + "debug": "Informācija", + "email": "E-pasts", + "mailcow_config": "Konfigurācija", "quarantine": "Karantīna", "restart_sogo": "Restartēt SOGo", - "user_settings": "Lietotāja uzstādījumi" + "user_settings": "Lietotāja uzstādījumi", + "mailcow_system": "Sistēma" }, "info": { "no_action": "No action applicable" }, "login": { - "delayed": "Pieslēgšanās aizkavējās par %s sekundēm.", + "delayed": "Pieteikšanās tika aizkavēta %s sekundēm.", "login": "Pieslēgties", "password": "Parole", "username": "Lietotājvārds" @@ -302,22 +328,22 @@ "activate": "Activate", "active": "Aktīvs", "add": "Pievienot", - "add_alias": "Pievienot alias", + "add_alias": "Pievienot aizstājvārdu", "add_bcc_entry": "Pievienot BCC karti", "add_domain": "Pievienot domēnu", - "add_domain_alias": "Pievienot domēna alias", + "add_domain_alias": "Pievienot domēna aizstājvārdu", "add_filter": "Pievienot filtru", "add_mailbox": "Pievienot pastkasti", "add_recipient_map_entry": "Pievienot saņēmēja karti", "add_resource": "Pievienot resursu", "address_rewriting": "Adreses pārrakstīšana", - "alias": "Alias", - "aliases": "Aliases", + "alias": "Aizstājvārds", + "aliases": "Aizstājvārdi", "backup_mx": "Rezerves kopija MX", "bcc": "BCC", "bcc_destination": "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.
\r\n   Vietējais galamērķis netiks informēts par piegādes neveiksmi. ", + "bcc_info": "BCC kartes tiek izmantotas, lai klusi pārsūtītu visu ziņojumu kopijas uz citu adresi. Saņēmēja kartes veida ieraksts tiek izmantots, kad vietējais galamērķis darbojas kā pasta saņēmējs. Sūtītāja kartes atbilst vienam un tam pašam principam.
\n Vietējais galamērķis netiks informēts par neizdevušos piegādi.", "bcc_local_dest": "Vietējais galamērķis", "bcc_map_type": "BCC veids", "bcc_maps": "BCC kartes", @@ -331,7 +357,7 @@ "dkim_key_length": "DKIM atslēgas garums (bits)", "domain": "Domēns", "domain_admins": "Domēna administratori", - "domain_aliases": "Domēna aliases", + "domain_aliases": "Domēna aizstājvārdi", "domain_quota": "Kvota", "domain_quota_total": "Kopējais domēna ierobežojums", "domains": "Domēns", @@ -349,7 +375,7 @@ "last_run_reset": "Ievietot sarakstā kā nākamo", "mailbox_quota": "Maks. pastkastes izmērs", "mailboxes": "Pastkaste", - "max_aliases": "Maks. iespejamās aliases", + "max_aliases": "Lielākais aizstājvārdu skaits", "max_mailboxes": "Maks. iespējamās pastkastes", "max_quota": "Maks. kvota uz pastkasti", "mins_interval": "Intervāls (min)", @@ -369,11 +395,11 @@ "running": "Darbojas", "set_postfilter": "Atzīmēt kā pēcfiltru", "set_prefilter": "Atzīmēt kā pimrsfiltru", - "sieve_info": "Jūs varat saglabāt vairākus filtrus katram lietotājam, bet tikai viens pirmsfiltrs un viens pēcfiltrs var būt aktīvs vienlaicīgi.
\r\nKatrs filtrs tiks apstrādāts aprakstītajā kārtībā. Kļūdains vai izdots skripts \"Paturēt;\" pārtrauks turpmāko skriptu apstrādi.
\r\nGlobal sieve prefilter → Pirmsfiltrs → Lietotāja skripts → Pēcfiltrs → Global sieve postfilter", - "spam_aliases": "Temp. alias", + "sieve_info": "Katram lietotājam var saglabāt vairākus filtrus, bet tikai viens pirmsfiltrs un viens pēcfiltrs var darboties vienlaicīgi.
\nKatrs filtrs tiks apstrādāts norādītajā kārtībā. Ne kļūdains skripts, ne izdots \"keep;\" nepārtrauks turpmāko skriptu apstrādi. Vispārējo sieve skriptu izmaiņas izsauks Dovecot pārsāknēšanu.

Vispārējais sieve pirmsfiltrs • Pirmsfiltrs • Lietotāja skripti • Pēcfiltrs • Vispārējais sieve pēcfiltrs", + "spam_aliases": "Pagaidu aizstājvārds", "status": "Status", "sync_jobs": "Sinhronizācijas darbi", - "target_address": "Doties uz adresi", + "target_address": "Doties uz adresi", "target_domain": "Mērķa domēns", "tls_enforce_in": "Piespiest TLS ienākošajiem", "tls_enforce_out": "Piespiest TLS izejošajiem", @@ -385,7 +411,16 @@ "daily": "Ik dienu", "hourly": "Ik stundu", "last_mail_login": "Pēdējā pieteikšanās pastkastē", - "mailbox": "Pastkaste" + "mailbox": "Pastkaste", + "sieve_preset_2": "Vienmēr atzīmēt noteikta sūtītāja e-pastu kā izlasītu", + "open_logs": "Atvērt žurnālus", + "sieve_preset_8": "Pārvirzīt noteikta sūtītāja e-pastu, atzīmēt kā izlasītu un ievietot to apakšmapē", + "sogo_visible": "Aizstājvārds ir redzams SOGo", + "sogo_visible_n": "Paslēpt aizstājvārdu SOGo", + "sogo_visible_y": "Rādīt aizstājvārdu SOGo", + "add_alias_expand": "Izvērst aizstājvārdu pār aizstājdomēniem", + "alias_domain_alias_hint": "Aizstājvārdi netiek automātiski piemēroti domēnu aizstājvārdiem. Aizstājadrese my-alias@domain nenosedz adresi my-alias@alias-domain (kur \"alias-domain\" ir iedomāts \"domain\" aizstājdomēns).
Lūgums izmantot sieta atlasi, lai pārvirzītu pastu uz ārēju pastkasti (skatīt cilti \"Atlasīšana\" vai izmantot SOGo -> Pārsūtītājs). \"Izvērst aizstājvārdu pār aizstājdomēniem\" ir izmantojams, lai automātiski pievienotu trūkstošos aiztājvārdus.", + "alias_domain_backupmx": "Aizstājdomēns ir neaktīvs retranslācijas domēnam" }, "quarantine": { "action": "Darbības", @@ -408,25 +443,29 @@ "subj": "Priekšmets", "text_from_html_content": "Saturs (konvertēts html)", "text_plain_content": "Saturs (teksts/vienkāršs)", - "toggle_all": "Pārslēgt visu" + "toggle_all": "Pārslēgt visu", + "disabled_by_config": "Pašreizējā sistēmas konfigurācija atspējo karantīnu. Lūgums iestatīt \"saglabāšanu katrai pastkastītei\" un \"lielākais pieļaujamais lielums\" karantīnas vienumiem.", + "qhandler_success": "Pieprasījums veiksmīgi nosūtīts sistēmai. Tagad var aizvērt logu.", + "qinfo": "Karantīnas sistēma datubāzē saglabās noraidīto pastu (sūtītājam netiks radīts iespaids par piegādātu pastu), kā arī pastu, kas tiek piegādāts kā kopija pastkastes mēstuļu mapē.\n
\"Apgūt kā surogātpastu un izdzēst\" apgūs ziņojumu kā surogātpastu ar Bajesa teorēmu un aprēķinās arī nestriktas jaucējvērtības, lai nākotnē noraidītu līdzīgus ziņojumus.\n
Lūgums apzināties, ka vairāku ziņojumu apgūšana var būt laikietilpīga atkarībā no sistēmas.
Melnā saraksta vienumi karantīnā netiek iekļauti." }, "queue": { - "queue_manager": "Queue Manager" + "queue_manager": "Queue Manager", + "info": "Pasta rinda satur visus e-pastus, kas gaida piegādi. Ja e-pasts ir iestrēdzis pasta rindā ilgu laiku, sistēma to automātiski izdzēš.
Attiecīgā pasta kļūdas ziņojums sniedz informāciju par to, kāpēc pastu neizdevās piegādāt." }, "start": { "help": "Rādīt/Paslēp palīdzības paneli", - "imap_smtp_server_auth_info": "Lūdzu, izmantojiet pilnu e-pasta adresi un PLAIN autentifikācijas mehānismu.
\r\nJūsu pieteikšanās dati tiks šifrēti, izmantojot servera puses obligātu šifrēšanu", + "imap_smtp_server_auth_info": "Lūgums izmantot pilnu e-pasta adresi un PLAIN autentifikācijas mehānismu.
\nPieteikšanās dati tiks šifrēti ar servera puses obligātu šifrēšanu.", "mailcow_apps_detail": "Izmantojiet lietotni mailcow, lai piekļūtu savam pastam, kalendāram, kontaktiem un citām lietām.", - "mailcow_panel_detail": "Domēna administrators izveidot, mainīt vai dzēst pastkastes un aliases, mainīt domēnus un lasīt papildu informāciju par saviem piešķirtajiem domēniem.
\r\n Pastkastes lietotāji var izveidot ierobežotus laika ierobežojumus (surogātpasta aliases), mainīt paroli un surogātpasta filtru iestatījumus." + "mailcow_panel_detail": "Domēna pārvaldītāji izveido, maina vai izdzēš pastkastes un aizstājvārdus, maina domēnus un lasa papildu informāciju par piešķirtajiem domēniem.
\nPastkastes lietotāji var izveidot laikā ierobežotus aizstājvārdus (surogātpasta aizstājvārdus), mainīt savu paroli un surogātpasta atlasīšanas iestatījumus." }, "success": { "admin_modified": "Izmaiņas administrātoram ir saglabātas", - "alias_added": "Aliasi pievienoti", - "alias_domain_removed": "Alias domēns %s tika noņemts", - "alias_modified": "Izmaiņas aliasiem %s ir saglabātas", - "alias_removed": "Alias %s ir noņemts", - "aliasd_added": "Pievients alias domēnam %s", - "aliasd_modified": "Izmaiņas aloas domēnam %s ir saglabātas", + "alias_added": "Aizstājadrese %s (%d) tika pievienota", + "alias_domain_removed": "Aizstājdomēns %s tika noņemts", + "alias_modified": "Aizstājadreses izmaiņas %s tika saglabātas", + "alias_removed": "Aizstājvārds %s tika noņemts", + "aliasd_added": "Pievienots aizstājdomēns %s", + "aliasd_modified": "Aizstājdomēna %s izmaiņas tika saglabātas", "app_links": "Saglabāt izmaiņas lietotņu saitēm", "dkim_added": "DKIM atslēga saglabāta", "dkim_removed": "DKIM atslēga %s ir noņemta", @@ -437,7 +476,7 @@ "domain_modified": "Izmaiņas domēnam %s ir saglabātas", "domain_removed": "Domēns %s ir noņemts", "eas_reset": "ActiveSync ierīces priekš lietotāja %s tika atiestatītas", - "f2b_modified": "Izmaiņas Fail2ban parameteriem ir saglabātas", + "f2b_modified": "Fail2ban parametru izmaiņas tika saglabātas", "forwarding_host_added": "Pāradresācijas hosts %s pievienotsd", "forwarding_host_removed": "Pāradresācijas hosts %s noņemts", "item_deleted": "Vērtība %s veiksmīgi dzēsta", @@ -462,7 +501,7 @@ "confirm_totp_token": "Lūdzu apstipriniet Jūsu izmaiņas ievadot uzģenerēto tekstu", "delete_tfa": "Atspējot TFA", "disable_tfa": "Atspējot TFA līdz nākamajai veiksmīgai pieteikšanās", - "enter_qr_code": "Jūsu TOTP kods, ja Jūsu ierīce nevar noskanēt QR kodus.", + "enter_qr_code": "TOTP kods, ja Tava ierīce nevar nolasīt kvadrātkodus", "key_id": "Jūsu YubiKey identifikators", "key_id_totp": "Identifikators Jūsu atslēgai", "none": "Deaktivizēt", @@ -480,24 +519,24 @@ "action": "Rīcība", "active": "Aktīvs", "active_sieve": "Aktīvais filtrs", - "alias": "Alias", - "alias_create_random": "Ģenerēt nejaušā nosaukuma alias", - "alias_extend_all": "Pagarināt alias par 1 stundu", + "alias": "Aizstājvārds", + "alias_create_random": "Izveidot nejaušu aizstājvārdu", + "alias_extend_all": "Pagarināt aizstājvārdus par 1 stundu", "alias_full_date": "d.m.Y, H:i:s T", - "alias_remove_all": "Noņemt visus alias", + "alias_remove_all": "Noņemt visus aizstājvārdus", "alias_select_validity": "Derīguma periods", "alias_time_left": "Laiks atlicis", "alias_valid_until": "Derīgs līdz", "aliases_also_send_as": "Atļauts arī sūtīt kā lietotājam", - "aliases_send_as_all": "Nepārbaudīt sūtītāja peikļuvi domēnam/iem un alias domēniem", + "aliases_send_as_all": "Nepārbaudīt sūtītāja piekļuvi šiem domēniem un to aizstājdomēniem", "change_password": "Nomainīt paroli", - "client_configuration": "Parādīt konfigurācijas piemērus dažādām iekārtām", + "client_configuration": "Parādīt konfigurācijas norādes e-pasta klientiem un tālruņiem", "create_syncjob": "Izveidot jaunu sinhronizācijas darbu", "day": "Dienas", - "direct_aliases": "Tiešas alias adreses", - "direct_aliases_desc": "Tiešie alias tiek ietekmēti no spam filtra un TLS politikas iestatījumiem affected by spam filter and TLS policy settings.", + "direct_aliases": "Tiešas aizstājadreses", + "direct_aliases_desc": "Tiešās aizstājadreses ir surogātpasta atlasīšanas un TLS nosacījumu iestatījumu ietekmētas.", "eas_reset": "Atiestatīt ActiveSync ierīces kešatmiņu", - "eas_reset_help": "Daudzos gadījumos ierīces kešatmiņas atiestatīšana palīdz atjaunot bojāto ActiveSync profilu.
Uzmanību: Visi elementi tiks atkārtoti ielādēti!", + "eas_reset_help": "Daudzos gadījumos ierīces kešatmiņas atiestatīšana palīdz atjaunot bojāto ActiveSync profilu.
Uzmanību: visi vienumi tiks atkārtoti lejupielādēti!", "eas_reset_now": "Atiestatīt tagad", "edit": "Labot", "encryption": "Šifrēšana", @@ -520,15 +559,15 @@ "remove": "Noņemt", "running": "Running", "save_changes": "Saglabāt izmaiņas", - "shared_aliases": "Koplietotās alias adreses", - "shared_aliases_desc": "Koplietotais alias netiek ietekmēts no lietotāju darbībām. Pielāgots spam filtra iestatījums var būt arhivēts no domēna ietvaros uzstādīta noteikuma no administrātora..", + "shared_aliases": "Kopīgotās aizstājadreses", + "shared_aliases_desc": "Tādi lietotāja iestatījumi kā surogātpasta atlasīšana vai šifrēšanas nosacījumi neietekmē kopīgotos aizstājvārdus. Atbilstošu surogātpasta atlasi var izveidot tikai pārvaldītājs kā domēnu aptverošu nosacījumu.", "show_sieve_filters": "Parādīt aktīvā lietotāja Sieve filtru", - "spam_aliases": "Pagaidu e-pasta alias", + "spam_aliases": "Pagaidu e-pasta aizstājvārdi", "spamfilter": "Mēstuļu filtrs", "spamfilter_behavior": "Reitings", "spamfilter_bl": "Melnais saraksts", - "spamfilter_bl_desc": "Melajā sarakstā iekļautās adreses vienmēr tiks uzskatītas par mēstulēm.", - "spamfilter_default_score": "Noklusētās vērtības:", + "spamfilter_bl_desc": "No melnajā sarakstā iekļautajām e-pasta adresēm saņemtās vēstules vienmēr tiks atzīmētas kā mēstules un noraidītas. Noraidītais pasts netiks ievietots karantīnā. Var izmantot aizstājzīmes. Atlasīšana tiek pielietota tikai tiešiem aizstājvārdiem (aizstājvārdiem ar vienu mērķa pastkasti), izņemot visu tverošos aizstājvārdus un pašu pastkasti.", + "spamfilter_default_score": "Noklusējuma vērtības", "spamfilter_green": "Zaļš: šī nav mēstule", "spamfilter_hint": "Pirmā vērtība norāda uz zemu \"Spam vērtējumu\" vērtējumu, otra vērtība par \"Augstu spam vērtējumu\".", "spamfilter_red": "Sarkans: Šī vēstule noteikti ir spams un tiek nekavējoties noraidīta", @@ -539,7 +578,7 @@ "spamfilter_table_remove": "noņemt", "spamfilter_table_rule": "Noteikums", "spamfilter_wl": "Baltais saraksts", - "spamfilter_wl_desc": "Baltajā sarakstā iekļautās adreses nekad netiks klasificētas kā mēstules.", + "spamfilter_wl_desc": "No baltā saraksta e-pasta adresēm saņemtās vēstules nekad netiks atzīmētas kā mēstules. Var tikt izmantotas aizstājzīmes. Atlase tiek piemērota tikai tiešiem aizstājvārdiem (aizstājvārdiem ar vienu mērķa pastkasti), izņemot visu tverošos aizstājvārdus un pašu pastkasti.", "spamfilter_yellow": "Dzeltens: šī vēstule visticamāk ir spams un tiks pārvietota uz Junk mapi", "status": "Status", "sync_jobs": "Sinhronizācijas uzdevumi", @@ -552,12 +591,15 @@ "tls_enforce_in": "Piespiest TLS ienākošajiem", "tls_enforce_out": "Piespiest TLS izejošajiem", "tls_policy": "Šifrēšanas politika", - "tls_policy_warning": "Uzmanību: Ja jūs izlemjat aktivizēt e-pastu šifrēšanu, Jūs varat pazaudēt vēstules.
Vēstules kas neatbilst politikai atleks atpakaļ no sistēmas ar kļūdu.
Šī opcija attiecas uz Jūsu primāro e-pasta adresi, visām adresēm, kas atvasinātas no alias domēniem, kā arī aliasi ,kas saistīti tikai ar šo pastkasti kā mērķis.", + "tls_policy_warning": "Brīdinājums: Ja tiek izlemts ieviest šifrēta pasta nosūtīšanu, var tikt pazaudēti e-pasti.
Ziņojumi, kas neatbilst nosacījumiem, pasta sistēma atmetīs ar kļūdu.
Šī iespēja attiecas uz galveno e-pasta adresi (pieteikšanās vārdu), visām adresēm, kas atvasinātas no aizsājdomēniem, kā arī aizstājadreses, kas norāda tikai uz šo pastkasti.", "user_settings": "Lietotāja iestatījumi", "username": "Lietotājvārds", "waiting": "Waiting", "week": "Nedēļa", - "weeks": "Nedēļas" + "weeks": "Nedēļas", + "open_logs": "Atvērt žurnālus", + "apple_connection_profile_mailonly": "Šis savienojuma profils iekļauj IMAP un SMTP konfigurācijas parametrus Apple ierīcei.", + "pushover_info": "Pašpiegādes paziņojumu iestatījumi attieksies uz visu tīro (ne surogātpasta) pastu, kas piegādāts uz %s, ieskaitot aizstājvārdus (kopīgotus, nekopīgotus, ar birkām)." }, "datatables": { "paginate": { @@ -566,6 +608,18 @@ } }, "debug": { - "last_modified": "Pēdējoreiz mainīts" + "last_modified": "Pēdējoreiz mainīts", + "static_logs": "Nemainīgie žurnāli", + "no_update_available": "Sistēma izmanto jaunāko versiju", + "in_memory_logs": "Atmiņā esošie žurnāli", + "system_containers": "Sistēma un konteineri", + "current_time": "Sistēmas laiks", + "external_logs": "Ārējie žurnāli", + "logs": "Žurnāli" + }, + "warning": { + "domain_added_sogo_failed": "Domēns pievienots, bet neizdevās pārsāknēt SOGO. Lūgums pārbaudīt servera žurnālus.", + "dovecot_restart_failed": "Dovecot neizdevās pārsāknēties. Lūgums pārbaudīt žurnālus", + "is_not_primary_alias": "Izlaists aizstājvārds %s, kas nav galvenais" } } diff --git a/data/web/lang/lang.nb-no.json b/data/web/lang/lang.nb-no.json new file mode 100644 index 00000000..a6a7a0ca --- /dev/null +++ b/data/web/lang/lang.nb-no.json @@ -0,0 +1,469 @@ +{ + "admin": { + "api_read_only": "Kun lesetilgang", + "advanced_settings": "Avanserte innstillinger", + "admin_details": "Endre administratordetaljer", + "add_row": "Legg til rad", + "active_rspamd_settings_map": "Aktivt innstillingskart", + "admins": "Administratorer", + "api_info": "APIet er under utvikling. Dokumentasjonen finnes på /api", + "admin_domains": "Domenetilordninger", + "add": "Legg til", + "active": "Aktiv", + "add_transport": "Legg til transport", + "api_key": "API-nøkkel", + "add_admin": "Legg til administrator", + "admin": "Administrator", + "allowed_methods": "Tilgangskontroll-Tillatte-Metoder", + "add_transports_hint": "Vær oppmerksom på at eventuelle autentiseringsdata vil bli lagret i klartekst.", + "add_relayhost": "Legg til sender-avhengig transport", + "additional_rows": " ekstra rader ble lagt til", + "admins_ldap": "LDAP-administratorer", + "action": "Handling", + "add_settings_rule": "Legg til innstillingsregel", + "allowed_origins": "Tilgangskontroll-Tillat-Opphav", + "api_allow_from": "Tillat API-tilgang fra disse IP/CIDR-nettverkene", + "activate_send": "Aktivér sendeknapp", + "access": "Tilgang", + "add_domain_admin": "Legg til domeneadministrator", + "add_forwarding_host": "Legg til videresendingsvert", + "activate_api": "Aktivér API", + "add_relayhost_hint": "Vennligst vær oppmerksom på at autentiseringsdata, om noe, vil bli lagret i klartekst.", + "app_links": "App-lenker", + "app_name": "App-navn", + "apps_name": "\"mailcow Apps\"-navn", + "arrival_time": "Ankomsttid (servertid)", + "authed_user": "Autorisert bruker", + "ays": "Er du sikker på at du vil fortsette?", + "change_logo": "Endre logo", + "logo_normal_label": "Normal", + "logo_dark_label": "Omvendt for mørk modus", + "configuration": "Konfigurasjon", + "convert_html_to_text": "Konvertér HTML til ren tekst", + "copy_to_clipboard": "Tekst kopiert til utklippstavle!", + "cors_settings": "CORS-innstillinger", + "credentials_transport_warning": "Advarsel: Å legge til en ny transport-mapping vil oppdatere innloggingsinformasjon for alle oppføringer med en tilsvarende \"next hop\"-kolonne.", + "customer_id": "Kunde-ID", + "customize": "Tilpass", + "destination": "Mål", + "dkim_add_key": "Legg til ARC/DKIM-nøkkel", + "dkim_domains_selector": "Velger", + "dkim_domains_wo_keys": "Velg domener med manglende nøkler", + "dkim_from": "Fra", + "dkim_key_length": "DKIM-nøkkellengde (bits)", + "dkim_key_missing": "Nøkkel mangler", + "dkim_key_unused": "Nøkkel ikke i bruk", + "dkim_key_valid": "Nøkkel gyldig", + "dkim_keys": "ARC/DKIM-nøkler", + "dkim_overwrite_key": "Overskriv eksisterende DKIM-nøkkel", + "dkim_private_key": "Privat nøkkel", + "dkim_to": "Til", + "domain_admins": "Domeneadministratorer", + "domain_s": "Domene/r", + "duplicate": "Duplikat", + "duplicate_dkim": "Duplisert DKIM-oppføring", + "edit": "Rediger", + "empty": "Ingen resultater", + "excludes": "Ekspluderer disse mottakerne", + "f2b_ban_time": "Utestengingstid (sek)", + "f2b_blacklist": "Svartelistede nettverk/verter", + "f2b_filter": "Regex-filtre", + "f2b_manage_external": "Betjene Fail2Ban eksternt", + "f2b_manage_external_info": "Fail2Ban vil fortsette å vedlikeholde utestengingslisten, men den vil ikke aktivt legge til regler for å blokkere trafikk. Bruk den genererte blokkeringslisten under for å blokkere trafikk eksternt.", + "f2b_max_attempts": "Maks antall forsøk", + "f2b_max_ban_time": "Maks utestengingstid (sek)", + "f2b_netban_ipv4": "IPv4-subnetstørrelse å aktivere blokkering for (8-32)", + "f2b_netban_ipv6": "IPv6-subnetstørrelse å aktivere blokkering for (8-128)", + "f2b_parameters": "Fail2Ban-parametre", + "f2b_retry_window": "Tidsrom (sek) for maks antall forsøk", + "f2b_whitelist": "Hvitelistede nettverk/verter", + "filter_table": "Filtreringstabell", + "forwarding_hosts": "Videresendingsverter", + "api_skip_ip_check": "Hopp over IP-sjekk for API", + "ban_list_info": "Se liste over utestengte IPer under: nettverk (gjenværende utestengingstid) - [handlinger].
IPer i kø for å bli tillatt igjen vil bli fjernet fra den aktive utestengingslisten i løpet av noen sekunder.
Røde etiketter indikerer aktive permanente utestenginger via svartelisting.", + "dkim_from_title": "Kildedomene å kopiere data fra", + "domain": "Domene", + "f2b_ban_time_increment": "Utestengingstid økes for hver ny utestenging", + "api_read_write": "Lese- og skrivetilgang", + "f2b_list_info": "En svartelistet vert eller nettverk vil alltid ha større vekt enn en hvitelistet oppføring.Oppdateringer av listen tar noen sekunder før de vises.", + "f2b_regex_info": "Logger tatt i betraktning: SOGo, Postfix, Dovecot, PHP-FHM.", + "dkim_to_title": "Måldomene/r - vil bli overskrevet", + "domain_admin": "Domeneadministrator", + "r_active": "Aktive begrensninger", + "queue_unban": "fjern blokkering", + "r_inactive": "Inaktive begrensninger", + "r_info": "Grå/deaktivere elementer i listen over aktive restriksjoner er ikke kjente som gyldige restriksjoner i mailcow og kan ikke flyttes. Ukjente begrensninger vil bli aktivert i den rekkefølgen de opptrer uansett.
Du kan legge til nye elementer i inc/vars.local.inc.php for å kunne slå dem av og på.", + "relayhosts_hint": "Definer sender-avhengige transportmetoder for å kunne velge dem i domenekonfigurasjonsdialogen
\n Transportmetoden er alltid \"smtp:\" og vil derfor forsøke TLS når tilbudt. Innpakket TLS (SMTPS) er ikke støttet. En brukers individuelle utgående TLS-policyinnstilling tas til etterretning.
\n Gjelder for valgte domener inkludert alias-domener.", + "rspamd_global_filters_regex": "Navnene forklarer deres mening. Alt innhold må inneholde gyldige regulære utstrykk etter formatet \"/mønster/alternativer\" (f.eks. /.+@domain\\.tld/i).
\n Selv om grove sjekkrutiner kjøres for hver linje regex, kan funksjonaliteten i Rspamd bli ødelagt dersom den ikke klarer å lese syntakset riktig.
\n Rspamd vil forsøke å lese innholdet når det endres. Hvis du opplever problemer, start Rspamd på nytt for å tvinge ny innlesing av mappingene.
Svartelistede elementer er ekskluderte fra karantene.", + "transport_test_rcpt_info": "• Bruk null@hosted.mailcow.de for å teste videresending til en ekstern destinasjon.", + "transports_hint": "• En transportmapping overstyrer en sender-avhengig transportmapping.
\n• MX-baserte transportmappinger er foretrukket brukt.
\n• Utgående TLS-policyinnstillinger per-bruker blir ignorert og kan kun tvinges via TLS-policymappinger.
\n• Transporttjenesten for definerte transportmetoder er alltid \"smtp:\" og vil derfor forsøke TLS når tilbudt. Innpakket TLS (SMTPS) støttes ikke.
\n• Adresser som matcher \"/localhost$/\" vil alltid sendes via \"local:\", derfor vil en \"*\"-destinasjon ikke gjelde disse adressene.
\n• For å bestemme identifikasjon for et eksempelvis neste hopp \"[host]:25\", vil Postfix alltid sende en forespørsel for \"host\" før den søker etter \"[host]:25\". Denne oppførselen gjør det umulig å bruke både \"host\" og \"[host]:25\" samtidig.", + "regex_maps": "Regex-mappinger", + "relay_from": "\"Fra:\"-adresse", + "relay_rcpt": "\"Til:\"-adresse", + "relay_run": "Kjør test", + "relayhosts": "Sender-avhengige transportmetoder", + "remove": "Fjern", + "remove_row": "Fjern rad", + "reset_default": "Tilbakestill til standardinnstillinger", + "reset_limit": "Fjern hash", + "routing": "Ruting", + "rsetting_add_rule": "Legg til regel", + "rsetting_content": "Regelinnhold", + "rsetting_desc": "Kort beskrivelse", + "rsetting_no_selection": "Vennligst velg en regel", + "rsetting_none": "Ingen regler tilgjengelig", + "rsettings_insert_preset": "Legg inn eksempel-forvalg \"%s\"", + "rsettings_preset_1": "Deaktiver alt unntatt DKIM og mengdebegrensning for autentiserte brukere", + "rsettings_preset_2": "Postmastere vil ha spam", + "rsettings_preset_3": "Bare tillat spesifikke sendere for en postboks (f.eks. kun bruk som intern postboks)", + "rsettings_preset_4": "Deaktiver Rspamd for et domene", + "rspamd_com_settings": "Et navn for innstillingen vil bli autogenerert, vennligst se eksempelforvalgene under. For ytterligere detaljer se Rspamd-dokumentasjonen", + "rspamd_global_filters": "Globale filtreringsmappinger", + "rspamd_global_filters_agree": "Jeg skal være forsiktig!", + "rspamd_global_filters_info": "Globale filtermappinger inneholder forskjellige typer globale svarte- og hvitelister.", + "rspamd_settings_map": "Rspamd innstillingsmapping", + "sal_level": "Moo-nivå", + "save": "Lagre endringer", + "search_domain_da": "Søk domener", + "send": "Send", + "sender": "Avsender", + "service": "Tjeneste", + "service_id": "TjenesteID", + "source": "Kilde", + "spamfilter": "Spamfilter", + "subject": "Emne", + "success": "Suksess", + "sys_mails": "Systemeposter", + "text": "Tekst", + "time": "Tid", + "title": "Tittel", + "title_name": "\"mailcow UI\" nettstedstittel", + "to_top": "Tilbake til toppen", + "transport_dest_format": "Regex eller syntaks: example.org, .example.org, *, box@example.org (flere verdier kan separeres via komma)", + "transport_maps": "Transportmappinger", + "ui_footer": "Bunntekst (HTML tillatt)", + "ui_header_announcement": "Annonseringer", + "ui_header_announcement_active": "Gjør annonsering aktiv", + "ui_header_announcement_content": "Tekst (HTML tillatt)", + "ui_header_announcement_help": "Annonseringen er synlig for alle innloggede brukere og på innloggingsskjermen for grensesnittet.", + "ui_header_announcement_select": "Velg annonseringstype", + "ui_header_announcement_type": "Type", + "ui_header_announcement_type_danger": "Veldig viktig", + "ui_header_announcement_type_info": "Info", + "ui_header_announcement_type_warning": "Viktig", + "ui_texts": "Grensesnittmerkelapper og tekster", + "unban_pending": "fjerning av utestenging avventes", + "unchanged_if_empty": "Hvis uendret, la være tomt", + "upload": "Last opp", + "username": "Brukernavn", + "validate_license_now": "Validér GUID mot lisenstjener", + "verify": "Validér", + "yes": "✓" + }, + "acl": { + "ratelimit": "Nivågrense", + "sogo_profile_reset": "Nullstill SOGo-profil", + "smtp_ip_access": "Endre tillatte verter for SMTP", + "tls_policy": "TLS-policy", + "spam_alias": "Midlertidige alias", + "spam_policy": "Svarteliste/Hvitliste", + "unlimited_quota": "Ubegrenset kvote for postkasser", + "sogo_access": "Tillat administrasjon av SOGo-tilgang", + "syncjobs": "Synkroniser jobber", + "spam_score": "Spam-resultat", + "recipient_maps": "Mottakerkart", + "alias_domains": "Legg til alias-domene", + "app_passwds": "Behandle app-passord", + "bcc_maps": "BCC-mappinger", + "delimiter_action": "Skilletegn-handling", + "domain_relayhost": "Endre videresendingsvert for et domene", + "eas_reset": "Nullstill EAS-enheter", + "filters": "Filtre", + "login_as": "Logg inn som postkassebruker", + "mailbox_relayhost": "Endre videresendingsvert for en postkasse", + "prohibited": "Forbudt av ACL", + "protocol_access": "Endre protokolltilgang", + "pushover": "Pushover", + "quarantine": "Karantenehandlinger", + "quarantine_attachments": "Sett vedlegg i karantene", + "quarantine_category": "Endre varslingskategori for karantene", + "quarantine_notification": "Endre karantenevarslinger", + "domain_desc": "Endre domenebeskrivelse", + "extend_sender_acl": "Tillat utvidelse av sender-ACL fra eksterne adresser" + }, + "add": { + "app_passwd_protocols": "Tillatte protokoller for app-passord", + "hostname": "Vert", + "goto_ham": "Lær som ham", + "custom_params": "Tilpassede parametre", + "target_address": "Gå-til-adresse", + "delete2": "Slett meldinger på måldestinasjonen som ikke finnes på kilden", + "syncjob": "Legg til synkroniseringsjobb", + "domain": "Domene", + "timeout1": "Tidsavbrudd for tilkobling til ekstern vert", + "goto_null": "Slett epost uten varsling", + "custom_params_hint": "Riktig: --param=xy, feil: --param xy", + "multiple_bookings": "Flere reservasjoner", + "alias_domain": "Aliasdomene", + "exclude": "Ekskludér objekter (regex)", + "validate": "Validér", + "dry": "Simulér synkronisering", + "relay_all_info": "↪ Hvis du velger å ikke videresende for alle mottakere, så må du legge til en (\"blind\") postkasse for hver eneste mottaker som det skal videresendes for.", + "description": "Beskrivelse", + "destination": "Måldestinasjon", + "alias_domain_info": "Kun gyldige domenenavn (kommaseparerte).", + "mailbox_username": "Brukernavn (venstre del av en epostadresse)", + "username": "Brukernavn", + "mins_interval": "Sjekkintervall (minutter)", + "disable_login": "Ikke tillat innlogging (innkommende epost blir fremdeles mottatt)", + "delete2duplicates": "Slett duplikater på måldestinasjonen", + "post_domain_add": "SOGo-kontaineren, \"sogo-mailcow\", må startes på nytt etter at man har lagt til et nytt domene!

I tillegg må domenets DNS-oppsett ses gjennom. Når DNS-oppsettet er godkjent, start \"acme-mailcow\" på nytt for å automatisk opprette sertifikater for det nye domenet (autoconfig.<domain>, autodiscover.<domain>).
Dette steget er valgfritt og vil bli forsøkt utført hver 24. time.", + "select": "Vennligst velg...", + "full_name": "Fullt navn", + "alias_address": "Aliasadresse/r", + "activate_filter_warn": "Alle andre filtre vil deaktiveres når aktive er valgt.", + "quota_mb": "Kvote (MiB)", + "gal_info": "Den globale adresselisten inneholder alle objekter i et domene og kan ikke redigeres av noen bruker. Ledig/opptatt-informasjon i SOGo vil mangle, hvis deaktivert! Start SOGo på nytt for å aktivere endringene.", + "alias_address_info": "Komplett/e epostadresse/r eller @example.com, for å fange opp alle meldinger til et domene (kommaseparert).Kun mailcow-domener.", + "bcc_dest_format": "BCC-mål må være én enkelt og gyldig epostadresse.
Hvis du trenger å sende en kopi til flere adresser, opprett et alias og bruk det her.", + "add": "Legg til", + "add_domain_only": "Legg til kun domene", + "kind": "Type", + "relay_domain": "Vidersend for dette domenet", + "add_domain_restart": "Legg til domene og start SOGo på nytt", + "enc_method": "Krypteringsmetode", + "app_name": "App-navn", + "relay_transport_info": "
Info
Du kan definere transport-kart for en egendefinert destinasjon for dette domenet. Hvis denne ikke er satt, vil det bli foretatt et MX-oppslag.", + "max_aliases": "Maks. antall mulige alias", + "comment_info": "En privat kommentar er ikke synlig for brukeren, mens en offentlig kommentar vises som et verktøytips når man holder muspekeren over i en brukers oversikt.", + "inactive": "Inaktiv", + "domain_quota_m": "Total domenekvote (MiB)", + "password": "Passord", + "delete1": "Slett fra kilde når fullført", + "tags": "Emneknagger", + "port": "Port", + "backup_mx_options": "Alternativer for videresending", + "gal": "Global Adresseliste", + "private_comment": "Privat kommentar", + "goto_spam": "Lær som spam", + "target_domain": "Måldomene", + "public_comment": "Offentlig kommentar", + "timeout2": "Tidsavbrudd for tilkobling til lokal vert", + "mailbox_quota_def": "Standard kvote for postkasser", + "skipcrossduplicates": "Hopp over duplikatmeldinger på tvers av mapper (førstemann til mølla)", + "sieve_desc": "Kort beskrivelse", + "mailbox_quota_m": "Maks. kvote pr. postkasse (MiB)", + "automap": "Forsøk automatisk mappe-tilordning (\"Sendte elementer\", \"Sendt\" => \"Sendt\" etc.)", + "validation_success": "Validering fullført", + "relay_all": "Videresend for alle mottakere", + "subscribeall": "Abonnér på alle mapper", + "domain_matches_hostname": "Domene %s er det samme som vertsnavn", + "generate": "opprett", + "app_password": "Legg til app-passord", + "max_mailboxes": "Maks. antall mulige postkasser", + "syncjob_hint": "Vær oppmerksom på at passord må lagres i klartekst!", + "relayhost_wrapped_tls_info": "Vennligst ikke bruk TLS-aktiverte porter (stort sett bare brukt på port 465).
\nBruk en annen ikke-TLS-aktivert port og send STARTTLS. En TLS-policy for å tvinge TLS kan opprettes i \"TLS-policy-mappinger\".", + "relay_unknown_only": "Videresend kun for ikke-eksisterende postkasser. Eksisterende postkasser vil bli levert lokalt.", + "sieve_type": "Filtertype", + "password_repeat": "Passordbekreftelse (gjenta)", + "nexthop": "Neste hopp", + "select_domain": "Vennligst velg et domene først", + "active": "Aktiv", + "target_address_info": "Komplett/e epostadresse/r (kommaseparert)." + }, + "danger": { + "dkim_domain_or_sel_exists": "En DKIM-nøkkel for \"%s\" eksisterer og vil ikke bli overskrevet", + "from_invalid": "Avsender kan ikke være tom", + "bcc_must_be_email": "BCC-destinasjon %s er ikke en gyldig epostadresse", + "domain_quota_m_in_use": "Domenekvote må være større enn eller lik %s MiB", + "access_denied": "Tilgang nektet eller ugyldige skjemadata", + "alias_domain_invalid": "Aliasdomene %s er ugyldig", + "alias_empty": "Aliasadresse kan ikke være tom", + "alias_goto_identical": "Alias og gå-til-adresse kan ikke være identiske", + "alias_invalid": "Aliasadresse %s er ugyldig", + "aliasd_targetd_identical": "Aliasdomene kan ikke være likt som måldomene: %s", + "aliases_in_use": "Max. aliaser må være større enn eller det samme som %d", + "app_name_empty": "App-navn kan ikke være tomt", + "app_passwd_id_invalid": "App-passord ID %s ugyldig", + "bcc_empty": "BCC-destinasjon kan ikke være tom", + "bcc_exists": "En BCC-mapping %s eksisterer for type %s", + "comment_too_long": "Kommentar for lang, maks 160 tegn tillatt", + "cors_invalid_method": "Ugyldig Allow-Method spesifisert", + "cors_invalid_origin": "Ugyldig Allow-Origin angitt", + "defquota_empty": "Standardkvote pr. postboks kan ikke være 0.", + "demo_mode_enabled": "Demomodus er aktivert", + "description_invalid": "Ressursbeskrivelse for %s er ugyldig", + "dkim_domain_or_sel_invalid": "DKIM-domene eller selector ugyldig: %s", + "domain_cannot_match_hostname": "Domenet kan ikke være det samme som vertsnavnet", + "domain_exists": "Domenet %s eksisterer allerede", + "domain_invalid": "Domenenavn er tomt eller ugyldig", + "domain_not_empty": "Kan ikke fjerne ikke-tomt domene %s", + "domain_not_found": "Domene %s ikke funnet", + "extended_sender_acl_denied": "manglende ACL for å angi ekstern avsenderadresse", + "extra_acl_invalid": "Ekstern avsenderadresse \"%s\" er ugyldig", + "extra_acl_invalid_domain": "Ekstern avsenderadresse \"%s\" bruker et ugyldig domene", + "fido2_verification_failed": "FIDO2-verifisering feilet: %s", + "file_open_error": "Fil kan ikke åpnes for skriving", + "filter_type": "Feil filtertype", + "global_filter_write_error": "Kunne ikke skrive filterfil: %s", + "global_map_invalid": "Global mapping-ID %s ugyldig", + "global_map_write_error": "Kunne ikke skrive global mapping-ID %s: %s", + "goto_empty": "En aliasadresse må inneholde minst en gyldig gå-til-adresse", + "goto_invalid": "Gå-til-adresse %s er ugyldig", + "ham_learn_error": "Ham-læringsfeil: %s", + "imagick_exception": "Feil: Imagick-avvik under lesing av bilde", + "img_invalid": "Kan ikke validere bildefil", + "img_tmp_missing": "Kan ikke validere bildefil: Midlertidig fil ikke funnet", + "invalid_bcc_map_type": "Ugyldig BCC-mappingtype", + "invalid_destination": "Målformat \"%s\" er ugyldig", + "invalid_filter_type": "Ugyldig filtertype", + "invalid_host": "Ugyldig vert angitt: %s", + "invalid_mime_type": "Ugyldig mime-type", + "invalid_nexthop": "\"Next hop\"-format er ugyldig", + "img_dimensions_exceeded": "Bildet overskriver maksimal bildestørrelse", + "img_size_exceeded": "Bildet overskrider maksimal filstørrelse" + }, + "debug": { + "logs": "Logger", + "update_available": "En oppdatering er tilgjengelig", + "service": "Tjeneste", + "show_ip": "Vis offentlig IP", + "solr_dead": "Solr starter, er deaktivert eller døde", + "memory": "Minne", + "online_users": "Tilkoblede brukere", + "restart_container": "Omstart", + "size": "Størrelse", + "solr_status": "Solr-status", + "started_at": "Startet ved", + "started_on": "Startet den", + "static_logs": "Statiske logger", + "success": "Suksess", + "system_containers": "System og kontainere", + "timezone": "Tidssone", + "uptime": "Oppetid", + "no_update_available": "Systemet kjører siste versjon", + "update_failed": "Kunne ikke se etter oppdateringer", + "username": "Brukernavn", + "wip": "Foreløpig under utvikling" + }, + "diagnostics": { + "dns_records_24hours": "Vennligst vær oppmerksom på at endringer gjort i DNS kan ta opp til 24 timer før riktig status vises på denne siden. Den er ment som en måte for deg å enkelt se hvordan du kan sette opp DNS-oppføringene dine og se at alle oppføringer er korrekt lagret i DNS.", + "cname_from_a": "Verdi hentet fra A/AAAA-oppføring. Dette er støttet så lenge oppføringen peker til riktig ressurs.", + "dns_records_docs": "Vennligst også se dokumentasjonen.", + "dns_records": "DNS-oppføringer", + "dns_records_data": "Korrekte data", + "dns_records_name": "Navn", + "dns_records_status": "Nåværende status", + "dns_records_type": "Type", + "optional": "Denne oppføringen er valgfri." + }, + "edit": { + "bcc_dest_format": "BCC-destinasjon må være en enkelt, gyldig epostadresse.
Hvis du trenger å sende en kopi til flere adresser, opprett et alias og bruk det her.", + "pushover_info": "Innstillinger for pushvarslinger vil gjelde alle rene (ikke-spam) eposter levert til %s, inkludert aliaser (delte, ikke-delte, taggede).", + "relay_transport_info": "
Info
Du kan definere transportmappinger for et spesifikt mål for dette domenet. Hvis dette ikke er definert, blir det gjort et MX-oppslag.", + "delete2duplicates": "Slett duplikater på målvert", + "description": "Beskrivelse", + "disable_login": "Ikke tillat innlogging (innkommende epost blir likevel mottatt)", + "domain_admin": "Endre domeneadministrator", + "max_mailboxes": "Maks antall mailbokser", + "quota_warning_bcc_info": "Advarsler blir sendt som separate kopier til de følgende mottakerne. Emnet vil få lagt til det korresponderende brukernavnet i parantes, for eksempel: Kvotevarsel (user@example.com).", + "domain_footer_skip_replies": "Ignorer bunntekst ved svar på epost", + "extended_sender_acl": "Eksterne avsenderadresser", + "extended_sender_acl_info": "En DKIM-domenenøkkel bør importeres, hvis tilgjengelig.
\n Husk å legge denne serveren til den korresponderende SPF TXT-oppføringen.
\n Når et domene eller aliasdomene legges til på denne serveren, og det overlapper med en ekstern adresse, blir den eksterne adressen fjernet.
\n Bruk @domain.tld for å tillate sending som *@domain.tld.", + "password_repeat": "Bekreft passord (gjenta)", + "pushover_title": "Varslingstittel", + "pushover_vars": "Når et avsenderfilter ikke er definert, vil alle epostere bli vurdert.
Regex-filtre såvel så eksakte avsendersjekker kan bli individuelt definert og vil bli vurdert sekvensielt. De er ikke avhengige av hverandre.
Tilgjengelige variabler for tekst og tittel (vennligst observer policyer for databeskyttelse)", + "admin": "Endre administrator", + "domain_footer_info": "Bunntekst for hele domenet leggese til alle utgående eposter assosiert med en adresse innenfor dette domenet.
De følgende variablene kan brukes for bunnteksten:", + "domain_footer_info_vars": { + "custom": "{= foo =} - Hvis mailboksen har en spesialattributt \"foo\" med verdi \"bar\", vil den vise \"bar\"", + "auth_user": "{= auth_user =} - Autentisert brukernavn spesifisert av en MTA", + "from_user": "{= from_user =} - Fra brukerdelen av konvolutten, f.eks. for \"moo@mailcow.tld\" vil den returnere \"moo\"", + "from_name": "{= from_name =} - Fra-navn fra konvolutten, f.eks. for \"Mailcow <moo@mailcow.tld>\" vil den vise \"Mailcow\"", + "from_addr": "{= from_addr =} - Fra adressedelen av konvolutten", + "from_domain": "{= from_domain =} - Fra domene-delen av konvolutten" + }, + "mailbox_relayhost_info": "Aktiveres kun for mailboksen og direkte aliaser, overstyrer domene-videresendingsvert.", + "mbox_rl_info": "Denne begrensningen gjelder for SASL-innloggingsnavnet, dersom det er likt noen \"from\"-adresser benyttet av den innloggede brukeren. En mailboks-begrensning overstyrer en domene-begrensning.", + "allow_from_smtp_info": "La stå tom for å tillate alle avsendere.
IPv4/IPv6-adresser og -nettverk.", + "domain": "Endre domene", + "encryption": "Kryptering", + "exclude": "Ekskluder objekter (regex)", + "footer_exclude": "Ekskluder fra bunntekst", + "gal_info": "GAL inneholder alle objeker i et domene og kan ikke redigeres av noen brukere. Ledig/opptatt-informasjon i SOGo mangler dersom den deaktiveres! Start SOGo på nytt for å aktivere endringene.", + "grant_types": "Grant-typer", + "hostname": "Vertsnavn", + "inactive": "Inaktiv", + "kind": "Type", + "last_modified": "Sist endret", + "lookup_mx": "Målet er et regex-uttrykk for å matche mot MX_navnet (*\\.google\\.com for å route all epost som skal til en MX-server som slutter på google.com, via dette målet)", + "mailbox": "Endre mailboks", + "mailbox_quota_def": "Standardkvote for mailboks", + "max_quota": "Maks kvote pr. mailboks (MiB)", + "maxage": "Maksimal alder for meldinger, i dager, som vil hentes fra ekstern
(0 = ignorer alder)", + "maxbytespersecond": "Maks bytes pr. sekund
(0 = ubegrenset)", + "pushover_sender_array": "Bare vurder de følgende avsenderadressene (komma-separert)", + "pushover_sender_regex": "Vurder følgende avsender-regex", + "pushover_text": "Varslingstekst", + "pushover_sound": "Lyd", + "pushover_verify": "Bekreft identifikasjon", + "quota_mb": "Kvote (MiB)", + "quota_warning_bcc": "Kvotevarsling BCC", + "ratelimit": "Mengdebegrensning", + "domain_footer": "Bunntekst for hele domenet", + "private_comment": "Privat kommentar", + "public_comment": "Offentlig kommentar", + "client_id": "Klient-ID", + "full_name": "Fullt navn", + "gal": "Global adresseliste", + "max_aliases": "Maks. antall aliaser", + "mins_interval": "Intervall (min)", + "multiple_bookings": "Flere bookinger", + "none_inherit": "Ingen / arve", + "acl": "ACL (rettighet)", + "active": "Aktiv", + "advanced_settings": "Avanserte innstillinger", + "alias": "Endre alias", + "allow_from_smtp": "Tillat kun disse IPene å bruke SMTP", + "allowed_protocols": "Tillatte protokoller", + "app_name": "Appnavn", + "app_passwd": "App-passord", + "app_passwd_protocols": "Tillatte protokoller for app-passord", + "automap": "Prøv å automatisk mappe opp mapper (\"Sent items\", \"Sent\" => \"Sendt\" etc.)", + "backup_mx_options": "Videresendingsalternativer", + "client_secret": "Klient-hemmelighet", + "comment_info": "En privat kommentar er ikke synlig for brukeren, mens en offentlig kommentar vises som et tooltip når man holder muspekeren over det", + "created_on": "Opprettet den", + "custom_attributes": "Valgfrie attributter", + "delete1": "Slett fra kilde når fullført", + "delete2": "Slett meldinger på målvert som ikke finnes på kildeverten", + "delete_ays": "Vennligst bekreft slettingen.", + "domain_footer_html": "HTML-bunntekst", + "domain_footer_plain": "PLAIN-bunntekst", + "domain_quota": "Domenekvote", + "domains": "Domener", + "dont_check_sender_acl": "Deaktivere sendersjekk for domene %s (+ aliasdomener)", + "edit_alias_domain": "Endre aliasdomene", + "force_pw_update": "Tving endring av passord ved neste innlogging", + "force_pw_update_info": "Denne brukeren vil bare kunne logge inn på %s. App-passord kan fremdeles brukes.", + "generate": "generer", + "nexthop": "Neste hopp", + "password": "Passord", + "previous": "Forrige side", + "pushover": "Pushover", + "pushover_evaluate_x_prio": "Eskaler mail med høy prioritet [X-Priority: 1]", + "pushover_only_x_prio": "Bare vurder epost med høy prioritet [X-Priority: 1]", + "redirect_uri": "Omdirigerings-/tilbakekallings-URL", + "relay_all": "Videresend alle mottakere", + "relay_all_info": "↪ Hvis du velger å ikke videresende alle mottakkere, så må du legge til en (\"blind\") mailboks for hver eneste mottaker det skal videresendes for.", + "relay_domain": "Videresend dette domenet", + "relay_unknown_only": "Videresend kun ikke-eksisterende mailbokser. Eksisterende mailbokser vil bli levert lokalt.", + "relayhost": "Avsender-avhengige transportmetoder", + "remove": "Fjern", + "resource": "Ressurs", + "save": "Lagre endringer", + "scope": "Omfang", + "sender_acl": "Tillat å sende som", + "sender_acl_disabled": "Avsender-sjekk er deaktivert" + } +} diff --git a/data/web/lang/lang.nl-nl.json b/data/web/lang/lang.nl-nl.json index efffa1d7..fdfc91c7 100644 --- a/data/web/lang/lang.nl-nl.json +++ b/data/web/lang/lang.nl-nl.json @@ -185,7 +185,7 @@ "filter_table": "Filtertabel", "forwarding_hosts": "Forwarding hosts", "forwarding_hosts_add_hint": "Het is mogelijk om IPv4- of IPv6-adressen, netwerken in CIDR-notatie, hostnames (worden omgezet naar IP-adressen) of domeinnamen (worden tevens omgezet naar IP-adressen of, bij gebrek daaraan, MX-records) op te geven.", - "forwarding_hosts_hint": "Inkomende berichten worden onvoorwaardelijk geaccepteerd vanaf iedere host hieronder vermeld. Deze hosts worden hierdoor niet gecontroleerd op DNSBLs, en zullen de greylisting omzeilen. Spam wordt daarentegen zoals gebruikelijk in de spamfolder geplaatst. Dit wordt vaak gebruikt om mailservers te specificeren die forwarden naar deze Mailcow-server.", + "forwarding_hosts_hint": "Inkomende berichten worden onvoorwaardelijk geaccepteerd vanaf iedere host hieronder vermeld. Deze hosts worden hierdoor niet gecontroleerd op DNSBLs, en zullen de greylisting omzeilen. Spam wordt daarentegen zoals gebruikelijk in de spamfolder geplaatst. Dit wordt vaak gebruikt om mailservers te specificeren die alles doorsturen naar deze Mailcow-server.", "from": "Afzender", "generate": "genereer", "guid": "Identificatienummer - GUID", @@ -295,7 +295,7 @@ "to_top": "Naar boven", "transport_dest_format": "Voorbeeld: example.org, .example.org, *, mailbox@example.org (meerdere waarden zijn kommagescheiden)", "transport_maps": "Transport-maps", - "transports_hint": "→ Een transport-map wordt boven een afzendergebonden transport-map verkozen.
→ Het uitgaande versleutelingsbeleid van individuele gebruikers wordt genegeerd en kan uitsluitend worden gehandhaafd doormiddel van globaal versleutelingsbeleid.
→ De transportservice is altijd \"smtp:\" en zal daarom met TLS proberen te verbinden. Wrapped TLS (SMTPS) wordt niet ondersteund.
→ Adressen overeenkomend met \"/localhost$/\" zullen altijd via \"local:\" getransporteerd worden, hierdoor zullen \"*\"-bestemmingen niet van toepassing zijn op deze adressen.
→ Om de aanmeldingsgegevens van een (voorbeeld) nexthop \"[host]:25\" te bepalen, zoekt Postfix altijd naar \"nexthop\" voodat er wordt gekeken naar \"[nexthop]:25\". Dit maakt het onmogelijk om \"nexthop\" en \"[nexthop]:25\" tegelijkertijd te gebruiken.", + "transports_hint": "→ Een transport-map wordt boven een afzendergebonden transport-map verkozen.
→ Het uitgaande versleutelingsbeleid van individuele gebruikers wordt genegeerd en kan uitsluitend worden gehandhaafd door middel van globaal versleutelingsbeleid.
→ De transportservice is altijd \"smtp:\" en zal daarom met TLS proberen te verbinden. Wrapped TLS (SMTPS) wordt niet ondersteund.
→ Adressen overeenkomend met \"/localhost$/\" zullen altijd via \"local:\" getransporteerd worden, hierdoor zullen \"*\"-bestemmingen niet van toepassing zijn op deze adressen.
→ Om de aanmeldingsgegevens van een (voorbeeld) nexthop \"[host]:25\" te bepalen, zoekt Postfix altijd naar \"nexthop\" voodat er wordt gekeken naar \"[nexthop]:25\". Dit maakt het onmogelijk om \"nexthop\" en \"[nexthop]:25\" tegelijkertijd te gebruiken.", "ui_footer": "Footer (HTML toegestaan)", "ui_header_announcement": "Aankondigingen", "ui_header_announcement_active": "Activeer aankondiging", @@ -473,7 +473,7 @@ "history_all_servers": "Geschiedenis (alle servers)", "in_memory_logs": "Geheugenlogs", "jvm_memory_solr": "JVM-geheugengebruik", - "log_info": "

Mailcows geheugenlogs worden elke minuut afgesneden naar maximaal %d regels (LOG_LINES) om de stabiliteit te garanderen.
Geheugenlogs zijn niet bedoeld om bewaard te blijven. Alle applicaties die geheugenlogs schrijven worden ook naar het Docker-proces gelogd.
De geheugenlogs kunnen gebruikt worden voor het oplossen van problemen met bepaalde containers.

Externe logs worden verzameld doormiddel van de API van deze applicaties.

Statische logs zijn activiteitenlogs die niet naar het Docker-proces worden gelogd, maar wel bewaard moeten blijven (uitgezonderd API-logs).

", + "log_info": "

Mailcows geheugenlogs worden elke minuut afgesneden naar maximaal %d regels (LOG_LINES) om de stabiliteit te garanderen.
Geheugenlogs zijn niet bedoeld om bewaard te blijven. Alle applicaties die geheugenlogs schrijven worden ook naar het Docker-proces gelogd.
De geheugenlogs kunnen gebruikt worden voor het oplossen van problemen met bepaalde containers.

Externe logs worden verzameld door middel van de API van deze applicaties.

Statische logs zijn activiteitenlogs die niet naar het Docker-proces worden gelogd, maar wel bewaard moeten blijven (uitgezonderd API-logs).

", "logs": "Logs", "restart_container": "Herstart", "solr_dead": "Solr is uitgeschakeld, uitgevallen of nog bezig met opstarten.", @@ -510,7 +510,7 @@ "cname_from_a": "Waarde afgeleid van een A- of AAAA-vermelding.", "dns_records": "DNS-configuratie", "dns_records_24hours": "Houd er rekening mee dat wijzigingen aan DNS tot wel 24 uur in beslag kunnen nemen voordat ze op deze pagina worden weergegeven. Deze informatie is bedoeld om gemakkelijk te bekijken of de DNS-configuratie aan de eisen voldoet.", - "dns_records_docs": "Raadpleeg ook de documentatie.", + "dns_records_docs": "Raadpleeg ook de documentatie.", "dns_records_data": "Correcte gegevens", "dns_records_name": "Naam", "dns_records_status": "Huidige staat", @@ -684,7 +684,7 @@ "add_tls_policy_map": "Voeg versleutelingsbeleid toe", "address_rewriting": "Adresomleidingen", "alias": "Alias", - "alias_domain_alias_hint": "Aliassen worden niet automatisch toegepast op domeinaliassen. Aliasadres alias@domein dekt het adres alias@alias-domein niet (waarbij \"alias-domein\" een aliasdomein is voor \"domein\").
Gebruik een filter om mail te forwarden naar een externe mailbox (zie het tabje \"Filters\" of gebruik SOGo -> Doorsturen).", + "alias_domain_alias_hint": "Aliassen worden niet automatisch toegepast op domeinaliassen. Aliasadres alias@domein dekt het adres alias@alias-domein niet (waarbij \"alias-domein\" een aliasdomein is voor \"domein\").
Gebruik een filter om mail door te sturen naar een externe mailbox (zie het tabje \"Filters\" of gebruik SOGo -> Doorsturen).", "alias_domain_backupmx": "Aliasdomein inactief voor geforward domein", "aliases": "Aliassen", "allow_from_smtp": "Sta enkel de volgende IP-adressen toe voor SMTP", @@ -694,7 +694,7 @@ "bcc": "BCC", "bcc_destination": "BCC-bestemming", "bcc_destinations": "BCC-bestemmingen", - "bcc_info": "BCC-maps worden gebruikt om kopieën van alle berichten naar een ander adres te forwarden.
Wees er van bewust dat er geen melding wordt gedaan van een mislukte aflevering.", + "bcc_info": "BCC-maps worden gebruikt om kopieën van alle berichten naar een ander adres door te sturen.
Wees er van bewust dat er geen melding wordt gedaan van een mislukte aflevering.", "bcc_local_dest": "Lokale bestemming", "bcc_map": "BCC-map", "bcc_map_type": "BCC-type", diff --git a/data/web/lang/lang.pt-br.json b/data/web/lang/lang.pt-br.json index 9acaf87c..5854cc1f 100644 --- a/data/web/lang/lang.pt-br.json +++ b/data/web/lang/lang.pt-br.json @@ -1,6 +1,6 @@ { "acl": { - "alias_domains": "Adicionar domínios alternativos", + "alias_domains": "Adicionar domínios alias", "app_passwds": "Gerenciar senhas de aplicativos", "bcc_maps": "Mapas BCC", "delimiter_action": "Ação delimitadora", @@ -28,7 +28,7 @@ "spam_score": "Pontuação de spam", "syncjobs": "Trabalhos de sincronização", "tls_policy": "Política de TLS", - "unlimited_quota": "Cota ilimitada para mailbox" + "unlimited_quota": "Cota ilimitada para mailboxes" }, "add": { "activate_filter_warn": "Todos os outros filtros serão desativados quando a opção ativa estiver marcada.", @@ -480,7 +480,9 @@ "username_invalid": "O nome de usuário %s não pode ser usado", "validity_missing": "Por favor, atribua um período de validade", "value_missing": "Forneça todos os valores", - "yotp_verification_failed": "Falha na verificação do Yubico OTP: %s" + "yotp_verification_failed": "Falha na verificação do Yubico OTP: %s", + "img_dimensions_exceeded": "A imagem excede o tamanho máximo", + "img_size_exceeded": "A imagem excede o tamanho máximo" }, "datatables": { "collapse_all": "Recolher tudo", @@ -554,7 +556,7 @@ "dns_records": "Registros DNS", "dns_records_24hours": "Observe que as alterações feitas no DNS podem levar até 24 horas para que seu estado atual seja refletido corretamente nesta página. O objetivo é uma forma de você ver facilmente como configurar seus registros DNS e verificar se todos os seus registros estão armazenados corretamente no DNS.", "dns_records_data": "Dados corretos", - "dns_records_docs": "Consulte também a documentação.", + "dns_records_docs": "Consulte também a documentação.", "dns_records_name": "Nome", "dns_records_status": "Estado atual", "dns_records_type": "Tipo", @@ -609,6 +611,7 @@ "extended_sender_acl_info": "Uma chave de domínio DKIM deve ser importada, se disponível.
\r\n Lembre-se de adicionar esse servidor ao registro TXT SPF correspondente.
\r\n Sempre que um domínio ou domínio de alias é adicionado a esse servidor, que se sobrepõe a um endereço externo, o endereço externo é removido.
\r\n Use @domain .tld para permitir o envio como * @domain .tld.", "force_pw_update": "Forçar a atualização da senha no próximo login", "force_pw_update_info": "Esse usuário só poderá fazer login em %s. As senhas do aplicativo permanecem utilizáveis.", + "footer_exclude": "Excluir do rodapé", "full_name": "Nome completo", "gal": "Lista de endereços global", "gal_info": "A GAL contém todos os objetos de um domínio e não pode ser editada por nenhum usuário. Faltam informações de disponibilidade no SoGo, se desativadas! Reinicie o SoGo para aplicar as alterações.", @@ -624,10 +627,10 @@ "mailbox_relayhost_info": "Aplicado somente à caixa de correio e aos aliases diretos, substitui um host de retransmissão de domínio.", "max_aliases": "Máximo de aliases", "max_mailboxes": "Número máximo de mailboxes possíveis", - "max_quota": "Cota máxima por caixa de correio (MiB)", + "max_quota": "Cota máxima por mailbox (MiB)", "maxage": "Duração máxima das mensagens em dias que serão pesquisadas remotamente
(0 = ignorar a idade)", "maxbytespersecond": "Máximo de bytes por segundo
(0 = ilimitado)", - "mbox_rl_info": "Esse limite de taxa é aplicado ao nome de login do SASL e corresponde a qualquer endereço “de” usado pelo usuário conectado. Um limite de taxa de caixa de correio substitui um limite de taxa em todo o domínio.", + "mbox_rl_info": "Esse limite de taxa é aplicado ao nome de login do SASL e corresponde a qualquer endereço “de” usado pelo usuário conectado. Um limite de taxa de mailbox substitui um limite de taxa em todo o domínio.", "mins_interval": "Intervalo (min)", "multiple_bookings": "Várias reservas", "none_inherit": "Nenhum/Herdar", @@ -654,7 +657,7 @@ "ratelimit": "Limite de taxa", "redirect_uri": "URL de redirecionamento/retorno de chamada", "relay_all": "Retransmita todos os destinatários", - "relay_all_info": "↪ Se você optar por não retransmitir todos os destinatários, precisará adicionar uma caixa de correio (“cega”) para cada destinatário que deve ser retransmitido.", + "relay_all_info": "↪ Se você optar por não retransmitir todos os destinatários, precisará adicionar uma mailbox (“cega”) para cada destinatário que deve ser retransmitido.", "relay_domain": "Retransmitir este domínio", "relay_transport_info": "
Informações
Você pode definir mapas de transporte para um destino personalizado para esse domínio. Se não for definido, uma pesquisa MX será feita.", "relay_unknown_only": "Retransmita somente mailboxes não existentes. As caixas de mailboxes serão entregues localmente.", @@ -665,14 +668,14 @@ "scope": "Escopo", "sender_acl": "Permitir enviar como", "sender_acl_disabled": "A verificação do remetente está desativada", - "sender_acl_info": "Se o usuário A da caixa de correio tiver permissão para enviar como usuário B da caixa de correio, o endereço do remetente não será exibido automaticamente como campo “de” selecionável no SoGo.
\r\n O usuário B da caixa de correio precisa criar uma delegação no SoGo para permitir que o usuário A da caixa de correio selecione seu endereço como remetente. Para delegar uma caixa de correio no SoGo, use o menu (três pontos) à direita do nome da sua caixa de correio no canto superior esquerdo enquanto estiver na visualização de e-mail. Esse comportamento não se aplica a endereços de alias.", + "sender_acl_info": "Se o usuário A da mailbox tiver permissão para enviar como usuário B da mailbox, o endereço do remetente não será exibido automaticamente como campo “de” selecionável no SoGo.
\n O usuário B da mailbox precisa criar uma delegação no SoGo para permitir que o usuário A da mailbox selecione seu endereço como remetente. Para delegar uma mailbox no SoGo, use o menu (três pontos) à direita do nome da sua caixa de correio no canto superior esquerdo enquanto estiver na visualização de e-mail. Esse comportamento não se aplica a endereços de alias.", "sieve_desc": "Breve descrição", "sieve_type": "Tipo de filtro", "skipcrossduplicates": "Ignore mensagens duplicadas entre pastas (primeiro a chegar, primeiro a ser servido)", "sogo_access": "Conceder acesso de login direto ao SoGo", "sogo_access_info": "O login único de dentro da interface do usuário de e-mail continua funcionando. Essa configuração não afeta o acesso a todos os outros serviços nem exclui ou altera o perfil SoGo existente de um usuário.", "sogo_visible": "O alias é visível no SoGo", - "sogo_visible_info": "Essa opção afeta somente objetos, que podem ser exibidos no SoGo (endereços de alias compartilhados ou não compartilhados apontando para pelo menos uma caixa de correio local). Se estiver oculto, um alias não aparecerá como remetente selecionável no SoGo.", + "sogo_visible_info": "Essa opção afeta somente objetos, que podem ser exibidos no SoGo (endereços de alias compartilhados ou não compartilhados apontando para pelo menos uma mailbox local). Se estiver oculto, um alias não aparecerá como remetente selecionável no SoGo.", "spam_alias": "Crie ou altere endereços de alias com limite de tempo", "spam_filter": "Filtro de spam", "spam_policy": "Adicionar ou remover itens da lista branca/negra", @@ -688,7 +691,7 @@ "username": "Nome de usuário", "validate_save": "Valide e salve", "custom_attributes": "Atributos personalizados", - "mbox_exclude": "Excluir mailboxes" + "domain_footer_skip_replies": "Ignore o rodapé nos e-mails de resposta" }, "fido2": { "confirm": "Confirme", @@ -724,7 +727,7 @@ "administration": "Configuração e detalhes", "apps": "Aplicativos", "debug": "Informações", - "email": "Correio eletrônico", + "email": "E-mail", "mailcow_system": "Sistema", "mailcow_config": "Configuração", "quarantine": "Quarentena", @@ -741,7 +744,7 @@ "delayed": "O login foi atrasado em %s segundos.", "fido2_webauthn": "Login do FIDO2/WebAuthn", "login": "Login", - "mobileconfig_info": "Faça login como usuário da caixa de correio para baixar o perfil de conexão Apple solicitado.", + "mobileconfig_info": "Faça login como usuário da mailbox para baixar o perfil de conexão Apple solicitado.", "other_logins": "Login com chave", "password": "Senha", "username": "Nome de usuário" @@ -758,16 +761,16 @@ "add_domain_alias": "Adicionar alias de domínio", "add_domain_record_first": "Por favor, adicione um domínio primeiro", "add_filter": "Adicionar filtro", - "add_mailbox": "Adicionar caixa de correio", + "add_mailbox": "Adicionar mailbox", "add_recipient_map_entry": "Adicionar mapa do destinatário", "add_resource": "Adicionar recurso", "add_template": "Adicionar modelo", "add_tls_policy_map": "Adicionar mapa de política TLS", "address_rewriting": "Reescrita de endereço", - "alias": "Pseudônimo", - "alias_domain_alias_hint": "Os aliases não são aplicados automaticamente aos aliases de domínio. Um endereço de alias my-alias @domain não cobre o endereço my-alias @alias -domain (onde “alias-domain” é um domínio de alias imaginário para “domain”).
Use um filtro de peneira para redirecionar e-mails para uma caixa de correio externa (consulte a guia “Filtros” ou use SoGo -> Forwarder). Use “Expandir alias em domínios de alias” para adicionar automaticamente os aliases ausentes.", + "alias": "Alias", + "alias_domain_alias_hint": "Os aliases não são aplicados automaticamente aos aliases de domínio. Um endereço de alias my-alias@domain não cobre o endereço my-alias@alias -domain (onde “alias-domain” é um domínio de alias imaginário para “domain”).
Use um filtro para redirecionar e-mails para uma mailbox externa (consulte a guia “Filtros” ou use SoGo -> Forwarder). Use “Expandir alias em domínios de alias” para adicionar automaticamente os aliases ausentes.", "alias_domain_backupmx": "Domínio de alias inativo para domínio de retransmissão", - "aliases": "Pseudônimos", + "aliases": "Aliases", "all_domains": "Todos os domínios", "allow_from_smtp": "Permita que esses IPs usem apenas SMTP", "allow_from_smtp_info": "Deixe em branco para permitir todos os remetentes. Endereços e
redes IPv4/IPv6.", @@ -829,16 +832,16 @@ "last_pw_change": "Última alteração de senha", "last_run": "Última corrida", "last_run_reset": "Programe a seguir", - "mailbox": "Caixa de correio", + "mailbox": "Mailbox", "mailbox_defaults": "Configurações padrão", "mailbox_defaults_info": "Defina as configurações padrão para novas mailboxes.", - "mailbox_defquota": "Tamanho padrão da caixa de correio", - "mailbox_templates": "Modelos de caixa de correio", - "mailbox_quota": "Tamanho máximo de uma caixa de correio", - "mailboxes": "mailboxes", + "mailbox_defquota": "Tamanho padrão da mailbox", + "mailbox_templates": "Modelos de mailbox", + "mailbox_quota": "Tamanho máximo de uma mailbox", + "mailboxes": "Mailboxes", "max_aliases": "Máximo de aliases", "max_mailboxes": "Número máximo de mailboxes possíveis", - "max_quota": "Cota máxima por caixa de correio", + "max_quota": "Cota máxima por mailbox", "mins_interval": "Intervalo (min)", "msg_num": "Mensagem #", "multiple_bookings": "Várias reservas", @@ -895,7 +898,7 @@ "syncjob_EXIT_CONNECTION_FAILURE": "Problema de conexão", "syncjob_EXIT_TLS_FAILURE": "Problema com conexão criptografada", "syncjob_EXIT_AUTHENTICATION_FAILURE": "Problema de autenticação", - "syncjob_EXIT_OVERQUOTA": "A caixa de correio de destino está acima da cota", + "syncjob_EXIT_OVERQUOTA": "A mailbox de destino está acima da cota", "syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Não é possível se conectar ao servidor remoto", "syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Nome de usuário ou senha incorretos", "table_size": "Tamanho da mesa", @@ -922,7 +925,7 @@ "yes": "✓" }, "oauth2": { - "access_denied": "Faça login como proprietário da caixa de correio para conceder acesso via OAuth2.", + "access_denied": "Faça login como proprietário da mailbox para conceder acesso via OAuth2.", "authorize_app": "Autorizar aplicativo", "deny": "Negar", "permit": "Autorizar aplicativo", @@ -938,7 +941,7 @@ "confirm_delete": "Confirme a exclusão desse elemento.", "danger": "Perigo", "deliver_inbox": "Entregar na caixa de entrada", - "disabled_by_config": "A configuração atual do sistema desativa a funcionalidade de quarentena. Defina “retenções por caixa de correio” e um “tamanho máximo” para os elementos de quarentena.", + "disabled_by_config": "A configuração atual do sistema desativa a funcionalidade de quarentena. Defina “retenções por mailbox” e um “tamanho máximo” para os elementos de quarentena.", "download_eml": "Baixar (.eml)", "empty": "Sem resultados", "high_danger": "Alto", @@ -951,7 +954,7 @@ "notified": "Notificado", "qhandler_success": "Solicitação enviada com sucesso para o sistema. Agora você pode fechar a janela.", "qid": "Respand AID", - "qinfo": "O sistema de quarentena salvará as mensagens rejeitadas no banco de dados (o remetente não terá a impressão de uma mensagem entregue), bem como as mensagens, que são entregues como cópia na pasta Lixo eletrônico de uma caixa de correio.\r\n
“Aprenda como spam e exclua” aprenderá uma mensagem como spam por meio do teorema bayesiano e também calculará hashes difusos para negar mensagens semelhantes no futuro.\r\n
Esteja ciente de que aprender várias mensagens pode ser demorado, dependendo do seu sistema.
Os elementos da lista negra são excluídos da quarentena.", + "qinfo": "O sistema de quarentena salvará as mensagens rejeitadas no banco de dados (o remetente não terá a impressão de uma mensagem entregue), bem como as mensagens, que são entregues como cópia na pasta Lixo eletrônico de uma mailbox.\n
“Aprenda como spam e exclua” aprenderá uma mensagem como spam por meio do Teorema de Bayes e também calculará hashes difusos para negar mensagens semelhantes no futuro.\n
Esteja ciente de que aprender várias mensagens pode ser demorado, dependendo do seu sistema.
Os elementos da lista negra são excluídos da quarentena.", "qitem": "Item de quarentena", "quarantine": "Quarentena", "quick_actions": "Ações", @@ -1010,7 +1013,7 @@ "help": "Mostrar/ocultar painel de ajuda", "imap_smtp_server_auth_info": "Use seu endereço de e-mail completo e o mecanismo de autenticação PLAIN.
\r\nSeus dados de login serão criptografados pela criptografia obrigatória do lado do servidor.", "mailcow_apps_detail": "Use um aplicativo mailcow para acessar seus e-mails, calendário, contatos e muito mais.", - "mailcow_panel_detail": "Os administradores de domínio criam, modificam ou excluem mailboxes e aliases, alteram domínios e leem mais informações sobre seus domínios atribuídos.
\nOs usuários de caixas de correio podem criar aliases com limite de tempo (aliases de spam), alterar suas configurações de senha e filtro de spam." + "mailcow_panel_detail": "Os administradores de domínio criam, modificam ou excluem mailboxes e aliases, alteram domínios e leem mais informações sobre seus domínios atribuídos.
\nOs usuários de mailbox podem criar aliases com limite de tempo (aliases de spam), alterar suas configurações de senha e filtro de spam." }, "success": { "acl_saved": "ACL para o objeto %s salvo", @@ -1062,9 +1065,9 @@ "learned_ham": "Identificação %s como ham aprendida com sucesso", "license_modified": "As alterações na licença foram salvas", "logged_in_as": "Conectado como %s", - "mailbox_added": "A caixa de correio %s foi adicionada", - "mailbox_modified": "As alterações na caixa de correio %s foram salvas", - "mailbox_removed": "A caixa de correio %s foi removida", + "mailbox_added": "A mailbox %s foi adicionada", + "mailbox_modified": "As alterações na mailbox %s foram salvas", + "mailbox_removed": "A mailbox %s foi removida", "nginx_reloaded": "O Nginx foi recarregado", "object_modified": "As alterações no objeto %s foram salvas", "password_policy_saved": "A política de senha foi salva com sucesso", @@ -1077,7 +1080,7 @@ "relayhost_removed": "A entrada de mapa %s foi removida", "reset_main_logo": "Redefinir para o logotipo padrão", "resource_added": "O recurso %s foi adicionado", - "resource_modified": "As alterações na caixa de correio %s foram salvas", + "resource_modified": "As alterações na mailbox %s foram salvas", "resource_removed": "O recurso %s foi removido", "rl_saved": "Limite de taxa para o objeto %s salvo", "rspamd_ui_pw_set": "Senha do Rspamd UI definida com sucesso", @@ -1123,14 +1126,15 @@ "webauthn": "Autenticação WebAuthn", "waiting_usb_auth": "Aguardando o dispositivo USB...

Toque no botão no seu dispositivo USB agora.", "waiting_usb_register": "Aguardando o dispositivo USB...

Digite sua senha acima e confirme seu registro tocando no botão no seu dispositivo USB.", - "yubi_otp": "Autenticação Yubico OTP" + "yubi_otp": "Autenticação Yubico OTP", + "authenticators": "Autenticadores" }, "user": { "action": "Ação", "active": "Ativo", "active_sieve": "Filtro ativo", "advanced_settings": "Configurações avançadas", - "alias": "Pseudônimo", + "alias": "Alias", "alias_create_random": "Gere um alias aleatório", "alias_extend_all": "Estenda os aliases em 1 hora", "alias_full_date": "D.M.Y., H: S T", @@ -1147,7 +1151,7 @@ "apple_connection_profile": "Perfil de conexão da Apple", "apple_connection_profile_complete": "Esse perfil de conexão inclui parâmetros IMAP e SMTP, bem como caminhos CalDAV (calendários) e CardDAV (contatos) para um dispositivo Apple.", "apple_connection_profile_mailonly": "Esse perfil de conexão inclui parâmetros de configuração IMAP e SMTP para um dispositivo Apple.", - "apple_connection_profile_with_app_password": "Uma nova senha de aplicativo é gerada e adicionada ao perfil para que nenhuma senha precise ser inserida ao configurar seu dispositivo. Não compartilhe o arquivo, pois ele concede acesso total à sua caixa de correio.", + "apple_connection_profile_with_app_password": "Uma nova senha de aplicativo é gerada e adicionada ao perfil para que nenhuma senha precise ser inserida ao configurar seu dispositivo. Não compartilhe o arquivo, pois ele concede acesso total à sua mailbox.", "change_password": "Alterar senha", "change_password_hint_app_passwords": "Sua conta tem %d senhas de aplicativos que não serão alteradas. Para gerenciá-las, acesse a guia Senhas do aplicativo.", "clear_recent_successful_connections": "Conexões bem-sucedidas e claras", @@ -1160,7 +1164,7 @@ "delete_ays": "Confirme o processo de exclusão.", "direct_aliases": "Endereços de alias diretos", "direct_aliases_desc": "Os endereços de alias diretos são afetados pelo filtro de spam e pelas configurações da política TLS.", - "direct_protocol_access": "Esse usuário da caixa de correio tem acesso externo direto aos seguintes protocolos e aplicativos. Essa configuração é controlada pelo administrador. As senhas de aplicativos podem ser criadas para conceder acesso a protocolos e aplicativos individuais.
O botão “Login no webmail” fornece login único no SoGo e está sempre disponível.", + "direct_protocol_access": "Esse usuário da mailbox tem acesso externo direto aos seguintes protocolos e aplicativos. Essa configuração é controlada pelo administrador. As senhas de aplicativos podem ser criadas para conceder acesso a protocolos e aplicativos individuais.
O botão “Login no webmail” fornece login único no SoGo e está sempre disponível.", "eas_reset": "Redefinir o cache do dispositivo ActiveSync", "eas_reset_help": "Em muitos casos, uma redefinição do cache do dispositivo ajudará a recuperar um perfil quebrado do ActiveSync.
Atenção: Todos os elementos serão baixados novamente!", "eas_reset_now": "Reinicie agora", @@ -1187,7 +1191,7 @@ "last_ui_login": "Último login na interface do usuário", "loading": "Carregando...", "login_history": "Histórico de login", - "mailbox": "Caixa de correio", + "mailbox": "Mailbox", "mailbox_details": "Detalhes", "mailbox_general": "Geral", "mailbox_settings": "Configurações", @@ -1239,7 +1243,7 @@ "spamfilter": "Filtro de spam", "spamfilter_behavior": "Avaliação", "spamfilter_bl": "Lista negra", - "spamfilter_bl_desc": "Endereços de e-mail na lista negra para sempre serem classificados como spam e rejeitados. E-mails rejeitados não serão copiados para a quarentena. Podem ser usados curingas. Um filtro só é aplicado a aliases diretos (aliases com uma única caixa de correio de destino), excluindo aliases abrangentes e a própria caixa de correio.", + "spamfilter_bl_desc": "Endereços de e-mail na lista negra para sempre serem classificados como spam e rejeitados. E-mails rejeitados não serão copiados para a quarentena. Podem ser usados curingas. Um filtro só é aplicado a aliases diretos (aliases com uma única caixa de correio de destino), excluindo aliases abrangentes e a própria mailbox.", "spamfilter_default_score": "Valores padrão", "spamfilter_green": "Verde: esta mensagem não é spam", "spamfilter_hint": "O primeiro valor descreve a “pontuação baixa de spam”, o segundo representa a “alta pontuação de spam”.", @@ -1251,7 +1255,7 @@ "spamfilter_table_remove": "remover", "spamfilter_table_rule": "Regra", "spamfilter_wl": "Lista branca", - "spamfilter_wl_desc": "Os endereços de e-mail incluídos na lista branca são programados para nunca serem classificados como spam. Podem ser usados curingas. Um filtro só é aplicado a aliases diretos (aliases com uma única caixa de correio de destino), excluindo aliases abrangentes e a própria caixa de correio.", + "spamfilter_wl_desc": "Os endereços de e-mail incluídos na lista branca são programados para nunca serem classificados como spam. Podem ser usados curingas. Um filtro só é aplicado a aliases diretos (aliases com uma única mailbox de destino), excluindo aliases abrangentes e a própria mailbox.", "spamfilter_yellow": "Amarelo: esta mensagem pode ser spam, será marcada como spam e movida para sua pasta de lixo eletrônico", "status": "Status", "sync_jobs": "Trabalhos de sincronização", @@ -1261,7 +1265,7 @@ "syncjob_EXIT_CONNECTION_FAILURE": "Problema de conexão", "syncjob_EXIT_TLS_FAILURE": "Problema com conexão criptografada", "syncjob_EXIT_AUTHENTICATION_FAILURE": "Problema de autenticação", - "syncjob_EXIT_OVERQUOTA": "A caixa de correio de destino está acima da cota", + "syncjob_EXIT_OVERQUOTA": "A mailbox de destino está acima da cota", "syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Não é possível se conectar ao servidor remoto", "syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Nome de usuário ou senha incorretos", "tag_handling": "Definir o tratamento para e-mails marcados", @@ -1275,7 +1279,7 @@ "tls_enforce_in": "Imponha a entrada de TLS", "tls_enforce_out": "Imponha a saída TLS", "tls_policy": "Política de criptografia", - "tls_policy_warning": "Aviso: Se você decidir impor a transferência de e-mail criptografada, poderá perder e-mails.
As mensagens que não satisfizerem a política serão devolvidas com uma falha grave pelo sistema de correio.
Essa opção se aplica ao seu endereço de e-mail principal (nome de login), a todos os endereços derivados de domínios de alias, bem como aos endereços de alias com apenas essa única caixa de correio como destino.", + "tls_policy_warning": "Aviso: Se você decidir impor a transferência de e-mail criptografada, poderá perder e-mails.
As mensagens que não satisfizerem a política serão devolvidas com uma falha grave pelo sistema de correio.
Essa opção se aplica ao seu endereço de e-mail principal (nome de login), a todos os endereços derivados de domínios de alias, bem como aos endereços de alias com apenas essa única mailbox como destino.", "user_settings": "Configurações do usuário", "username": "Nome de usuário", "verify": "Verificar", diff --git a/data/web/lang/lang.pt-pt.json b/data/web/lang/lang.pt-pt.json index bfd640fd..624acd6d 100644 --- a/data/web/lang/lang.pt-pt.json +++ b/data/web/lang/lang.pt-pt.json @@ -12,7 +12,7 @@ "domain_quota_m": "Total de espaço por domínio (MiB):", "full_name": "Nome:", "mailbox_quota_m": "Máximo espaço por conta (MiB):", - "mailbox_username": "Usuário (primeira parte do endereço de email):", + "mailbox_username": "Utilizador (primeira parte do endereço de email):", "max_aliases": "Máximo de apelidos:", "max_mailboxes": "Máximo de contas:", "password": "Senha:", @@ -96,7 +96,7 @@ "sender_acl_invalid": "Campo Sender ACL é inválido", "target_domain_invalid": "O endereço de Domínio Destino é inválido", "targetd_not_found": "Domínio de Destino não encontrado", - "username_invalid": "Nome de usuário inválido", + "username_invalid": "Nome de utilizador inválido", "validity_missing": "Você deve definir um período de validade" }, "edit": { @@ -138,7 +138,7 @@ "administration": "Administração", "email": "E-Mail", "mailcow_config": "Configuração", - "user_settings": "Configurações do usuário" + "user_settings": "Configurações do utilizador" }, "info": { "no_action": "Nenhuma ação foi definida" @@ -147,7 +147,7 @@ "delayed": "Sua entrada será atrasada por %s segundos.", "login": "Entrar", "password": "Senha", - "username": "Usuário" + "username": "Utilizador" }, "mailbox": { "action": "Ação", @@ -186,7 +186,7 @@ "target_domain": "Domínio Destino", "tls_enforce_in": "Forçar TLS na entrada", "tls_enforce_out": "Forçar TLS na saída", - "username": "Usuário" + "username": "Utilizador" }, "quarantine": { "action": "Ação", @@ -199,7 +199,7 @@ "help": "Mostrar/Ocultar painel de ajuda", "imap_smtp_server_auth_info": "Utilize o endereço de email completo com o método de autentucação PLAIN.
\r\nOs dados de login serão encryptados pelo servidor.", "mailcow_apps_detail": "Use um mailcow app para acessar seus emails, calendário, contatos e outras informações.", - "mailcow_panel_detail": "Administradores: podem criar, alterar ou apagar contas e apelidos , alterar domínios e outras informações de seus domínios atribuídos.
\r\n\tUsuários: podem criar apelidos por tempo determinado , alterar senha e configuração do nível do filtro de spam." + "mailcow_panel_detail": "Administradores: podem criar, alterar ou apagar contas e apelidos , alterar domínios e outras informações de seus domínios atribuídos.
\r\n\tutilizadors: podem criar apelidos por tempo determinado , alterar senha e configuração do nível do filtro de spam." }, "success": { "admin_modified": "Administrador alterado com sucesso", @@ -267,7 +267,7 @@ "tls_enforce_out": "Forçar TLS na saída", "tls_policy": "Regras de Encryptação", "tls_policy_warning": "Aviso: Se você selecionar para forçar o envio encryptado , alguns emails poderão ser rejeitados.
Mensages que não satisfizerem as politicas dos outros servidores serão rejeitadas definitivamente.", - "user_settings": "Configurações do usuário", + "user_settings": "Configurações do utilizador", "username": "Administrador", "week": "Semana", "weeks": "Semanas" diff --git a/data/web/lang/lang.ro-ro.json b/data/web/lang/lang.ro-ro.json index 5c7b29b0..90c96c21 100644 --- a/data/web/lang/lang.ro-ro.json +++ b/data/web/lang/lang.ro-ro.json @@ -504,7 +504,7 @@ "cname_from_a": "Valoare derivată din înregistrarea A/AAAA. Acest lucru este acceptat atâta timp cât înregistrarea indică resursele corecte.", "dns_records": "Înregistrări DNS", "dns_records_24hours": "Rețineți că modificările aduse DNS-ului pot dura până la 24 de ore pentru a reflecta corect starea lor curentă pe această pagină. Acest mecanism este conceput ca o modalitate să vezi ușor cum să îți configurezi înregistrările DNS și să verifici dacă toate înregistrările sunt stocate corect în DNS.", - "dns_records_docs": "Vă rugăm să consultați și documentația.", + "dns_records_docs": "Vă rugăm să consultați și documentația.", "dns_records_data": "Date corecte", "dns_records_name": "Nume", "dns_records_status": "Stare curentă", diff --git a/data/web/lang/lang.ru-ru.json b/data/web/lang/lang.ru-ru.json index 2a959ab3..21775cb1 100644 --- a/data/web/lang/lang.ru-ru.json +++ b/data/web/lang/lang.ru-ru.json @@ -2,7 +2,7 @@ "acl": { "alias_domains": "Создание псевдонимов домена", "app_passwds": "Пароли приложений", - "bcc_maps": "Правила BBC", + "bcc_maps": "Правила BCC", "delimiter_action": "Обработка тегированной почты", "domain_desc": "Изменение описания домена", "domain_relayhost": "Изменение промежуточных узлов для домена", @@ -389,7 +389,7 @@ "imagick_exception": "Ошибка в Imagick при чтении изображения", "img_invalid": "Невозможно проверить файл изображения", "img_tmp_missing": "Невозможно проверить файл изображения: временный файл не найден", - "invalid_bcc_map_type": "Неверный тип правила BBC", + "invalid_bcc_map_type": "Неверный тип правила BCC", "invalid_destination": "Назначение \"%s\" указано неверно", "invalid_filter_type": "Неверный тип фильтра", "invalid_host": "Хост %s указан неверно", @@ -504,7 +504,7 @@ "dns_records": "Записи DNS", "dns_records_24hours": "Обратите внимание, что для внесения изменений в DNS может потребоваться до 24 часов, чтобы правильно отобразить их текущее состояние на этой странице. Эта страница предназначен для того, чтобы вы могли легко увидеть, как настроить записи DNS и проверить, все ли записи правильно занесены в DNS.", "dns_records_data": "Значение", - "dns_records_docs": "Пожалуйста, ознакомьтесь с документацией.", + "dns_records_docs": "Пожалуйста, ознакомьтесь с документацией.", "dns_records_name": "Название", "dns_records_status": "Статус", "dns_records_type": "Тип", @@ -523,7 +523,7 @@ "app_passwd": "Пароль приложения", "automap": "Автоматическое слияние папок (\"Sent items\", \"Sent\" => \"Sent\" etc.)", "backup_mx_options": "Параметры резервного копирования MX", - "bcc_dest_format": "Назначением для правила BBC должен быть единственный действительный адрес электронной почты.", + "bcc_dest_format": "Назначением для правила BCC должен быть единственный действительный адрес электронной почты.", "client_id": "ID клиента", "client_secret": "Секретный ключ пользователя", "comment_info": "Приватный комментарий не виден пользователям, а публичный - отображается рядом с псевдонимом в личном кабинете пользователя", @@ -546,6 +546,7 @@ "extended_sender_acl_info": "Для внешних доменов должен быть импортирован или сгенерирован доменный ключ DKIM с соответствующей записью TXT в домене, если внешний домен использует DMARC.
\r\n Не забудьте добавить этот сервер к соответствующей записи SPF TXT внешнего домена.
\r\n Добавление домена из списка внешних адресов в mailcow автоматически удалит соответствующие записи из внешних адресов пользователей.
\r\n Чтобы разрешить пользователю отправку от имени *@domain.tld, укажите @domain.tld.", "force_pw_update": "Требовать смены пароля при следующем входе в систему", "force_pw_update_info": "Пользователь должен будет войти в %s и сменить свой пароль. mailcow OAuth2, SOGo, EAS, IMAP/POP3 и SMTP будут не доступны до смены пароля.", + "footer_exclude": "Исключить из нижнего колонтитула", "full_name": "Полное имя", "gal": "GAL - Глобальная адресная книга", "gal_info": "GAL содержит все объекты домена и не подлежит редактированию. Информация о занятости в SOGo будет отсутствовать для домена, если данная функция будет отключена! Требуется перезапустить SOGo, чтобы применить изменения.", @@ -635,7 +636,6 @@ "domain_footer": "Нижний колонтитул домена", "domain_footer_html": "HTML нижний колонтитул", "domain_footer_plain": "ПРОСТОЙ нижний колонтитул", - "mbox_exclude": "Исключить почтовые ящики", "custom_attributes": "Пользовательские атрибуты" }, "fido2": { @@ -700,7 +700,7 @@ "add": "Добавить", "add_alias": "Добавить псевдоним", "add_alias_expand": "Скопировать псевдонимы на псевдонимы домена", - "add_bcc_entry": "Добавить правило BBC", + "add_bcc_entry": "Добавить правило BCC", "add_domain": "Добавить домен", "add_domain_alias": "Добавить псевдоним домена", "add_domain_record_first": "Пожалуйста, сначала добавьте домен", @@ -719,14 +719,14 @@ "allow_from_smtp_info": "Укажите IPv4/IPv6 адреса и/или подсети.
Оставьте поле пустым, чтобы разрешить отправку с любых адресов.", "allowed_protocols": "Разрешенные протоколы", "backup_mx": "Резервный MX", - "bcc": "Правила BBC", + "bcc": "Правила BCC", "bcc_destination": "Назначение BCC", "bcc_destinations": "Назначение BCC", "bcc_info": "Правила BCC используются для скрытой пересылки копий всех сообщений на другой адрес. Правило типа \"получатель\" используется, когда локальный получатель выступает в качестве получателя почты. Правило типа \"отправитель\" соответствуют тому же принципу. Локальный домен не будут проинформированы о неудачной доставке.", "bcc_local_dest": "Локальный домен", - "bcc_map": "Правила BBC", + "bcc_map": "Правила BCC", "bcc_map_type": "Тип BCC", - "bcc_maps": "Правила BBC", + "bcc_maps": "Правила BCC", "bcc_rcpt_map": "Получатель", "bcc_sender_map": "Отправитель", "bcc_to_rcpt": "Переключиться на тип \"получатель\"", @@ -1224,6 +1224,8 @@ "session_ua": "Неверный токен формы: ошибка проверки User-Agent" }, "datatables": { + "collapse_all": "Свернуть все", + "expand_all": "Развернуть все", "infoPostFix": "" } } diff --git a/data/web/lang/lang.si-si.json b/data/web/lang/lang.si-si.json index cf1cf799..e9468e0c 100644 --- a/data/web/lang/lang.si-si.json +++ b/data/web/lang/lang.si-si.json @@ -107,7 +107,8 @@ "post_domain_add": "SOGo container \"sogo-mailcow\" mora biti ponovno zagnan po dodajanju nove domene!

Dodatno se mora preveriti DNS konfiguracija domene. Ko je DNS konfiguracija domene odobrena, ponovno zaženite \"acme-mailcow\" za samodejno generiranje certifikatov za novo domeno (autoconfig.<domain>, autodiscover.<domain>).
Ta korak je opcijski in se ponovno poskuša vsakih 24 ur.", "relay_transport_info": "
Info
Definirate lahko preslikave transportov za cilj po meri za to domeno. Če ni nastavljena, se ustvari MX poizvedba.", "syncjob_hint": "Pozor! Gesla se morajo shraniti v plain-text!", - "timeout2": "Časovna omejitev za povezavo do lokalnega gostitelja" + "timeout2": "Časovna omejitev za povezavo do lokalnega gostitelja", + "dry": "Simuliraj sinhronizacijo" }, "admin": { "access": "Dostop", @@ -347,7 +348,10 @@ "logo_dark_label": "Za temni način", "cors_settings": "Nastavitve CORS", "allowed_methods": "Dovoljene metode za upravljanje dostopa", - "allowed_origins": "Upravljanje-dostopa-Dovoljeni-Viri" + "allowed_origins": "Upravljanje-dostopa-Dovoljeni-Viri", + "copy_to_clipboard": "Besedilo kopirano v odložišče!", + "f2b_manage_external": "Zunanje upravljanje Fail2Ban", + "f2b_manage_external_info": "Fail2ban bo še vedno vzdrževal seznam prepovedi, vendar ne bo aktivno nastavil pravil za blokiranje prometa. Uporabite spodnji ustvarjeni seznam prepovedi za zunanje blokiranje prometa." }, "danger": { "alias_goto_identical": "Alias in goto naslov morata biti identična", @@ -476,7 +480,9 @@ "temp_error": "Začasna napaka", "cors_invalid_method": "Navedena neveljavna Allow metoda", "cors_invalid_origin": "Naveden neveljaven Allow-Origin", - "invalid_recipient_map_new": "Naveden neveljaven nov prejemnik: %s" + "invalid_recipient_map_new": "Naveden neveljaven nov prejemnik: %s", + "img_dimensions_exceeded": "Slika presega največje dovoljene dimenzije", + "img_size_exceeded": "Slika presega največjo dovoljeno velikost datoteke" }, "debug": { "containers_info": "Informacije o vsebniku (containerju)", @@ -511,7 +517,13 @@ "no_update_available": "Sistem je na najnovejši verziji", "update_failed": "Ni mogoče preveriti za posodobitve", "username": "Uporabniško ime", - "wip": "Trenutno v delu" + "wip": "Trenutno v delu", + "log_info": "

mailcow in-memory dnevniki se zbirajo v Redis seznamih in se vsako minuto omejijo na LOG_LINES (%d) da se zmanjša obremenitev.\n
In-memory dnevniki niso namenjeni trajnemu shranjevanju. Vse aplikacije, ki beležijo dnevnike in-memory, tudi beležijo v Docker daemon in posledično v privzeti gonilnik za dnevnik.\n
In-memory dnevniki se naj uporabljajo za odpravljanje manjših napak s containerji.

\n

Eksterni dnevniki se zbirajo preko API-ja posamezne aplikacije.

\n

Statični dnevniki so večinoma dnevniki aktivnosti, ki se ne beležijo v Dockerd, a jih je vseeno treba hraniti (razen API dnevnikov).

", + "login_time": "Čas", + "logs": "Dnevniki", + "memory": "Spomin", + "online_users": "Prijavljeni uporabniki", + "restart_container": "Ponovno zaženi" }, "datatables": { "infoFiltered": "(filtrirano od _MAX_ skupaj zapisov)", @@ -543,7 +555,7 @@ "dns_records": "DNS zapisi", "dns_records_24hours": "Prosim upoštevajte, da lahko traja do 24 ur da se spremembe v DNS pravilno prikažejo na tej strani. Namen je da lahko enostavno vidite, kako konfigurirati svoje DNS zapise in preverite ali so vaši zapisi pravilno shranjeni v DNS.", "dns_records_data": "Pravilni podatki", - "dns_records_docs": "Prosim preverite tudi dokumentacijo.", + "dns_records_docs": "Prosim preverite tudi dokumentacijo.", "dns_records_name": "Ime", "dns_records_status": "Trenutno stanje", "dns_records_type": "Vrsta", @@ -551,6 +563,98 @@ }, "edit": { "acl": "ACL (Dovoljenje)", - "active": "Aktivno" + "active": "Aktivno", + "allow_from_smtp": "Dovoli samo tem IP naslovom da uporabijo SMTP", + "bcc_dest_format": "Cilj BCC mora biti en veljaven email naslov.
Če morate poslati kopijo na več naslovov, ustvarite alias in ga uporabite tukaj.", + "automap": "Poskušaj samodejno preslikati mape (\"Sent items\", \"Sent\" => \"Poslano\" ipd.)", + "admin": "Uredi skrbnika", + "domain_footer_info_vars": { + "custom": "{= foo =} - Če ima poštni predal atribut po meri \"foo\" z vrednostjo \"bar\", spremenljivka vrne \"bar\"", + "auth_user": "{= auth_user =} - Prijavljeno uporabniško ime, ki ga določi MTA", + "from_user": "{= from_user =} - leva stran email naslova uporabnika, npr. za \"moo@mailcow.tld\" vrne \"moo\"", + "from_name": "{= from_name =} - Prikazno ime, npr. za \"Mailcow <moo@mailcow.tld>\" vrne \"Mailcow\"", + "from_addr": "{= from_addr =} - e-poštni naslov \"Od\"", + "from_domain": "{= from_domain =} - domena e-poštnega naslova \"Od\"" + }, + "dont_check_sender_acl": "Onemogoči kontrolo pošiljatelja za domeno %s (+ alias domene)", + "pushover_title": "Naslov obvestila", + "domains": "Domene", + "extended_sender_acl_info": "Če je DKIM domenski ključ na voljo, ga uvozite.
\n Ne pozabite dodati ta strežnik k ustreznemu SPF TXT zapisu.
\n Kadar koli je domena ali alias domena dodana k tem strežniku, ki se prekriva z zunanjim naslovom, je zunanji naslov odstranjen.
\n uporabite @domain.tld da dovolite pošiljanje kot *@domain.tld.", + "lookup_mx": "Cilj je regular expression za ujemanje MX zapisov (.*\\.google\\.com za usmeritev vse pošte na MX, ki se konča z google.com, preko tega skoka)", + "maxbytespersecond": "Največ bytov na sekundo
(0 = neomejeno)", + "pushover_sender_array": "Upoštevaj samo sledeče e-poštne naslove pošiljateljev (ločeni z vejico)", + "mbox_rl_info": "Ta omejitev velja za SASL uporabniško ime, preverja se ujemanje s katerim koli \"from\" naslovom, ki ga uporablja prijavljeni uporabnik. Omejitev pošiljanja za poštni predal preglasi pravilo omejitve za domeno.", + "kind": "Tip", + "client_secret": "Client secret", + "comment_info": "Zasebni komentar ni viden uporabniku, javni komentar pa je viden kot tooltip v uporabnikovem pregledu.", + "created_on": "Ustvarjeno", + "custom_attributes": "Atributi po meri", + "delete1": "Izbriši na viru, ko je končano", + "delete2": "Izbriši sporočila na cilju, ki ne obstajajo na viru", + "delete2duplicates": "Izbriši dvojnike na cilju", + "delete_ays": "Prosim potrdite proces izbrisa.", + "description": "Opis", + "disable_login": "Onemogoči prijavo (dohodna pošta je še vedno sprejeta)", + "domain": "Uredi domeno", + "domain_admin": "Uredi domenskega skrbnika", + "domain_footer": "Noga za celo domeno", + "domain_footer_html": "HTML noga", + "pushover_vars": "Če ni definiran noben filter pošiljatelja, bodo upoštevana vsa sporočila.
Regex filtre in natančna preverjanja pošiljateljev je mogoče definirati posamezno in bodo obravnavani v nadaljevanju. Niso odvisni drug od drugega.
Uporabne spremenljivke za besedilo in naslov (prosimo, upoštevajte politike varstva podatkov)", + "pushover_verify": "Preveri poverilnice", + "quota_mb": "Omejitev (MiB)", + "quota_warning_bcc": "BCC za sporočilo z opozorilom omejitve", + "quota_warning_bcc_info": "Opozorila bodo poslana kot ločene kopije sledečim prejemnikom. K naslovu sporočila bo dodano uporabniško ime v oklepajih, npr. Opozorilo omejitve (user@example.com)", + "ratelimit": "Omejitev pošiljanja", + "advanced_settings": "Napredne nastavitve", + "allow_from_smtp_info": "Pustite prazno da dovolite vse pošiljatelje.
IPv4/IPv6 naslovi in omrežja.", + "allowed_protocols": "Dovoljeni protokoli", + "app_name": "Ime aplikacije", + "app_passwd": "Geslo aplikacije", + "app_passwd_protocols": "Dovoljeni protokoli za geslo aplikacije", + "backup_mx_options": "Možnosti posredovanja (relay)", + "client_id": "Client ID", + "domain_footer_info": "Noge za celo domeno so dodane k vsem izhodnim e-poštnim sporočilom v tej domeni.
V nogi se lahko uporabijo sledeče spremenljivke:", + "domain_footer_plain": "PLAIN noga", + "domain_footer_skip_replies": "Ne dodajaj noge v odgovorih na e-poštna sporočila", + "domain_quota": "Omejitev (kvota) domene", + "edit_alias_domain": "Uredi alias domeno", + "exclude": "Izključi objekte (regex)", + "extended_sender_acl": "Naslovi zunanjih pošiljateljev", + "force_pw_update": "Obvezna zamenjava gesla ob naslednji prijavi", + "force_pw_update_info": "Ta uporabnik se bo lahko prijavil samo v %s. Gesla aplikacij ostajajo v rabi.", + "footer_exclude": "Izključi iz noge", + "full_name": "Polno ime", + "gal": "Globalni seznam naslovov (GAL)", + "gal_info": "GAL vsebuje vse objekte v domeni in jih uporabniki ne morejo urejati. Če je onemogočeno, ni podatkov o o zasedenosti objekta! Ponovno zaženite SOGo za uveljavitev sprememb.", + "generate": "generiraj", + "grant_types": "Vrste dovoljenj", + "hostname": "Ime gostitelja", + "inactive": "Neaktivno", + "last_modified": "Nazadnje spremenjeno", + "mailbox": "Uredi poštni predal", + "mailbox_quota_def": "Privzeta omejitev/kvota za poštni predal", + "mailbox_relayhost_info": "Velja samo za poštni predal in neposredne aliase. Ne prepiše domenskega relay gostitelja.", + "max_aliases": "Največ aliasov", + "max_mailboxes": "Največ možnih poštnih predalov", + "max_quota": "Največja omejitev/kvota na poštni predal (MiB)", + "maxage": "Največja starost sporočil (v dnevih), po katerih bo poizvedeno iz oddaljenega vira
(0 = ne omejuj)", + "mins_interval": "Interval (min)", + "multiple_bookings": "Več rezervacij", + "none_inherit": "Brez / podeduj", + "nexthop": "Naslednji skok", + "password": "Geslo", + "password_repeat": "Potrditev gesla (ponovite)", + "previous": "Prejšnja stran", + "private_comment": "Zasebni komentar", + "public_comment": "Javni komentar", + "pushover": "Pushover", + "pushover_evaluate_x_prio": "Eskaliraj visoko prednostno pošto [X-Priority: 1]", + "pushover_info": "Nastavitve potisnih obvestil bodo veljala za vsa čisto (ne spam) elektronsko pošto dostavljeno v %s vključno z aliasi (deljeni, nedeljeni, označeni)", + "pushover_only_x_prio": "Upoštevaj samo pošto z visoko prioriteto [X-Priority: 1]", + "pushover_sender_regex": "Upoštevaj sledeči regex za pošiljatelja", + "pushover_text": "Besedilo obvestila", + "pushover_sound": "Zvok", + "encryption": "Šifriranje", + "alias": "Uredi alias" } } diff --git a/data/web/lang/lang.sk-sk.json b/data/web/lang/lang.sk-sk.json index d656a2cd..466afdb8 100644 --- a/data/web/lang/lang.sk-sk.json +++ b/data/web/lang/lang.sk-sk.json @@ -523,7 +523,7 @@ "dns_records": "DNS záznamy", "dns_records_24hours": "Berte prosím do úvahy, že zmeny v DNS môžu trvať až 24 hodín, aby sa zmeny prejavili na tejto stránke. Pre jednoduchosť DNS konfigurácie môžete použiť údaje uvedené nižšie, prípadne skontrolovať tak správnosť záznamov v DNS.", "dns_records_data": "Správne dáta", - "dns_records_docs": "Pozrite si prosím dokumentáciu.", + "dns_records_docs": "Pozrite si prosím dokumentáciu.", "dns_records_name": "Meno", "dns_records_status": "Súčasný stav", "dns_records_type": "Typ", diff --git a/data/web/lang/lang.sv-se.json b/data/web/lang/lang.sv-se.json index ba97e705..bbf0d958 100644 --- a/data/web/lang/lang.sv-se.json +++ b/data/web/lang/lang.sv-se.json @@ -60,7 +60,7 @@ "exclude": "Exkludera objekt (regex-filter)", "full_name": "Fullständiga namn", "gal": "Global adressbok", - "gal_info": "Den global adressboken innehåller alla objekt i en domän och kan inte redigeras av någon användare. Informationen om tillgänglighet i SOGo är endast synlig när den globala adressboken är påslagen. Starta om SOGo för att tillämpa ändringar.", + "gal_info": "Den global adressboken innehåller alla objekt i en domän och kan inte redigeras av någon användare. Informationen om tillgänglighet i SOGo är endast synlig när den globala adressboken är påslagen. Starta om SOGo för att tillämpa ändringar.", "generate": "generera", "goto_ham": "Markera detta som en felaktig spam-registrering, detta kommer förhindra liknande fel i framtiden", "goto_null": "Kasta e-postmeddelanande omedelbart", @@ -473,7 +473,7 @@ "cname_from_a": "Värde härstammar från A/AAAA-uppslaget. Detta stöds så länge som uppslaget pekar mot rätt resurs.", "dns_records": "DNS-uppslag", "dns_records_24hours": "Observera att ändringar gjorda i DNS kan ta upp till 24 timmar innan det visas korrekt på denna sida. Syftet med sidan är att enkelt se hur DNS-uppslagen är konfigurerade. Det är lätt att kontrollera att DNS-uppslagen är korrekt uppsatta.", - "dns_records_docs": "Se även dokumentationen.", + "dns_records_docs": "Se även dokumentationen.", "dns_records_data": "Korrektdata", "dns_records_name": "Namn", "dns_records_status": "Nuvarande status", diff --git a/data/web/lang/lang.tr-tr.json b/data/web/lang/lang.tr-tr.json index 5219c41d..e7fb623c 100644 --- a/data/web/lang/lang.tr-tr.json +++ b/data/web/lang/lang.tr-tr.json @@ -1,6 +1,6 @@ { "acl": { - "alias_domains": "Alias domain ekle", + "alias_domains": "Takma alan adı ekle", "app_passwds": "Uygulama şifrelerini yönet", "bcc_maps": "BCC haritası", "delimiter_action": "Sınırlandırma işlemi", @@ -68,7 +68,7 @@ "goto_null": "Postaları çöpe at", "goto_spam": "Spam olarakişaretle", "hostname": "Ana sunucu", - "inactive": "İnaktif", + "inactive": "Pasif", "kind": "Tür", "mailbox_quota_def": "Varsayılan e-posta kotası", "mailbox_quota_m": "E-posta başına maksimum kota (MiB)", @@ -77,7 +77,7 @@ "max_mailboxes": "Maksimum e-posta hesabı", "mins_interval": "Sorgulama döngüsü (dakika)", "multiple_bookings": "Birden fazla rezervasyon", - "nexthop": "Next hop", + "nexthop": "Sonraki atlama", "password": "Şifre", "password_repeat": "Şifre (tekrar)", "port": "Port", @@ -107,7 +107,8 @@ "timeout2": "Yerel ana bilgisayara bağlantı için zaman aşımı", "username": "Kullanıcı Adı", "validate": "Doğrula", - "validation_success": "Doğrulama başarılı" + "validation_success": "Doğrulama başarılı", + "dry": "Senkronizasyonu simüle et" }, "admin": { "action": "İşlem", @@ -133,7 +134,223 @@ "duplicate_dkim": "Çift DKIM kayıtları", "f2b_ban_time": "Yasaklama süresi (saniye)", "f2b_max_attempts": "Maksimum giriş denemesi", - "f2b_retry_window": "Maksimum girişim için deneme pencere(leri)" + "f2b_retry_window": "Maksimum girişim için deneme pencere(leri)", + "ip_check_disabled": "IP kontrolü devre dışı. Bunu
Sistem > Yapılandırma > Seçenekler > Özelleştir altında etkinleştirebilirsiniz.", + "logo_info": "Resminiz, üst gezinme çubuğu için 40 piksel yüksekliğe ve maks. başlangıç sayfası için 250 piksel genişlik. Ölçeklenebilir bir grafik şiddetle tavsiye edilir.", + "forwarding_hosts_add_hint": "IPv4/IPv6 adreslerini, CIDR gösterimindeki ağları, ana bilgisayar adlarını (IP adreslerine çözümlenecek) veya alan adlarını (SPF kayıtlarını veya yokluğunda MX kayıtlarını sorgulayarak IP adreslerine çözümlenecek) belirtebilirsiniz.", + "include_exclude_info": "Varsayılan olarak - seçim yapılmadan - tüm posta kutuları adreslenir", + "credentials_transport_warning": "Uyarı: Yeni bir ulaşım haritası girişi eklemek, eşleşen bir sonraki atlama sütunuyla tüm girişlerin kimlik bilgilerini güncelleyecektir.", + "f2b_manage_external_info": "Fail2ban yasak listeyi koruyacak fakat trafiğe engel olacak kurallar koymayacak.Trafiği dışarıdan engellemek için aşağıda oluşturulan yasak listesini kullanın.", + "add_settings_rule": "Ayarlar kuralı ekle", + "add_transports_hint": "Lütfen, varsa, kimlik doğrulama verilerinin düz metin olarak saklanacağını unutmayın.", + "additional_rows": " ek satırlar eklendi", + "admin": "Yönetici", + "admins": "Yöneticiler", + "admins_ldap": "LDAP yöneticileri", + "advanced_settings": "Gelişmiş ayarlar", + "allowed_origins": "Access-Control-Allow-Origin", + "cors_settings": "CORS ayarları", + "last_applied": "Son uygulanan", + "logo_normal_label": "Normal", + "logo_dark_label": "Karanlık moda çevir", + "f2b_max_ban_time": "Max. yasaklanma süresi (s)", + "guid": "GUID - benzersiz örnek kimliği", + "guid_and_license": "GUID & Lisans", + "copy_to_clipboard": "Metni panoya kopyala", + "dkim_add_key": "ARC/DKIM key ekle", + "dkim_domains_selector": "Seçici", + "dkim_from": "Gönderen", + "dkim_key_length": "DKIM anahtar uzunluğu (bit)", + "dkim_key_missing": "Anahtar eksik", + "dkim_key_unused": "Anahtar kullanılamaz", + "dkim_key_valid": "Anahtar geçerli", + "dkim_keys": "ARC/DKIM anahtarları", + "dkim_overwrite_key": "Mevcut DKIM anahtarının üzerine yaz", + "dkim_private_key": "Özel anahtar", + "f2b_ban_time_increment": "Yasaklanma süresi her engellemede artar", + "f2b_manage_external": "Fail2Ban'ı dışarıdan yönetin", + "f2b_regex_info": "Dikkate alınan günlükler: SOGo, Postfix, Dovecot, PHP-FPM.", + "f2b_whitelist": "Beyaz listeye alınan ağlar/ana bilgisayarlar", + "filter_table": "Tabloyu filtrele", + "forwarding_hosts": "Yönlendirme Ana Bilgisayarları", + "forwarding_hosts_hint": "Gelen mesajlar burada listelenen tüm ana bilgisayarlardan koşulsuz olarak kabul edilir. Bu ana bilgisayarlar daha sonra DNSBL'lere karşı kontrol edilmez veya gri listeye tabi tutulmaz. Onlardan gelen istenmeyen e-postalar asla reddedilmez, ancak isteğe bağlı olarak Önemsiz klasörüne dosyalanabilir. Bunun en yaygın kullanımı, gelen e-postaları mailcow sunucunuza ileten bir kural kurduğunuz posta sunucularını belirtmektir.", + "from": "Kimden", + "generate": "oluştur", + "hash_remove_info": "Bir hız sınırı karmasını (hala mevcutsa) kaldırmak, sayacını tamamen sıfırlayacaktır.
\n Her karma ayrı bir renkle belirtilir.", + "help_text": "Oturum açma maskesinin altındaki yardım metnini geçersiz kıl (HTML'ye izin verilir)", + "host": "Host", + "html": "HTML", + "import": "İçe aktar", + "import_private_key": "Özel anahtarı içe aktar", + "in_use_by": "tarafından kullanımda", + "inactive": "Pasif", + "include_exclude": "Dahil et, hariç tut", + "includes": "Bu alıcıları dahil et", + "ip_check_opt_in": "Harici IP adreslerini çözümlemek için ipv4.mailcow.email ve ipv6.mailcow.email üçüncü taraf hizmetini kullanmayı seçin.", + "is_mx_based": "MX tabanlı", + "link": "Link", + "loading": "Lütfen bekleyin…", + "login_time": "Giriş zamanı", + "lookup_mx": "Hedef, MX adıyla eşleşecek normal bir ifadedir (google.com ile biten bir MX'e hedeflenen tüm postaları bu atlama üzerinden yönlendirmek için .*google\\\\.com)", + "main_name": "“mailcow UI” adı", + "merged_vars_hint": "Grileştirilmiş satırlar vars.(local.)inc.php dosyasından birleştirildi ve değiştirilemez.", + "message": "Mesaj", + "message_size": "Mesaj boyutu", + "nexthop": "Sonraki atlama", + "no": "✕", + "no_active_bans": "Aktif yasak yok", + "allowed_methods": "Access-Control-Allow-Methods", + "f2b_netban_ipv4": "Yasak uygulanacak IPv4 alt ağ boyutu (8-32)", + "f2b_netban_ipv6": "Yasak uygulanacak IPv6 alt ağ boyutu (8-32)", + "f2b_parameters": "Fail2ban parametreleri", + "empty": "Sonuç yok", + "excludes": "Bu alıcıları hariç tutar", + "f2b_blacklist": "Kara listeye alınan ağlar/ana bilgisayarlar", + "f2b_filter": "Regex filtreleri", + "f2b_list_info": "Kara listeye alınmış bir ana bilgisayar veya ağ, her zaman beyaz listedeki bir varlıktan daha ağır basacaktır. Liste güncellemelerinin uygulanması birkaç saniye sürecektir.", + "ip_check": "IP Kontrol", + "access": "Erişim", + "activate_api": "API etkinleştir", + "activate_send": "Gönder düğmesini etkinleştir", + "active": "Etkinleştir", + "active_rspamd_settings_map": "Aktif ayarlar haritası", + "add_admin": "Yönetici ekle", + "add_relayhost": "Gönderene bağlı aktarım ekle", + "add_relayhost_hint": "Lütfen, varsa, kimlik doğrulama verilerinin düz metin olarak saklanacağını unutmayın.", + "add_row": "Satır ekle", + "api_allow_from": "Bu IP'lerden/CIDR ağ gösterimlerinden API erişimine izin ver", + "api_key": "API anahtarı", + "api_read_only": "Sadece okuma", + "api_read_write": "Okuma yazma", + "api_skip_ip_check": "API için IP kontrolünü atla", + "app_links": "Uygulama linkleri", + "app_name": "Uygulama adı", + "arrival_time": "Varış zamanı (sunucu zamanı)", + "customer_id": "Müşteri Kimliği", + "customize": "Özelleştir", + "destination": "Hedef", + "ays": "Devam etmek istediğinizden emin misiniz?", + "change_logo": "Logoyu değiştir", + "convert_html_to_text": "HTML'yi düz metne dönüştürün", + "edit": "Düzenle", + "no_new_rows": "Başka satır yok", + "oauth2_client_secret": "Client anahtarı", + "quarantine_release_format": "Serbest bırakılan öğelerin biçimi", + "oauth2_info": "OAuth2 uygulaması, \"Yetkilendirme Kodu\" verme türünü destekler ve yenileme belirteçleri yayınlar.
\nSunucu, bir yenileme belirteci kullanıldıktan sonra otomatik olarak yeni yenileme belirteçleri de verir.

\n• Varsayılan kapsam profil'dir. OAuth2'ye karşı yalnızca posta kutusu kullanıcılarının kimliği doğrulanabilir. Kapsam parametresi atlanırsa, profile'ye geri döner.
\n• state parametresinin, yetkilendirme isteğinin bir parçası olarak istemci tarafından gönderilmesi gerekir.

\nOAuth2 API'sine yapılan istekler için yollar:
\n< ul>\n
  • Yetkilendirme bitiş noktası: /oauth/authorize
  • \n
  • Token bitiş noktası: /oauth/token\n
  • Kaynak sayfası: /oauth/profile
  • \n\nİstemci sırrının yeniden oluşturulması, mevcut yetkilendirme kodlarının süresinin dolmasına neden olmaz, ancak belirteçlerini yenileyemezler.

    \nİstemci belirteçlerini iptal etmek, tüm etkin oturumların derhal sonlandırılmasına neden olur. Tüm istemcilerin yeniden kimlik doğrulaması yapması gerekir.", + "license_info": "Lisans gerekli değildir ancak daha fazla geliştirmeye yardımcı olur.
    GUID'inizi buraya kaydedin. or Mailcow kurulumunuz için destek satın alın.", + "no_record": "Kayıt yok", + "oauth2_apps": "OAuth2 Uygulamaları", + "oauth2_add_client": "OAuth2 client ekle", + "oauth2_client_id": "Client ID", + "optional": "isteğe bağlı", + "oauth2_redirect_uri": "URI Yönlendirmesi", + "oauth2_renew_secret": "Yeni client anahtarı oluştur", + "oauth2_revoke_tokens": "Tüm client tokenlarını iptal et", + "quarantine": "Karantina", + "options": "Seçenekler", + "password": "Şifre", + "password_length": "Parola uzunluğu", + "password_policy": "Şifre politikası", + "password_policy_chars": "En az bir alfabetik karakter içermelidir", + "password_policy_length": "Minimum parola uzunluğu %d'dir", + "password_policy_lowerupper": "Küçük ve büyük harf karakterleri içermelidir", + "password_policy_numbers": "En az bir sayı içermelidir", + "password_policy_special_chars": "Özel karakterler içermelidir", + "password_repeat": "Onay şifresi (tekrar)", + "priority": "Öncelik", + "private_key": "Özel anahtar", + "quarantine_bcc": "Tüm bildirimlerin bir kopyasını (BCC) bu alıcıya gönderin:
    Devre dışı bırakmak için boş bırakın. İmzasız, işaretlenmemiş posta. Yalnızca dahili olarak teslim edilmelidir.", + "quarantine_exclude_domains": "Alan adlarını ve diğer alan adlarını hariç tut", + "quarantine_max_age": "Gün cinsinden maksimum yaş
    Değer 1 güne eşit veya daha büyük olmalıdır.", + "quarantine_max_score": "Bir epostanın spam puanı bu değerden yüksekse bildirim at:
    Varsayılan değer 9999,0", + "quota_notifications_vars": "{{percent}}, kullanıcının mevcut kotasına eşittir
    {{username}} posta kutusu adıdır", + "quarantine_max_size": "MiB cinsinden maksimum boyut (daha büyük öğeler atılır):
    0 sınırsız olduğunu değil göstermez.", + "quarantine_notification_html": "Bildirim e-posta şablonu:
    Varsayılan şablonu geri yüklemek için boş bırakın.", + "quarantine_notification_sender": "Bildirim e-postası gönderen", + "quarantine_notification_subject": "Bildirim e-postası konusu", + "quarantine_redirect": "Tüm bildirimleri bu alıcıya yönlendir:
    Devre dışı bırakmak için boş bırakın. İmzasız, kontrol edilmemiş posta. Yalnızca dahili olarak teslim edilmelidir.", + "quarantine_release_format_att": "Ek olarak", + "quarantine_release_format_raw": "Değiştirilmemiş orijinal", + "quarantine_retention_size": "Posta kutusu başına tutma sayısı:
    0, etkin değil anlamına gelir.", + "quota_notification_html": "Bildirim e-posta şablonu:
    Varsayılan şablonu geri yüklemek için boş bırakın.", + "quota_notification_sender": "Bildirim e-postası gönderen", + "quota_notification_subject": "Bildirim e-postası konusu", + "quota_notifications": "Kota bildirimleri", + "quota_notifications_info": "Kota bildirimleri, kullanıcılara %80'i geçtiğinde ve %95'i geçtiğinde bir kez gönderilir.", + "queue_unban": "Kuyruk yasağını kaldır", + "r_active": "Aktif kısıtlamalar", + "r_inactive": "Pasif kısıtlamalar", + "r_info": "Etkin kısıtlamalar listesindeki grileştirilmiş/devre dışı bırakılmış öğeler, posta kutusu için geçerli kısıtlamalar olarak bilinmez ve taşınamaz. Bilinmeyen kısıtlamalar yine de görünüm sırasına göre ayarlanacaktır.
    Onları değiştirebilmek için inc/vars.local.inc.php içine yeni öğeler ekleyebilirsiniz.", + "rate_name": "Puan adı", + "recipients": "Alıcılar", + "refresh": "Yenile", + "regen_api_key": "API anahtarını yeniden oluştur", + "regex_maps": "Regex haritaları", + "relay_from": "\"Kimden:\" adresi", + "relay_rcpt": "\"Kime:\" adresi", + "relay_run": "Test çalıştır", + "relayhosts": "Gönderene bağlı aktarımlar", + "relayhosts_hint": "Etki alanı yapılandırma iletişim kutusunda seçebilmek için gönderene bağlı aktarımları tanımlayın.
    \nAktarım hizmeti her zaman \"smtp:\" şeklindedir ve bu nedenle teklif edildiğinde TLS'yi deneyecektir. Sarılmış TLS (SMTPS) desteklenmez. Kullanıcıların bireysel giden TLS politikası ayarı dikkate alınır.\n
    Takma ad alanları da dahil olmak üzere seçili alan adlarını etkiler.", + "rspamd_global_filters_regex": "İsimleri amaçlarını açıklıyor. Tüm içerik, \"/pattern/options\" biçiminde geçerli normal ifade içermelidir (ör. /.+@domain\\.tld/i).
    \n İlkel olmasına rağmen kontroller regex'in her satırında yürütülüyor, sözdizimini doğru okuyamazsa Rspamds işlevi bozulabilir.
    \nRspamd değiştirildiğinde harita içeriğini okumaya çalışır. Sorun yaşarsanız, Rspamd'yi yeniden başlatın bir haritanın yeniden yüklenmesini zorunlu kılmak için.
    Kara listeye alınan öğeler karantinadan hariç tutulur.", + "transport_dest_format": "Regex veya sözdizimi: example.org, .example.org, *, box@example.org (birden çok değer virgülle ayrılabilir)", + "transports_hint": "• Bir aktarım haritası girişi, gönderene bağlı bir aktarım haritasını geçersiz kılar.
    \n• Tercihen MX tabanlı aktarımlar kullanılır.
    \n• Kullanıcı başına giden TLS ilke ayarları yoksayılır ve yalnızca TLS ilke eşleme girişleri tarafından zorunlu kılınabilir.
    \n• Tanımlanmış taşımalar için taşıma hizmeti her zaman \"smtp:\" şeklindedir ve bu nedenle teklif edildiğinde TLS'yi deneyecektir. Sarılmış TLS (SMTPS) desteklenmez.
    \n• \"/localhost$/\" ile eşleşen adresler her zaman \"local:\" yoluyla taşınır, bu nedenle bu adresler için bir \"*\" hedefi uygulanmaz.
    \n• Örnek bir sonraki sıçrama \"[host]:25\" için kimlik bilgilerini belirlemek için, Postfix her zaman \"[host]:25\" için arama yapmadan önce \"host\" için sorgular. Bu davranış, aynı anda \"host\" ve \"[host]:25\" kullanımını imkansız hale getirir.", + "search_domain_da": "Alan adlarını ara", + "send": "Gönder", + "rspamd_com_settings": "Bir ayar adı otomatik olarak oluşturulacaktır, lütfen aşağıdaki örnek ön ayarlara bakın. Daha fazla ayrıntı için Rspamd belgelerine bakın", + "rspamd_global_filters": "Küresel filtre haritaları", + "rspamd_global_filters_agree": "Dikkatli olacağım!", + "ui_header_announcement_type_warning": "Önemli", + "rsetting_desc": "Kısa tanım", + "rsetting_no_selection": "Lütfen bir kural seçin", + "rsetting_none": "Kullanılabilir kural yok", + "rsettings_insert_preset": "Örnek hazır ayar ekle \"%s\"", + "rsettings_preset_1": "Kimliği doğrulanmış kullanıcılar için DKIM ve hız sınırı hariç tümünü devre dışı bırakın", + "rsettings_preset_2": "Posta yöneticileri spam istiyor", + "rsettings_preset_3": "Bir posta kutusu için yalnızca belirli gönderenlere izin ver (yani yalnızca dahili posta kutusu olarak kullanım)", + "rsettings_preset_4": "Bir etki alanı için Rspamd'yi devre dışı bırakın", + "rspamd_global_filters_info": "Küresel filtre haritaları, farklı türde küresel kara ve beyaz listeler içerir.", + "rspamd_settings_map": "Rspamd ayarları haritası", + "sal_level": "Moo seviye", + "save": "Değişiklikleri kaydet", + "sender": "Gönderen", + "service": "Servis", + "service_id": "Servis ID", + "source": "Kaynak", + "spamfilter": "Spam filtresi", + "subject": "Konu", + "success": "Başarılı", + "sys_mails": "Sistem postaları", + "text": "Metin", + "time": "Zaman", + "title": "Başlık", + "title_name": "\"mailcow UI\" web sitesi başlığı", + "to_top": "Başa dön", + "transport_maps": "Ulaşım Haritaları", + "transport_test_rcpt_info": "• Yabancı bir hedefe geçişi test etmek için null@hosted.mailcow.de adresini kullanın.", + "ui_footer": "Altbilgi (HTML'ye izin verilir)", + "ui_header_announcement": "Duyurular", + "ui_header_announcement_active": "Duyuruyu etkin olarak ayarla", + "ui_header_announcement_content": "Metin (HTML'ye izin verilir)", + "ui_header_announcement_help": "Duyuru, oturum açmış tüm kullanıcılar tarafından ve kullanıcı arayüzünün oturum açma ekranında görülebilir.", + "ui_header_announcement_select": "Duyuru türünü seçin", + "ui_header_announcement_type_danger": "Çok önemli", + "ui_header_announcement_type_info": "Bilgi", + "ui_texts": "UI etiketleri ve metinleri", + "unban_pending": "Beklemede olan yasağı kaldır", + "unchanged_if_empty": "Değişmediyse boş bırakın", + "upload": "Yükle", + "username": "Kullanıcı adı", + "validate_license_now": "GUID'yi lisans sunucusuna göre doğrulayın", + "verify": "Doğrulayın", + "yes": "✓", + "ui_header_announcement_type": "Türü", + "remove": "Kaldır", + "remove_row": "Satırı kaldır", + "reset_default": "Öntanımlı değerlere dön", + "reset_limit": "Hashi kaldır", + "routing": "Yönlendirme", + "rsetting_add_rule": "Kural ekle", + "rsetting_content": "Kural içeriği" }, "warning": { "cannot_delete_self": "Cannot delete logged in user", @@ -147,5 +364,944 @@ "quota_exceeded_scope": "Domain kotası aşıldı: Bu domain kapsamında yalnızca sınırsız e-posta oluşturulabilir!", "session_token": "Form token geçersiz: Token uyuşmadı", "session_ua": "Form token geçersiz: User-Agent doğrulama hatası" + }, + "datatables": { + "decimal": ".", + "info": "TOPLAM_ girişlerin _BAŞLANGIÇ_ ile _SON_ arası gösteriliyor", + "paginate": { + "first": "İlk", + "last": "Son", + "next": "Sonraki", + "previous": "Önceki" + }, + "aria": { + "sortAscending": ": sütunu artan sıralama için etkinleştir", + "sortDescending": ": sütunu azalan şekilde sıralama için etkinleştirin" + }, + "thousands": ",", + "collapse_all": "Tümünü Daralt", + "emptyTable": "Tabloda veri mevcut değil", + "expand_all": "Tümünü Genişlet", + "infoEmpty": "0 girişten 0 ila 0 arası gösteriliyor", + "infoFiltered": "(_MAX_ toplam girişlerden filtrelendi)", + "lengthMenu": "_MENU_ girişlerini göster", + "loadingRecords": "Yükleniyor...", + "processing": "Lütfen bekleyin...", + "search": "Ara:", + "zeroRecords": "Eşleşen kayıt bulunamadı" + }, + "edit": { + "inactive": "Pasif", + "mailbox": "Posta kutusunu düzenle", + "mailbox_quota_def": "Varsayılan posta kutusu kotası", + "mailbox_relayhost_info": "Yalnızca posta kutusuna ve doğrudan takma adlara uygulanır, etki alanı geçiş ana bilgisayarını geçersiz kılar.", + "max_aliases": "Maks. takma adlar", + "max_mailboxes": "Maks. olası posta kutuları", + "max_quota": "Maks. posta kutusu başına kota (MiB)", + "extended_sender_acl_info": "Varsa, bir DKIM etki alanı anahtarı içe aktarılmalıdır.
    \\r\\n Bu sunucuyu karşılık gelen SPF TXT kaydına eklemeyi unutmayın.
    \\r\\n Bu sunucuya bir etki alanı veya takma ad etki alanı eklendiğinde, harici bir adresle çakışırsa, harici adres kaldırılır.
    \\r\\n *@domain.tld olarak göndermeye izin vermek için @domain.tld kullanın.", + "footer_exclude": "Footerdan hariç tut", + "last_modified": "Son değişiklik", + "lookup_mx": "Hedef, MX adıyla eşleşecek normal bir ifadedir (google.com ile biten bir MX'e hedeflenen tüm postaları bu atlama üzerinden yönlendirmek için .*google\\\\.com)", + "sogo_access_info": "Posta kullanıcı arayüzünden tek oturum açma çalışmaya devam eder. Bu ayar, diğer tüm hizmetlere erişimi etkilemez veya bir kullanıcının mevcut SOGo profilini silmez veya değiştirmez.", + "comment_info": "Gizli bir yorum kullanıcı tarafından görülmezken, genel bir yorum, kullanıcının genel bakışında üzerine gelindiğinde araç ipucu olarak gösterilir.", + "sender_acl_info": "Posta kutusu A kullanıcısının posta kutusu kullanıcısı B olarak göndermesine izin veriliyorsa, gönderen adresi SOGo'da seçilebilir \\\"gönderen\\\" alanı olarak otomatik olarak görüntülenmez.
    \\r\\n Posta kutusu B kullanıcısının izin vermesi için SOGo'da bir yetkilendirme oluşturması gerekir. posta kutusu kullanıcısı A, adresini gönderen olarak seçmek için. SOGo'da bir posta kutusuna yetki vermek için, posta görünümündeyken sol üstteki posta kutusu adınızın sağındaki menüyü (üç nokta) kullanın. Bu davranış, diğer ad adresleri için geçerli değildir.", + "sogo_visible_info": "Bu seçenek yalnızca SOGo'da görüntülenebilen nesneleri etkiler (en az bir yerel posta kutusuna işaret eden paylaşılan veya paylaşılmayan diğer ad adresleri). Gizliyse, bir takma ad SOGo'da seçilebilir gönderici olarak görünmez.", + "kind": "Nitelik", + "maxage": "Uzaktan sorgulanacak mesajların gün cinsinden maksimum ileti yaşı
    (0 = yaşı yoksay)", + "maxbytespersecond": "Maks. saniye başına bayt
    (0 = sınırsız)", + "redirect_uri": "Yönlendirme URI'i", + "relay_all": "Tüm alıcıları aktar", + "domain_footer_skip_replies": "Yanıt postasındaki altbilgiyi yoksay", + "exclude": "Nesneleri hariç tut (normal ifade)", + "extended_sender_acl": "Harici gönderen adresleri", + "force_pw_update": "Bir sonraki girişte şifre güncellemesini zorla", + "password": "Şifre", + "password_repeat": "Onay şifresi (tekrar)", + "private_comment": "Özel yorum", + "public_comment": "Genel yorum", + "pushover": "Pushover", + "pushover_evaluate_x_prio": "Yüksek öncelikli postayı iletin [X-Priority: 1]", + "pushover_info": "Anında iletme bildirimi ayarları, takma adlar (paylaşılan, paylaşılmayan, etiketli) dahil %s adresine teslim edilen tüm temiz (spam olmayan) postalara uygulanacaktır.", + "pushover_sender_array": "Yalnızca aşağıdaki gönderen e-posta adreslerini göz önünde bulundurun (virgülle ayrılmış)", + "scope": "Kapsam", + "skipcrossduplicates": "Klasörler arasında yinelenen mesajları atlayın (ilk gelen, ilk hizmet)", + "sogo_visible": "Takma ad SOGo'da görünür", + "relay_unknown_only": "Yalnızca var olmayan posta kutularını aktarın. Mevcut posta kutuları yerel olarak teslim edilecektir.", + "relayhost": "Göndericiye bağlı aktarımlar", + "remove": "Kaldır", + "resource": "Kaynak", + "save": "Değişiklikleri Kaydet", + "spam_policy": "Beyaz/kara listeye öğe ekleyin veya kaldırın", + "spam_score": "Özel bir spam puanı ayarlayın", + "subfolder2": "Hedefteki alt klasörle senkronize et
    (boş = alt klasörü kullanmayın)", + "syncjob": "Senkronizasyon işini düzenle", + "target_address": "Adrese git (virgülle ayrılmış)", + "target_domain": "Hedef alan", + "timeout1": "Uzak ana bilgisayara bağlantı için zaman aşımı", + "timeout2": "Yerel ana bilgisayara bağlantı için zaman aşımı", + "unchanged_if_empty": "Değişmediyse boş bırakın", + "username": "Kullanıcı adı", + "validate_save": "Doğrula ve kaydet", + "acl": "ACL (İzin)", + "active": "Aktif", + "admin": "Yöneticiyi düzenle", + "advanced_settings": "Gelişmiş ayarlar", + "alias": "Takma adı düzenle", + "generate": "oluştur", + "previous": "Önceki sayfa", + "domain_footer_info_vars": { + "from_addr": "Mail adresindeki adres kısmını verir", + "from_domain": "Mail adresindeki alan adını verir", + "custom": "Posta kutusu \\\"foo\\\" özelliğine ve \\\"bar\\\" değerine sahipse, \\\"bar\\\" döndürür\"", + "from_name": "Mail adresindeki gönderen alanını verir. Örn: Bilgi islem bilgiislem@canakkale.bel.tr nin Bilgi islem kısmını verir.", + "auth_user": "MTA tarafından belirtilen doğrulanmış kullanıcı adı", + "from_user": "Mail adresindeki kullanıcı adını alanını verir. Örn: bilgiislem@canakkale.bel.tr nin bilgiislem kısmını verir." + }, + "custom_attributes": "Kullanıcı tanımlı özellikler", + "delete_ays": "Lütfen silme işlemini onaylayın.", + "description": "Açıklama", + "pushover_only_x_prio": "Yalnızca yüksek öncelikli postayı dikkate alın [X-Priority: 1]", + "delete2duplicates": "Hedefteki kopyaları sil", + "domain_footer": "Domain footer", + "domain_footer_html": "HTML footer", + "edit_alias_domain": "Takma ad alanını düzenle", + "encryption": "Şifreleme", + "domain_footer_info": "Bu alan adındaki bir adresle ilişkili tüm giden e-postalara domain-wide footer eklenir. Footer için aşağıdaki değişkenler kullanılabilir :", + "domains": "Alan adları", + "dont_check_sender_acl": "%s etki alanı için gönderen kontrolünü devre dışı bırakın (+ takma ad etki alanları)", + "sieve_desc": "Kısa tanım", + "sieve_type": "Filtre türü", + "sender_acl": "olarak göndermeye izin ver", + "sender_acl_disabled": "Gönderen denetimi devre dışı", + "allow_from_smtp": "Yalnızca bu IP'lerin SMTP kullanmasına izin verin", + "allow_from_smtp_info": "Tüm gönderenlere izin vermek için boş bırakın.
    IPv4/IPv6 adresleri ve ağları.", + "allowed_protocols": "İzin verilen protokoller", + "app_name": "Uygulama adı", + "app_passwd": "Uygulama şifresi", + "app_passwd_protocols": "Uygulama şifresi için izin verilen protokoller", + "automap": "Klasörleri otomatik eşlemeyi deneyin (\\\"Gönderilmiş öğeler\\\", \\\"Gönderildi\\\" => \\\"Gönderildi\\\" vb.)", + "backup_mx_options": "Relay seçenekleri", + "bcc_dest_format": "BCC, tek bir geçerli e-posta adresi olmalıdır.
    Bir kopyayı birden fazla adrese göndermeniz gerekiyorsa, bir takma ad oluşturun ve burada kullanın.", + "client_id": "Müşteri Kimliği", + "client_secret": "Müşteri sırrı", + "created_on": "Oluşturuldu", + "delete1": "Tamamlandığında kaynaktan silin", + "delete2": "Kaynakta olmayan hedefteki mesajları sil", + "domain_footer_plain": "PLAIN footer", + "multiple_bookings": "Çoklu rezervasyon", + "none_inherit": "Yok / Miras", + "nexthop": "Sonraki atlama", + "pushover_sender_regex": "Aşağıdaki gönderen regexini göz önünde bulundurun", + "pushover_text": "Bildirim metni", + "force_pw_update_info": "Bu kullanıcı yalnızca %s'de oturum açabilecek. Uygulama şifreleri kullanılabilir durumda kalır.", + "full_name": "Ad Soyad", + "gal": "Genel Adres Listesi", + "gal_info": "GAL, bir etki alanının tüm nesnelerini içerir ve herhangi bir kullanıcı tarafından düzenlenemez. Devre dışı bırakılmışsa, SOGo'da serbest/meşgul bilgisi eksik! Değişiklikleri uygulamak için SOGo'yu yeniden başlatın.", + "grant_types": "Yetki türleri", + "hostname": "Ana bilgisayar adı", + "mbox_rl_info": "Bu hız sınırı SASL oturum açma adına uygulanır, oturum açmış kullanıcı tarafından kullanılan herhangi bir \\\"gönderen\\\" adresiyle eşleşir. Posta kutusu hız sınırı, alan genelindeki hız sınırını geçersiz kılar.", + "mins_interval": "Aralık(dakika)", + "pushover_title": "Bildirim başlığı", + "pushover_sound": "Ses", + "pushover_vars": "Gönderici filtresi tanımlanmadığında, tüm postalar dikkate alınacaktır.
    Regex filtreleri ve tam gönderen kontrolleri ayrı ayrı tanımlanabilir ve sıralı olarak değerlendirilecektir. Birbirlerine bağlı değildirler.
    Metin ve başlık için kullanılabilir değişkenler (lütfen veri koruma politikalarını dikkate alın)", + "pushover_verify": "Kimlik bilgilerini doğrulayın", + "quota_warning_bcc": "Kota uyarısı BCC", + "quota_warning_bcc_info": "Uyarılar, aşağıdaki alıcılara ayrı kopyalar halinde gönderilecektir. Konunun sonuna parantez içinde karşılık gelen kullanıcı adı eklenecektir, örneğin: Kota uyarısı (user@example.com).", + "ratelimit": "Hız sınırı", + "relay_all_info": "↪ Tüm alıcıları geçirmek için değil seçerseniz, aktarılması gereken her alıcı için bir (\\\"kör\\\") posta kutusu eklemeniz gerekir.", + "relay_domain": "Bu etki alanını aktar", + "relay_transport_info": "
    Bilgi
    Bu etki alanı için özel bir hedef için taşıma haritaları tanımlayabilirsiniz. Ayarlanmazsa, bir MX araması yapılır.", + "sogo_access": "SOGo'ya doğrudan giriş erişimi verin", + "spam_alias": "Zaman sınırlı takma ad adresleri oluşturun veya değiştirin", + "spam_filter": "Spam filtresi", + "disable_login": "Oturum açmaya izin verme (gelen posta hala kabul edilir)", + "domain": "Etki alanını düzenle", + "domain_admin": "Etki alanı yöneticisini düzenle", + "domain_quota": "Etki alanı kotası", + "quota_mb": "Kota (MiB)", + "title": "Nesneyi düzenle" + }, + "diagnostics": { + "dns_records_docs": "Lütfen ayrıca belgelere bakın.", + "cname_from_a": "A/AAAA kaydından elde edilen değer. Bu, kayıt doğru kaynağa işaret ettiği sürece desteklenir.", + "dns_records_24hours": "DNS'de yapılan değişikliklerin mevcut durumlarının bu sayfaya doğru bir şekilde yansıtılmasının 24 saat kadar sürebileceğini lütfen unutmayın. DNS kayıtlarınızı nasıl yapılandıracağınızı kolayca görebilmeniz ve tüm kayıtlarınızın DNS'de doğru şekilde depolanıp depolanmadığını kontrol edebilmeniz için tasarlanmıştır.", + "optional": "Bu kayıt isteğe bağlıdır.", + "dns_records_data": "Doğru veri", + "dns_records_name": "İsim", + "dns_records_status": "Mevcut Durum", + "dns_records_type": "Tür", + "dns_records": "DNS Kayıtları" + }, + "danger": { + "is_alias_or_mailbox": "%s zaten takma ad, posta kutusu veya takma ad etki alanından genişletilmiş bir takma ad adresi olarak biliniyor.", + "pushover_credentials_missing": "Pushover belirteci ve / veya anahtarı eksik", + "quota_not_0_not_numeric": "Kota sayısal ve >= 0 olmalıdır", + "extended_sender_acl_denied": "harici gönderen adreslerini ayarlamak için eksik ACL", + "invalid_destination": "Hedef biçimi \\\"%s\\\" geçersiz", + "mailbox_quota_left_exceeded": "Yeterli alan kalmadı (boş alan: %d MiB)", + "value_missing": "Lütfen tüm değerleri sağlayın", + "img_dimensions_exceeded": "Görüntü maksimum resim boyutunu aşıyor", + "max_quota_in_use": "Posta kutusu kotası %d MiB'den büyük veya buna eşit olmalıdır", + "object_exists": "%s nesnesi zaten var", + "webauthn_verification_failed": "WebAuthn doğrulaması başarısız oldu: %s", + "invalid_nexthop_authenticated": "Sonraki atlama, farklı kimlik bilgileriyle var, lütfen önce bu sonraki atlama için mevcut kimlik bilgilerini güncelleyin.", + "alias_domain_invalid": "%s takma ad alanı geçersiz", + "aliases_in_use": "Maks. takma adlar %d'den büyük veya eşit olmalıdır", + "app_name_empty": "Uygulama adı boş olamaz", + "app_passwd_id_invalid": "Uygulama şifresi kimliği %s geçersiz", + "bcc_empty": "BCC hedefi boş olamaz", + "alias_empty": "Takma ad adresi boş bırakılamaz", + "alias_goto_identical": "Takma ad ve varış adresi aynı olmamalıdır", + "alias_invalid": "%s takma ad adresi geçersiz", + "aliasd_targetd_identical": "Takma ad etki alanı, hedef etki alanına eşit olmamalıdır: %s", + "cors_invalid_method": "Geçersiz Allow-Method belirtildi", + "cors_invalid_origin": "Geçersiz Allow-Origin belirtildi", + "defquota_empty": "Posta kutusu başına varsayılan kota 0 olmamalıdır.", + "from_invalid": "Gönderen boş olmamalıdır", + "global_filter_write_error": "Filtre dosyası yazılamadı: %s", + "global_map_invalid": "Küresel harita kimliği %s geçersiz", + "maxquota_empty": "Maks. posta kutusu başına kota 0 olmamalıdır.", + "mysql_error": "MySQL hatası: %s", + "webauthn_authenticator_failed": "Seçilen kimlik doğrulayıcı bulunamadı.", + "webauthn_publickey_failed": "Seçilen kimlik doğrulayıcı için ortak anahtar saklanmadı", + "webauthn_username_failed": "Seçilen kimlik doğrulayıcı başka bir hesaba ait", + "global_map_write_error": "%s global harita kimliği yazılamadı: %s", + "access_denied": "Erişim reddedildi veya geçersiz form verisi", + "bcc_exists": "%s türü için %s BCC haritası var", + "bcc_must_be_email": "BCC %s geçerli bir e-posta adresi değil", + "comment_too_long": "Yorum çok uzun, maksimum 160 karaktere izin verilir", + "demo_mode_enabled": "Demo Mod açık", + "description_invalid": "%s için kaynak açıklaması geçersiz", + "dkim_domain_or_sel_exists": "\\\"%s\\\" için bir DKIM anahtarı var ve üzerine yazılmayacak", + "dkim_domain_or_sel_invalid": "DKIM etki alanı veya seçici geçersiz: %s", + "domain_cannot_match_hostname": "Alan, ana bilgisayar adıyla eşleşemez", + "domain_exists": "%s alanı zaten var", + "domain_invalid": "Alan adı boş veya geçersiz", + "domain_not_empty": "Boş olmayan alan adı %s kaldırılamıyor", + "domain_not_found": "%s alanı bulunamadı", + "domain_quota_m_in_use": "Etki alanı kotası %s MiB'den büyük veya buna eşit olmalıdır", + "extra_acl_invalid": "Harici gönderen adresi \\\"%s\\\" geçersiz", + "extra_acl_invalid_domain": "Harici gönderici \\\"%s\\\" geçersiz bir etki alanı kullanıyor", + "fido2_verification_failed": "FIDO2 doğrulaması başarısız oldu: %s", + "file_open_error": "Dosya yazmak için açılamıyor", + "filter_type": "Yanlış filtre türü", + "goto_empty": "Bir takma ad adresi, en az bir geçerli git adresi içermelidir", + "goto_invalid": "%s adresine git geçersiz", + "ham_learn_error": "Öğrenme hatası: %s", + "imagick_exception": "Hata: Görüntü okunurken Imagick istisnası", + "img_invalid": "Resim dosyası doğrulanamıyor", + "img_tmp_missing": "Resim dosyası doğrulanamıyor: Geçici dosya bulunamadı", + "password_complexity": "Şifre politikaya uygun değil", + "policy_list_from_exists": "Verilen ada sahip bir kayıt var", + "img_size_exceeded": "Görüntü maksimum dosya boyutunu aşıyor", + "invalid_bcc_map_type": "Geçersiz BCC harita türü", + "invalid_filter_type": "Geçersiz filtre türü", + "invalid_host": "Geçersiz ana bilgisayar belirtildi: %s", + "invalid_mime_type": "Geçersiz mime türü", + "invalid_nexthop": "Sonraki atlama biçimi geçersiz", + "invalid_recipient_map_new": "Geçersiz yeni alıcı belirtildi: %s", + "invalid_recipient_map_old": "Geçersiz orijinal alıcı belirtildi: %s", + "ip_list_empty": "İzin verilen IP'lerin listesi boş olamaz", + "is_alias": "%s zaten bir takma ad adresi olarak biliniyor", + "is_spam_alias": "%s zaten geçici bir takma ad adresi olarak biliniyor (spam takma ad adresi)", + "last_key": "Son anahtar silinemez, lütfen bunun yerine TFA'yı devre dışı bırakın.", + "login_failed": "Giriş başarısız", + "mailbox_defquota_exceeds_mailbox_maxquota": "Varsayılan kota, maksimum kota sınırını aşıyor", + "mailbox_invalid": "Posta kutusu adı geçersiz", + "mailbox_quota_exceeded": "Kota, alan sınırını aşıyor (maks. %d MiB)", + "mailbox_quota_exceeds_domain_quota": "Maks. kota, alan kota sınırını aşıyor", + "mailboxes_in_use": "Maks. posta kutuları %d'den büyük veya eşit olmalıdır", + "malformed_username": "Hatalı biçimlendirilmiş kullanıcı adı", + "map_content_empty": "Harita içeriği boş olamaz", + "max_alias_exceeded": "Maks. takma adlar aşıldı", + "max_mailbox_exceeded": "Maks. posta kutuları aşıldı (%d / %d)", + "network_host_invalid": "Geçersiz ağ veya ana bilgisayar: %s", + "next_hop_interferes": "%s, nexthop %s ile çakışıyor", + "next_hop_interferes_any": "Mevcut bir sonraki atlama %s ile çakışıyor", + "nginx_reload_failed": "Nginx yeniden yükleme başarısız oldu: %s", + "no_user_defined": "Kullanıcı tanımlı değil", + "object_is_not_numeric": "%s değeri sayısal değil", + "password_empty": "Şifre boş olmamalıdır", + "password_mismatch": "Onay şifresi eşleşmiyor", + "policy_list_from_invalid": "Kayıt geçersiz biçime sahip", + "private_key_error": "Özel anahtar hatası: %s", + "pushover_key": "Pushover anahtarı yanlış formatta", + "pushover_token": "Pushover token yanlış formatta", + "recipient_map_entry_exists": "Alıcı haritası girişi \\\"%s\\\" var", + "redis_error": "Redis hatası: %s", + "relayhost_invalid": "%s harita girişi geçersiz", + "template_exists": "%s isimli şablon zaten mevcut", + "template_id_invalid": "Şablon kimliği %s geçersiz", + "text_empty": "Metin boş olmamalıdır", + "unknown": "Bilinmeyen bir hata oluştu", + "unknown_tfa_method": "Bilinmeyen TFA yöntemi", + "unlimited_quota_acl": "ACL tarafından yasaklanan sınırsız kota", + "username_invalid": "Kullanıcı adı %s kullanılamaz", + "validity_missing": "Lütfen bir geçerlilik süresi atayın", + "yotp_verification_failed": "Yubico OTP doğrulaması başarısız oldu: %s", + "rspamd_ui_pw_length": "Rspamd UI şifresi en az 6 karakter uzunluğunda olmalıdır", + "tfa_token_invalid": "Hatalı TFA belirteci", + "release_send_failed": "Mesaj bırakılamadı: %s", + "reset_f2b_regex": "Regex filtresi zamanında sıfırlanamadı, lütfen tekrar deneyin veya birkaç saniye daha bekleyin ve web sitesini yeniden yükleyin.", + "resource_invalid": "%s kaynak adı geçersiz", + "rl_timeframe": "Hız sınırı zaman çerçevesi yanlış", + "script_empty": "Komut dosyası boş olamaz", + "sender_acl_invalid": "Gönderen ACL değeri %s geçersiz", + "set_acl_failed": "ACL ayarlanamadı", + "settings_map_invalid": "Ayarlar haritası kimliği %s geçersiz", + "sieve_error": "Elek ayrıştırıcı hatası: %s", + "spam_learn_error": "Spam öğrenme hatası: %s", + "subject_empty": "Konu boş olmamalıdır", + "target_domain_invalid": "Hedef alan %s geçersiz", + "targetd_not_found": "Hedef alan %s bulunamadı", + "targetd_relay_domain": "Hedef etki alanı %s bir geçiş etki alanıdır", + "template_name_invalid": "Şablon adı geçersiz", + "temp_error": "Geçici hata", + "tls_policy_map_dest_invalid": "Politika hedefi geçersiz", + "tls_policy_map_entry_exists": "Bir TLS ilke haritası girişi \\\"%s\\\" mevcut", + "tls_policy_map_parameter_invalid": "Politika parametresi geçersiz", + "totp_verification_failed": "TOTP doğrulaması başarısız oldu", + "transport_dest_exists": "\\\"%s\\\" aktarım hedefi mevcut" + }, + "debug": { + "container_disabled": "Container durduruldu veya devre dışı bırakıldı", + "last_modified": "Son değişiklik", + "log_info": "

    mailcow bellek içi günlükler, Redis listelerinde toplanır ve çekiçlemeyi azaltmak için her dakika LOG_LINES (%d) olacak şekilde kırpılır.\\r\\n
    Bellek içi günlükler ısrarcı. Bellekte oturum açan tüm uygulamalar, ayrıca Docker arka plan programında ve dolayısıyla varsayılan günlük sürücüsünde oturum açar.\\r\\n
    Bellek içi günlük türü, kapsayıcılarla ilgili küçük sorunları ayıklamak için kullanılmalıdır.

    \\r\\n

    Harici günlükler, verilen uygulamanın API'si aracılığıyla toplanır.

    \\r\\n

    Statik günlükler çoğunlukla etkinlik günlükleridir. Dockerd'da günlüğe kaydedilmez ancak yine de kalıcı olmaları gerekir (API günlükleri hariç).

    ", + "architecture": "Mimari", + "chart_this_server": "Grafik (bu sunucu)", + "containers_info": "Kapsayıcı bilgileri", + "container_running": "Çalıştırılıyor...", + "login_time": "Zaman", + "logs": "Loglar", + "static_logs": "Statik günlükler", + "success": "Başarılı", + "started_on": "Başladı", + "update_available": "Mevcut bir güncelleme var", + "container_stopped": "Durduruldu", + "cores": "Çekirdekler", + "current_time": "Sistem Zamanı", + "disk_usage": "Disk kullanımı", + "error_show_ip": "Genel IP adresleri çözümlenemedi.", + "external_logs": "Harici günlükler", + "history_all_servers": "Geçmiş (tüm sunucular)", + "in_memory_logs": "Bellek içi günlükler", + "jvm_memory_solr": "JVM bellek kullanımı", + "memory": "Hafıza", + "online_users": "Aktif kullanıcılar", + "restart_container": "Yeniden başlat", + "service": "Servis", + "show_ip": "Genel IP'yi göster", + "size": "Boyut", + "solr_dead": "Solr başlatılıyor, devre dışı bırakıldı veya öldü.", + "solr_status": "Solr durumu", + "started_at": "Başlangıç", + "system_containers": "Sistem ve Konteynerler", + "timezone": "Zaman Dilimi", + "uptime": "Çalışma Süresi", + "no_update_available": "Sistem en son sürümde", + "update_failed": "Güncelleme olup olmadığı kontrol edilemedi", + "username": "Kullanıcı Adı", + "wip": "Şu Anda Çalışma Devam Ediyor", + "docs": "Dokümanlar" + }, + "mailbox": { + "domain_admins": "Etki alanı yöneticileri", + "insert_preset": "Örnek ön ayar \\\"%s\\\" ekle", + "mins_interval": "Aralık (dk)", + "bcc_info": "BCC haritaları, tüm mesajların kopyalarını başka bir adrese sessizce iletmek için kullanılır. Yerel hedef bir postanın alıcısı olarak hareket ettiğinde, bir alıcı eşleme türü girişi kullanılır. Gönderici haritaları aynı prensibe uygundur.
    \\r\\n Yerel hedef, başarısız bir teslimat hakkında bilgilendirilmez.", + "booking_custom": "Özel bir rezervasyon miktarıyla sabit sınırlama", + "force_pw_update": "Bir sonraki girişte parola güncellemesini zorunlu kıl", + "allow_from_smtp_info": "Tüm gönderenlere izin vermek için boş bırakın.
    IPv4/IPv6 adresleri ve ağları.", + "tls_policy_maps_enforced_tls": "Bu ilkeler, giden TLS bağlantılarını zorlayan posta kutusu kullanıcılarının davranışını da geçersiz kılar. Aşağıda herhangi bir politika yoksa, bu kullanıcılar smtp_tls_mandatory_protocols ve smtp_tls_mandatory_ciphers olarak belirtilen varsayılan değerleri uygular.", + "tls_map_parameters_info": "Boş veya parametreler, örneğin: protokoller=!SSLv2 şifreleri=orta hariç tutma=3DES", + "recipient_map": "Alıcı haritası", + "sieve_info": "Kullanıcı başına birden fazla filtre saklayabilirsiniz, ancak aynı anda yalnızca bir ön filtre ve bir son filtre etkin olabilir.
    \\r\\nHer filtre açıklanan sırayla işlenir. Ne başarısız bir komut dosyası ne de verilen bir \\\"keep;\\\", başka komut dosyalarının işlenmesini durdurmayacaktır. Global elek komut dosyalarında yapılan değişiklikler, Dovecot'un yeniden başlatılmasını tetikleyecektir.

    Global elek ön filtresi • Ön filtre • Kullanıcı komut dosyaları • Son filtre • Küresel elek son filtresi", + "syncjob_EXIT_AUTHENTICATION_FAILURE": "Kimlik doğrulama sorunu", + "tls_enforce_in": "TLS gelenini uygula", + "tls_policy_maps_info": "Bu politika haritası, bir kullanıcının TLS politika ayarlarından bağımsız olarak giden TLS aktarım kurallarını geçersiz kılar.
    \\r\\n Lütfen \\\"smtp_tls_policy_maps\\\" dokümanları.", + "remove": "Kaldır", + "resources": "Kaynaklar", + "running": "Çalıştırılıyor...", + "sender": "Gönderen", + "set_postfilter": "Son filtre olarak işaretle", + "set_prefilter": "Ön filtre olarak işaretle", + "add_domain": "Alan adı ekle", + "action": "İşlem", + "activate": "Etkinleştir", + "active": "Aktif", + "add": "Ekle", + "add_alias": "Takma ad ekle", + "add_alias_expand": "Diğer adları diğer ad etki alanları üzerinde genişletin", + "add_tls_policy_map": "TLS politika haritası ekle", + "address_rewriting": "Adresi yeniden yaz", + "alias": "Takma ad", + "alias_domain_alias_hint": "Takma adlar, alan takma adlarına otomatik olarak uygulanmaz. Bir takma ad adresi takma ad@etki alanım kapsamıyor takma ad@takma ad-domain adresini (burada \\\"takma ad-domain\\\" \\\"domain\\\" için hayali bir takma addır.
    Postaları harici bir posta kutusuna yönlendirmek için lütfen bir elek filtresi kullanın (\\\"Filtreler\\\" sekmesine bakın veya SOGo -> Yönlendiriciyi kullanın). Eksik takma adları otomatik olarak eklemek için \\\"Takma adı diğer ad alanları üzerinden genişlet\\\" seçeneğini kullanın.", + "booking_custom_short": "Kesin sınır", + "booking_ltnull": "Sınırsız, ancak rezervasyon yapıldığında meşgul olarak göster", + "catch_all": "Hepsini Yakala", + "created_on": "Oluşturuldu.", + "daily": "Günlük", + "deactivate": "Devre dışı bırak", + "mailbox": "Posta Kutusu", + "mailbox_defaults": "Varsayılan ayarlar", + "mailbox_defaults_info": "Yeni posta kutuları için varsayılan ayarları tanımlayın.", + "mailbox_defquota": "Varsayılan posta kutusu boyutu", + "mailbox_templates": "Mail Kutusu Şablonları", + "mailbox_quota": "Maks. posta kutusu boyutu", + "mailboxes": "Posta kutuları", + "public_comment": "Genel yorum", + "q_add_header": "önemsiz klasörüne taşındığında", + "q_all": " önemsiz klasörüne taşındığında ve reddedildiğinde", + "q_reject": "Red aşamasında", + "quarantine_category": "Karantina bildirim kategorisi", + "quarantine_notification": "Karantina bildirimleri", + "quick_actions": "İşlemler", + "stats": "İstatistikler", + "status": "Durum", + "tls_policy_maps_long": "Giden TLS politika haritası geçersiz kılmaları", + "toggle_all": "Tümünü değiştir", + "booking_lt0_short": "Esnek sınır", + "msg_num": "Mesaj #", + "spam_aliases": "Geçici takma ad", + "sieve_preset_2": "Her zaman belirli bir gönderenin e-postasını görüldüğü gibi işaretleyin", + "add_bcc_entry": "BCC haritası ekle", + "add_domain_alias": "Alan adı ekle", + "add_domain_record_first": "Lütfen önce bir alan adı ekleyin", + "add_filter": "Filtre ekle", + "add_mailbox": "Posta kutusu ekle", + "add_recipient_map_entry": "Alıcı haritası ekle", + "add_resource": "Kaynak ekle", + "add_template": "Şablon Ekle", + "alias_domain_backupmx": "Takma alan adı geçiş alanı için etkin değil", + "aliases": "Takma Adlar", + "all_domains": "Tüm Alan Adları", + "allow_from_smtp": "Yalnızca bu IP'lerin SMTP kullanmasına izin verin", + "allowed_protocols": "Doğrudan kullanıcı erişimi için izin verilen protokoller (uygulama parola protokollerini etkilemez)", + "backup_mx": "Geçiş alanı", + "bcc": "BCC", + "bcc_destination": "Gizli hedef", + "bcc_destinations": "Gizli hedef", + "bcc_local_dest": "Yerel hedef", + "bcc_map": "BCC haritası", + "bcc_map_type": "BCC türü", + "bcc_maps": "BCC haritaları", + "bcc_rcpt_map": "Alıcı haritası", + "bcc_sender_map": "Gönderen haritası", + "bcc_to_rcpt": "Alıcı harita türüne geç", + "bcc_to_sender": "Gönderici harita türüne geç", + "bcc_type": "BCC türü", + "booking_null": "Her zaman ücretsiz olarak göster", + "booking_0_short": "Her zaman ücretsiz", + "description": "Açıklama", + "disable_login": "Oturum açmaya izin verme (gelen posta hala kabul edilir)", + "disable_x": "Devre dışı bırak", + "dkim_domains_selector": "Seçici", + "dkim_key_length": "DKIM anahtar uzunluğu (bit)", + "domain": "Etki Alanı", + "domain_aliases": "Alan adı takma adları", + "domain_templates": "Etki Alanı Şablonları", + "domain_quota": "Kota", + "domain_quota_total": "Toplam alan kotası", + "domains": "Etki Alanları", + "edit": "Düzenle", + "empty": "Sonuç yok", + "enable_x": "Etkinleştir", + "excludes": "Hariç tutulanlar", + "filter_table": "Tabloyu filtrele", + "filters": "Filtreler", + "fname": "Tam adı", + "gal": "Genel Adres Listesi", + "goto_ham": "ham olarak öğrenin", + "goto_spam": "spam olarak öğrenin", + "hourly": "Saatlik", + "in_use": "Kullanılan (%)", + "inactive": "Pasif", + "kind": "Nitelik", + "last_mail_login": "Son posta girişi", + "last_modified": "Son değişiklik", + "last_pw_change": "Son şifre değişikliği", + "last_run": "Son çalıştırma", + "last_run_reset": "Sonrakini planla", + "max_aliases": "Max. kısayollar", + "max_mailboxes": "Max. mail kutuları", + "max_quota": "Mail kutusu başına max. kota", + "multiple_bookings": "Çoklu rezervasyonlar", + "never": "Hiçbir zaman", + "no": "✕", + "no_record": "%s nesnesi için kayıt yok", + "no_record_single": "Kayıt yok", + "open_logs": "Logları aç", + "owner": "Sahip", + "private_comment": "Özel yorum", + "recipient": "Alıcı", + "recipient_map_info": "Alıcı haritaları, teslim edilmeden önce bir mesajdaki hedef adresi değiştirmek için kullanılır.", + "recipient_map_new": "Yeni alıcı", + "recipient_map_old_info": "Bir alıcı eşleme orijinal hedefi, geçerli e-posta adresleri veya bir alan adı olmalıdır.", + "recipient_maps": "Alıcı haritaları", + "relay_all": "Tüm alıcıları ilet", + "relay_unknown": "Bilinmeyen posta kutularını aktar", + "sieve_preset_1": "Olası tehlikeli dosya türlerine sahip postaları atın", + "sieve_preset_3": "Sessizce atın, tüm diğer elek işlemlerini durdurun", + "sieve_preset_4": "INBOX'a dosyalayın, elek filtreleriyle daha fazla işlemi atlayın", + "sieve_preset_5": "Otomatik yanıtlayıcı (tatil)", + "sieve_preset_6": "Postayı reddedildi olarak yanıtla", + "sieve_preset_7": "Yönlendir ve sakla/bırak", + "sieve_preset_8": "Gönderenin parçası olduğu bir takma ad adresine gönderilen mesajı atın", + "sieve_preset_header": "Lütfen aşağıdaki örnek ön ayarlara bakın. Daha fazla ayrıntı için Wikipedia'ya bakın.", + "sogo_visible": "Takma ad SOGo'da görünür", + "sogo_visible_n": "SOGo'da takma adı gizle", + "sogo_visible_y": "SOGo'da takma adı göster", + "sync_jobs": "İşleri senkronize et", + "syncjob_check_log": "Günlüğü kontrol et", + "syncjob_last_run_result": "Son çalıştırma sonucu", + "syncjob_EX_OK": "Başarılı", + "syncjob_EXIT_CONNECTION_FAILURE": "Bağlantı sorunu", + "syncjob_EXIT_TLS_FAILURE": "Şifreli bağlantıyla ilgili sorun", + "syncjob_EXIT_OVERQUOTA": "Hedef posta kutusu kotayı aştı", + "syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Uzak sunucuya bağlanılamıyor", + "syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Yanlış kullanıcı adı veya şifre", + "table_size": "Tablo boyutu", + "table_size_show_n": "%s öğeleri göster", + "target_address": "Adrese git", + "target_domain": "Hedef alan", + "templates": "Şablonlar", + "template": "Şablon", + "tls_enforce_out": "TLS gidenini uygula", + "tls_map_dest_info": "Örnekler: example.org, .example.org, [mail.example.org]:25", + "tls_map_policy": "Politika", + "tls_policy_maps": "TLS politika haritaları", + "username": "Kullanıcı Adı", + "waiting": "Bekliyor...", + "weekly": "Haftalık", + "yes": "OK", + "recipient_map_new_info": "Alıcı harita hedefi geçerli bir e-posta adresi olmalıdır.", + "recipient_map_old": "Orijinal alıcı", + "tls_map_dest": "Hedef", + "tls_map_parameters": "Parametreler" + }, + "login": { + "mobileconfig_info": "İstenen Apple bağlantı profilini indirmek için lütfen posta kutusu kullanıcısı olarak oturum açın.", + "delayed": "Giriş %s saniye gecikti.", + "fido2_webauthn": "FIDO2/WebAuthn Giriş", + "login": "Giriş", + "password": "Şifre", + "username": "Kullanıcı Adı", + "other_logins": "Anahtar girişi" + }, + "success": { + "bcc_saved": "BCC harita girişi kaydedildi", + "item_deleted": "Öğe %s başarıyla silindi", + "verified_webauthn_login": "Doğrulanmış WebAuthn girişi", + "f2b_modified": "Fail2ban parametrelerinde yapılan değişiklikler kaydedildi", + "rl_saved": "Kaydedilen %s nesnesi için hız sınırı", + "alias_added": "Takma ad adresi %s (%d) eklendi", + "aliasd_modified": "%s takma ad etki alanında yapılan değişiklikler kaydedildi", + "global_filter_written": "Filtre dosyaya başarıyla yazıldı", + "dkim_removed": "DKIM anahtarı %s kaldırıldı", + "pushover_settings_edited": "Pushover ayarları başarıyla ayarlandı, lütfen kimlik bilgilerini doğrulayın.", + "verified_yotp_login": "Doğrulanmış Yubico OTP girişi", + "deleted_syncjobs": "Silinen senkronizasyon işleri: %s", + "sogo_profile_reset": "%s kullanıcısı için SOGo profili sıfırlandı", + "domain_admin_removed": "Alan yöneticisi %s kaldırıldı", + "domain_admin_modified": "Alan yöneticisi %s'de yapılan değişiklikler kaydedildi", + "domain_footer_modified": "Domain footer değişiklikleri %s kaydedildi", + "domain_removed": "%s etki alanı kaldırıldı", + "dovecot_restart_success": "Dovecot başarıyla yeniden başlatıldı", + "hash_deleted": "Hash silindi", + "items_deleted": "Öğe %s başarıyla silindi", + "items_released": "Seçilen öğeler yayınlandı.", + "learned_ham": "Kimlik %s jambon olarak başarıyla öğrenildi", + "license_modified": "Lisansta yapılan değişiklikler kaydedildi", + "logged_in_as": "%s olarak oturum açıldı", + "mailbox_added": "Posta kutusu %s eklendi", + "mailbox_modified": "%s posta kutusunda yapılan değişiklikler kaydedildi", + "mailbox_removed": "Posta kutusu %s kaldırıldı", + "nginx_reloaded": "Nginx yeniden yüklendi", + "object_modified": "%s nesnesindeki değişiklikler kaydedildi", + "reset_main_logo": "Varsayılan logoya sıfırla", + "saved_settings": "Kaydedilen ayarlar", + "eas_reset": "%s kullanıcısı için ActiveSync cihazları sıfırlandı", + "domain_added": "%s etki alanı eklendi", + "template_modified": "%s şablonuna değişiklikler işlendi", + "ui_texts": "Kullanıcı arayüzü metinlerinde yapılan değişiklikler kaydedildi", + "template_added": "%s şablonu eklendi", + "acl_saved": "%s nesnesi için ACL kaydedildi", + "admin_added": "%s yöneticisi eklendi", + "admin_api_modified": "API'deki değişiklikler kaydedildi", + "admin_modified": "Yönetici değişiklikleri kaydedildi", + "admin_removed": "%s yöneticisi kaldırıldı", + "alias_domain_removed": "Takma ad alan adı %s kaldırıldı", + "alias_modified": "%s takma ad adresindeki değişiklikler kaydedildi", + "alias_removed": "%s takma adı kaldırıldı", + "aliasd_added": "%s takma ad alanı eklendi", + "app_links": "Uygulama bağlantılarında yapılan değişiklikler kaydedildi", + "app_passwd_added": "Yeni uygulama şifresi eklendi", + "app_passwd_removed": "Kaldırılan uygulama parolası kimliği %s", + "bcc_deleted": "BCC harita girişleri silindi: %s", + "bcc_edited": "BCC harita girişi %s düzenlendi", + "cors_headers_edited": "CORS ayarları kaydedildi", + "db_init_complete": "Veritabanı başlatma işlemi tamamlandı", + "delete_filter": "Silinen filtre kimliği %s", + "delete_filters": "Silinen filtreler: %s", + "deleted_syncjob": "Syncjob kimliği %s silindi.", + "dkim_added": "DKIM anahtarı %s kaydedildi", + "domain_add_dkim_available": "Bir DKIM anahtarı zaten mevcuttu", + "dkim_duplicated": "%s etki alanı için DKIM anahtarı %s'ye kopyalandı", + "domain_admin_added": "Alan yöneticisi %s eklendi", + "domain_modified": "%s etki alanında yapılan değişiklikler kaydedildi", + "f2b_banlist_refreshed": "Banlist ID başarıyla yenilendi.", + "forwarding_host_added": "Yönlendirme ana bilgisayarı %s eklendi", + "forwarding_host_removed": "Yönlendirme ana bilgisayarı %s kaldırıldı", + "ip_check_opt_in_modified": "IP kontrolü başarıyla kaydedildi", + "item_released": "Öğe %s yayınlandı", + "password_policy_saved": "Parola politikası başarıyla kaydedildi", + "qlearn_spam": "Mesaj kimliği %s spam olarak öğrenildi ve silindi", + "queue_command_success": "Kuyruk komutu başarıyla tamamlandı", + "recipient_map_entry_deleted": "Alıcı harita kimliği %s silindi", + "recipient_map_entry_saved": "Alıcı harita girişi \\\"%s\\\" kaydedildi", + "relayhost_added": "%s harita girişi eklendi", + "relayhost_removed": "%s harita girişi kaldırıldı", + "resource_added": "Kaynak %s eklendi", + "resource_modified": "%s posta kutusunda yapılan değişiklikler kaydedildi", + "resource_removed": "Kaynak %s kaldırıldı", + "rspamd_ui_pw_set": "Rspamd UI parolası başarıyla ayarlandı", + "settings_map_added": "Ayarlar haritası girişi eklendi", + "settings_map_removed": "Kaldırılan ayarlar haritası kimliği %s", + "template_removed": "%s şablonu silindi", + "tls_policy_map_entry_deleted": "TLS politika haritası kimliği %s silindi", + "tls_policy_map_entry_saved": "TLS ilke haritası girişi \\\"%s\\\" kaydedildi", + "upload_success": "Dosya başarıyla yüklendi", + "verified_fido2_login": "Doğrulanmış FIDO2 girişi", + "verified_totp_login": "Doğrulanmış TOTP girişi" + }, + "quarantine": { + "remove": "Kaldır", + "disabled_by_config": "Geçerli sistem yapılandırması, karantina işlevini devre dışı bırakır. Lütfen karantina öğeleri için \\\"posta kutusu başına tutma\\\" ve \\\"maksimum boyut\\\" ayarlayın.", + "qinfo": "Karantina sistemi, reddedilen postaları veritabanına (gönderene teslim edilmiş bir posta izlenimi verilmeyecek) ve bir posta kutusunun Önemsiz klasörüne kopya olarak teslim edilen postayı kaydeder.\\r\\n
    \\\"Spam olarak öğren ve sil\\\", Bayes teoremi aracılığıyla bir mesajı spam olarak öğrenecek ve ayrıca gelecekte benzer mesajları reddetmek için bulanık karmaları hesaplayacaktır.\\r\\n
    Lütfen birden fazla öğrenmenin olduğunu unutmayın. iletiler - sisteminize bağlı olarak - zaman alabilir.
    Kara listeye alınan öğeler karantinadan hariç tutulur.", + "sender_header": "Gönderen (\"Kimden\" başlığı)", + "table_size": "Tablo boyutu", + "confirm_delete": "Bu öğenin silinmesini onaylayın.", + "danger": "Tehlike", + "deliver_inbox": "Gelen kutusuna teslim et", + "download_eml": "İndir (.eml)", + "show_item": "Öğeyi göster", + "spam": "Spam", + "spam_score": "Skor", + "subj": "Konu", + "table_size_show_n": "%s öğeleri göster", + "text_from_html_content": "İçerik (dönüştürülmüş html)", + "text_plain_content": "İçerik (metin/düz)", + "toggle_all": "Hepsini aç/kapat", + "type": "Tür", + "qhandler_success": "İstek sisteme başarıyla gönderildi. Artık pencereyi kapatabilirsiniz.", + "recipients": "Alıcılar", + "refresh": "Yenile", + "received": "Alındı.", + "action": "İşlem", + "atts": "Ekler", + "check_hash": "Dosya hash @ VT ara", + "confirm": "Onayla", + "empty": "Sonuç Yok", + "high_danger": "Yüksek", + "info": "Bilgi", + "junk_folder": "Gereksiz klasör", + "learn_spam_delete": "Spam olarak öğren ve sil", + "low_danger": "Düşük", + "medium_danger": "Orta", + "neutral_danger": "Nötr", + "notified": "Bildirildi.", + "qid": "Rspamd QID", + "qitem": "Karantina öğesi", + "quarantine": "Karantina", + "quick_actions": "İşlemler", + "quick_delete_link": "Hızlı silme bağlantısını aç", + "quick_info_link": "Bilgi bağlantısını aç", + "quick_release_link": "Hızlı yayın bağlantısını aç", + "rcpt": "Alıcı", + "rejected": "Reddedildi.", + "release": "Serbest Bırak", + "release_body": "Mesajınızı eml dosyası olarak bu mesaja ekledik.", + "release_subject": "Potansiyel olarak zarar veren karantina öğesi %s", + "rewrite_subject": "Konuyu yeniden yaz", + "rspamd_result": "Rspamd sonucu", + "sender": "Gönderen (SMTP)", + "settings_info": "Karantinaya alınacak maksimum öğe miktarı: %s
    Maksimum e-posta boyutu: %s MiB" + }, + "tfa": { + "waiting_usb_register": "USB cihazı bekleniyor...

    Lütfen şifrenizi yukarıya girin ve USB cihazınızdaki düğmeye dokunarak kaydınızı onaylayın.", + "scan_qr_code": "Lütfen aşağıdaki kodu kimlik doğrulama uygulamanızla tarayın veya kodu manuel olarak girin.", + "u2f_deprecated": "Anahtarınız, kullanımdan kaldırılmış U2F yöntemi kullanılarak kaydedilmiş gibi görünüyor. İki Faktörlü Kimlik Doğrulamayı sizin için devre dışı bırakacağız ve Anahtarınızı sileceğiz.", + "none": "Devre dışı bırak", + "authenticators": "Kimlik doğrulayıcılar", + "api_register": "%s, Yubico Bulut API'sini kullanır. Lütfen anahtarınız için buradan bir API anahtarı edinin. ", + "confirm": "Onayla", + "confirm_totp_token": "Lütfen oluşturulan jetonu girerek değişikliklerinizi onaylayın", + "delete_tfa": "Çift faktörlü doğrulamayı kaldırın", + "disable_tfa": "Bir olayla başarılı girişe kadar çift geçişli çıkışı devre dışı bırak", + "enter_qr_code": "Cihazınız QR kodlarını tarayamıyorsa TOTP kodunuz", + "error_code": "Hata kodu", + "init_webauthn": "Başlatılıyor, lütfen bekleyin...", + "key_id": "Cihazınız için bir tanımlayıcı", + "key_id_totp": "Anahtarınız için bir tanımlayıcı", + "reload_retry": "- (hata devam ederse tarayıcıyı yeniden yükleyin)", + "select": "Lütfen seçiniz", + "set_tfa": "Çift faktörlü yöntem metodu", + "tfa_token_invalid": "Çift faktörlü doğrulama geçersiz", + "totp": "Zamana dayalı OTP (Google Authenticator, Authy, vb.)", + "u2f_deprecated_important": "Lütfen Anahtarınızı yeni WebAuthn yöntemiyle yönetici panelinde kaydedin.", + "webauthn": "WebAuthn kimlik doğrulaması", + "waiting_usb_auth": "USB cihazı bekleniyor...

    Lütfen şimdi USB cihazınızdaki düğmeye dokunun.", + "yubi_otp": "Yubico OTP kimlik doğrulaması", + "start_webauthn_validation": "Doğrulamayı başlat", + "tfa": "Çift faktörlü doğrulama" + }, + "start": { + "mailcow_panel_detail": "Etki alanı yöneticileri posta kutuları ve takma adlar oluşturur, değiştirir veya siler, alan adlarını değiştirir ve atanan alan adları hakkında daha fazla bilgi okur.
    \\r\\nPosta kutusu kullanıcıları zaman oluşturabilir -sınırlı takma adlar (spam takma adları), şifrelerini ve spam filtresi ayarlarını değiştirin.", + "imap_smtp_server_auth_info": "Lütfen tam e-posta adresinizi ve PLAIN kimlik doğrulama mekanizmasını kullanın.
    \\r\\nGiriş verileriniz, sunucu tarafı zorunlu şifreleme ile şifrelenecektir.", + "mailcow_apps_detail": "Postalarınıza, takviminize, kişilerinize ve daha fazlasına erişmek için bir mailcow uygulaması kullanın.", + "help": "Yardım panelini göster/gizle" + }, + "queue": { + "hold_mail_legend": "Seçilen postaları bekletir. (Daha fazla teslimat girişimini önler)", + "legend": "Posta kuyruğu eylemleri işlevleri:", + "ays": "Lütfen geçerli kuyruktaki tüm öğeleri silmek istediğinizi onaylayın.", + "deliver_mail": "Teslim Et", + "deliver_mail_legend": "Seçilen postaları yeniden teslim etme girişimleri.", + "delete": "Tümünü Sil", + "flush": "Kuyruğu Temizle", + "info": "Posta kuyruğu, teslim edilmeyi bekleyen tüm e-postaları içerir. Bir mail uzun süre mail kuyruğunda kalırsa sistem tarafından otomatik olarak silinir.
    İlgili mailin hata mesajı mailin neden teslim edilemediği hakkında bilgi verir.", + "queue_manager": "Kuyruk Yöneticisi", + "show_message": "Mesajı göster", + "unban": "Yasağı Kaldır", + "unhold_mail": "Bırak", + "unhold_mail_legend": "Seçilen postaları teslimat için serbest bırakır. (önceden bekletme gerektirir)", + "hold_mail": "Tut" + }, + "fido2": { + "confirm": "Onayla", + "fido2_auth": "FIDO2 ile giriş yap", + "fido2_success": "Cihaz başarıyla kaydedildi", + "set_fido2": "FIDO2 cihazını kaydedin", + "set_fn": "Kolay ad belirleyin", + "start_fido2_validation": "FIDO2 doğrulamasını başlat", + "fido2_validation_failed": "Doğrulama başarısız", + "fn": "Kolay ad", + "known_ids": "Bilinen Kimlikler", + "none": "Engellendi.", + "register_status": "Kayıt Durumu", + "rename": "Yeniden adlandır", + "set_fido2_touchid": "Apple M1'de Touch ID'yi kaydedin" + }, + "footer": { + "confirm_delete": "Silmeyi Onayla", + "delete_now": "Şimdi sil", + "delete_these_items": "Lütfen aşağıdaki nesne kimliğindeki değişikliklerinizi onaylayın", + "restart_container_info": "Önemli: Düzgün bir yeniden başlatmanın tamamlanması biraz zaman alabilir, lütfen bitmesini bekleyin.", + "restart_now": "Şimdi yeniden başlat", + "restarting_container": "Konteyner yeniden başlatılıyor, bu işlem biraz zaman alabilir", + "hibp_check": "haveibeenpwned.com adresinden kontrol edin", + "cancel": "İptal", + "hibp_nok": "Eşleşti! Bu potansiyel olarak tehlikeli bir şifredir!", + "hibp_ok": "Eşleşme bulunamadı.", + "loading": "Lütfen bekleyin...", + "nothing_selected": "Seçim yapılmadı", + "restart_container": "Konteyneri yeniden başlat" + }, + "header": { + "administration": "Yapılandırma ve Ayrıntılar", + "apps": "Uygulamalar", + "debug": "Bilgi", + "email": "E-Posta", + "mailcow_system": "Sistem", + "mailcow_config": "Yapılandırma", + "quarantine": "Karantina", + "restart_netfilter": "netfilter'ı yeniden başlat", + "restart_sogo": "SOGo'yu yeniden başlat", + "user_settings": "Kullanıcı Ayarları" + }, + "info": { + "awaiting_tfa_confirmation": "TFA onayı bekleniyor", + "no_action": "Uygulanabilir bir işlem yok", + "session_expires": "Oturumunuz yaklaşık 15 saniye içinde sona erecek" + }, + "oauth2": { + "access_denied": "OAuth2 aracılığıyla erişim izni vermek için lütfen posta kutusu sahibi olarak giriş yapın.", + "authorize_app": "Uygulamayı yetkilendir", + "deny": "Reddet", + "permit": "Uygulamayı yetkilendir", + "profile": "Profil", + "profile_desc": "Kişisel bilgileri görüntüleyin: kullanıcı adı, tam ad, oluşturuldu, değiştirildi, etkin", + "scope_ask_permission": "Bir uygulama aşağıdaki izinleri istedi" + }, + "ratelimit": { + "disabled": "Engellendi", + "second": "mesaj / saniye", + "minute": "mesaj / dakika", + "hour": "mesaj / saat", + "day": "mesaj / gün" + }, + "user": { + "advanced_settings": "Gelişmiş ayarlar", + "aliases_also_send_as": "Kullanıcı olarak göndermeye de izin verilir", + "direct_aliases_desc": "Doğrudan takma ad adresleri spam filtresi ve TLS ilke ayarlarından etkilenir.", + "direct_protocol_access": "Bu posta kutusu kullanıcısının aşağıdaki protokollere ve uygulamalara doğrudan, harici erişimi vardır. Bu ayar yöneticiniz tarafından kontrol edilir. Bireysel protokollere ve uygulamalara erişim vermek için uygulama şifreleri oluşturulabilir.< br>\\\"Web postasında oturum aç\\\" düğmesi, SOGo'da tek oturum açmayı sağlar ve her zaman kullanılabilir.", + "pushover_info": "Push bildirim ayarları, takma adlar (paylaşılan, paylaşılmayan, etiketli) dahil %s adresine teslim edilen tüm temiz (spam olmayan) postalar için geçerli olacaktır.", + "last_pw_change": "Son şifre değişikliği", + "mailbox_details": "Detaylar", + "quarantine_notification_info": "Bir bildirim gönderildiğinde, öğeler \\\"bildirildi\\\" olarak işaretlenecek ve bu belirli öğe için başka bildirim gönderilmeyecek.", + "alias_extend_all": "Takma adları 1 saat uzat", + "app_hint": "Uygulama parolaları, IMAP, SMTP, CalDAV, CardDAV ve EAS oturum açma bilgileriniz için alternatif parolalardır. Kullanıcı adı değişmeden kalır. SOGo web postası, uygulama parolalarıyla kullanılamaz.", + "apple_connection_profile_mailonly": "Bu bağlantı profili, bir Apple aygıtı için IMAP ve SMTP yapılandırma parametrelerini içerir.", + "no_last_login": "Son kullanıcı arayüzü oturum açma bilgisi yok", + "pushover_vars": "Gönderen filtresi tanımlanmadığında, tüm postalar dikkate alınacaktır.
    Düzenli ifade filtreleri ve tam gönderen kontrolleri ayrı ayrı tanımlanabilir ve sıralı olarak değerlendirilecektir. Birbirlerine bağlı değildirler.
    Metin ve başlık için kullanılabilir değişkenler (lütfen veri koruma politikalarını dikkate alın)", + "shared_aliases_desc": "Paylaşılan takma adlar, spam filtresi veya şifreleme politikası gibi kullanıcıya özel ayarlardan etkilenmez. Karşılık gelen spam filtreleri yalnızca bir yönetici tarafından etki alanı çapında bir politika olarak yapılabilir.", + "action": "Eylem", + "create_app_passwd": "Uygulama parolası oluştur", + "create_syncjob": "Yeni senkronizasyon işi oluştur", + "change_password": "Şifre değiştirme", + "clear_recent_successful_connections": "Görünen başarılı bağlantıları temizle", + "client_configuration": "E-posta istemcileri ve akıllı telefonlar için yapılandırma kılavuzlarını göster", + "messages": "mesajlar", + "spam_aliases": "Geçici e-posta takma adları", + "spam_score_reset": "Sunucu varsayılanına sıfırla", + "years": "Yıllar", + "change_password_hint_app_passwords": "Hesabınızda değiştirilmeyecek uygulama şifresi var. Bunları yönetmek için Uygulama şifreleri sekmesine gidin.", + "pushover_evaluate_x_prio": "Yüksek öncelikli postayı ilet [X-Priority: 1]", + "spamfilter_table_add": "Öge Ekle", + "spamfilter_table_domain_policy": "n/a (alan politikası)", + "spamfilter_table_empty": "Görüntülenecek veri yok\"", + "spamfilter_table_remove": "Kaldır", + "tls_policy_warning": "Uyarı: Şifreli posta aktarımını zorunlu kılmaya karar verirseniz, e-postalarınızı kaybedebilirsiniz.
    Politikayı karşılamayan iletiler, posta sistemi tarafından kesin bir başarısızlıkla geri döner.< br>Bu seçenek, birincil e-posta adresiniz (oturum açma adı), takma ad alanlarından türetilen tüm adresler ve ayrıca hedef olarak yalnızca bu tek posta kutusuyla takma ad adresleri için geçerlidir.", + "interval": "Aralık", + "username": "Kullanıcı adı", + "verify": "Doğrula", + "waiting": "Bekliyor", + "spamfilter_default_score": "Varsayılan değerler", + "status": "Durum", + "active": "Aktif", + "active_sieve": "Aktif filtre", + "alias": "Takma ad", + "alias_create_random": "Rastgele takma ad oluştur", + "alias_full_date": "d.m.Y, H:i:s T", + "alias_remove_all": "Tüm takma adları kaldır", + "alias_select_validity": "Geçerlilik süresi", + "alias_time_left": "Kalan süre", + "alias_valid_until": "Tarihe Kadar Geçerli", + "aliases_send_as_all": "Aşağıdaki alan(lar) ve takma ad alanları için gönderici erişimini kontrol etmeyin", + "allowed_protocols": "İzin verilen protokoller", + "app_name": "Uygulama adı", + "app_passwds": "Uygulama şifreleri", + "apple_connection_profile": "Apple bağlantı profili", + "apple_connection_profile_complete": "Bu bağlantı profili, bir Apple aygıtı için IMAP ve SMTP parametrelerinin yanı sıra CalDAV (takvimler) ve CardDAV (kişiler) yollarını içerir.", + "apple_connection_profile_with_app_password": "Yeni bir uygulama parolası oluşturulur ve profile eklenir, böylece cihazınızı kurarken parola girilmesi gerekmez. Posta kutunuza tam erişim sağladığı için lütfen dosyayı paylaşmayın.", + "attribute": "Özellik", + "created_on": "Oluşturulma tarihi", + "daily": "Günlük", + "day": "Gün", + "delete_ays": "Lütfen silme işlemini onaylayın.", + "direct_aliases": "Doğrudan takma ad adresleri", + "eas_reset_help": "Birçok durumda cihaz önbelleğini sıfırlama, bozuk bir ActiveSync profilini kurtarmaya yardımcı olur.
    Dikkat: Tüm öğeler yeniden indirilecek!", + "edit": "Düzenle", + "email": "e-posta", + "email_and_dav": "e-posta, takvimler ve kişiler", + "empty": "Sonuç yok", + "encryption": "Şifreleme", + "excludes": "Hariçtir", + "expire_in": "Son kullanma tarihi", + "fido2_webauthn": "FIDO2/WebAuthn", + "force_pw_update": "Grup yazılımıyla ilgili hizmetlere erişebilmek için yeni bir parola gerekir ayarlamalısınız.", + "from": "Kimden", + "generate": "Oluştur", + "hour": "Saat", + "hourly": "Saatlik", + "hours": "Saatler", + "in_use": "Kullanılmış", + "is_catch_all": "Alan/alanlar için tümünü yakala", + "last_mail_login": "Son posta girişi", + "last_run": "Son çalıştırma", + "last_ui_login": "Kullanıcının son arayüzü girişi", + "loading": "Yükleniyor...", + "login_history": "Giriş geçmişi", + "mailbox": "Posta Kutusu", + "mailbox_general": "Genel", + "mailbox_settings": "Ayarlar", + "month": "Ay", + "months": "Aylar", + "never": "Asla", + "new_password": "Yeni şifre", + "new_password_repeat": "Onay şifresi (tekrar)", + "no_active_filter": "Aktif filtre mevcut değil", + "no_record": "Kayıt yok", + "open_logs": "Günlükleri açın", + "open_webmail_sso": "Web postasına giriş yapın", + "password": "Şifre", + "password_now": "Geçerli şifre (değişiklikleri onaylayın)", + "password_repeat": "Şifre (tekrar)", + "pushover_only_x_prio": "Yalnızca yüksek öncelikli postaları dikkate alın [X-Priority: 1]", + "pushover_sender_array": "Aşağıdaki gönderen e-posta adreslerini (virgülle ayrılmış) göz önünde bulundurun", + "pushover_sender_regex": "Gönderenleri aşağıdaki normal ifadeye göre eşleştir", + "pushover_text": "Bildirim metni", + "pushover_title": "Bildirim başlığı", + "pushover_sound": "Ses", + "pushover_verify": "Kimlik bilgilerini doğrula", + "q_add_header": "Önemsiz klasör", + "q_all": "Tüm kategoriler", + "quarantine_category": "Karantina bildirim kategorisi", + "quarantine_category_info": "\\\"Reddedildi\\\" bildirim kategorisi reddedilen postaları içerirken, \\\"Önemsiz klasör\\\" bir kullanıcıyı önemsiz klasörüne konan postalar hakkında bilgilendirir.", + "quarantine_notification": "Karantina bildirimleri", + "recent_successful_connections": "Başarılı bağlantılar görüldü", + "remove": "Kaldır.", + "running": "Çalıştırılıyor...", + "save": "Değişiklikleri Kaydet", + "save_changes": "Değişiklikleri Kaydet", + "sender_acl_disabled": "Gönderen denetimi devre dışı", + "shared_aliases": "Paylaşılan takma ad adresleri", + "show_sieve_filters": "Etkin kullanıcı elek filtresini göster", + "sogo_profile_reset": "SOGo profilini sıfırla", + "sogo_profile_reset_help": "Bu, kullanıcının SOGo profilini yok edecek ve geri alınamayan tüm kişi ve takvim verilerini siler.", + "sogo_profile_reset_now": "Profili şimdi sıfırla", + "spamfilter": "Spam filtresi", + "spamfilter_behavior": "Derecelendirme", + "spamfilter_bl": "Kara liste", + "sync_jobs": "İşleri senkronize et", + "spamfilter_bl_desc": "Spam olarak sınıflandırılacak ve reddedilecek her zaman kara listeye alınan e-posta adresleri. Reddedilen postalar karantinaya kopyalanmaz. Joker karakterler kullanılabilir. Bir filtre yalnızca şunlara uygulanır tüm takma adları ve bir posta kutusunun kendisi hariç doğrudan takma adlar (tek bir hedef posta kutusuna sahip takma adlar).", + "spamfilter_green": "Yeşil: bu mesaj spam değil", + "spamfilter_hint": "İlk değer \\\"düşük spam puanını\\\" tanımlar, ikincisi \\\"yüksek spam puanını\\\" temsil eder.", + "spamfilter_red": "Kırmızı: Bu ileti istenmeyen postadır ve sunucu tarafından reddedilecektir", + "spamfilter_table_action": "Eylem", + "spamfilter_table_rule": "Kural", + "spamfilter_wl": "Beyaz liste", + "spamfilter_wl_desc": "Beyaz listeye alınan e-posta adresleri spam olarak asla sınıflandırılmayacak şekilde programlanmıştır. Joker karakterler kullanılabilir. Bir filtre yalnızca, tümünü yakalama takma adları ve bir posta kutusunun kendisi.", + "spamfilter_yellow": "Sarı: bu mesaj spam olabilir, spam olarak etiketlenecek ve gereksiz klasörünüze taşınacak", + "syncjob_check_log": "İşleri senkronize et", + "syncjob_last_run_result": "Son çalıştırma sonucu", + "syncjob_EX_OK": "Başarılı", + "syncjob_EXIT_CONNECTION_FAILURE": "Bağlantı sorunu", + "syncjob_EXIT_TLS_FAILURE": "Şifreli bağlantı ile ilgili sorun", + "syncjob_EXIT_AUTHENTICATION_FAILURE": "Kimlik doğrulama sorunu", + "syncjob_EXIT_OVERQUOTA": "Hedef posta kutusu kotayı aştı", + "syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Uzak sunucuya bağlanılamıyor", + "syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Yanlış kullanıcı adı veya şifre", + "tag_handling": "Etiketli postalar için işlemeyi ayarla", + "tag_help_example": "Etiketli bir e-posta adresi örneği: ben+Facebook@example.org", + "tag_help_explain": "Alt klasörde: INBOX (\\\"INBOX/Facebook\\\") altında etiketten sonra adlandırılan yeni bir alt klasör oluşturulacak.
    \\r\\nKonuda: etiketlerin adı posta konusunun önüne eklenecek, örnek: \\\"[Facebook] Haberlerim\\\".", + "tag_in_none": "Hiçbir şey yapma", + "tag_in_subfolder": "Alt klasörde", + "tag_in_subject": "Konuda", + "text": "Metin", + "title": "Başlık", + "tls_enforce_in": "TLS gelenini zorunlu kıl", + "tls_enforce_out": "TLS gidenini zorunlu kıl", + "tls_policy": "Şifreleme politikası", + "user_settings": "Kullanıcı ayarları", + "value": "Değer", + "weekly": "Haftalık", + "weeks": "Haftalar", + "with_app_password": "Uygulama şifresi ile", + "year": "Yıl", + "eas_reset": "ActiveSync cihaz önbelleğini sıfırla", + "eas_reset_now": "Şimdi sıfırla", + "q_reject": "Reddedildi", + "week": "Hafta" } } diff --git a/data/web/lang/lang.uk-ua.json b/data/web/lang/lang.uk-ua.json index e778f156..5cc70445 100644 --- a/data/web/lang/lang.uk-ua.json +++ b/data/web/lang/lang.uk-ua.json @@ -391,7 +391,7 @@ "last_key": "Останній ключ не можна видалити, натомість вимкніть TFA.", "login_failed": "Введено неправильний логін або пароль", "mailbox_invalid": "Неприпустима адреса поштового акаунту", - "mailbox_quota_left_exceeded": "Недостатньо вільного місця (місця залишилося: %d МіБ)", + "mailbox_quota_left_exceeded": "Недостатньо вільного місця (залишилося: %d МіБ)", "malformed_username": "Некоректне ім'я користувача", "map_content_empty": "Зміст правила не може бути порожнім", "max_alias_exceeded": "Перевищено максимальну кількість псевдонімів", @@ -478,7 +478,8 @@ "extended_sender_acl_denied": "відсутній ACL для встановлення зовнішніх адрес відправників", "template_exists": "Шаблон %s вже існує", "template_id_invalid": "Ідентифікатор шаблону %s недійсний", - "template_name_invalid": "Ім'я шаблону невірне" + "template_name_invalid": "Ім'я шаблону невірне", + "img_size_exceeded": "Зображення перевищує максимальний розмір файлу" }, "debug": { "chart_this_server": "Діаграма (цей сервер)", @@ -525,7 +526,7 @@ "cname_from_a": "Значення, отримане із запису A/AAAA. Це підтримується, поки запис вказує на правильний ресурс.", "dns_records": "Записи DNS", "dns_records_data": "Значення", - "dns_records_docs": "Також перегляньте документацію.", + "dns_records_docs": "Також перегляньте документацію.", "dns_records_name": "Назва", "dns_records_status": "Статус", "optional": "Цей запис необов'язковий.", @@ -561,6 +562,7 @@ "extended_sender_acl": "Зовнішні адреси пошти", "force_pw_update": "Вимагати зміну пароля при наступному вході до системи", "force_pw_update_info": "Цей користувач зможе увійти лише в %s. Паролі додатків залишаються придатними для використання.", + "footer_exclude": "Виключити з нижнього колонтитула", "full_name": "Повне ім'я", "gal": "GAL - Глобальна адресна книга", "generate": "згенерувати", @@ -625,7 +627,7 @@ "admin": "Редагувати адміністратора", "allow_from_smtp": "Дозволити SMTP тільки для цих IP", "allow_from_smtp_info": "Вкажіть IPv4/IPv6 адреси та/або підмережі.
    Залиште поле порожнім, щоб дозволити відправлення з будь-яких адрес.", - "bcc_dest_format": "Призначенням правила BBC має бути єдина дійсна адреса електронної пошти.
    Якщо вам потрібно надіслати копію на кілька адрес, створіть псевдонім і використовуйте його тут.", + "bcc_dest_format": "Призначенням правила BCC має бути єдина дійсна адреса електронної пошти.
    Якщо вам потрібно надіслати копію на кілька адрес, створіть псевдонім і використовуйте його тут.", "comment_info": "Приватний коментар не видно користувачам, а публічний - відображається поряд із псевдонімом в особистому кабінеті користувача", "domain_quota": "Квота домену", "dont_check_sender_acl": "Вимкнути перевірку відправника для домену %s та псевдонімів домену", @@ -659,8 +661,7 @@ }, "domain_footer_html": "Нижній колонтитул HTML", "domain_footer_plain": "ЗВИЧАЙНИЙ нижній колонтитул", - "custom_attributes": "Користувацькі атрибути", - "mbox_exclude": "Виключити поштові скриньки" + "custom_attributes": "Користувацькі атрибути" }, "fido2": { "confirm": "Підтвердити", @@ -725,7 +726,7 @@ "add": "Додати", "add_alias": "Додати псевдонім", "add_alias_expand": "Копіювати псевдоніми на псевдоніми домену", - "add_bcc_entry": "Додати правило BBC", + "add_bcc_entry": "Додати правило BCC", "add_domain": "Додати домен", "add_domain_alias": "Додати псевдонім домену", "add_filter": "Додати фільтр", @@ -745,7 +746,7 @@ "bcc_local_dest": "Локальний домен", "bcc_map": "Правила ВВС", "bcc_map_type": "Тип BCC", - "bcc_maps": "Правила BBC", + "bcc_maps": "Правила BCC", "bcc_rcpt_map": "Одержувач", "bcc_sender_map": "Відправник", "bcc_to_rcpt": "Перейти на тип \"одержувач\"", diff --git a/data/web/lang/lang.zh-cn.json b/data/web/lang/lang.zh-cn.json index b1aacf5c..0d660c18 100644 --- a/data/web/lang/lang.zh-cn.json +++ b/data/web/lang/lang.zh-cn.json @@ -336,7 +336,9 @@ "validate_license_now": "通过证书服务器验证 GUID", "verify": "验证", "yes": "✓", - "options": "选项" + "options": "选项", + "f2b_max_ban_time": "最长封禁时间(秒)", + "copy_to_clipboard": "复制到粘贴板" }, "danger": { "access_denied": "访问被拒绝或者表单数据无效", @@ -356,7 +358,7 @@ "description_invalid": "%s 的资源描述无效", "dkim_domain_or_sel_exists": "\"%s\"的 DKIM 密钥已存在,因此不会被覆盖", "dkim_domain_or_sel_invalid": "DKIM 域名或选择器无效: %s", - "domain_cannot_match_hostname": "域名与主机名称不匹配", + "domain_cannot_match_hostname": "域名不应与主机名相同", "domain_exists": "域名 %s 已存在", "domain_invalid": "域名地址为空或无效", "domain_not_empty": "不能删除非空域名 %s", @@ -456,7 +458,8 @@ "validity_missing": "请设置有效期", "value_missing": "请填入所有值", "yotp_verification_failed": "Yubico OTP 认证失败: %s", - "template_exists": "模板 %s 已存在" + "template_exists": "模板 %s 已存在", + "template_name_invalid": "模板名称无效" }, "debug": { "chart_this_server": "图表 (此服务器)", @@ -487,14 +490,18 @@ "container_disabled": "容器已被停止或禁用", "container_running": "运行中", "cores": "核心数", - "memory": "内存" + "memory": "内存", + "error_show_ip": "无法解析公网IP地址", + "show_ip": "显示公网IP", + "update_available": "有可用更新", + "update_failed": "无法检查更新" }, "diagnostics": { "cname_from_a": "来自 A/AAAA 记录的值。但只要记录指向正确的资源即可。", "dns_records": "DNS 记录", "dns_records_24hours": "请注意 DNS 记录的更改可能需要24小时才可以使此页面的当前状态显示正确。此页面为你提供了一个可以便捷查询如何配置 DNS 记录以及检查你的 DNS 记录是否正确的方式。", "dns_records_data": "正确数据", - "dns_records_docs": "请同时也参考这个文档.", + "dns_records_docs": "请同时也参考这个文档.", "dns_records_name": "名称", "dns_records_status": "当前状态", "dns_records_type": "类型", @@ -903,7 +910,7 @@ "disabled": "禁用", "second": "msgs / 秒", "minute": "msgs / 分钟", - "hour": "msgs / 小说", + "hour": "msgs / 小时", "day": "msgs / 天" }, "start": { @@ -1202,7 +1209,8 @@ "paginate": { "first": "第一页", "last": "最后一页", - "previous": "上一页" + "previous": "上一页", + "next": "下一页" } } } diff --git a/data/web/lang/lang.zh-tw.json b/data/web/lang/lang.zh-tw.json index 4d84b211..c3c2cf71 100644 --- a/data/web/lang/lang.zh-tw.json +++ b/data/web/lang/lang.zh-tw.json @@ -88,7 +88,7 @@ "relay_all": "中繼所有收件人", "relay_all_info": "↪ 如果選擇中繼所有收件人,你會需要幫每個應該中繼的收件人新增一個 (\"盲\") 信箱。", "relay_domain": "中繼此域名", - "relay_transport_info": "
    資訊
    你可以為此域名定義傳輸規則以自訂目的地,如果留空則會遵照 MX 紀錄。", + "relay_transport_info": "
    資訊
    你可以為此域名定義傳輸規則以自訂目的地,如果留空則會遵照 MX 紀錄。", "relay_unknown_only": "只為不存在的信箱地址中繼。已存在的信箱地址則在本區域遞送。", "relayhost_wrapped_tls_info": "請 不要 使用\"已包裝 TLS\"的通訊埠 (大多為通訊埠 465).
    \r\n使用其他\"未包裝\"的通訊埠發起 STARTTLS. 你可以在\"TLS 規則表\"中新增強制使用 TLS 的規則。", "select": "請選擇...", @@ -519,14 +519,15 @@ "show_ip": "顯示公網IP", "update_available": "有可用更新", "no_update_available": "系統已經是最新版本", - "update_failed": "無法檢查更新" + "update_failed": "無法檢查更新", + "wip": "工作正在進行中" }, "diagnostics": { "cname_from_a": "由 A/AAAA 紀錄獲取。只要紀錄指向正確的資源,此功能就會持續運作。", "dns_records": "DNS 紀錄", "dns_records_24hours": "請注意 DNS 紀錄的更改可能需要 24 小時才能正確顯示於此頁面。此頁面的目的是為了讓你可以輕鬆的了解如何設定 DNS 紀錄並檢查 DNS 是否設定正確。", "dns_records_data": "正確值", - "dns_records_docs": "請同時另外查看 文件.", + "dns_records_docs": "請同時另外查看 文件.", "dns_records_name": "名稱", "dns_records_status": "目前狀態", "dns_records_type": "類型", @@ -569,6 +570,7 @@ "extended_sender_acl_info": "如果可以的話,請匯入 DKIM 域名金鑰。
    \r\n別忘記將此伺服器新增到相應的 SPF TXT 中。
    \r\n當域名或域名別名被新增時,若其與此外部寄件人地址交疊,則外部寄件人地址會被移除。
    \r\n填入 @domain.tld 以允許作為 *@domain.tld 發送郵件。", "force_pw_update": "在下一次登入時強制要求更新密碼", "force_pw_update_info": "此使用者只能登入至 %s。應用程式密碼仍可正常使用", + "footer_exclude": "从页脚排除", "full_name": "全名", "gal": "全域聯絡人清單", "gal_info": "全域聯絡人清單包含了域名下的所有物件,且使用者不可編輯。如果關閉,使用者的 空閒/繁忙 訊息將不能在 SOGo 中顯示。重新啟動 SOGo 以應用更改。", @@ -615,7 +617,7 @@ "relay_all": "中繼所有收件人", "relay_all_info": "↪ 如果選擇中繼所有收件人,你會需要幫每個應該中繼的收件人新增一個 (\"盲\") 信箱。", "relay_domain": "中繼這個域名", - "relay_transport_info": "
    資訊
    你可以為此域名定義傳輸規則以自訂目的地,如果留空則會遵照 MX 紀錄。", + "relay_transport_info": "
    資訊
    你可以為此域名定義傳輸規則以自訂目的地,如果留空則會遵照 MX 紀錄。", "relay_unknown_only": "只為不存在的信箱地址中繼。已存在的信箱地址則在本區域遞送。", "relayhost": "中繼傳輸", "remove": "移除", @@ -623,7 +625,7 @@ "save": "儲存更改", "scope": "範圍", "sender_acl": "允許發送為", - "sender_acl_disabled": "寄件人檢查已關閉", + "sender_acl_disabled": "寄件人檢查已關閉", "sender_acl_info": "如果信箱使用者 A 被允許以信箱使用者 B 發送郵件,該寄件人地址不會出現在 SOGo 中\"發送自\"的下拉選項中。
    \r\n信箱使用者 B 需要新增授權以允許信箱使用者 A 選擇 B 的地址作為寄件人;授權方法為,在 SOGo 中點擊右上方信箱名稱左邊的選項按鈕(三個點)並授權。此行為不會套用於信箱別名。", "sieve_desc": "簡短描述", "sieve_type": "過濾器類型", @@ -648,7 +650,6 @@ "validate_save": "驗證並儲存", "domain_footer_info": "網域範圍的頁尾將會新增至與該網域內的位址關聯的所有外發電子郵件。
    以下變數可用於頁尾:", "custom_attributes": "自訂屬性", - "mbox_exclude": "排除信箱", "pushover_sound": "聲音" }, "fido2": { @@ -684,7 +685,7 @@ "header": { "administration": "設定和管理", "apps": "應用程式", - "debug": "系統訊息", + "debug": "系統資訊", "quarantine": "隔離", "restart_netfilter": "重新啟動 netfilter", "restart_sogo": "重新啟動 SOGo", @@ -829,7 +830,7 @@ "sender": "寄件人", "set_postfilter": "標記為 postfilter", "set_prefilter": "標記為 prefilter", - "sieve_info": "你可以為每個使用者儲存多個過濾器,但只能同時啟用一個 prefilter 和一個 postfilter。
    \r\n過濾器將按清單中的順序依次執行,下一個腳本不會因為上一個腳本失敗或\"keep;\"而停止。更改全域 sieve 腳本會重新啟動 Dovecot。

    全域 sieve prefilter → Prefilter → 使用者腳本 → Postfilter → 全域 sieve postfilter", + "sieve_info": "你可以為每個使用者儲存多個過濾器,但只能同時啟用一個 prefilter 和一個 postfilter。
    \n過濾器將按清單中的順序依次執行,下一個腳本不會因為上一個腳本失敗或保留而停止。更改全域 sieve 腳本會重新啟動 Dovecot。

    全域 sieve prefilter • Prefilter • 使用者腳本 • Postfilter • 全域 sieve postfilter", "sieve_preset_1": "丟棄含有潛在危險檔案格式的信件", "sieve_preset_2": "永遠標記來自指定寄件人的郵件為已讀", "sieve_preset_3": "無聲刪除,並停止運行後續的 sieve 腳本", @@ -837,7 +838,7 @@ "sieve_preset_5": "自動回覆 (休假)", "sieve_preset_6": "拒絕郵件並回應", "sieve_preset_7": "重新導向並保留/刪除", - "sieve_preset_8": "刪除寄件人發送給包含自己別名地址的郵件", + "sieve_preset_8": "重新導向來自特定寄件者的電子郵件,標記為已讀取並分類到子資料夾中", "sieve_preset_header": "請看下方的範例預設。 查看 Wikipedia 以瞭解更多細節。", "sogo_visible": "別名會顯示於 SOGo", "sogo_visible_n": "在 SOGo 中隱藏別名", @@ -1171,7 +1172,7 @@ "running": "運行中", "save": "儲存變更", "save_changes": "儲存變更", - "sender_acl_disabled": "寄件人檢查已關閉", + "sender_acl_disabled": "寄件人檢查已關閉", "shared_aliases": "共享別名地址", "shared_aliases_desc": "共用別名不會受使用者的個別設定如垃圾過濾器和加密規則等影響。共享別名地址的垃圾信件過濾只能由管理員透過域名級別規則修改。", "show_sieve_filters": "顯示使用者啟用的 sieve 過濾器", @@ -1231,7 +1232,8 @@ "year": "年", "years": "年", "attribute": "屬性", - "pushover_sound": "聲音" + "pushover_sound": "聲音", + "value": "數值" }, "warning": { "cannot_delete_self": "不能刪除已登入的使用者", @@ -1282,6 +1284,9 @@ "ays": "請確認您要刪除目前隊列中的所有項目。", "deliver_mail": "遞送", "queue_manager": "隊列管理器", - "unhold_mail_legend": "釋放選定的郵件以供投遞。 (需事先持有)" + "unhold_mail_legend": "釋放選定的郵件以供投遞。 (需事先持有)", + "hold_mail_legend": "保存選定的郵件。(防止進一步的交付嘗試)", + "hold_mail": "保留", + "unhold_mail": "取消保留" } } diff --git a/data/web/reset-password.php b/data/web/reset-password.php new file mode 100644 index 00000000..a0225dc6 --- /dev/null +++ b/data/web/reset-password.php @@ -0,0 +1,31 @@ + str_contains($_SESSION['index_query_string'], 'mobileconfig'), + 'is_reset_token_valid' => $is_reset_token_valid, + 'reset_token' => $_GET['token'] +]; + +require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php'; diff --git a/data/web/templates/admin.twig b/data/web/templates/admin.twig index 33f2422b..0d238eee 100644 --- a/data/web/templates/admin.twig +++ b/data/web/templates/admin.twig @@ -22,7 +22,7 @@
  • -
  • +
  • @@ -51,7 +51,7 @@ {% include 'admin/tab-config-quota.twig' %} {% include 'admin/tab-config-rsettings.twig' %} {% include 'admin/tab-config-customize.twig' %} - {% include 'admin/tab-config-password-policy.twig' %} + {% include 'admin/tab-config-password-settings.twig' %} {% include 'admin/tab-sys-mails.twig' %} {% include 'admin/tab-globalfilter-regex.twig' %} diff --git a/data/web/templates/admin/tab-config-password-policy.twig b/data/web/templates/admin/tab-config-password-policy.twig deleted file mode 100644 index 8209ba54..00000000 --- a/data/web/templates/admin/tab-config-password-policy.twig +++ /dev/null @@ -1,40 +0,0 @@ -
    -
    -
    - - {{ lang.admin.password_policy }} -
    -
    -
    - {% for name, value in password_complexity %} - {% if name == 'length' %} -
    - -
    - -
    -
    - {% else %} - -
    -
    - -
    -
    - {% endif %} - {% endfor %} -
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    diff --git a/data/web/templates/admin/tab-config-password-settings.twig b/data/web/templates/admin/tab-config-password-settings.twig new file mode 100644 index 00000000..5998c638 --- /dev/null +++ b/data/web/templates/admin/tab-config-password-settings.twig @@ -0,0 +1,102 @@ +
    +
    +
    + + {{ lang.admin.password_settings }} +
    +
    +
    +
    +
    + + {{ lang.admin.password_policy }} + +
    +
    +
    + {% for name, value in password_complexity %} + {% if name == 'length' %} +
    + +
    + +
    +
    + {% else %} + +
    +
    + +
    +
    + {% endif %} + {% endfor %} +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    + + {{ lang.admin.password_reset_settings }} + +
    + {{ lang.admin.reset_password_vars|raw }}

    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + {{ lang.admin.password_reset_tmpl_text }} + {{ lang.admin.restore_template }} +
    +
    + +
    +
    + {{ lang.admin.password_reset_tmpl_html }} + {{ lang.admin.restore_template }} +
    +
    + +
    +
    + +
    +
    +
    +
    diff --git a/data/web/templates/base.twig b/data/web/templates/base.twig index ca744d2a..bd1f5b41 100644 --- a/data/web/templates/base.twig +++ b/data/web/templates/base.twig @@ -146,7 +146,6 @@ var lang_fido2 = {{ lang_fido2|raw }}; var docker_timeout = {{ docker_timeout|raw }} * 1000; var mailcow_cc_role = '{{ mailcow_cc_role }}'; - var last_login = '{{ last_login }}'; var mailcow_info = { version_tag: '{{ mailcow_info.version_tag }}', last_version_tag: '{{ mailcow_info.last_version_tag }}', diff --git a/data/web/templates/edit/domain.twig b/data/web/templates/edit/domain.twig index 8a700d06..6d1d85c7 100644 --- a/data/web/templates/edit/domain.twig +++ b/data/web/templates/edit/domain.twig @@ -26,6 +26,15 @@ +
    + +
    + {{ result.domain_h_name }} + {% if result.domain_h_name != result.domain_name %} + {{ result.domain_name }} + {% endif %} +
    +
    @@ -289,9 +298,9 @@ {{ lang.edit.domain_footer_info_vars.custom }}
    - +
    - {% for mailbox in mailboxes %} {% endfor %} + {% for alias_domain in alias_domains %} + + {% endfor %}
    diff --git a/data/web/templates/edit/mailbox-templates.twig b/data/web/templates/edit/mailbox-templates.twig index f606bd45..6d150b26 100644 --- a/data/web/templates/edit/mailbox-templates.twig +++ b/data/web/templates/edit/mailbox-templates.twig @@ -112,6 +112,7 @@ +
    diff --git a/data/web/templates/edit/mailbox.twig b/data/web/templates/edit/mailbox.twig index 8960ee93..8de0095f 100644 --- a/data/web/templates/edit/mailbox.twig +++ b/data/web/templates/edit/mailbox.twig @@ -203,6 +203,13 @@ +
    + +
    + + {{ lang.admin.password_reset_info }} +
    +
    diff --git a/data/web/templates/index.twig b/data/web/templates/index.twig index aa282547..90e232ca 100644 --- a/data/web/templates/index.twig +++ b/data/web/templates/index.twig @@ -63,6 +63,9 @@ {% endif %}
    + {% if login_delay %}

    {{ lang.login.delayed|format(login_delay) }}

    {% endif %} diff --git a/data/web/templates/modals/mailbox.twig b/data/web/templates/modals/mailbox.twig index 22807c8d..0f1b23a7 100644 --- a/data/web/templates/modals/mailbox.twig +++ b/data/web/templates/modals/mailbox.twig @@ -149,6 +149,7 @@ +
    @@ -318,6 +319,7 @@ + @@ -381,6 +383,12 @@ + +
    @@ -155,7 +156,7 @@ - + {{ lang.user.clear_recent_successful_connections }} diff --git a/docker-compose.yml b/docker-compose.yml index 63df42e8..ba989076 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,7 @@ -version: '2.1' services: unbound-mailcow: - image: mailcow/unbound:1.21 + image: mailcow/unbound:1.23 environment: - TZ=${TZ} - SKIP_UNBOUND_HEALTHCHECK=${SKIP_UNBOUND_HEALTHCHECK:-n} @@ -62,7 +61,7 @@ services: - redis clamd-mailcow: - image: mailcow/clamd:1.64 + image: mailcow/clamd:1.66 restart: always depends_on: unbound-mailcow: @@ -81,7 +80,7 @@ services: - clamd rspamd-mailcow: - image: mailcow/rspamd:1.95 + image: mailcow/rspamd:1.97 stop_grace_period: 30s depends_on: - dovecot-mailcow @@ -91,6 +90,7 @@ services: - IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} + - SPAMHAUS_DQS_KEY=${SPAMHAUS_DQS_KEY:-} volumes: - ./data/hooks/rspamd:/hooks:Z - ./data/conf/rspamd/custom/:/etc/rspamd/custom:z @@ -111,7 +111,7 @@ services: - rspamd php-fpm-mailcow: - image: mailcow/phpfpm:1.87 + image: mailcow/phpfpm:1.89 command: "php-fpm -d date.timezone=${TZ} -d expose_php=0" depends_on: - redis-mailcow @@ -168,6 +168,7 @@ services: - DEMO_MODE=${DEMO_MODE:-n} - WEBAUTHN_ONLY_TRUSTED_VENDORS=${WEBAUTHN_ONLY_TRUSTED_VENDORS:-n} - CLUSTERMODE=${CLUSTERMODE:-} + - FLATCURVE_EXPERIMENTAL=${FLATCURVE_EXPERIMENTAL:-} restart: always networks: mailcow-network: @@ -175,7 +176,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.122.1 + image: mailcow/sogo:1.125 environment: - DBNAME=${DBNAME} - DBUSER=${DBUSER} @@ -222,7 +223,7 @@ services: - sogo dovecot-mailcow: - image: mailcow/dovecot:1.28.2 + image: mailcow/dovecot:2.1 depends_on: - mysql-mailcow - netfilter-mailcow @@ -265,6 +266,7 @@ services: - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized} + - FLATCURVE_EXPERIMENTAL=${FLATCURVE_EXPERIMENTAL:-n} ports: - "${DOVEADM_PORT:-127.0.0.1:19991}:12345" - "${IMAP_PORT:-143}:143" @@ -290,7 +292,7 @@ services: ofelia.job-exec.dovecot_sarules.schedule: "@every 24h" ofelia.job-exec.dovecot_sarules.command: "/bin/bash -c \"/usr/local/bin/sa-rules.sh\"" ofelia.job-exec.dovecot_fts.schedule: "@every 24h" - ofelia.job-exec.dovecot_fts.command: "/usr/bin/curl http://solr:8983/solr/dovecot-fts/update?optimize=true" + ofelia.job-exec.dovecot_fts.command: "/bin/bash -c \"/usr/local/bin/gosu vmail /usr/local/bin/optimize-fts.sh\"" ofelia.job-exec.dovecot_repl_health.schedule: "@every 5m" ofelia.job-exec.dovecot_repl_health.command: "/bin/bash -c \"/usr/local/bin/gosu vmail /usr/local/bin/repl_health.sh\"" ulimits: @@ -305,7 +307,7 @@ services: - dovecot postfix-mailcow: - image: mailcow/postfix:1.74 + image: mailcow/postfix:1.76 depends_on: mysql-mailcow: condition: service_started @@ -405,13 +407,14 @@ services: condition: service_started unbound-mailcow: condition: service_healthy - image: mailcow/acme:1.87 + image: mailcow/acme:1.90 dns: - ${IPV4_NETWORK:-172.22.1}.254 environment: - LOG_LINES=${LOG_LINES:-9999} - ACME_CONTACT=${ACME_CONTACT:-} - ADDITIONAL_SAN=${ADDITIONAL_SAN} + - AUTODISCOVER_SAN=${AUTODISCOVER_SAN:-y} - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - DBNAME=${DBNAME} - DBUSER=${DBUSER} @@ -441,7 +444,7 @@ services: - acme netfilter-mailcow: - image: mailcow/netfilter:1.57 + image: mailcow/netfilter:1.59 stop_grace_period: 30s restart: always privileged: true @@ -460,7 +463,7 @@ services: - /lib/modules:/lib/modules:ro watchdog-mailcow: - image: mailcow/watchdog:2.02 + image: mailcow/watchdog:2.05 dns: - ${IPV4_NETWORK:-172.22.1}.254 tmpfs: @@ -477,7 +480,6 @@ services: - mysql-mailcow - acme-mailcow - redis-mailcow - environment: - IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - LOG_LINES=${LOG_LINES:-9999} @@ -532,7 +534,7 @@ services: - watchdog dockerapi-mailcow: - image: mailcow/dockerapi:2.07 + image: mailcow/dockerapi:2.08 security_opt: - label=disable restart: always @@ -553,7 +555,7 @@ services: ##### Will be removed soon ##### solr-mailcow: - image: mailcow/solr:1.8.2 + image: mailcow/solr:1.8.3 restart: always depends_on: - netfilter-mailcow @@ -565,6 +567,7 @@ services: - TZ=${TZ} - SOLR_HEAP=${SOLR_HEAP:-1024} - SKIP_SOLR=${SKIP_SOLR:-y} + - FLATCURVE_EXPERIMENTAL=${FLATCURVE_EXPERIMENTAL:-n} networks: mailcow-network: aliases: @@ -572,7 +575,7 @@ services: ################################ olefy-mailcow: - image: mailcow/olefy:1.12 + image: mailcow/olefy:1.13 restart: always environment: - TZ=${TZ} @@ -592,9 +595,10 @@ services: ofelia-mailcow: image: mcuadros/ofelia:latest restart: always - command: daemon --docker + command: daemon --docker -f label=com.docker.compose.project=${COMPOSE_PROJECT_NAME} environment: - TZ=${TZ} + - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME} depends_on: - sogo-mailcow - dovecot-mailcow diff --git a/generate_config.sh b/generate_config.sh index 05d9ee2f..f5a2a01b 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -9,7 +9,7 @@ if [[ "$(uname -r)" =~ ^4\.15\.0-60 ]]; then fi if [[ "$(uname -r)" =~ ^4\.4\. ]]; then - if grep -q Ubuntu <<< $(uname -a); then + if grep -q Ubuntu <<< "$(uname -a)"; then echo "DO NOT RUN mailcow ON THIS UBUNTU KERNEL!"; echo "Please update to linux-generic-hwe-16.04 by running \"apt-get install --install-recommends linux-generic-hwe-16.04\"" exit 1 @@ -25,13 +25,23 @@ for bin in openssl curl docker git awk sha1sum grep cut; do if [[ -z $(which ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi done +# Check Docker Version (need at least 24.X) +docker_version=$(docker -v | grep -oP '\d+\.\d+\.\d+' | cut -d '.' -f 1) + +if [[ $docker_version -lt 24 ]]; then + echo -e "\e[31mCannot find Docker with a Version higher or equals 24.0.0\e[0m" + echo -e "\e[33mmailcow needs a newer Docker version to work properly...\e[0m" + echo -e "\e[31mPlease update your Docker installation... exiting\e[0m" + exit 1 +fi + if docker compose > /dev/null 2>&1; then if docker compose version --short | grep -e "^2." -e "^v2." > /dev/null 2>&1; then COMPOSE_VERSION=native echo -e "\e[33mFound Docker Compose Plugin (native).\e[0m" echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m" 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 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://docs.mailcow.email/install/\e[0m" @@ -147,40 +157,44 @@ done MEM_TOTAL=$(awk '/MemTotal/ {print $2}' /proc/meminfo) -if [ ${MEM_TOTAL} -le "2621440" ]; then - echo "Installed memory is <= 2.5 GiB. It is recommended to disable ClamAV to prevent out-of-memory situations." - echo "ClamAV can be re-enabled by setting SKIP_CLAMD=n in mailcow.conf." - read -r -p "Do you want to disable ClamAV now? [Y/n] " response - case $response in - [nN][oO]|[nN]) - SKIP_CLAMD=n +if [ -z "${SKIP_CLAMD}" ]; then + if [ "${MEM_TOTAL}" -le "2621440" ]; then + echo "Installed memory is <= 2.5 GiB. It is recommended to disable ClamAV to prevent out-of-memory situations." + echo "ClamAV can be re-enabled by setting SKIP_CLAMD=n in mailcow.conf." + read -r -p "Do you want to disable ClamAV now? [Y/n] " response + case $response in + [nN][oO]|[nN]) + SKIP_CLAMD=n + ;; + *) + SKIP_CLAMD=y ;; - *) - SKIP_CLAMD=y - ;; - esac -else - SKIP_CLAMD=n + esac + else + SKIP_CLAMD=n + fi fi -if [ ${MEM_TOTAL} -le "2097152" ]; then - echo "Disabling Solr on low-memory system." - SKIP_SOLR=y -elif [ ${MEM_TOTAL} -le "3670016" ]; then - echo "Installed memory is <= 3.5 GiB. It is recommended to disable Solr to prevent out-of-memory situations." - echo "Solr is a prone to run OOM and should be monitored. The default Solr heap size is 1024 MiB and should be set in mailcow.conf according to your expected load." - echo "Solr can be re-enabled by setting SKIP_SOLR=n in mailcow.conf but will refuse to start with less than 2 GB total memory." - read -r -p "Do you want to disable Solr now? [Y/n] " response - case $response in - [nN][oO]|[nN]) - SKIP_SOLR=n +if [ -z "${SKIP_SOLR}" ]; then + if [ "${MEM_TOTAL}" -le "2097152" ]; then + echo "Disabling Solr on low-memory system." + SKIP_SOLR=y + elif [ "${MEM_TOTAL}" -le "3670016" ]; then + echo "Installed memory is <= 3.5 GiB. It is recommended to disable Solr to prevent out-of-memory situations." + echo "Solr is a prone to run OOM and should be monitored. The default Solr heap size is 1024 MiB and should be set in mailcow.conf according to your expected load." + echo "Solr can be re-enabled by setting SKIP_SOLR=n in mailcow.conf but will refuse to start with less than 2 GB total memory." + read -r -p "Do you want to disable Solr now? [Y/n] " response + case $response in + [nN][oO]|[nN]) + SKIP_SOLR=n + ;; + *) + SKIP_SOLR=y ;; - *) - SKIP_SOLR=y - ;; - esac -else - SKIP_SOLR=n + esac + else + SKIP_SOLR=n + fi fi if [[ ${SKIP_BRANCH} != y ]]; then @@ -192,7 +206,7 @@ if [[ ${SKIP_BRANCH} != y ]]; then sleep 1 while [ -z "${MAILCOW_BRANCH}" ]; do - read -r -p "Choose the Branch with it´s number [1/2] " branch + read -r -p "Choose the Branch with it's number [1/2] " branch case $branch in [2]) MAILCOW_BRANCH="nightly" @@ -204,7 +218,7 @@ if [[ ${SKIP_BRANCH} != y ]]; then done git fetch --all - git checkout -f $MAILCOW_BRANCH + git checkout -f "$MAILCOW_BRANCH" elif [[ ${SKIP_BRANCH} == y ]]; then echo -e "\033[33mEnabled Dev Mode.\033[0m" @@ -336,6 +350,13 @@ MAILDIR_GC_TIME=7200 ADDITIONAL_SAN= +# Obtain certificates for autodiscover.* and autoconfig.* domains. +# This can be useful to switch off in case you are in a scenario where a reverse proxy already handles those. +# There are mixed scenarios where ports 80,443 are occupied and you do not want to share certs +# between services. So acme-mailcow obtains for maildomains and all web-things get handled +# in the reverse proxy. +AUTODISCOVER_SAN=y + # Additional server names for mailcow UI # # Specify alternative addresses for the mailcow UI to respond to diff --git a/helper-scripts/backup_and_restore.sh b/helper-scripts/backup_and_restore.sh index 03390927..dc30d5ea 100755 --- a/helper-scripts/backup_and_restore.sh +++ b/helper-scripts/backup_and_restore.sh @@ -55,10 +55,10 @@ ENV_FILE=${SCRIPT_DIR}/../.env THREADS=$(echo ${THREADS:-1}) ARCH=$(uname -m) -if ! [[ "${THREADS}" =~ ^[1-9]+$ ]] ; then +if ! [[ "${THREADS}" =~ ^[1-9][0-9]?$ ]] ; then echo "Thread input is not a number!" exit 1 -elif [[ "${THREADS}" =~ ^[1-9]+$ ]] ; then +elif [[ "${THREADS}" =~ ^[1-9][0-9]?$ ]] ; then echo "Using ${THREADS} Thread(s) for this run." echo "Notice: You can set the Thread count with the THREADS Variable before you run this script." fi @@ -199,7 +199,7 @@ function restore() { case "$1" in vmail) docker stop $(docker ps -qf name=dovecot-mailcow) - docker run -it --name mailcow-backup --rm \ + docker run -i --name mailcow-backup --rm \ -v ${RESTORE_LOCATION}:/backup:z \ -v $(docker volume ls -qf name=^${CMPS_PRJ}_vmail-vol-1$):/vmail:z \ ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_vmail.tar.gz @@ -218,7 +218,7 @@ function restore() { ;; redis) docker stop $(docker ps -qf name=redis-mailcow) - docker run -it --name mailcow-backup --rm \ + docker run -i --name mailcow-backup --rm \ -v ${RESTORE_LOCATION}:/backup:z \ -v $(docker volume ls -qf name=^${CMPS_PRJ}_redis-vol-1$):/redis:z \ ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_redis.tar.gz @@ -226,7 +226,7 @@ function restore() { ;; crypt) docker stop $(docker ps -qf name=dovecot-mailcow) - docker run -it --name mailcow-backup --rm \ + docker run -i --name mailcow-backup --rm \ -v ${RESTORE_LOCATION}:/backup:z \ -v $(docker volume ls -qf name=^${CMPS_PRJ}_crypt-vol-1$):/crypt:z \ ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_crypt.tar.gz @@ -239,7 +239,7 @@ function restore() { echo -e "Continuing anyhow. If rspamd is crashing opon boot try remove the rspamd volume with docker volume rm ${CMPS_PRJ}_rspamd-vol-1 after you've stopped the stack.\e[0m" sleep 2 docker stop $(docker ps -qf name=rspamd-mailcow) - docker run -it --name mailcow-backup --rm \ + docker run -i --name mailcow-backup --rm \ -v ${RESTORE_LOCATION}:/backup:z \ -v $(docker volume ls -qf name=^${CMPS_PRJ}_rspamd-vol-1$):/rspamd:z \ ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_rspamd.tar.gz @@ -250,7 +250,7 @@ function restore() { echo -e "Skipping rspamd due to compatibility issues!\e[0m" else docker stop $(docker ps -qf name=rspamd-mailcow) - docker run -it --name mailcow-backup --rm \ + docker run -i --name mailcow-backup --rm \ -v ${RESTORE_LOCATION}:/backup:z \ -v $(docker volume ls -qf name=^${CMPS_PRJ}_rspamd-vol-1$):/rspamd:z \ ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_rspamd.tar.gz @@ -259,7 +259,7 @@ function restore() { ;; postfix) docker stop $(docker ps -qf name=postfix-mailcow) - docker run -it --name mailcow-backup --rm \ + docker run -i --name mailcow-backup --rm \ -v ${RESTORE_LOCATION}:/backup:z \ -v $(docker volume ls -qf name=^${CMPS_PRJ}_postfix-vol-1$):/postfix:z \ ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_postfix.tar.gz @@ -295,7 +295,7 @@ function restore() { ${SQLIMAGE} /bin/bash -c "shopt -s dotglob ; /bin/rm -rf /var/lib/mysql/* ; rsync -avh --usermap=root:mysql --groupmap=root:mysql /backup/ /var/lib/mysql/" elif [[ -f "${RESTORE_LOCATION}/backup_mysql.gz" ]]; then docker run \ - -it --name mailcow-backup --rm \ + -i --name mailcow-backup --rm \ -v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/var/lib/mysql/:z \ --entrypoint= \ -u mysql \ diff --git a/helper-scripts/docker-compose.override.yml.d/BUILD_FLAGS/docker-compose.override.yml b/helper-scripts/docker-compose.override.yml.d/BUILD_FLAGS/docker-compose.override.yml index 99cd0148..d2dd0f60 100644 --- a/helper-scripts/docker-compose.override.yml.d/BUILD_FLAGS/docker-compose.override.yml +++ b/helper-scripts/docker-compose.override.yml.d/BUILD_FLAGS/docker-compose.override.yml @@ -1,4 +1,3 @@ -version: '2.1' services: unbound-mailcow: build: ./data/Dockerfiles/unbound @@ -16,8 +15,6 @@ services: build: context: ./data/Dockerfiles/sogo dockerfile: Dockerfile - args: - - SOGO_DEBIAN_REPOSITORY=http://packages.inverse.ca/SOGo/nightly/5/debian/ dovecot-mailcow: build: ./data/Dockerfiles/dovecot diff --git a/helper-scripts/docker-compose.override.yml.d/EXTERNAL_DNS/docker-compose.override.yml b/helper-scripts/docker-compose.override.yml.d/EXTERNAL_DNS/docker-compose.override.yml index 74763bf2..a3566540 100644 --- a/helper-scripts/docker-compose.override.yml.d/EXTERNAL_DNS/docker-compose.override.yml +++ b/helper-scripts/docker-compose.override.yml.d/EXTERNAL_DNS/docker-compose.override.yml @@ -1,4 +1,3 @@ -version: '2.1' services: clamd-mailcow: diff --git a/helper-scripts/docker-compose.override.yml.d/EXTERNAL_MYSQL_SOCKET/docker-compose.override.yml b/helper-scripts/docker-compose.override.yml.d/EXTERNAL_MYSQL_SOCKET/docker-compose.override.yml index 53d9193b..5e0e98f4 100644 --- a/helper-scripts/docker-compose.override.yml.d/EXTERNAL_MYSQL_SOCKET/docker-compose.override.yml +++ b/helper-scripts/docker-compose.override.yml.d/EXTERNAL_MYSQL_SOCKET/docker-compose.override.yml @@ -1,4 +1,3 @@ -version: '2.1' services: php-fpm-mailcow: @@ -26,6 +25,6 @@ services: - /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysqld.sock mysql-mailcow: - image: alpine:3.19 + image: alpine:3.20 command: /bin/true restart: "no" diff --git a/helper-scripts/docker-compose.override.yml.d/HAPROXY/docker-compose.override.yml b/helper-scripts/docker-compose.override.yml.d/HAPROXY/docker-compose.override.yml index 5009f4c9..4e1166a4 100644 --- a/helper-scripts/docker-compose.override.yml.d/HAPROXY/docker-compose.override.yml +++ b/helper-scripts/docker-compose.override.yml.d/HAPROXY/docker-compose.override.yml @@ -2,7 +2,6 @@ ## Set haproxy_trusted_networks in Dovecots extra.conf! ## -version: '2.1' services: dovecot-mailcow: diff --git a/helper-scripts/nextcloud.sh b/helper-scripts/nextcloud.sh index 60d6ed78..19b4c28c 100755 --- a/helper-scripts/nextcloud.sh +++ b/helper-scripts/nextcloud.sh @@ -1,6 +1,39 @@ #!/usr/bin/env bash # renovate: datasource=github-releases depName=nextcloud/server versioning=semver extractVersion=^v(?.*)$ -NEXTCLOUD_VERSION=28.0.1 +NEXTCLOUD_VERSION=28.0.6 + +display_warning() { + local message=("$@") + local max_length=0 + + for line in "${message[@]}"; do + if (( ${#line} > max_length )); then + max_length=${#line} + fi + done + + local border=$(printf '%*s' "$((max_length + 4))" '' | tr ' ' '#') + + echo -e "\e[31m${border}" + for line in "${message[@]}"; do + printf "\e[31m# %-*s #\n" "$max_length" "$line" + done + echo -e "\e[31m${border}" + echo -e "\e[0m" +} + +display_warning "WARNING: This Script is deprecated and will be removed in December 2024!" \ + "mailcow will drop this installation/maintenance script within December 2024..." \ + "To ensure you can still use your Nextcloud Datas, please migrate to a standalone" \ + "Nextcloud instance either on a new Host or this host." \ + "You can either use Nextcloud in Docker or install it manually." \ + " "\ + "mailcow will NOT DELETE any Nextcloud Data, even when this script was removed!!" + +echo -e "Waiting 5 seconds before continuing..." + + +sleep 5 echo -ne "Checking prerequisites..." sleep 1 diff --git a/update.sh b/update.sh index f1e31652..dcc2020e 100755 --- a/update.sh +++ b/update.sh @@ -22,13 +22,13 @@ prefetch_images() { fi fi RET_C=0 - until docker pull ${image}; do + until docker pull "${image}"; do RET_C=$((RET_C + 1)) echo -e "\e[33m\nError pulling $image, retrying...\e[0m" [ ${RET_C} -gt 3 ] && { echo -e "\e[31m\nToo many failed retries, exiting\e[0m"; exit 1; } sleep 1 done - done < <(git show origin/${BRANCH}:docker-compose.yml | grep "image:" | awk '{ gsub("image:","", $3); print $2 }') + done < <(git show "origin/${BRANCH}:docker-compose.yml" | grep "image:" | awk '{ gsub("image:","", $3); print $2 }') } docker_garbage() { @@ -39,9 +39,9 @@ docker_garbage() { COMPOSE_IMAGES=($(grep -oP "image: \Kmailcow.+" "${SCRIPT_DIR}/docker-compose.yml")) for existing_image in $(docker images --format "{{.ID}}:{{.Repository}}:{{.Tag}}" | grep 'mailcow/'); do - ID=$(echo $existing_image | cut -d ':' -f 1) - REPOSITORY=$(echo $existing_image | cut -d ':' -f 2) - TAG=$(echo $existing_image | cut -d ':' -f 3) + ID=$(echo "$existing_image" | cut -d ':' -f 1) + REPOSITORY=$(echo "$existing_image" | cut -d ':' -f 2) + TAG=$(echo "$existing_image" | cut -d ':' -f 3) if [[ " ${COMPOSE_IMAGES[@]} " =~ " ${REPOSITORY}:${TAG} " ]]; then continue @@ -109,12 +109,12 @@ migrate_docker_nat() { echo -e "\e[33mWarning:\e[0m You seem to have modified the /etc/docker/daemon.json configuration by yourself and not fully/correctly activated the native IPv6 NAT implementation." echo "You will need to merge your existing configuration manually or fix/delete the existing daemon.json configuration before trying the update process again." echo -e "Please merge the following content and restart the Docker daemon:\n" - echo ${NAT_CONFIG} + echo "${NAT_CONFIG}" return 1 fi else echo "Working on IPv6 NAT, please wait..." - echo ${NAT_CONFIG} > /etc/docker/daemon.json + echo "${NAT_CONFIG}" > /etc/docker/daemon.json ip6tables -F -t nat [[ -e /etc/rc.conf ]] && rc-service docker restart || systemctl restart docker.service if [[ $? -ne 0 ]]; then @@ -165,7 +165,7 @@ remove_obsolete_nginx_ports() { fi fi fi - done + done } detect_docker_compose_command(){ @@ -176,11 +176,11 @@ if ! [[ "${DOCKER_COMPOSE_VERSION}" =~ ^(native|standalone)$ ]]; then COMPOSE_COMMAND="docker compose" echo -e "\e[33mFound Docker Compose Plugin (native).\e[0m" echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m" - sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' $SCRIPT_DIR/mailcow.conf + sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' "$SCRIPT_DIR/mailcow.conf" sleep 2 echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m" 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://docs.mailcow.email/install/\e[0m" exit 1 fi @@ -191,58 +191,58 @@ if ! [[ "${DOCKER_COMPOSE_VERSION}" =~ ^(native|standalone)$ ]]; then COMPOSE_COMMAND="docker-compose" echo -e "\e[33mFound Docker Compose Standalone.\e[0m" echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m" - sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' $SCRIPT_DIR/mailcow.conf + sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' "$SCRIPT_DIR/mailcow.conf" 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" 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://docs.mailcow.email/install/\e[0m" exit 1 fi fi 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://docs.mailcow.email/install/\e[0m" exit 1 fi elif [ "${DOCKER_COMPOSE_VERSION}" == "native" ]; then COMPOSE_COMMAND="docker compose" - # Check if Native Compose works and has not been deleted + # 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[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/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 + sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' "$SCRIPT_DIR/mailcow.conf" sleep 2 fi elif [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then COMPOSE_COMMAND="docker-compose" - # Check if Standalone Compose works and has not been deleted + # 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[31mCannot find Docker Compose.\e[0m" echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/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 + sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' "$SCRIPT_DIR/mailcow.conf" sleep 2 fi fi @@ -297,7 +297,7 @@ if [[ "$(uname -r)" =~ ^4\.15\.0-60 ]]; then fi if [[ "$(uname -r)" =~ ^4\.4\. ]]; then - if grep -q Ubuntu <<< $(uname -a); then + if grep -q Ubuntu <<< "$(uname -a)"; then echo "DO NOT RUN mailcow ON THIS UBUNTU KERNEL!" echo "Please update to linux-generic-hwe-16.04 by running \"apt-get install --install-recommends linux-generic-hwe-16.04\"" exit 1 @@ -322,28 +322,38 @@ unset COMPOSE_COMMAND unset DOCKER_COMPOSE_VERSION for bin in curl docker git awk sha1sum grep cut; do - if [[ -z $(command -v ${bin}) ]]; then - echo "Cannot find ${bin}, exiting..." + if [[ -z $(command -v ${bin}) ]]; then + echo "Cannot find ${bin}, exiting..." exit 1; - fi + fi done +# Check Docker Version (need at least 24.X) +docker_version=$(docker -v | grep -oP '\d+\.\d+\.\d+' | cut -d '.' -f 1 | head -1) + +if [[ $docker_version -lt 24 ]]; then + echo -e "\e[31mCannot find Docker with a Version higher or equals 24.0.0\e[0m" + echo -e "\e[33mmailcow needs a newer Docker version to work properly... continuing on your own risk!\e[0m" + echo -e "\e[31mPlease update your Docker installation... sleeping 10s\e[0m" + sleep 10 +fi + export LC_ALL=C DATE=$(date +%Y-%m-%d_%H_%M_%S) -BRANCH=$(cd ${SCRIPT_DIR}; git rev-parse --abbrev-ref HEAD) +BRANCH="$(cd "${SCRIPT_DIR}"; git rev-parse --abbrev-ref HEAD)" while (($#)); do case "${1}" in --check|-c) echo "Checking remote code for updates..." - LATEST_REV=$(git ls-remote --exit-code --refs --quiet https://github.com/mailcow/mailcow-dockerized ${BRANCH} | cut -f1) - if [ $? -ne 0 ]; then + LATEST_REV=$(git ls-remote --exit-code --refs --quiet https://github.com/mailcow/mailcow-dockerized "${BRANCH}" | cut -f1) + if [ "$?" -ne 0 ]; then echo "A problem occurred while trying to fetch the latest revision from github." exit 99 fi if [[ -z $(git log HEAD --pretty=format:"%H" | grep "${LATEST_REV}") ]]; then echo -e "Updated code is available.\nThe changes can be found here: https://github.com/mailcow/mailcow-dockerized/commits/master" - git log --date=short --pretty=format:"%ad - %s" $(git rev-parse --short HEAD)..origin/master + git log --date=short --pretty=format:"%ad - %s" "$(git rev-parse --short HEAD)"..origin/master exit 0 else echo "No updates available." @@ -360,7 +370,7 @@ while (($#)); do SKIP_PING_CHECK=y ;; --stable) - CURRENT_BRANCH="$(cd ${SCRIPT_DIR}; git rev-parse --abbrev-ref HEAD)" + CURRENT_BRANCH="$(cd "${SCRIPT_DIR}"; git rev-parse --abbrev-ref HEAD)" NEW_BRANCH="master" ;; --gc) @@ -369,7 +379,7 @@ while (($#)); do exit 0 ;; --nightly) - CURRENT_BRANCH="$(cd ${SCRIPT_DIR}; git rev-parse --abbrev-ref HEAD)" + CURRENT_BRANCH="$(cd "${SCRIPT_DIR}"; git rev-parse --abbrev-ref HEAD)" NEW_BRANCH="nightly" ;; --prefetch) @@ -394,22 +404,23 @@ while (($#)); do --nightly - Switch your mailcow updates to the unstable (nightly) branch. FOR TESTING PURPOSES ONLY!!!! --prefetch - Only prefetch new images and exit (useful to prepare updates) --skip-start - Do not start mailcow after update - --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. -f|--force - Force update, do not ask questions -d|--dev - Enables Developer Mode (No Checkout of update.sh for tests) ' - exit 1 + exit 0 esac shift done +[[ ! -f mailcow.conf ]] && { echo -e "\e[31mmailcow.conf is missing! Is mailcow installed?\e[0m"; exit 1;} + chmod 600 mailcow.conf source mailcow.conf detect_docker_compose_command -[[ ! -f mailcow.conf ]] && { echo "mailcow.conf is missing! Is mailcow installed?"; exit 1;} DOTS=${MAILCOW_HOSTNAME//[^.]}; if [ ${#DOTS} -lt 1 ]; then echo -e "\e[31mMAILCOW_HOSTNAME (${MAILCOW_HOSTNAME}) is not a FQDN!\e[0m" @@ -424,7 +435,7 @@ elif [ ${#DOTS} -eq 1 ]; then echo "Find more information about why this message exists here: https://github.com/mailcow/mailcow-dockerized/issues/1572" read -r -p "Do you want to proceed anyway? [y/N] " response if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then - echo "OK. Procceding." + echo "OK. Proceeding." else echo "OK. Exiting." exit 1 @@ -450,6 +461,7 @@ CONFIG_ARRAY=( "SKIP_CLAMD" "SKIP_IP_CHECK" "ADDITIONAL_SAN" + "AUTODISCOVER_SAN" "DOVEADM_PORT" "IPV4_NETWORK" "IPV6_NETWORK" @@ -487,19 +499,19 @@ CONFIG_ARRAY=( detect_bad_asn sed -i --follow-symlinks '$a\' mailcow.conf -for option in ${CONFIG_ARRAY[@]}; do +for option in "${CONFIG_ARRAY[@]}"; do if [[ ${option} == "ADDITIONAL_SAN" ]]; then - if ! grep -q ${option} mailcow.conf; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo "${option}=" >> mailcow.conf fi - elif [[ ${option} == "COMPOSE_PROJECT_NAME" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "COMPOSE_PROJECT_NAME" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo "COMPOSE_PROJECT_NAME=mailcowdockerized" >> mailcow.conf fi - elif [[ ${option} == "DOCKER_COMPOSE_VERSION" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "DOCKER_COMPOSE_VERSION" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo "# Used Docker Compose version" >> mailcow.conf echo "# Switch here between native (compose plugin) and standalone" >> mailcow.conf @@ -509,73 +521,73 @@ for option in ${CONFIG_ARRAY[@]}; do echo "" >> mailcow.conf echo "DOCKER_COMPOSE_VERSION=${DOCKER_COMPOSE_VERSION}" >> mailcow.conf fi - elif [[ ${option} == "DOVEADM_PORT" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "DOVEADM_PORT" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo "DOVEADM_PORT=127.0.0.1:19991" >> mailcow.conf fi - elif [[ ${option} == "WATCHDOG_NOTIFY_EMAIL" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "WATCHDOG_NOTIFY_EMAIL" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo "WATCHDOG_NOTIFY_EMAIL=" >> mailcow.conf fi - elif [[ ${option} == "LOG_LINES" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "LOG_LINES" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Max log lines per service to keep in Redis logs' >> mailcow.conf echo "LOG_LINES=9999" >> mailcow.conf fi - elif [[ ${option} == "IPV4_NETWORK" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "IPV4_NETWORK" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Internal IPv4 /24 subnet, format n.n.n. (expands to n.n.n.0/24)' >> mailcow.conf echo "IPV4_NETWORK=172.22.1" >> mailcow.conf fi - elif [[ ${option} == "IPV6_NETWORK" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "IPV6_NETWORK" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Internal IPv6 subnet in fc00::/7' >> mailcow.conf echo "IPV6_NETWORK=fd4d:6169:6c63:6f77::/64" >> mailcow.conf fi - elif [[ ${option} == "SQL_PORT" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "SQL_PORT" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Bind SQL to 127.0.0.1 on port 13306' >> mailcow.conf echo "SQL_PORT=127.0.0.1:13306" >> mailcow.conf fi - elif [[ ${option} == "API_KEY" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "API_KEY" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Create or override API key for web UI' >> mailcow.conf echo "#API_KEY=" >> mailcow.conf fi - elif [[ ${option} == "API_KEY_READ_ONLY" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "API_KEY_READ_ONLY" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Create or override read-only API key for web UI' >> mailcow.conf echo "#API_KEY_READ_ONLY=" >> mailcow.conf fi - elif [[ ${option} == "API_ALLOW_FROM" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "API_ALLOW_FROM" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Must be set for API_KEY to be active' >> mailcow.conf echo '# IPs only, no networks (networks can be set via UI)' >> mailcow.conf echo "#API_ALLOW_FROM=" >> mailcow.conf fi - elif [[ ${option} == "SNAT_TO_SOURCE" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "SNAT_TO_SOURCE" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Use this IPv4 for outgoing connections (SNAT)' >> mailcow.conf echo "#SNAT_TO_SOURCE=" >> mailcow.conf fi - elif [[ ${option} == "SNAT6_TO_SOURCE" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "SNAT6_TO_SOURCE" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Use this IPv6 for outgoing connections (SNAT)' >> mailcow.conf echo "#SNAT6_TO_SOURCE=" >> mailcow.conf fi - elif [[ ${option} == "MAILDIR_GC_TIME" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "MAILDIR_GC_TIME" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Garbage collector cleanup' >> mailcow.conf echo '# Deleted domains and mailboxes are moved to /var/vmail/_garbage/timestamp_sanitizedstring' >> mailcow.conf @@ -583,8 +595,8 @@ for option in ${CONFIG_ARRAY[@]}; do echo '# Check interval is hourly' >> mailcow.conf echo 'MAILDIR_GC_TIME=1440' >> mailcow.conf fi - elif [[ ${option} == "ACL_ANYONE" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "ACL_ANYONE" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Set this to "allow" to enable the anyone pseudo user. Disabled by default.' >> mailcow.conf echo '# When enabled, ACL can be created, that apply to "All authenticated users"' >> mailcow.conf @@ -592,96 +604,96 @@ for option in ${CONFIG_ARRAY[@]}; do echo '# Otherwise a user might share data with too many other users.' >> mailcow.conf echo 'ACL_ANYONE=disallow' >> mailcow.conf fi - elif [[ ${option} == "SOLR_HEAP" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "SOLR_HEAP" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Solr heap size, there is no recommendation, please see Solr docs.' >> mailcow.conf echo '# Solr is a prone to run OOM on large systems and should be monitored. Unmonitored Solr setups are not recommended.' >> mailcow.conf echo '# Solr will refuse to start with total system memory below or equal to 2 GB.' >> mailcow.conf echo "SOLR_HEAP=1024" >> mailcow.conf fi - elif [[ ${option} == "SKIP_SOLR" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "SKIP_SOLR" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Solr is disabled by default after upgrading from non-Solr to Solr-enabled mailcows.' >> mailcow.conf echo '# Disable Solr or if you do not want to store a readable index of your mails in solr-vol-1.' >> mailcow.conf echo "SKIP_SOLR=y" >> mailcow.conf fi - elif [[ ${option} == "ENABLE_SSL_SNI" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "ENABLE_SSL_SNI" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Create seperate certificates for all domains - y/n' >> mailcow.conf echo '# this will allow adding more than 100 domains, but some email clients will not be able to connect with alternative hostnames' >> mailcow.conf echo '# see https://wiki.dovecot.org/SSL/SNIClientSupport' >> mailcow.conf echo "ENABLE_SSL_SNI=n" >> mailcow.conf fi - elif [[ ${option} == "SKIP_SOGO" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "SKIP_SOGO" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Skip SOGo: Will disable SOGo integration and therefore webmail, DAV protocols and ActiveSync support (experimental, unsupported, not fully implemented) - y/n' >> mailcow.conf echo "SKIP_SOGO=n" >> mailcow.conf fi - elif [[ ${option} == "MAILDIR_SUB" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "MAILDIR_SUB" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# MAILDIR_SUB defines a path in a users virtual home to keep the maildir in. Leave empty for updated setups.' >> mailcow.conf echo "#MAILDIR_SUB=Maildir" >> mailcow.conf echo "MAILDIR_SUB=" >> mailcow.conf fi - elif [[ ${option} == "WATCHDOG_NOTIFY_WEBHOOK" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "WATCHDOG_NOTIFY_WEBHOOK" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Send notifications to a webhook URL that receives a POST request with the content type "application/json".' >> mailcow.conf echo '# You can use this to send notifications to services like Discord, Slack and others.' >> mailcow.conf echo '#WATCHDOG_NOTIFY_WEBHOOK=https://discord.com/api/webhooks/XXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' >> mailcow.conf fi - elif [[ ${option} == "WATCHDOG_NOTIFY_WEBHOOK_BODY" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "WATCHDOG_NOTIFY_WEBHOOK_BODY" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# JSON body included in the webhook POST request. Needs to be in single quotes.' >> mailcow.conf echo '# Following variables are available: SUBJECT, BODY' >> mailcow.conf WEBHOOK_BODY='{"username": "mailcow Watchdog", "content": "**${SUBJECT}**\n${BODY}"}' echo "#WATCHDOG_NOTIFY_WEBHOOK_BODY='${WEBHOOK_BODY}'" >> mailcow.conf fi - elif [[ ${option} == "WATCHDOG_NOTIFY_BAN" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "WATCHDOG_NOTIFY_BAN" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Notify about banned IP. Includes whois lookup.' >> mailcow.conf echo "WATCHDOG_NOTIFY_BAN=y" >> mailcow.conf fi - elif [[ ${option} == "WATCHDOG_NOTIFY_START" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "WATCHDOG_NOTIFY_START" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Send a notification when the watchdog is started.' >> mailcow.conf echo "WATCHDOG_NOTIFY_START=y" >> mailcow.conf fi - elif [[ ${option} == "WATCHDOG_SUBJECT" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "WATCHDOG_SUBJECT" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Subject for watchdog mails. Defaults to "Watchdog ALERT" followed by the error message.' >> mailcow.conf echo "#WATCHDOG_SUBJECT=" >> mailcow.conf fi - elif [[ ${option} == "WATCHDOG_EXTERNAL_CHECKS" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "WATCHDOG_EXTERNAL_CHECKS" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Checks if mailcow is an open relay. Requires a SAL. More checks will follow.' >> mailcow.conf echo '# No data is collected. Opt-in and anonymous.' >> mailcow.conf echo '# Will only work with unmodified mailcow setups.' >> mailcow.conf echo "WATCHDOG_EXTERNAL_CHECKS=n" >> mailcow.conf fi - elif [[ ${option} == "SOGO_EXPIRE_SESSION" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "SOGO_EXPIRE_SESSION" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# SOGo session timeout in minutes' >> mailcow.conf echo "SOGO_EXPIRE_SESSION=480" >> mailcow.conf fi - elif [[ ${option} == "REDIS_PORT" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "REDIS_PORT" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo "REDIS_PORT=127.0.0.1:7654" >> mailcow.conf fi - elif [[ ${option} == "DOVECOT_MASTER_USER" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "DOVECOT_MASTER_USER" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# DOVECOT_MASTER_USER and _PASS must _both_ be provided. No special chars.' >> mailcow.conf echo '# Empty by default to auto-generate master user and password on start.' >> mailcow.conf @@ -689,22 +701,22 @@ for option in ${CONFIG_ARRAY[@]}; do echo '# LEAVE EMPTY IF UNSURE' >> mailcow.conf echo "DOVECOT_MASTER_USER=" >> mailcow.conf fi - elif [[ ${option} == "DOVECOT_MASTER_PASS" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "DOVECOT_MASTER_PASS" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# LEAVE EMPTY IF UNSURE' >> mailcow.conf echo "DOVECOT_MASTER_PASS=" >> mailcow.conf fi - elif [[ ${option} == "MAILCOW_PASS_SCHEME" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "MAILCOW_PASS_SCHEME" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to 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 '# see https://docs.mailcow.email/models/model-passwd/' >> mailcow.conf echo "MAILCOW_PASS_SCHEME=BLF-CRYPT" >> mailcow.conf fi - elif [[ ${option} == "ADDITIONAL_SERVER_NAMES" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "ADDITIONAL_SERVER_NAMES" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Additional server names for mailcow UI' >> mailcow.conf echo '#' >> mailcow.conf @@ -715,8 +727,20 @@ for option in ${CONFIG_ARRAY[@]}; do echo '# Comma separated list without spaces! Example: ADDITIONAL_SERVER_NAMES=a.b.c,d.e.f' >> mailcow.conf echo 'ADDITIONAL_SERVER_NAMES=' >> mailcow.conf fi - elif [[ ${option} == "ACME_CONTACT" ]]; then - if ! grep -q ${option} mailcow.conf; then + + elif [[ "${option}" == "AUTODISCOVER_SAN" ]]; then + if ! grep -q "${option}" mailcow.conf; then + echo "Adding new option \"${option}\" to mailcow.conf" + echo '# Obtain certificates for autodiscover.* and autoconfig.* domains.' >> mailcow.conf + echo '# This can be useful to switch off in case you are in a scenario where a reverse proxy already handles those.' >> mailcow.conf + echo '# There are mixed scenarios where ports 80,443 are occupied and you do not want to share certs' >> mailcow.conf + echo '# between services. So acme-mailcow obtains for maildomains and all web-things get handled' >> mailcow.conf + echo '# in the reverse proxy.' >> mailcow.conf + echo 'AUTODISCOVER_SAN=y' >> mailcow.conf + fi + + elif [[ "${option}" == "ACME_CONTACT" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Lets Encrypt registration contact information' >> mailcow.conf echo '# Optional: Leave empty for none' >> mailcow.conf @@ -725,16 +749,16 @@ for option in ${CONFIG_ARRAY[@]}; do echo '# https://docs.mailcow.email/troubleshooting/debug-reset_tls/' >> mailcow.conf echo 'ACME_CONTACT=' >> mailcow.conf fi - elif [[ ${option} == "WEBAUTHN_ONLY_TRUSTED_VENDORS" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "WEBAUTHN_ONLY_TRUSTED_VENDORS" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo "# WebAuthn device manufacturer verification" >> mailcow.conf echo '# After setting WEBAUTHN_ONLY_TRUSTED_VENDORS=y only devices from trusted manufacturers are allowed' >> mailcow.conf echo '# root certificates can be placed for validation under mailcow-dockerized/data/web/inc/lib/WebAuthn/rootCertificates' >> mailcow.conf echo 'WEBAUTHN_ONLY_TRUSTED_VENDORS=n' >> mailcow.conf fi - elif [[ ${option} == "SPAMHAUS_DQS_KEY" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "SPAMHAUS_DQS_KEY" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo "# Spamhaus Data Query Service Key" >> mailcow.conf echo '# Optional: Leave empty for none' >> mailcow.conf @@ -743,32 +767,32 @@ for option in ${CONFIG_ARRAY[@]}; do echo '# Otherwise it will work as usual.' >> mailcow.conf echo 'SPAMHAUS_DQS_KEY=' >> mailcow.conf fi - elif [[ ${option} == "WATCHDOG_VERBOSE" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "WATCHDOG_VERBOSE" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Enable watchdog verbose logging' >> mailcow.conf echo 'WATCHDOG_VERBOSE=n' >> mailcow.conf fi - elif [[ ${option} == "SKIP_UNBOUND_HEALTHCHECK" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "SKIP_UNBOUND_HEALTHCHECK" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Skip Unbound (DNS Resolver) Healthchecks (NOT Recommended!) - y/n' >> mailcow.conf echo 'SKIP_UNBOUND_HEALTHCHECK=n' >> mailcow.conf fi - elif [[ ${option} == "DISABLE_NETFILTER_ISOLATION_RULE" ]]; then - if ! grep -q ${option} mailcow.conf; then + elif [[ "${option}" == "DISABLE_NETFILTER_ISOLATION_RULE" ]]; then + if ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo '# Prevent netfilter from setting an iptables/nftables rule to isolate the mailcow docker network - y/n' >> mailcow.conf echo '# CAUTION: Disabling this may expose container ports to other neighbors on the same subnet, even if the ports are bound to localhost' >> mailcow.conf echo 'DISABLE_NETFILTER_ISOLATION_RULE=n' >> mailcow.conf - fi - elif ! grep -q ${option} mailcow.conf; then + fi + elif ! grep -q "${option}" mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo "${option}=n" >> mailcow.conf fi done -if [[( ${SKIP_PING_CHECK} == "y")]]; then +if [[ ("${SKIP_PING_CHECK}" == "y") ]]; then echo -e "\e[32mSkipping Ping Check...\e[0m" else @@ -781,58 +805,58 @@ else fi fi -if ! [ $NEW_BRANCH ]; then +if ! [ "$NEW_BRANCH" ]; then echo -e "\e[33mDetecting which build your mailcow runs on...\e[0m" sleep 1 - if [ ${BRANCH} == "master" ]; then + if [ "${BRANCH}" == "master" ]; then echo -e "\e[32mYou are receiving stable updates (master).\e[0m" echo -e "\e[33mTo change that run the update.sh Script one time with the --nightly parameter to switch to nightly builds.\e[0m" - elif [ ${BRANCH} == "nightly" ]; then + elif [ "${BRANCH}" == "nightly" ]; then echo -e "\e[31mYou are receiving unstable updates (nightly). These are for testing purposes only!!!\e[0m" sleep 1 echo -e "\e[33mTo change that run the update.sh Script one time with the --stable parameter to switch to stable builds.\e[0m" else - echo -e "\e[33mYou are receiving updates from a unsupported branch.\e[0m" + echo -e "\e[33mYou are receiving updates from an unsupported branch.\e[0m" sleep 1 echo -e "\e[33mThe mailcow stack might still work but it is recommended to switch to the master branch (stable builds).\e[0m" echo -e "\e[33mTo change that run the update.sh Script one time with the --stable parameter to switch to stable builds.\e[0m" fi -elif [ $FORCE ]; then +elif [ "$FORCE" ]; then echo -e "\e[31mYou are running in forced mode!\e[0m" echo -e "\e[31mA Branch Switch can only be performed manually (monitored).\e[0m" echo -e "\e[31mPlease rerun the update.sh Script without the --force/-f parameter.\e[0m" sleep 1 -elif [ $NEW_BRANCH == "master" ] && [ $CURRENT_BRANCH != "master" ]; then - echo -e "\e[33mYou are about to switch your mailcow Updates to the stable (master) branch.\e[0m" +elif [ "$NEW_BRANCH" == "master" ] && [ "$CURRENT_BRANCH" != "master" ]; then + echo -e "\e[33mYou are about to switch your mailcow updates to the stable (master) branch.\e[0m" sleep 1 - echo -e "\e[33mBefore you do: Please take a backup of all components to ensure that no Data is lost...\e[0m" + echo -e "\e[33mBefore you do: Please take a backup of all components to ensure that no data is lost...\e[0m" sleep 1 - echo -e "\e[31mWARNING: Please see on GitHub or ask in the communitys if a switch to master is stable or not. - In some rear cases a Update back to master can destroy your mailcow configuration in case of Database Upgrades etc. - Normally a upgrade back to master should be safe during each full release. - Check GitHub for Database Changes and Update only if there similar to the full release!\e[0m" + echo -e "\e[31mWARNING: Please see on GitHub or ask in the community if a switch to master is stable or not. + In some rear cases an update back to master can destroy your mailcow configuration such as database upgrade, etc. + Normally an upgrade back to master should be safe during each full release. + Check GitHub for Database changes and update only if there similar to the full release!\e[0m" read -r -p "Are you sure you that want to continue upgrading to the stable (master) branch? [y/N] " response if [[ ! "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then echo "OK. If you prepared yourself for that please run the update.sh Script with the --stable parameter again to trigger this process here." exit 0 fi - BRANCH=$NEW_BRANCH + BRANCH="$NEW_BRANCH" DIFF_DIRECTORY=update_diffs - DIFF_FILE=${DIFF_DIRECTORY}/diff_before_upgrade_to_master_$(date +"%Y-%m-%d-%H-%M-%S") - mv diff_before_upgrade* ${DIFF_DIRECTORY}/ 2> /dev/null + DIFF_FILE="${DIFF_DIRECTORY}/diff_before_upgrade_to_master_$(date +"%Y-%m-%d-%H-%M-%S")" + mv diff_before_upgrade* "${DIFF_DIRECTORY}/" 2> /dev/null if ! git diff-index --quiet HEAD; then echo -e "\e[32mSaving diff to ${DIFF_FILE}...\e[0m" - mkdir -p ${DIFF_DIRECTORY} - git diff ${BRANCH} --stat > ${DIFF_FILE} - git diff ${BRANCH} >> ${DIFF_FILE} + mkdir -p "${DIFF_DIRECTORY}" + git diff "${BRANCH}" --stat > "${DIFF_FILE}" + git diff "${BRANCH}" >> "${DIFF_FILE}" fi echo -e "\e[32mSwitching Branch to ${BRANCH}...\e[0m" git fetch origin - git checkout -f ${BRANCH} + git checkout -f "${BRANCH}" -elif [ $NEW_BRANCH == "nightly" ] && [ $CURRENT_BRANCH != "nightly" ]; then +elif [ "$NEW_BRANCH" == "nightly" ] && [ "$CURRENT_BRANCH" != "nightly" ]; then echo -e "\e[33mYou are about to switch your mailcow Updates to the unstable (nightly) branch.\e[0m" sleep 1 echo -e "\e[33mBefore you do: Please take a backup of all components to ensure that no Data is lost...\e[0m" @@ -850,27 +874,27 @@ elif [ $NEW_BRANCH == "nightly" ] && [ $CURRENT_BRANCH != "nightly" ]; then if ! git diff-index --quiet HEAD; then echo -e "\e[32mSaving diff to ${DIFF_FILE}...\e[0m" mkdir -p ${DIFF_DIRECTORY} - git diff ${BRANCH} --stat > ${DIFF_FILE} - git diff ${BRANCH} >> ${DIFF_FILE} + git diff "${BRANCH}" --stat > "${DIFF_FILE}" + git diff "${BRANCH}" >> "${DIFF_FILE}" fi git fetch origin - git checkout -f ${BRANCH} + git checkout -f "${BRANCH}" fi -if [ ! $DEV ]; then +if [ ! "$DEV" ]; then echo -e "\e[32mChecking for newer update script...\e[0m" - SHA1_1=$(sha1sum update.sh) + SHA1_1="$(sha1sum update.sh)" git fetch origin #${BRANCH} - git checkout origin/${BRANCH} update.sh + git checkout "origin/${BRANCH}" update.sh SHA1_2=$(sha1sum update.sh) - if [[ ${SHA1_1} != ${SHA1_2} ]]; then + if [[ "${SHA1_1}" != "${SHA1_2}" ]]; then echo "update.sh changed, please run this script again, exiting." chmod +x update.sh exit 2 fi fi -if [ ! $FORCE ]; then +if [ ! "$FORCE" ]; then read -r -p "Are you sure you want to update mailcow: dockerized? All containers will be stopped. [y/N] " response if [[ ! "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then echo "OK, exiting." @@ -892,8 +916,8 @@ fi echo -e "\e[32mChecking for conflicting bridges...\e[0m" MAILCOW_BRIDGE=$($COMPOSE_COMMAND config | grep -i com.docker.network.bridge.name | cut -d':' -f2) while read NAT_ID; do - iptables -t nat -D POSTROUTING $NAT_ID -done < <(iptables -L -vn -t nat --line-numbers | grep $IPV4_NETWORK | grep -E 'MASQUERADE.*all' | grep -v ${MAILCOW_BRIDGE} | cut -d' ' -f1) + iptables -t nat -D POSTROUTING "$NAT_ID" +done < <(iptables -L -vn -t nat --line-numbers | grep "$IPV4_NETWORK" | grep -E 'MASQUERADE.*all' | grep -v "${MAILCOW_BRIDGE}" | cut -d' ' -f1) DIFF_DIRECTORY=update_diffs DIFF_FILE=${DIFF_DIRECTORY}/diff_before_update_$(date +"%Y-%m-%d-%H-%M-%S") @@ -901,8 +925,8 @@ mv diff_before_update* ${DIFF_DIRECTORY}/ 2> /dev/null if ! git diff-index --quiet HEAD; then echo -e "\e[32mSaving diff to ${DIFF_FILE}...\e[0m" mkdir -p ${DIFF_DIRECTORY} - git diff --stat > ${DIFF_FILE} - git diff >> ${DIFF_FILE} + git diff --stat > "${DIFF_FILE}" + git diff >> "${DIFF_FILE}" fi echo -e "\e[32mPrefetching images...\e[0m" @@ -924,13 +948,13 @@ done # Silently fixing remote url from andryyy to mailcow # git remote set-url origin https://github.com/mailcow/mailcow-dockerized -DEFAULT_REPO=https://github.com/mailcow/mailcow-dockerized +DEFAULT_REPO="https://github.com/mailcow/mailcow-dockerized" CURRENT_REPO=$(git config --get remote.origin.url) -if [ "$CURRENT_REPO" != "$DEFAULT_REPO" ]; then +if [ "$CURRENT_REPO" != "$DEFAULT_REPO" ]; then echo "The Repository currently used is not the default Mailcow Repository." echo "Currently Repository: $CURRENT_REPO" echo "Default Repository: $DEFAULT_REPO" - if [ ! $FORCE ]; then + if [ ! "$FORCE" ]; then read -r -p "Should it be changed back to default? [y/N] " repo_response if [[ "$repo_response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then git remote set-url origin $DEFAULT_REPO @@ -941,7 +965,7 @@ if [ "$CURRENT_REPO" != "$DEFAULT_REPO" ]; then fi fi -if [ ! $DEV ]; then +if [ ! "$DEV" ]; then echo -e "\e[32mCommitting current status...\e[0m" [[ -z "$(git config user.name)" ]] && git config user.name moo [[ -z "$(git config user.email)" ]] && git config user.email moo@cow.moo @@ -952,14 +976,14 @@ if [ ! $DEV ]; then git fetch origin #${BRANCH} echo -e "\e[32mMerging local with remote code (recursive, strategy: \"${MERGE_STRATEGY:-theirs}\", options: \"patience\"...\e[0m" git config merge.defaultToUpstream true - git merge -X${MERGE_STRATEGY:-theirs} -Xpatience -m "After update on ${DATE}" + git merge -X"${MERGE_STRATEGY:-theirs}" -Xpatience -m "After update on ${DATE}" # Need to use a variable to not pass return codes of if checks MERGE_RETURN=$? if [[ ${MERGE_RETURN} == 128 ]]; then echo -e "\e[31m\nOh no, what happened?\n=> You most likely added files to your local mailcow instance that were now added to the official mailcow repository. Please move them to another location before updating mailcow.\e[0m" exit 1 elif [[ ${MERGE_RETURN} == 1 ]]; then - echo -e "\e[93mPotenial conflict, trying to fix...\e[0m" + echo -e "\e[93mPotential conflict, trying to fix...\e[0m" git status --porcelain | grep -E "UD|DU" | awk '{print $2}' | xargs rm -v git add -A git commit -m "After update on ${DATE}" > /dev/null @@ -971,7 +995,7 @@ if [ ! $DEV ]; then echo "Run $COMPOSE_COMMAND up -d to restart your stack without updates or try again after fixing the mentioned errors." exit 1 fi -elif [ $DEV ]; then +elif [ "$DEV" ]; then echo -e "\e[33mDEVELOPER MODE: Not creating a git diff and commiting it to prevent development stuff within a backup diff...\e[0m" fi @@ -1018,7 +1042,7 @@ fi # Set app_info.inc.php if [ ${BRANCH} == "master" ]; then - mailcow_git_version=$(git describe --tags `git rev-list --tags --max-count=1`) + mailcow_git_version=$(git describe --tags $(git rev-list --tags --max-count=1)) elif [ ${BRANCH} == "nightly" ]; then mailcow_git_version=$(git rev-parse --short $(git rev-parse @{upstream})) mailcow_last_git_version="" @@ -1027,7 +1051,7 @@ else mailcow_last_git_version="" fi -mailcow_git_commit=$(git rev-parse origin/${BRANCH}) +mailcow_git_commit=$(git rev-parse "origin/${BRANCH}") mailcow_git_commit_date=$(git log -1 --format=%ci @{upstream} ) if [ $? -eq 0 ]; then