freedombox Debian release 25.9.3

-----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEEfWrbdQ+RCFWJSEvmd8DHXntlCAgFAmh+5csWHGp2YWxsZXJv
 eUBtYWlsYm94Lm9yZwAKCRB3wMdee2UICBJTEACkXodViasvoeQrzQg910c1JLVO
 YnENNLfwoBlhlqoAImMV1Ih1BYzkYLBMNl8bbrxZOmmpYwlkuiSLPz/GwNLmGcRV
 ekxONZuR1cOCM+ZhyTuhrvTAapqRsEmaylRV5JObZGF/0mHwfLqq0uTjIVMDFHTl
 nxaAbvskO8G7CYFUXBg8VL1PMX2x+/AuuBmdNDoIC34uV3HMTzBkg6BDUpSvIh6o
 GOHPnXHy2Y5nmk9y2qBCL+Z54fCLUig2IXXE48EiC1fqjfK8WS1dr89MksVfVyvX
 skQQeRLtl5wjHj5YrHXgk9blsdVxanaKeq4z2se86ADihSMQ5cnJ2Oy6rLebcPkv
 FHcKIT+RG6tW/iUC6NMutZ3We8DrC5idK0JuLMM/GWqPkM9KyNt4WNx39u3uxGfY
 qLNUweISYHpoEN/6+xBc5M+b47ooappc8HMULToNbdU6WlkKWRzouUsRBHr4W8+r
 eR4I74ZvoeEw5UCQhAiJpdx4MZR1bd4rDMG80LI7/PjXsDaUkyuQrIXZ9sDe+XXA
 vAKYuDsgGVHA0ZxwFWXnuFvgItnelAsPmLocsfsQ+KkE1Tq4jRpyLOwet1DK146Q
 bPPMlsFunTkxGbZXtlq4JxTGUlulHnuUpdetj7mV0UqgUm3WS0iEVjoqggJMgsLo
 YCWEDVBjdPb2s0ApcA==
 =j8oe
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEEfWrbdQ+RCFWJSEvmd8DHXntlCAgFAmiEs8EWHGp2YWxsZXJv
 eUBtYWlsYm94Lm9yZwAKCRB3wMdee2UICFpUD/wPfy0ENTkzMVkoUkeV0aHRzLhu
 3cQwb4kCCtHNh4I06TxSN8NW5o29ubKZIua6e2JUwNcSn86MVEJuzhNQQRRpObeR
 5Z7cvTMbD/uOzvS/6mEKNCSvZvZgFy0QlwkUi81PVQN2rzL94Ksa/IDc5dewlGqt
 RVR3mi/EYMEOVZzIFndUVOR1PhER3lN2Ojpl6lDfN0sp0axnsNs2+B0+PUCn31nZ
 Hlai1rNViTvg3DcHSLKSx3GGpw2qGX3tU8Q1IiwvguAVS1Rlmi5ht2Zu0QVSrAcf
 3GDZa+AfO3uvvgUxlBGax6WgD3PDGXmGIaSrp6AJG2nTbfE4FWpvUh8rOkAvC+jB
 v5w26L1BK+qrhlHZkcKLWQNqrktSOfWiPuivHjIqXKgH6FnekXVkjjAE0Xm/I6S3
 gyCVVJixBT6w7bggWNpiPgXl+KXK3s1KjiOy1oPBIdN+1+VBrPuO74Kb34PpduJb
 8u+XQc1csAvWM9BCifygx1pGiePJuOoxj2BbLNiQpYZOsdW8lEtG8PnLr4LLCLoa
 sEkAqw1Zk9jaVX8i7y6NBz0/kWBa7gbtGzHBiz9LwB8Zh9A9jVMSV1FsJSJEcxoV
 bLYt522obWcj/8gAzQBhGezACQJh3blOtfl5yY6lbKE+bZ+CQE24K/878CWo4WZM
 YKC3edeeJ9q/OiZ8Zw==
 =iu54
 -----END PGP SIGNATURE-----

Merge tag 'v25.9.3' into debian/bookworm-backports

freedombox Debian release 25.9.3
This commit is contained in:
James Valleroy 2025-07-26 06:53:48 -04:00
commit ccb31816f6
38 changed files with 669 additions and 237 deletions

30
debian/changelog vendored
View File

@ -1,3 +1,33 @@
freedombox (25.9.3) unstable; urgency=medium
[ J AK ]
* Translated using Weblate (Albanian)
[ Besnik Bleta ]
* Translated using Weblate (Albanian)
[ kosagi ]
* Translated using Weblate (Catalan)
[ தமிழ்நேரம் ]
* Translated using Weblate (Tamil)
[ Benedek Nagy ]
* sogo: Fix typo in configuration for sieve server
* email: Add support for Dovecot 2.4
[ Sunil Mohan Adapa ]
* config: Allow overriding target path in dropin config component
* email: Start servers during re-setup if they are not running
[ 109247019824 ]
* Translated using Weblate (Bulgarian)
[ Priit Jõerüüt ]
* Translated using Weblate (Estonian)
-- James Valleroy <jvalleroy@mailbox.org> Mon, 21 Jul 2025 19:29:32 -0400
freedombox (25.9.2~bpo12+1) bookworm-backports; urgency=medium
* Rebuild for bookworm-backports.

View File

@ -3,4 +3,4 @@
Package init file.
"""
__version__ = '25.9.2'
__version__ = '25.9.3'

View File

@ -108,14 +108,12 @@ class DropinConfigs(app_module.FollowerComponent):
return results
@staticmethod
def get_target_path(path):
def get_target_path(self, path):
"""Return Path object for a target path."""
target = pathlib.Path(DropinConfigs.ROOT)
target /= DropinConfigs.DROPIN_CONFIG_ROOT.lstrip('/')
target = pathlib.Path(self.ROOT)
target /= self.DROPIN_CONFIG_ROOT.lstrip('/')
return target / path.lstrip('/')
@staticmethod
def get_etc_path(path):
def get_etc_path(self, path):
"""Return Path object for etc path."""
return pathlib.Path(DropinConfigs.ROOT) / path.lstrip('/')
return pathlib.Path(self.ROOT) / path.lstrip('/')

View File

@ -8,9 +8,9 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-21 20:08-0400\n"
"PO-Revision-Date: 2025-02-25 21:04+0000\n"
"Last-Translator: 109247019824 <109247019824@users.noreply.hosted.weblate."
"org>\n"
"PO-Revision-Date: 2025-07-20 18:01+0000\n"
"Last-Translator: 109247019824 <109247019824@users.noreply.hosted.weblate.org>"
"\n"
"Language-Team: Bulgarian <https://hosted.weblate.org/projects/freedombox/"
"freedombox/bg/>\n"
"Language: bg\n"
@ -18,7 +18,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.10.2-dev\n"
"X-Generator: Weblate 5.13-dev\n"
#: config.py:103
#, python-brace-format
@ -199,7 +199,7 @@ msgstr "Домейн в местната мрежа"
#: modules/avahi/manifest.py:14
msgid "Auto-discovery"
msgstr ""
msgstr "Автоматично откриване"
#: modules/avahi/manifest.py:14 modules/backups/manifest.py:17
msgid "Local"
@ -207,7 +207,7 @@ msgstr "Местно"
#: modules/avahi/manifest.py:14
msgid "mDNS"
msgstr ""
msgstr "mDNS"
#: modules/backups/__init__.py:24
msgid "Backups allows creating and managing backup archives."
@ -8203,10 +8203,8 @@ msgstr ""
#: modules/upgrades/templates/upgrades-dist-upgrade-notification.html:9
#: modules/upgrades/templates/upgrades-dist-upgrade.html:11
#: modules/upgrades/templates/upgrades_configure.html:16
#, fuzzy
#| msgid "Distribution update started"
msgid "Distribution Update"
msgstr "Започнато е обновяване на дистрибуцията"
msgstr "Начало на бновяване на дистрибуцията"
#: modules/upgrades/__init__.py:396
msgid "Check for package holds"
@ -8267,10 +8265,8 @@ msgid "Next"
msgstr "Напред"
#: modules/upgrades/templates/upgrades-dist-upgrade-confirm.html:11
#, fuzzy
#| msgid "Could not start distribution update"
msgid "Confirm Distribution Update?"
msgstr "Обновяването на дистрибуцията не може да бъде стартирано"
msgstr "Потвърждавате ли бновяване на дистрибуцията?"
#: modules/upgrades/templates/upgrades-dist-upgrade-confirm.html:21
#, python-format
@ -8303,10 +8299,8 @@ msgid "If the process is interrupted, you should be able to continue it."
msgstr ""
#: modules/upgrades/templates/upgrades-dist-upgrade-confirm.html:66
#, fuzzy
#| msgid "Could not start distribution update"
msgid "Confirm & Start Distribution Update"
msgstr "Обновяването на дистрибуцията не може да бъде стартирано"
msgstr "Потвърждаване и обновяване на дистрибуцията"
#: modules/upgrades/templates/upgrades-dist-upgrade-notification.html:15
msgid ""
@ -8336,10 +8330,8 @@ msgid ""
msgstr ""
#: modules/upgrades/templates/upgrades-dist-upgrade-notification.html:42
#, fuzzy
#| msgid "Test Distribution Upgrade"
msgid "Go to Distribution Update"
msgstr "Надграждане на дистрибуцията до тестова"
msgstr "Към обновяване на дистрибуцията"
#: modules/upgrades/templates/upgrades-dist-upgrade-notification.html:46
#: modules/upgrades/templates/upgrades-new-release.html:22
@ -8368,16 +8360,12 @@ msgid ""
msgstr ""
#: modules/upgrades/templates/upgrades-dist-upgrade.html:50
#, fuzzy
#| msgid "Frequent feature updates are activated."
msgid "Automatic updates are disabled."
msgstr "Честото обновяване на пакети е включено."
msgstr "Автоматичното обновяване е изключено."
#: modules/upgrades/templates/upgrades-dist-upgrade.html:54
#, fuzzy
#| msgid "Distribution update started"
msgid "Distribution upgrades are disabled."
msgstr "Започнато е обновяване на дистрибуцията"
msgstr "Обновяванията на дистрибуцията са изключени."
#: modules/upgrades/templates/upgrades-dist-upgrade.html:58
msgid ""
@ -8390,10 +8378,8 @@ msgid "Your current distribution is mixed or not understood."
msgstr ""
#: modules/upgrades/templates/upgrades-dist-upgrade.html:72
#, fuzzy
#| msgid "Test Distribution Upgrade"
msgid "Current Distribution:"
msgstr "Надграждане на дистрибуцията до тестова"
msgstr "Текуща дистрибуция:"
#: modules/upgrades/templates/upgrades-dist-upgrade.html:74
msgid "Unknown or mixed"
@ -8409,10 +8395,8 @@ msgid "Released: %(date)s."
msgstr ""
#: modules/upgrades/templates/upgrades-dist-upgrade.html:91
#, fuzzy
#| msgid "Test Distribution Upgrade"
msgid "Next Stable Distribution:"
msgstr "Надграждане на дистрибуцията до тестова"
msgstr "Следваща стабилна дистрибуция:"
#: modules/upgrades/templates/upgrades-dist-upgrade.html:93
msgid "Unknown"
@ -8467,22 +8451,16 @@ msgstr ""
#: modules/upgrades/templates/upgrades-dist-upgrade.html:157
#: modules/upgrades/templates/upgrades-dist-upgrade.html:172
#, fuzzy
#| msgid "Test Distribution Upgrade"
msgid "Start Distribution Update"
msgstr "Надграждане на дистрибуцията до тестова"
msgstr "Начало на обновяване на дистрибуцията"
#: modules/upgrades/templates/upgrades-dist-upgrade.html:162
#, fuzzy
#| msgid "Test Distribution Upgrade"
msgid "Continue Distribution Update"
msgstr "Надграждане на дистрибуцията до тестова"
msgstr "Продължаване обновяването на дистрибуцията"
#: modules/upgrades/templates/upgrades-dist-upgrade.html:167
#, fuzzy
#| msgid "Starting distribution upgrade test."
msgid "Start Distribution Update (for testing)"
msgstr "Начало на опит за обновяване на дистрибуцията."
msgstr "Начало на обновяване на дистрибуцията (за проба)"
#: modules/upgrades/templates/upgrades-new-release.html:9
#, python-format
@ -8562,10 +8540,8 @@ msgid "Error when configuring unattended-upgrades"
msgstr "Грешка при настройка на unattended-upgrades"
#: modules/upgrades/views.py:117
#, fuzzy
#| msgid "Starting distribution upgrade test."
msgid "Started distribution update."
msgstr "Начало на опит за обновяване на дистрибуцията."
msgstr "Обновяване на дистрибуцията е започнато."
#: modules/upgrades/views.py:153
msgid "Upgrade process started."

View File

@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-21 20:08-0400\n"
"PO-Revision-Date: 2025-05-29 10:01+0000\n"
"PO-Revision-Date: 2025-06-25 22:04+0000\n"
"Last-Translator: kosagi <marti.torra@natana.cat>\n"
"Language-Team: Catalan <https://hosted.weblate.org/projects/freedombox/"
"freedombox/ca/>\n"
@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.12-dev\n"
"X-Generator: Weblate 5.13-dev\n"
#: config.py:103
#, python-brace-format
@ -2599,26 +2599,28 @@ msgid ""
"Wiki title and description can be set from within the wiki. This file name "
"is independent of the wiki title."
msgstr ""
"El títol i la descripció del wiki es poden establir des de dins del wiki. "
"Aquest nom de fitxer és independent del títol del wiki."
#: modules/featherwiki/forms.py:23 modules/tiddlywiki/forms.py:23
msgid "New name for the wiki file, with file extension \".html\""
msgstr ""
msgstr "Nou nom per al fitxer del wiki, amb l'extensió de fitxer \".html\""
#: modules/featherwiki/forms.py:25 modules/tiddlywiki/forms.py:25
msgid "Renaming the file has no effect on the title of the wiki."
msgstr ""
msgstr "Canviar el nom del fitxer no té cap efecte sobre el títol del wiki."
#: modules/featherwiki/forms.py:32
msgid "A Feather Wiki file with .html file extension"
msgstr ""
msgstr "Un fitxer Feather Wiki amb l'extensió de fitxer .html"
#: modules/featherwiki/forms.py:35
msgid "Feather Wiki files must be in HTML format"
msgstr ""
msgstr "Els fitxers Feather Wiki han d'estar en format HTML"
#: modules/featherwiki/forms.py:37
msgid "Upload an existing Feather Wiki file from this computer."
msgstr ""
msgstr "Carrega un fitxer Feather Wiki existent des d'aquest ordinador."
#: modules/featherwiki/manifest.py:18
#: modules/help/templates/help_about.html:108 modules/ikiwiki/manifest.py:15
@ -2629,7 +2631,7 @@ msgstr "Wiki"
#: modules/featherwiki/manifest.py:18 modules/infinoted/manifest.py:46
#: modules/tiddlywiki/manifest.py:20
msgid "Note taking"
msgstr ""
msgstr "Prendre notes"
#: modules/featherwiki/manifest.py:18 modules/ikiwiki/manifest.py:15
#: modules/mediawiki/manifest.py:25 modules/tiddlywiki/manifest.py:21
@ -2639,17 +2641,17 @@ msgstr "Pàgina Web"
#: modules/featherwiki/manifest.py:18 modules/tiddlywiki/manifest.py:25
msgid "Quine"
msgstr ""
msgstr "Quine"
#: modules/featherwiki/manifest.py:18 modules/nextcloud/manifest.py:56
#: modules/tiddlywiki/manifest.py:26
msgid "Non-Debian"
msgstr ""
msgstr "No-Debian"
#: modules/featherwiki/templates/featherwiki_configure.html:12
#: modules/tiddlywiki/templates/tiddlywiki_configure.html:12
msgid "Manage Wikis"
msgstr ""
msgstr "Gestiona les Wikis"
#: modules/featherwiki/templates/featherwiki_configure.html:16
#: modules/featherwiki/templates/featherwiki_configure.html:18
@ -2658,100 +2660,102 @@ msgstr ""
#: modules/tiddlywiki/templates/tiddlywiki_configure.html:18
#: modules/tiddlywiki/views.py:47
msgid "Create Wiki"
msgstr ""
msgstr "Crea una Wiki"
#: modules/featherwiki/templates/featherwiki_configure.html:21
#: modules/featherwiki/templates/featherwiki_configure.html:23
#: modules/tiddlywiki/templates/tiddlywiki_configure.html:21
#: modules/tiddlywiki/templates/tiddlywiki_configure.html:23
msgid "Upload Wiki"
msgstr ""
msgstr "Penja una Wiki"
#: modules/featherwiki/templates/featherwiki_configure.html:30
#: modules/tiddlywiki/templates/tiddlywiki_configure.html:30
msgid "No wikis available."
msgstr ""
msgstr "No hi ha wikis disponibles."
#: modules/featherwiki/templates/featherwiki_configure.html:36
#: modules/tiddlywiki/templates/tiddlywiki_configure.html:36
#, python-format
msgid "Go to wiki %(wiki)s"
msgstr ""
msgstr "Ves a la wiki %(wiki)s"
#: modules/featherwiki/templates/featherwiki_configure.html:43
#: modules/tiddlywiki/templates/tiddlywiki_configure.html:43
#, python-format
msgid "Rename wiki %(wiki)s"
msgstr ""
msgstr "Reanomena la wiki %(wiki)s"
#: modules/featherwiki/templates/featherwiki_configure.html:50
#: modules/tiddlywiki/templates/tiddlywiki_configure.html:50
#, python-format
msgid "Delete wiki %(wiki)s"
msgstr ""
msgstr "Elimina la wiki %(wiki)s"
#: modules/featherwiki/templates/featherwiki_delete.html:12
#: modules/tiddlywiki/templates/tiddlywiki_delete.html:12
#, python-format
msgid "Delete wiki <em>%(name)s</em>"
msgstr ""
msgstr "Elimina la wiki <em>%(name)s</em>"
#: modules/featherwiki/templates/featherwiki_delete.html:18
msgid ""
"<strong>Hint</strong>: You can download a copy of this wiki from within "
"Feather Wiki before deleting it."
msgstr ""
"<strong>Consell</strong>: Pots descarregar una còpia d'aquest wiki des de "
"dins de Feather Wiki abans d'eliminar-lo."
#: modules/featherwiki/templates/featherwiki_delete.html:25
#: modules/tiddlywiki/templates/tiddlywiki_delete.html:25
msgid "Delete this wiki file permanently?"
msgstr ""
msgstr "Eliminar aquest fitxer de wiki de manera permanent?"
#: modules/featherwiki/templates/featherwiki_upload_file.html:20
#: modules/tiddlywiki/templates/tiddlywiki_upload_file.html:20
msgid "Upload"
msgstr ""
msgstr "Penja"
#: modules/featherwiki/views.py:20 modules/tiddlywiki/views.py:20
msgid "A wiki file with the given name already exists."
msgstr ""
msgstr "Ja hi ha un fitxer de wiki amb aquest nom."
#: modules/featherwiki/views.py:54 modules/tiddlywiki/views.py:54
msgid "Wiki created."
msgstr ""
msgstr "Wiki creada."
#: modules/featherwiki/views.py:59 modules/tiddlywiki/views.py:59
msgid "An error occurred while creating the wiki."
msgstr ""
msgstr "Hi ha hagut un error al crear la wiki."
#: modules/featherwiki/views.py:76 modules/tiddlywiki/views.py:76
msgid "Rename Wiki"
msgstr ""
msgstr "Reanomena la Wiki"
#: modules/featherwiki/views.py:84 modules/tiddlywiki/views.py:84
msgid "Wiki renamed."
msgstr ""
msgstr "Nom de la wiki actualitzat."
#: modules/featherwiki/views.py:89 modules/tiddlywiki/views.py:89
msgid "An error occurred while renaming the wiki."
msgstr ""
msgstr "Hi ha hagut un error al reanomenar la wiki."
#: modules/featherwiki/views.py:106 modules/tiddlywiki/views.py:106
msgid "Upload Wiki File"
msgstr ""
msgstr "Penja un fitxer de Wiki"
#: modules/featherwiki/views.py:115 modules/tiddlywiki/views.py:116
msgid "Wiki file added."
msgstr ""
msgstr "Fitxer de Wiki afegit."
#: modules/featherwiki/views.py:119 modules/tiddlywiki/views.py:120
msgid "Failed to add wiki file."
msgstr ""
msgstr "No s'ha pogut afegir el fitxer de wiki."
#: modules/featherwiki/views.py:138 modules/tiddlywiki/views.py:139
#, python-brace-format
msgid "Could not delete {name}"
msgstr ""
msgstr "No s'ha pogut eliminar {name}"
#: modules/firewall/__init__.py:25
#, python-brace-format
@ -2760,83 +2764,87 @@ msgid ""
"network traffic on your {box_name}. Keeping a firewall enabled and properly "
"configured reduces risk of security threat from the Internet."
msgstr ""
"El tallafocs és un sistema de seguretat que controla el trànsit de xarxa "
"entrant i sortint del teu {box_name}. Mantenir el tallafocs activat i "
"configurat correctament redueix el risc damenaces de seguretat des "
"dInternet."
#: modules/firewall/__init__.py:61
msgid "Firewall"
msgstr ""
msgstr "Tallafocs"
#: modules/firewall/__init__.py:262
msgid "Default zone is external"
msgstr ""
msgstr "La zona per defecte és externa"
#: modules/firewall/__init__.py:272
msgid "Firewall backend is nftables"
msgstr ""
msgstr "El backend del tallafocs és nftables"
#: modules/firewall/__init__.py:286
msgid "Direct passthrough rules exist"
msgstr ""
msgstr "Existeixen regles de pas directe"
#: modules/firewall/components.py:139
#, python-brace-format
msgid "Port {name} ({details}) available for internal networks"
msgstr ""
msgstr "Port {name} ({details}) disponible per a xarxes internes"
#: modules/firewall/components.py:154
#, python-brace-format
msgid "Port {name} ({details}) available for external networks"
msgstr ""
msgstr "Port {name} ({details}) disponible per a xarxes externes"
#: modules/firewall/components.py:160
#, python-brace-format
msgid "Port {name} ({details}) unavailable for external networks"
msgstr ""
msgstr "Port {name} ({details}) no disponible per a xarxes externes"
#: modules/firewall/manifest.py:10 modules/tor/templates/tor.html:25
msgid "Ports"
msgstr ""
msgstr "Ports"
#: modules/firewall/manifest.py:10
msgid "Blocking"
msgstr ""
msgstr "Bloquejant"
#: modules/firewall/manifest.py:10 modules/networks/forms.py:319
#: modules/upgrades/manifest.py:10
msgid "Automatic"
msgstr ""
msgstr "Automàtic"
#: modules/firewall/templates/firewall.html:21
msgid "Service/Port"
msgstr ""
msgstr "Servei/Port"
#: modules/firewall/templates/firewall.html:40
#: modules/letsencrypt/templates/letsencrypt.html:69
#: modules/snapshot/forms.py:23 modules/snapshot/forms.py:29
msgid "Enabled"
msgstr ""
msgstr "Habilitat"
#: modules/firewall/templates/firewall.html:43
#: modules/letsencrypt/templates/letsencrypt.html:71
#: modules/snapshot/forms.py:23 modules/snapshot/forms.py:29
#: templates/cards.html:38
msgid "Disabled"
msgstr ""
msgstr "Inhabilitat"
#: modules/firewall/templates/firewall.html:58
msgid "Permitted"
msgstr ""
msgstr "Permès"
#: modules/firewall/templates/firewall.html:61
msgid "Permitted (internal only)"
msgstr ""
msgstr "Permès (només intern)"
#: modules/firewall/templates/firewall.html:64
msgid "Permitted (external only)"
msgstr ""
msgstr "Permès (només extern)"
#: modules/firewall/templates/firewall.html:67
msgid "Blocked"
msgstr ""
msgstr "Bloquejat"
#: modules/firewall/templates/firewall.html:80
msgid ""
@ -2844,22 +2852,28 @@ msgid ""
"also permitted in the firewall and when you disable a service it is also "
"disabled in the firewall."
msgstr ""
"L'operació del tallafocs és automàtica. Quan actives un servei, també està "
"permès al tallafocs, i quan desactives un servei, també es desactiva al "
"tallafocs."
#: modules/firewall/templates/firewall.html:88
#: modules/networks/templates/networks_configuration.html:22
#: modules/storage/templates/storage.html:93
msgid "Advanced"
msgstr ""
msgstr "Avançat"
#: modules/firewall/templates/firewall.html:90
msgid ""
"Advanced firewall operations such as opening custom ports are provided by "
"the <a href=\"/_cockpit/network/firewall\">Cockpit</a> app."
msgstr ""
"Les operacions avançades del tallafocs, com ara obrir ports personalitzats, "
"les proporciona l'aplicació <a href=\"/_cockpit/network/firewall\""
">Cockpit</a>."
#: modules/first_boot/__init__.py:61
msgid "Setup complete! Next steps:"
msgstr ""
msgstr "Configuració completada! Properes passes:"
#: modules/first_boot/__init__.py:63
#, python-brace-format
@ -2867,14 +2881,16 @@ msgid ""
"Initial setup has been completed. Perform the next steps to make your "
"{box_name} operational."
msgstr ""
"La configuració inicial sha completat. Realitza els següents passos per fer "
"que el teu {box_name} estigui operatiu."
#: modules/first_boot/__init__.py:66
msgid "Next steps"
msgstr ""
msgstr "Propers passos"
#: modules/first_boot/__init__.py:73
msgid "See next steps"
msgstr ""
msgstr "Veure els passos següents"
#: modules/first_boot/forms.py:14
#, python-brace-format
@ -2883,14 +2899,17 @@ msgid ""
"also be obtained by running the command \"sudo cat /var/lib/plinth/firstboot-"
"wizard-secret\" on your {box_name}"
msgstr ""
"Introdueix el secret generat durant la instal·lació de FreedomBox. Aquest "
"secret també es pot obtenir executant la comanda "
"\"sudo cat /var/lib/plinth/firstboot-wizard-secret\" al teu {box_name}"
#: modules/first_boot/forms.py:19
msgid "Firstboot Wizard Secret"
msgstr ""
msgstr "Secret de l'Assistent de Primera Execució"
#: modules/first_boot/templates/firstboot_complete.html:14
msgid "Setup Complete! Next Steps:"
msgstr ""
msgstr "Configuració completada! Passos següents:"
#: modules/first_boot/templates/firstboot_complete.html:21
#, python-format
@ -2898,17 +2917,22 @@ msgid ""
"Automatic <a href=\"%(upgrades_url)s\" target=\"_blank\">software update</a> "
"runs daily by default. For the first time, manually run it now."
msgstr ""
"L<a href=\"%(upgrades_url)s\" target=\"_blank\">actualització automàtica de "
"programari</a> sexecuta diàriament per defecte. Per primera vegada, executa-"
"la manualment ara."
#: modules/first_boot/templates/firstboot_complete.html:30
#: modules/upgrades/templates/upgrades_configure.html:119
msgid "Update now"
msgstr ""
msgstr "Actualitza-ho ara"
#: modules/first_boot/templates/firstboot_complete.html:39
#, python-format
msgid ""
"Review <a href=\"%(privacy_url)s\" target=\"_blank\">privacy options</a>."
msgstr ""
"Revisa les <a href=\"%(privacy_url)s\" target=\"_blank\">opcions de "
"privadesa</a>."
#: modules/first_boot/templates/firstboot_complete.html:49
#, python-format
@ -2916,12 +2940,16 @@ msgid ""
"Review and setup <a href=\"%(networks_url)s\" target=\"_blank\">network "
"connections</a>. Change the default Wi-Fi password, if applicable."
msgstr ""
"Revisa i configura les <a href=\"%(networks_url)s\" target=\"_blank\""
">connexions de xarxa</a>. Canvia la contrasenya Wi-Fi per defecte, si "
"sescau."
#: modules/first_boot/templates/firstboot_complete.html:60
#, python-format
msgid ""
"Configure a <a href=\"%(names_url)s\" target=\"_blank\">domain name</a>."
msgstr ""
"Configura un <a href=\"%(names_url)s\" target=\"_blank\">nom de domini</a>."
#: modules/first_boot/templates/firstboot_complete.html:70
#, python-format
@ -2929,6 +2957,8 @@ msgid ""
"Configure and schedule remote <a href=\"%(backups_url)s\" "
"target=\"_blank\">backups</a>."
msgstr ""
"Configura i programa còpies de seguretat <a href=\"%(backups_url)s\" target="
"\"_blank\">remotes</a>."
#: modules/first_boot/templates/firstboot_complete.html:81
#, python-format
@ -2936,14 +2966,16 @@ msgid ""
"Put %(box_name)s to use by installing <a href=\"%(apps_url)s\" "
"target=\"_blank\">apps</a>."
msgstr ""
"Posa %(box_name)s en funcionament instal·lant <a href=\"%(apps_url)s\" "
"target=\"_blank\">aplicacions</a>."
#: modules/first_boot/templates/firstboot_welcome.html:29
msgid "Start Setup"
msgstr ""
msgstr "Inicia la configuració"
#: modules/first_boot/views.py:41
msgid "Setup Complete"
msgstr ""
msgstr "Configuració completada"
#: modules/gitweb/__init__.py:22
msgid ""
@ -2955,16 +2987,25 @@ msgid ""
"available graphical clients. And you can share your code with people around "
"the world."
msgstr ""
"Git és un sistema de control de versions distribuït per fer el seguiment de "
"canvis en el codi font durant el desenvolupament de programari. Gitweb "
"proporciona una interfície web als repositoris Git. Pots navegar per "
"l'historial i el contingut del codi font, utilitzar la cerca per trobar "
"commits i codi rellevants. També pots clonar repositoris i pujar canvis de "
"codi amb un client Git de línia de comandes o amb diversos clients gràfics "
"disponibles. I pots compartir el teu codi amb persones de tot el món."
#: modules/gitweb/__init__.py:29
msgid ""
"To learn more on how to use Git visit <a href=\"https://git-scm.com/docs/"
"gittutorial\">Git tutorial</a>."
msgstr ""
"Per aprendre més sobre com utilitzar Git, visita <a href="
"\"https://git-scm.com/docs/gittutorial\">tutorial de Git</a>."
#: modules/gitweb/__init__.py:45
msgid "Read-write access to Git repositories"
msgstr ""
msgstr "Accés de lectura i escriptura als repositoris Git"
#: modules/gitweb/__init__.py:48 modules/gitweb/manifest.py:10
msgid "Gitweb"
@ -2972,128 +3013,130 @@ msgstr "Gitweb"
#: modules/gitweb/forms.py:59
msgid "Invalid repository URL."
msgstr ""
msgstr "URL del repositori no vàlida."
#: modules/gitweb/forms.py:69
msgid "Invalid repository name."
msgstr ""
msgstr "Nom del repositori no vàlid."
#: modules/gitweb/forms.py:77
msgid "Name of a new repository or URL to import an existing repository."
msgstr ""
msgstr "Nom dun repositori nou o URL per importar un repositori existent."
#: modules/gitweb/forms.py:83
msgid "Description of the repository"
msgstr ""
msgstr "Descripció del repositori"
#: modules/gitweb/forms.py:84 modules/gitweb/forms.py:88
msgid "Optional, for displaying on Gitweb."
msgstr ""
msgstr "Opcional, per mostrar a Gitweb."
#: modules/gitweb/forms.py:86
msgid "Repository's owner name"
msgstr ""
msgstr "Nom del propietari del Repositori"
#: modules/gitweb/forms.py:91
msgid "Private repository"
msgstr ""
msgstr "Repositori privat"
#: modules/gitweb/forms.py:92
msgid "Allow only authorized users to access this repository."
msgstr ""
msgstr "Permet que només usuaris autoritzats accedeixin a aquest repositori."
#: modules/gitweb/forms.py:113 modules/gitweb/forms.py:155
msgid "A repository with this name already exists."
msgstr ""
msgstr "Ja existeix un repositori amb aquest nom."
#: modules/gitweb/forms.py:126
msgid "Name of the repository"
msgstr ""
msgstr "Nom del repositori"
#: modules/gitweb/forms.py:130
msgid "An alpha-numeric string that uniquely identifies a repository."
msgstr ""
msgstr "Una cadena alfanumèrica que identifica de manera única un repositori."
#: modules/gitweb/forms.py:134
msgid "Default branch"
msgstr ""
msgstr "Branca principal"
#: modules/gitweb/forms.py:135
msgid "Gitweb displays this as a default branch."
msgstr ""
msgstr "La Gitweb sempre mostra això com a branca principal."
#: modules/gitweb/manifest.py:18
msgid "Git"
msgstr ""
msgstr "Git"
#: modules/gitweb/manifest.py:37
msgid "Git hosting"
msgstr ""
msgstr "Allotjament Git"
#: modules/gitweb/manifest.py:37
msgid "Version control"
msgstr ""
msgstr "Control de versions"
#: modules/gitweb/manifest.py:37
msgid "Developer tool"
msgstr ""
msgstr "Eines de desenvolupador"
#: modules/gitweb/templates/gitweb_configure.html:13
msgid "Manage Repositories"
msgstr ""
msgstr "Gestiona Repositoris"
#: modules/gitweb/templates/gitweb_configure.html:17
#: modules/gitweb/templates/gitweb_configure.html:19
msgid "Create repository"
msgstr ""
msgstr "Crea un repositori"
#: modules/gitweb/templates/gitweb_configure.html:26
msgid "No repositories available."
msgstr ""
msgstr "No hi ha repositoris disponibles."
#: modules/gitweb/templates/gitweb_configure.html:35
#, python-format
msgid "Go to repository %(repo.name)s"
msgstr ""
msgstr "Ves al repositori %(repo.name)s"
#: modules/gitweb/templates/gitweb_configure.html:42
msgid "Cloning…"
msgstr ""
msgstr "Clonant…"
#: modules/gitweb/templates/gitweb_configure.html:59
#, python-format
msgid "Delete repository %(repo.name)s"
msgstr ""
msgstr "Elimina el repositori %(repo.name)s"
#: modules/gitweb/templates/gitweb_delete.html:12
#, python-format
msgid "Delete Git Repository <em>%(name)s</em>"
msgstr ""
msgstr "Elimina el repositori Git <em>%(name)s</em>"
#: modules/gitweb/templates/gitweb_delete.html:18
msgid "Delete this repository permanently?"
msgstr ""
msgstr "Vols eliminar aquest repositori permanentment?"
#: modules/gitweb/views.py:46
msgid "Repository created."
msgstr ""
msgstr "Repositori creat."
#: modules/gitweb/views.py:69
msgid "An error occurred while creating the repository."
msgstr ""
msgstr "Hi ha hagut un error al crear el repositori."
#: modules/gitweb/views.py:84
msgid "Repository edited."
msgstr ""
msgstr "Repositori editat."
#: modules/gitweb/views.py:89
msgid "Edit repository"
msgstr ""
msgstr "Edita el repositori"
#: modules/gnome/__init__.py:18
msgid ""
"GNOME is a desktop environment that focuses on simplicity and ease of use."
msgstr ""
"GNOME és un entorn d'escriptori que se centra en la simplicitat i la "
"facilitat d'ús."
#: modules/gnome/__init__.py:21
#, python-brace-format
@ -3103,12 +3146,20 @@ msgid ""
"suite, and other basic utilities are available. You may install further "
"graphical applications using the software center provided within."
msgstr ""
"Aquesta aplicació transforma el teu {box_name} en un ordinador descriptori "
"si hi connectes físicament un monitor, un teclat i un ratolí. Tens "
"disponible un navegador, una suite dofimàtica i altres utilitats bàsiques. "
"També pots instal·lar més aplicacions gràfiques mitjançant el centre de "
"programari que sofereix a linterior."
#: modules/gnome/__init__.py:26
msgid ""
"This app is not suitable for low-end hardware. It requires at least 4GiB of "
"RAM, 4GiB of disk space and a GPU capable of basic 3D acceleration."
msgstr ""
"Aquesta aplicació no és adequada per a maquinari de baix rendiment. "
"Requereix com a mínim 4 GiB de RAM, 4 GiB d'espai al disc i una GPU capaç "
"d'acceleració 3D bàsica."
#: modules/gnome/__init__.py:30
#, python-brace-format
@ -3117,45 +3168,48 @@ msgid ""
"need to <a href=\"{power_url}\">restart</a> the machine for changes to take "
"effect."
msgstr ""
"Després dinstal·lar, activar, desactivar o desinstal·lar laplicació, "
"hauràs de <a href=\"{power_url}\">reiniciar</a> la màquina perquè els canvis "
"tinguin efecte."
#: modules/gnome/__init__.py:48
msgid "GNOME"
msgstr ""
msgstr "GNOME"
#: modules/gnome/manifest.py:9 templates/clients.html:42
msgid "Desktop"
msgstr ""
msgstr "Escriptori"
#: modules/gnome/manifest.py:10
msgid "Browser"
msgstr ""
msgstr "Navegador"
#: modules/gnome/manifest.py:11
msgid "Office suite"
msgstr ""
msgstr "Suite dofimàtica"
#: modules/gnome/manifest.py:12
msgid "Software store"
msgstr ""
msgstr "Botiga d'aplicacions"
#: modules/gnome/manifest.py:13
msgid "GUI"
msgstr ""
msgstr "Interfície Gràfica d'Usuari"
#: modules/gnome/manifest.py:14
msgid "Graphical apps"
msgstr ""
msgstr "Aplicacions gràfiques"
#: modules/help/__init__.py:33 modules/help/templates/help_index.html:14
#: templates/help-menu.html:8 templates/help-menu.html:14
msgid "Help"
msgstr ""
msgstr "Ajuda"
#: modules/help/__init__.py:37 modules/help/templates/help_about.html:104
#: templates/help-menu.html:20 templates/help-menu.html:21
msgctxt "User guide"
msgid "Manual"
msgstr ""
msgstr "Manual"
#: modules/help/__init__.py:41 modules/help/templates/help_support.html:9
#: modules/help/views.py:93 templates/help-menu.html:27
@ -3167,7 +3221,7 @@ msgstr "Rep Suport"
#: modules/help/views.py:87 templates/help-menu.html:33
#: templates/help-menu.html:34
msgid "Submit Feedback"
msgstr ""
msgstr "Enviar comentaris"
#: modules/help/__init__.py:49 modules/help/templates/help_about.html:113
#: modules/help/templates/help_contribute.html:9 modules/help/views.py:76
@ -3183,13 +3237,13 @@ msgstr "Sobre"
#: modules/help/templates/help_about.html:25 templates/messages.html:23
msgid "Success:"
msgstr ""
msgstr "Reeixit:"
#: modules/help/templates/help_about.html:29
#: modules/upgrades/templates/upgrades_configure.html:31
#, python-format
msgid "You are running %(os_release)s and %(box_name)s version %(version)s."
msgstr ""
msgstr "Estàs executant %(os_release)s i la versió %(version)s de %(box_name)s."
#: modules/help/templates/help_about.html:35
#, python-format
@ -3197,12 +3251,14 @@ msgid ""
"There is a new %(box_name)s version <a href=\"%(upgrades_url)s\">available</"
"a>."
msgstr ""
"Hi ha una nova versió de %(box_name)s <a href=\"%(upgrades_url)s\""
">disponible</a>."
#: modules/help/templates/help_about.html:40
#: modules/upgrades/templates/upgrades_configure.html:42
#, python-format
msgid "%(box_name)s is up to date."
msgstr ""
msgstr "%(box_name)s està actualitzat."
#: modules/help/templates/help_about.html:49
#, python-format
@ -3215,6 +3271,14 @@ msgid ""
"and a Tor relay, on a device that can replace your Wi-Fi router, so that "
"your data stays with you."
msgstr ""
"%(box_name)s és un projecte comunitari per desenvolupar, dissenyar i "
"promoure servidors personals que executen programari lliure per a "
"comunicacions privades i personals. És un dispositiu de xarxa dissenyat "
"per permetre la interacció amb la resta dInternet sota condicions de "
"privadesa i seguretat de dades protegides. Allotja aplicacions com bloc, "
"wiki, lloc web, xarxa social, correu electrònic, proxy web i un relé Tor, en "
"un dispositiu que pot substituir el teu router Wi-Fi, perquè les teves dades "
"es quedin amb tu."
#: modules/help/templates/help_about.html:62
msgid ""
@ -3225,6 +3289,12 @@ msgid ""
"giving back power to the users over their networks and machines, we are "
"returning the Internet to its intended peer-to-peer architecture."
msgstr ""
"Vivim en un món on lús que fem de la xarxa està mediatitzat per aquells que "
"sovint vetllen pels nostres interessos. Construint programari que no "
"depengui dun servei central, podem recuperar el control i la privadesa. "
"Guardant les nostres dades a casa, obtenim proteccions legals útils sobre "
"elles. Tornant el poder als usuaris sobre les seves xarxes i màquines, "
"estem retornant Internet a la seva arquitectura peer-to-peer prevista."
#: modules/help/templates/help_about.html:75
#, python-format
@ -3233,6 +3303,9 @@ msgid ""
"services; %(box_name)s aims to bring them all together in a convenient "
"package."
msgstr ""
"Hi ha diversos projectes que treballen per fer realitat un futur de serveis "
"distribuïts; %(box_name)s té com a objectiu reunir-los tots en un paquet "
"còmode."
#: modules/help/templates/help_about.html:83
#, python-format
@ -3244,6 +3317,13 @@ msgid ""
"href=\"https://sources.debian.org/\">Debian Sources</a> site, or by running "
"\"apt source <i>package_name</i>\" in a terminal (using Cockpit or SSH)."
msgstr ""
"%(box_name)s és programari lliure, llicenciat sota la GNU Affero General "
"Public License. El codi font està disponible en línia al <a href="
"\"https://salsa.debian.org/freedombox-team/freedombox\">repositori de "
"%(box_name)s</a>. A més, el codi font de qualsevol paquet Debian es pot "
"obtenir des del lloc <a href=\"https://sources.debian.org/\">Debian Sources</"
"a>, o executant \"apt source <i>nom\\_paquet</i>\" en un terminal ("
"utilitzant Cockpit o SSH)."
#: modules/help/templates/help_about.html:97
msgid "Learn"
@ -3255,11 +3335,11 @@ msgstr "Fes una Donació"
#: modules/help/templates/help_about.html:119
msgid "Join project"
msgstr ""
msgstr "Suma't al projecte"
#: modules/help/templates/help_about.html:123
msgid "Translate"
msgstr ""
msgstr "Tradueix"
#: modules/help/templates/help_about.html:129
msgid "Support"
@ -3271,21 +3351,21 @@ msgstr "Forum"
#: modules/help/templates/help_about.html:138
msgid "IRC Chatroom"
msgstr ""
msgstr "Sala de xat IRC"
#: modules/help/templates/help_about.html:143
msgid "Mailing list"
msgstr ""
msgstr "Llista de correu electrònic"
#: modules/help/templates/help_base.html:21
#: modules/help/templates/help_index.html:63
#, python-format
msgid "%(box_name)s Setup"
msgstr ""
msgstr "Configuració de %(box_name)s"
#: modules/help/templates/help_contribute.html:12
msgid "The FreedomBox project welcomes contributions of all kinds."
msgstr ""
msgstr "El projecte FreedomBox accepta contribucions de qualsevol tipus."
#: modules/help/templates/help_contribute.html:18
msgid ""
@ -3295,6 +3375,10 @@ msgid ""
"into your language, hosting hackathons or install fests, and by spreading "
"the word."
msgstr ""
"Pots contribuir escrivint codi, provant i reportant errors, debatent nous "
"casos dús i aplicacions, dissenyant logotips i obres dart, oferint suport "
"als teus companys usuaris, traduint FreedomBox i les seves aplicacions al "
"teu idioma, organitzant hackathons o install fests, i difonent la iniciativa."
#: modules/help/templates/help_contribute.html:28
msgid ""
@ -3307,52 +3391,63 @@ msgid ""
"throughout the world. The FreedomBox Foundation would not exist without its "
"supporters."
msgstr ""
"També pots ajudar el projecte econòmicament <a href="
"\"https://freedomboxfoundation.org/donate/\">fent una donació</a> a la "
"FreedomBox Foundation, una organització sense ànim de lucre. Fundada el "
"2011, la FreedomBox Foundation és una entitat sense ànim de lucre amb "
"estatus 501(c)(3) amb seu a Nova York que existeix per donar suport a "
"FreedomBox. Proporciona infraestructura tècnica i serveis legals pel "
"projecte, cerca aliances i defensa FreedomBox arreu del món. La FreedomBox "
"Foundation no existiria sense els seus col·laboradors."
#: modules/help/templates/help_contribute.html:42
#: modules/power/templates/power_restart.html:27
#: modules/power/templates/power_shutdown.html:26 templates/app-header.html:65
msgid "Learn more..."
msgstr ""
msgstr "Aprèn-ne més..."
#: modules/help/templates/help_contribute.html:46
msgid "How can I help?"
msgstr ""
msgstr "Com puc ajudar?"
#: modules/help/templates/help_contribute.html:48
msgid ""
"Below is a list of opportunities for contributing to Debian. It has been "
"filtered to only show packages that are installed on this system."
msgstr ""
"A continuació hi ha una llista de maneres de contribuir a Debian. Sha "
"filtrat per mostrar només els paquets que estan instal·lats en aquest "
"sistema."
#: modules/help/templates/help_contribute.html:59
msgid "Show issues"
msgstr ""
msgstr "Mostra incidències"
#: modules/help/templates/help_contribute.html:63
msgid "Packages that will be removed from Debian testing"
msgstr ""
msgstr "Paquets que seran eliminats de Debian testing"
#: modules/help/templates/help_contribute.html:69
#: modules/help/templates/help_contribute.html:85
msgid "source package:"
msgstr ""
msgstr "paquet font:"
#: modules/help/templates/help_contribute.html:80
msgid "Packages that are not in Debian testing"
msgstr ""
msgstr "Paquets que no estan a Debian testing"
#: modules/help/templates/help_contribute.html:92
msgid "Good first issues for beginners"
msgstr ""
msgstr "Bons primers reptes per a principiants"
#: modules/help/templates/help_contribute.html:104
msgid "Issues for which the package maintainer has requested help"
msgstr ""
msgstr "Incidències per a les quals qui manté del paquet ha sol·licitat ajuda"
#: modules/help/templates/help_feedback.html:12
#, python-format
msgid "Your feedback will help us improve %(box_name)s!"
msgstr ""
msgstr "Els teus comentaris ens ajudaran a millorar %(box_name)s!"
#: modules/help/templates/help_feedback.html:18
msgid ""
@ -3360,6 +3455,9 @@ msgid ""
"improve them on our <a href=\"https://discuss.freedombox.org\" "
"target=\"_blank\"> discussion forum</a>."
msgstr ""
"Fes-nos saber les funcions que falten, les teves aplicacions preferides i "
"com podem millorar-les al nostre <a href=\"https://discuss.freedombox.org\" "
"target=\"_blank\">fòrum de discussió</a>."
#: modules/help/templates/help_feedback.html:26
msgid ""
@ -3368,10 +3466,15 @@ msgid ""
"tracker</a> to let our developers know. To report, first check if the issue "
"is already reported and then use the \"New issue\" button."
msgstr ""
"Si trobes algun error o incidència, si us plau utilitza el <a href="
"\"https://salsa.debian.org/freedombox-team/freedombox/issues\" target="
"\"_blank\">seguiment dincidències</a> per informar els nostres "
"desenvolupadors. Per informar, primer comprova si lincidència ja està "
"reportada i després utilitza el botó \"Nova incidència\"."
#: modules/help/templates/help_feedback.html:36
msgid "Thank you!"
msgstr ""
msgstr "Gràcies!"
#: modules/help/templates/help_index.html:18
#, python-format
@ -3379,6 +3482,8 @@ msgid ""
"The <a href=\"%(manual_url)s\">%(box_name)s Manual</a> is the best place to "
"start for information regarding %(box_name)s."
msgstr ""
"El <a href=\"%(manual_url)s\">Manual de %(box_name)s</a> és el millor lloc "
"per començar a trobar informació sobre %(box_name)s."
#: modules/help/templates/help_index.html:25
#, python-format
@ -3386,6 +3491,8 @@ msgid ""
"<a href=\"http://wiki.debian.org/FreedomBox\" target=\"_blank\"> "
"%(box_name)s project wiki </a> contains further information."
msgstr ""
"L<a href=\"http://wiki.debian.org/FreedomBox\" target=\"_blank\">wiki del "
"projecte %(box_name)s</a> conté més informació."
#: modules/help/templates/help_index.html:32
#, python-format
@ -3395,6 +3502,11 @@ msgid ""
"discuss\"> mailing list</a>. The list archives also contain information "
"about problems faced by other users and possible solutions."
msgstr ""
"Per sol·licitar ajuda a la comunitat de %(box_name)s, es poden publicar "
"consultes a la <a href="
"\"https://lists.alioth.debian.org/mailman/listinfo/freedombox-discuss\"> "
"llista de correu</a>. Els arxius de la llista també contenen informació "
"sobre problemes que han tingut altres usuaris i possibles solucions."
#: modules/help/templates/help_index.html:42
#, python-format
@ -3404,10 +3516,14 @@ msgid ""
"oftc.net/?randomnick=1&channels=freedombox&prompt=1\"> #freedombox</a> "
"channel using the IRC web interface."
msgstr ""
"Molts contribuïdors i usuaris de %(box_name)s també estan disponibles a la "
"xarxa IRC irc.oftc.net. Uneix-te i sol·licita ajuda al canal <a href=\"https"
"://webchat.oftc.net/?randomnick=1&amp;channels=freedombox&amp;prompt=1\"> "
"#freedombox</a> mitjançant la interfície web IRC."
#: modules/help/templates/help_manual.html:18
msgid "Download as PDF"
msgstr ""
msgstr "Descarrega-ho com a PDF"
#: modules/help/templates/help_support.html:12
#, python-format
@ -3416,12 +3532,17 @@ msgid ""
"using %(box_name)s, you can ask for help from our community of users and "
"contributors."
msgstr ""
"Si necessites ajuda per fer alguna cosa o si tens problemes utilitzant "
"%(box_name)s, pots demanar ajuda a la nostra comunitat dusuaris i "
"contribuïdors."
#: modules/help/templates/help_support.html:20
msgid ""
"Search for past discussions or post a new query on our <a href=\"https://"
"discuss.freedombox.org\" target=\"_blank\">discussion forum</a>."
msgstr ""
"Cerca discussions passades o publica una nova consulta al nostre <a href="
"\"https://discuss.freedombox.org\" target=\"_blank\">fòrum de discussió</a>."
#: modules/help/templates/help_support.html:27
msgid ""
@ -3430,6 +3551,10 @@ msgid ""
"Or send an email to our <a href=\"mailto:freedombox-discuss@alioth-lists."
"debian.net\">mailing list</a>."
msgstr ""
"També pots xatejar amb nosaltres als nostres canals IRC i Matrix "
"(connectats): <ul> <li>#freedombox a irc.oftc.net</li> <li>#freedombox\\"
":matrix.org</li> </ul> O enviar un correu electrònic a la nostra <a href="
"\"mailto:freedombox-discuss@alioth-lists.debian.net\">llista de correu</a>."
#: modules/help/templates/statuslog.html:10
msgid "Status Log"

View File

@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-21 20:08-0400\n"
"PO-Revision-Date: 2025-06-19 22:01+0000\n"
"Last-Translator: Priit Jõerüüt <hwlate@joeruut.com>\n"
"PO-Revision-Date: 2025-07-20 18:01+0000\n"
"Last-Translator: Priit Jõerüüt <jrthwlate@users.noreply.hosted.weblate.org>\n"
"Language-Team: Estonian <https://hosted.weblate.org/projects/freedombox/"
"freedombox/et/>\n"
"Language: et\n"
@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.12.1\n"
"X-Generator: Weblate 5.13-dev\n"
#: config.py:103
#, python-brace-format
@ -921,7 +921,7 @@ msgstr ""
#: modules/miniflux/forms.py:14 modules/networks/forms.py:282
#: modules/shadowsocks/forms.py:32 modules/shadowsocksserver/forms.py:37
msgid "Password"
msgstr ""
msgstr "Salasõna"
#: modules/bepasty/views.py:19
msgid "admin"

View File

@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-21 20:08-0400\n"
"PO-Revision-Date: 2025-04-09 13:07+0000\n"
"PO-Revision-Date: 2025-06-25 22:04+0000\n"
"Last-Translator: Besnik Bleta <besnik@programeshqip.org>\n"
"Language-Team: Albanian <https://hosted.weblate.org/projects/freedombox/"
"freedombox/sq/>\n"
@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.11-dev\n"
"X-Generator: Weblate 5.13-dev\n"
#: config.py:103
#, python-brace-format

View File

@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-21 20:08-0400\n"
"PO-Revision-Date: 2024-12-27 01:03+0000\n"
"Last-Translator: James Valleroy <jvalleroy@mailbox.org>\n"
"PO-Revision-Date: 2025-06-30 09:01+0000\n"
"Last-Translator: தமிழ்நேரம் <anishprabu.t@gmail.com>\n"
"Language-Team: Tamil <https://hosted.weblate.org/projects/freedombox/"
"freedombox/ta/>\n"
"Language: ta\n"
@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.10-dev\n"
"X-Generator: Weblate 5.13-dev\n"
#: config.py:103
#, python-brace-format
@ -26,7 +26,7 @@ msgstr "நிலையான உள்ளமைவு {etc_path} சரிய
#: context_processors.py:21 views.py:168
msgid "FreedomBox"
msgstr ""
msgstr "ஃப்ரீடோம்பாக்ச்"
#: daemon.py:124
#, python-brace-format
@ -101,7 +101,7 @@ msgstr "உலாவியில் உள்ள மொழி விருப்
#: menu.py:116 templates/base.html:120
msgid "Home"
msgstr ""
msgstr "வீடு"
#: menu.py:117 templates/base.html:129
msgid "Apps"
@ -681,7 +681,7 @@ msgstr "காப்புப்பிரதி இருப்பிடத்
#: modules/backups/templates/backups_repository.html:88
msgid "Download"
msgstr ""
msgstr "பதிவிறக்கம்"
#: modules/backups/templates/backups_repository.html:114
msgid "No archives currently exist."
@ -2637,7 +2637,7 @@ msgstr "இந்த கணினியிலிருந்து ஏற்க
#: modules/help/templates/help_about.html:108 modules/ikiwiki/manifest.py:15
#: modules/mediawiki/manifest.py:25 modules/tiddlywiki/manifest.py:19
msgid "Wiki"
msgstr ""
msgstr "விக்கி"
#: modules/featherwiki/manifest.py:18 modules/infinoted/manifest.py:46
#: modules/tiddlywiki/manifest.py:20
@ -2648,7 +2648,7 @@ msgstr "குறிப்பு"
#: modules/mediawiki/manifest.py:25 modules/tiddlywiki/manifest.py:21
#: modules/wordpress/manifest.py:26
msgid "Website"
msgstr ""
msgstr "வலைத்தளம்"
#: modules/featherwiki/manifest.py:18 modules/tiddlywiki/manifest.py:25
msgid "Quine"
@ -3213,7 +3213,7 @@ msgstr "கையேடு"
#: modules/help/views.py:93 templates/help-menu.html:27
#: templates/help-menu.html:28
msgid "Get Support"
msgstr ""
msgstr "ஆதரவை பெறு"
#: modules/help/__init__.py:45 modules/help/templates/help_feedback.html:9
#: modules/help/views.py:87 templates/help-menu.html:33
@ -3225,13 +3225,13 @@ msgstr "கருத்துக்களை சமர்ப்பிக்க
#: modules/help/templates/help_contribute.html:9 modules/help/views.py:76
#: templates/help-menu.html:39 templates/help-menu.html:40
msgid "Contribute"
msgstr ""
msgstr "பங்களிப்பு"
#: modules/help/__init__.py:53 templates/base.html:216 templates/base.html:219
#: templates/help-menu.html:46 templates/help-menu.html:47
#: templates/index.html:96
msgid "About"
msgstr ""
msgstr "பற்றி"
#: modules/help/templates/help_about.html:25 templates/messages.html:23
msgid "Success:"
@ -3322,11 +3322,11 @@ msgstr ""
#: modules/help/templates/help_about.html:97
msgid "Learn"
msgstr ""
msgstr "அறிக"
#: modules/help/templates/help_about.html:116 templates/toolbar.html:19
msgid "Donate"
msgstr ""
msgstr "நன்கொடை"
#: modules/help/templates/help_about.html:119
msgid "Join project"
@ -3338,7 +3338,7 @@ msgstr "மொழிபெயர்த்திடு"
#: modules/help/templates/help_about.html:129
msgid "Support"
msgstr ""
msgstr "உதவி"
#: modules/help/templates/help_about.html:133
msgid "Forum"
@ -6943,7 +6943,7 @@ msgstr "நாட்காட்டி"
#: modules/radicale/manifest.py:91 modules/roundcube/manifest.py:23
msgid "Contacts"
msgstr ""
msgstr "தொடர்புகள்"
#: modules/radicale/manifest.py:91 modules/sogo/manifest.py:75
msgid "CalDAV"
@ -7018,7 +7018,7 @@ msgstr ""
#: modules/roundcube/manifest.py:23
msgid "Email"
msgstr ""
msgstr "மின்னஞ்சல்"
#: modules/rssbridge/__init__.py:21
msgid ""
@ -10248,7 +10248,7 @@ msgstr "விரலிடைத் தோல்"
#: templates/clients.html:28
msgid "Launch"
msgstr ""
msgstr "ஏவுதல்"
#: templates/clients.html:53
msgid "GNU/Linux"

View File

@ -20,7 +20,7 @@ from plinth.privileged import service as service_privileged
from plinth.signals import domain_added, domain_removed
from plinth.utils import format_lazy, gettext_noop
from . import aliases, manifest, privileged
from . import aliases, dovecot, manifest, privileged
_description = [
_('This is a complete email server solution using Postfix, Dovecot, '
@ -52,7 +52,7 @@ class EmailApp(plinth.app.App):
app_id = 'email'
_version = 6
_version = 7
def __init__(self) -> None:
"""Initialize the email app."""
@ -95,21 +95,12 @@ class EmailApp(plinth.app.App):
'dovecot-lmtpd', 'dovecot-managesieved', 'dovecot-ldap',
'rspamd', 'redis-server', 'openssl'
], conflicts=['exim4-base', 'exim4-config', 'exim4-daemon-light'],
conflicts_action=Packages.ConflictsAction.REMOVE)
conflicts_action=Packages.ConflictsAction.REMOVE,
rerun_setup_on_upgrade=True)
self.add(packages)
dropin_configs = DropinConfigs('dropin-configs-email', [
'/etc/apache2/conf-available/email-freedombox.conf',
'/etc/dovecot/conf.d/05-freedombox-passdb.conf',
'/etc/dovecot/conf.d/05-freedombox-userdb.conf',
'/etc/dovecot/conf.d/15-freedombox-auth.conf',
'/etc/dovecot/conf.d/15-freedombox-mail.conf',
'/etc/dovecot/conf.d/90-freedombox-imap.conf',
'/etc/dovecot/conf.d/90-freedombox-lmtp.conf',
'/etc/dovecot/conf.d/90-freedombox-mailboxes.conf',
'/etc/dovecot/conf.d/90-freedombox-master.conf',
'/etc/dovecot/conf.d/90-freedombox-tls.conf',
'/etc/dovecot/conf.d/freedombox-ldap.conf.ext',
'/etc/fail2ban/jail.d/dovecot-freedombox.conf',
'/etc/postfix/freedombox-aliases.cf',
'/etc/rspamd/local.d/freedombox-logging.inc',
@ -121,10 +112,24 @@ class EmailApp(plinth.app.App):
dropin_configs_sieve = DropinConfigs('dropin-configs-email-sieve', [
'/etc/dovecot/freedombox-sieve/learn-ham.sieve',
'/etc/dovecot/freedombox-sieve/learn-spam.sieve',
'/etc/dovecot/freedombox-sieve-after/sort-spam.sieve',
'/etc/dovecot/conf.d/95-freedombox-sieve.conf'
'/etc/dovecot/freedombox-sieve-after/sort-spam.sieve'
])
self.add(dropin_configs_sieve)
dropin_configs_dovecot = DovecotDropinConfigs(
'dropin-configs-email-dovecot', [
'/etc/dovecot/conf.d/05-freedombox-passdb.conf',
'/etc/dovecot/conf.d/05-freedombox-userdb.conf',
'/etc/dovecot/conf.d/15-freedombox-auth.conf',
'/etc/dovecot/conf.d/15-freedombox-mail.conf',
'/etc/dovecot/conf.d/90-freedombox-imap.conf',
'/etc/dovecot/conf.d/90-freedombox-lmtp.conf',
'/etc/dovecot/conf.d/90-freedombox-mailboxes.conf',
'/etc/dovecot/conf.d/90-freedombox-master.conf',
'/etc/dovecot/conf.d/90-freedombox-tls.conf',
'/etc/dovecot/conf.d/95-freedombox-sieve.conf',
'/etc/dovecot/conf.d/freedombox-ldap.conf.ext'
])
self.add(dropin_configs_dovecot)
listen_ports = [(25, 'tcp4'), (25, 'tcp6'), (465, 'tcp4'),
(465, 'tcp6'), (587, 'tcp4'), (587, 'tcp6')]
@ -212,13 +217,15 @@ class EmailApp(plinth.app.App):
# Enable drop-in configuration files component for sieve (temporarily)
# to ensure that sievec can compile.
self.get_component('dropin-configs-email-sieve').enable()
self.get_component('dropin-configs-email-dovecot').enable()
service_privileged.try_restart('dovecot')
privileged.setup_spam()
# Restart daemons
service_privileged.try_restart('postfix')
service_privileged.try_restart('dovecot')
service_privileged.try_restart('rspamd')
if self.is_enabled():
service_privileged.restart('postfix')
service_privileged.restart('dovecot')
service_privileged.restart('rspamd')
# Expose to public internet
if old_version == 0:
@ -228,6 +235,20 @@ class EmailApp(plinth.app.App):
service_privileged.try_restart('rspamd')
class DovecotDropinConfigs(DropinConfigs):
"""Configure dovecot based on its package version."""
def get_target_path(self, path):
"""Return Path object for a target path."""
version = '2.3'
if dovecot.is_version_24():
version = '2.4'
target_path = super().get_target_path(path)
target_path = target_path.parent / version / target_path.name
return target_path
def _get_first_admin():
"""Return an admin user in the system or None if non exist."""
from django.contrib.auth.models import User

View File

@ -0,0 +1,20 @@
# Do not edit this file. Manage your settings on FreedomBox.
# See:
# https://doc.dovecot.org/main/core/config/auth/passdb.html
# https://doc.dovecot.org/main/howto/active_directory.html
#
# For passdb, the passwd driver looks up using NSS. In FreedomBox, NSS is
# configured to lookup LDAP with the help of libnss-ldapd. Lookup using passdb
# would have been sufficient if FreedomBox allowed all its users to login using
# pam. However, by default, FreedomBox disallows all users but 'admin' group to
# login. Hence, the need for LDAP lookup.
#
passdb freedombox-ldap {
driver = ldap
ldap_uris = ldapi:///
ldap_base = dc=thisbox
ldap_bind = yes
ldap_bind_userdn = uid=%{user},ou=users,dc=thisbox
ldap_filter = (&(objectClass=posixAccount)(uid=%{user}))
}

View File

@ -0,0 +1,32 @@
# Do not edit this file. Manage your settings on FreedomBox.
# See:
# https://doc.dovecot.org/main/core/config/auth/userdb.html
#
# Users in FreedomBox are not expected to access mail by logging into the
# system. Storing the mail in single location instead of home directories and
# with single UID/GID simplifies security reasoning and backup/restore
# operations.
#
# When FreedomBox has multiple domains a user is expected to get a mailbox that
# is same across the domains. Changing an domain name is not uncommon in
# FreedomBox. So, authenticate and store mails based on username only instead of
# including domain names in storage path.
#
# Directories are created under /var/mail as necessary by dovecot. Permissions
# for newly created directories are inherited from parent directory. FreedomBox
# will remove all permissions for 'others' from /var/mail to ensure that mail is
# not read by non-root users.
#
# userdb provides lookup for three parameters after authentication of a user.
# These parameters are uid, gid, and home directory of the user. If these do not
# change from user to user, a 'static' database type with fixed values is
# sufficient as userdb.
userdb freedombox-static {
driver = static
fields {
uid=mail
gid=mail
home=/var/mail/%{user | username | lower}
}
}

View File

@ -0,0 +1,10 @@
# Do not edit this file. Manage your settings on FreedomBox.
# See:
# https://doc.dovecot.org/main/core/config/auth/basic.html
# https://doc.dovecot.org/main/core/config/auth/databases/ldap.html#username
# Outlook and Windows Mail work only with LOGIN mechanism, not the standard PLAIN
auth_mechanisms = plain login
auth_username_format = %{user | lower}

View File

@ -0,0 +1,18 @@
# Do not edit this file. Manage your settings on FreedomBox.
# See: https://doc.dovecot.org/main/core/config/mail_location.html
# Use sdbox, a format specific to dovecot, for storing mails. The format allows
# better performance with some IMAP queries. When this is combined with Full
# Text Search (FTS), users will get optimal web and desktop mail experience.
# Don't pick mdbox format because is requires regular expunge maintenance. We
# have enabled btrfs filesystem compression by default.
mail_driver = sdbox
mail_path = ~/mail
# We try to deliver all mail using a single UID 'mail' and a single GID 'mail'.
# In Debian, UID of mail user is 8 and GID of mail user is 8 as set in
# /usr/share/base-passwd/{passwd|group}.master. By default first valid UID in
# dovecot is 500.
first_valid_uid = 8
last_valid_uid = 8

View File

@ -0,0 +1,11 @@
# Do not edit this file. Manage your settings on FreedomBox.
# Make rspamd learn spam/ham when the user marks mails as junk or not junk.
# https://doc.dovecot.org/main/core/config/sieve/overview.html
# https://doc.dovecot.org/main/core/plugins/sieve.html
protocol imap {
mail_plugins {
imap_sieve = yes
}
}

View File

@ -0,0 +1,12 @@
# Do not edit this file. Manage your settings on FreedomBox.
# See:
# https://doc.dovecot.org/main/core/config/sieve/overview.html
# https://doc.dovecot.org/main/core/plugins/sieve.html
# Enable the sieve plugin to sort mail during delivery using sieve scripts.
protocol lmtp {
mail_plugins {
sieve = yes
}
}

View File

@ -0,0 +1,72 @@
# Do not edit this file. Manage your settings on FreedomBox.
# Mark various mailboxes with special use flags (RFC 6154). Various names used
# in mail clients for mailboxes: https://www.imapwiki.org/SpecialUse
# See:
# https://doc.dovecot.org/main/core/config/mail_location.html#custom-namespace-location
namespace inbox {
# Archive
mailbox Archive {
auto = subscribe
special_use = \Archive
}
mailbox Archives { # Thunderbird
auto = no
special_use = \Archive
}
# Drafts
mailbox Drafts {
auto = subscribe
special_use = \Drafts
}
# Sent
mailbox Sent {
auto = subscribe
special_use = \Sent
}
mailbox "Sent Items" { # Outlook 2010/2013
auto = no
special_use = \Sent
}
mailbox "Sent Messages" { # iOS
auto = no
special_use = \Sent
}
# Junk
mailbox Junk {
auto = subscribe
autoexpunge = 60d
special_use = \Junk
}
mailbox Spam { # KMail, K-9 Mail
auto = no
autoexpunge = 60d
special_use = \Junk
}
mailbox "Junk E-mail" { # Outlook 2010
auto = no
autoexpunge = 60d
special_use = \Junk
}
mailbox INBOX.Junk {
auto = no
autoexpunge = 60d
special_use = \Junk
}
# Trash
mailbox Trash {
auto = subscribe
autoexpunge = 60d
special_use = \Trash
}
mailbox INBOX.Trash {
auto = no
autoexpunge = 60d
special_use = \Trash
}
}

View File

@ -0,0 +1,21 @@
# Do not edit this file. Manage your settings on FreedomBox.
# Listen on Unix domain sockets for postfix to use dovecot SASL authentication
# and for postfix to deliver mail using dovecot to local mailboxes. See:
# https://doc.dovecot.org/main/howto/sasl/postfix.html#postfix-and-dovecot-sasl
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0600
user = postfix
group = postfix
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}

View File

@ -0,0 +1,12 @@
# Do not edit this file. Manage your settings on FreedomBox.
# Mozilla Guideline v5.7, Dovecot 2.3.21, OpenSSL 3.4.0, intermediate.
# Generated 2025-07-16: https://ssl-config.mozilla.org/
# See: https://doc.dovecot.org/main/core/config/ssl.html
ssl = required
ssl_min_protocol = TLSv1.2
ssl_server_prefer_ciphers = client
ssl_curve_list = X25519:prime256v1:secp384r1
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305

View File

@ -0,0 +1,43 @@
# Do not edit this file. Manage your settings on FreedomBox.
# Default sieve scripts applied for delivery to all users. To move mail to Junk
# folder based on classification headers set by rspamd. See:
# https://doc.dovecot.org/main/core/plugins/sieve.html
sieve_script freedombox-after {
type = after
driver = file
path = /etc/dovecot/freedombox-sieve-after
}
sieve_plugins {
sieve_imapsieve = yes
sieve_extprograms = yes
}
sieve_global_extensions {
vnd.dovecot.pipe = yes
vnd.dovecot.environment = yes
}
# Make rspamd learn spam/ham when the user marks mails as junk or not junk.
# https://doc.dovecot.org/main/core/config/spam_reporting.html
sieve_pipe_bin_dir = /usr/bin
# When moving a mail from to Junk folder from elsewhere
mailbox Junk {
sieve_script learn-spam {
type = before
cause = copy
path = /etc/dovecot/freedombox-sieve/learn-spam.sieve
}
}
# When moving a mail from from Junk folder to elsewhere
imapsieve_from Junk {
sieve_script learn-ham {
type = before
cause = copy
path = /etc/dovecot/freedombox-sieve/learn-ham.sieve
}
}

View File

@ -0,0 +1,4 @@
# Do not edit this file. Manage your settings on FreedomBox.
# This file is not needed for Dovecot >= 2.4. It is only needed for simplifying
# compatibility with Dovecot 2.3.

View File

@ -0,0 +1,17 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Utilities to configure Dovecot."""
import apt
from plinth.utils import Version
def is_version_24():
"""Return the currently installed version of Dovecot."""
cache = apt.Cache()
try:
version = cache['dovecot-core'].installed.version
except KeyError:
return True
return Version(version) >= Version('1:2.4')

View File

@ -2,8 +2,7 @@
"""Provides privileged actions that run as root."""
from .aliases import setup_aliases
from .dkim import (get_dkim_public_key, setup_dkim,
fix_incorrect_key_ownership)
from .dkim import fix_incorrect_key_ownership, get_dkim_public_key, setup_dkim
from .domain import set_domains
from .home import setup_home
from .postfix import setup_postfix

View File

@ -10,6 +10,7 @@ See: https://doc.dovecot.org/configuration_manual/dovecot_ssl_configuration/
import pathlib
from .. import postfix
from ..dovecot import is_version_24
# Mozilla Guideline v5.6, Postfix 1.17.7, OpenSSL 1.1.1d, intermediate
# Generated 2021-08
@ -68,15 +69,27 @@ def set_postfix_config(primary_domain, all_domains):
def set_dovecot_config(primary_domain, all_domains):
"""Set dovecot configuration for TLS certificates."""
is_new_version = is_version_24()
# Determine whether to prefix file paths with '<' based on version
prefix = ''
cert_naming = 'ssl_server_cert_file'
key_naming = 'ssl_server_key_file'
if not is_new_version:
prefix = '<'
cert_naming = 'ssl_cert'
key_naming = 'ssl_key'
content = f'''# This file is managed by FreedomBox
ssl_cert = </etc/dovecot/letsencrypt/{primary_domain}/cert.pem
ssl_key = </etc/dovecot/letsencrypt/{primary_domain}/privkey.pem
{cert_naming} = {prefix}/etc/dovecot/letsencrypt/{primary_domain}/cert.pem
{key_naming} = {prefix}/etc/dovecot/letsencrypt/{primary_domain}/privkey.pem
'''
for domain in all_domains:
content += f'''
local_name {domain} {{
ssl_cert = </etc/dovecot/letsencrypt/{domain}/cert.pem
ssl_key = </etc/dovecot/letsencrypt/{domain}/privkey.pem
{cert_naming} = {prefix}/etc/dovecot/letsencrypt/{domain}/cert.pem
{key_naming} = {prefix}/etc/dovecot/letsencrypt/{domain}/privkey.pem
}}
'''
cert_config = pathlib.Path('/etc/dovecot/conf.d/91-freedombox-tls.conf')

View File

@ -38,7 +38,7 @@ class SOGoApp(app_module.App):
app_id = 'sogo'
_version = 1
_version = 2
def __init__(self) -> None:
"""Create components for the app."""

View File

@ -81,7 +81,7 @@ def _create_config(db_password: str):
SOGoTrashFolderName = "Trash";
SOGoJunkFolderName = "Junk";
SOGoIMAPServer = "imap://127.0.0.1:143/?tls=YES&tlsVerifyMode=allowInsecureLocalhost";
SOGoSieveServer = "sieve://127.0.0.14190/?tls=YES&tlsVerifyMode=allowInsecureLocalhost";
SOGoSieveServer = "sieve://127.0.0.1:4190/?tls=YES&tlsVerifyMode=allowInsecureLocalhost";
/* LDAP */
SOGoUserSources = ({{

View File

@ -10,7 +10,7 @@ from plinth import module_loader
from plinth.actions import privileged
def _assert_managed_dropin_config(app_id: str, path: str):
def _get_managed_dropin_config(app_id: str, path: str):
"""Check that this is a path managed by the specified app."""
module_path = module_loader.get_module_import_path(app_id)
module = importlib.import_module(module_path)
@ -25,7 +25,7 @@ def _assert_managed_dropin_config(app_id: str, path: str):
components = app.get_components_of_type(DropinConfigs)
for component in components:
if path in component.etc_paths:
return
return component
raise AssertionError('Not a managed drop-in config')
@ -37,10 +37,9 @@ def dropin_is_valid(app_id: str, path: str, copy_only: bool,
Optionally, drop the link if it is invalid.
"""
_assert_managed_dropin_config(app_id, path)
from plinth.config import DropinConfigs
etc_path = DropinConfigs.get_etc_path(path)
target = DropinConfigs.get_target_path(path)
component = _get_managed_dropin_config(app_id, path)
etc_path = component.get_etc_path(path)
target = component.get_target_path(path)
if etc_path.exists() or etc_path.is_symlink():
if (not copy_only and etc_path.is_symlink()
and etc_path.readlink() == target):
@ -59,10 +58,9 @@ def dropin_is_valid(app_id: str, path: str, copy_only: bool,
@privileged
def dropin_link(app_id: str, path: str, copy_only: bool):
"""Create a symlink from /etc/ to /usr/share/freedombox/etc."""
_assert_managed_dropin_config(app_id, path)
from plinth.config import DropinConfigs
target = DropinConfigs.get_target_path(path)
etc_path = DropinConfigs.get_etc_path(path)
component = _get_managed_dropin_config(app_id, path)
target = component.get_target_path(path)
etc_path = component.get_etc_path(path)
etc_path.parent.mkdir(parents=True, exist_ok=True)
if copy_only:
shutil.copyfile(target, etc_path)
@ -73,7 +71,6 @@ def dropin_link(app_id: str, path: str, copy_only: bool):
@privileged
def dropin_unlink(app_id: str, path: str, missing_ok: bool = False):
"""Remove a symlink in /etc/."""
_assert_managed_dropin_config(app_id, path)
from plinth.config import DropinConfigs
etc_path = DropinConfigs.get_etc_path(path)
component = _get_managed_dropin_config(app_id, path)
etc_path = component.get_etc_path(path)
etc_path.unlink(missing_ok=missing_ok)

View File

@ -31,9 +31,10 @@ def fixture_dropin_configs():
@pytest.fixture(autouse=True)
def fixture_assert_dropin_config():
def fixture_assert_dropin_config(dropin_configs):
"""Mock asserting dropin config path."""
with patch('plinth.privileged.config._assert_managed_dropin_config'):
with patch('plinth.privileged.config._get_managed_dropin_config') as mock:
mock.return_value = dropin_configs
yield
@ -95,7 +96,7 @@ def test_dropin_configs_enable_disable_symlinks(dropin_configs, tmp_path):
# Enable when a file already exists
dropin_configs.disable()
etc_path = DropinConfigs.get_etc_path('/etc/test/path1')
etc_path = dropin_configs.get_etc_path('/etc/test/path1')
etc_path.touch()
dropin_configs.enable()
_assert_symlinks(dropin_configs, tmp_path, should_exist=True)
@ -108,7 +109,7 @@ def test_dropin_configs_enable_disable_symlinks(dropin_configs, tmp_path):
# When symlink already exists to correct location
dropin_configs.disable()
target_path = DropinConfigs.get_target_path('/etc/test/path1')
target_path = dropin_configs.get_target_path('/etc/test/path1')
etc_path.symlink_to(target_path)
dropin_configs.enable()
_assert_symlinks(dropin_configs, tmp_path, should_exist=True)
@ -119,7 +120,7 @@ def test_dropin_configs_enable_disable_copy_only(dropin_configs, tmp_path):
with patch('plinth.config.DropinConfigs.ROOT', new=tmp_path):
dropin_configs.copy_only = True
for path in ['/etc/test/path1', '/etc/path2']:
target = DropinConfigs.get_target_path(path)
target = dropin_configs.get_target_path(path)
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text('test-config-content')
@ -135,7 +136,7 @@ def test_dropin_configs_enable_disable_copy_only(dropin_configs, tmp_path):
# Enable when a file already exists with wrong content
dropin_configs.disable()
etc_path = DropinConfigs.get_etc_path('/etc/test/path1')
etc_path = dropin_configs.get_etc_path('/etc/test/path1')
etc_path.write_text('x-invalid-content')
dropin_configs.enable()
_assert_symlinks(dropin_configs, tmp_path, should_exist=True,
@ -182,7 +183,7 @@ def test_dropin_config_diagnose_symlinks(dropin_configs, tmp_path):
# A file exists instead of symlink
dropin_configs.disable()
etc_path = DropinConfigs.get_etc_path('/etc/test/path1')
etc_path = dropin_configs.get_etc_path('/etc/test/path1')
etc_path.touch()
results = dropin_configs.diagnose()
assert results[0].result == 'failed'
@ -204,7 +205,7 @@ def test_dropin_config_diagnose_copy_only(dropin_configs, tmp_path):
with patch('plinth.config.DropinConfigs.ROOT', new=tmp_path):
dropin_configs.copy_only = True
for path in ['/etc/test/path1', '/etc/path2']:
target = DropinConfigs.get_target_path(path)
target = dropin_configs.get_target_path(path)
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text('test-config-content')
@ -221,7 +222,7 @@ def test_dropin_config_diagnose_copy_only(dropin_configs, tmp_path):
# A symlink exists instead of a copied file
dropin_configs.disable()
etc_path = DropinConfigs.get_etc_path('/etc/test/path1')
etc_path = dropin_configs.get_etc_path('/etc/test/path1')
etc_path.symlink_to('/blah')
results = dropin_configs.diagnose()
assert results[0].result == 'failed'