diff --git a/README.rst b/README.rst index d98c1dd09..7c17f005f 100644 --- a/README.rst +++ b/README.rst @@ -11,8 +11,8 @@ as an administration panel or a webmail. Modoboa integrates with well known software such as `Postfix `_ or `Dovecot `_. A SQL database (`MySQL `_, `PostgreSQL -`_ or `SQLite `_) -is used as a central point of communication between all components. +`_) is used as a central point of +communication between all components. Modoboa is developed with modularity in mind, expanding it is really easy. Actually, all current features are extensions. diff --git a/doc/additional/migrating.rst b/doc/additional/migrating.rst index beaaa66c1..448e7fdd1 100644 --- a/doc/additional/migrating.rst +++ b/doc/additional/migrating.rst @@ -16,7 +16,7 @@ existing `PostfixAdmin (version 2.3.3+) First, you must follow the :ref:`installation` step to create a fresh Modoboa database. -Once done, edit the *setting.py* file. First, add a new database +Once done, edit the :file:`settings.py` file. First, add a new database connection named ``pfxadmin`` into the ``DATABASES`` variable corresponding to your PostfixAdmin setup:: @@ -56,7 +56,7 @@ used by PostfixAdmin, check its configuration file if you're not sure) Click on the *Save* button. -The procedure is over, edit the *settings.py* file and: +The procedure is over, edit the :file:`settings.py` file and: * remove the ``pfxadmin`` database connection from the ``DATABASES`` variable diff --git a/doc/additional/virtualmachine.rst b/doc/additional/virtualmachine.rst index 942da5a10..471c2c418 100644 --- a/doc/additional/virtualmachine.rst +++ b/doc/additional/virtualmachine.rst @@ -4,9 +4,9 @@ Using the virtual machine Introduction ============ -A virtual machine with a ready-to-use *Modoboa* setup is available -`here `_. It is composed -of the following components: +A virtual machine with a ready-to-use Modoboa setup is available `here +`_. It is composed of +the following components: * Debian 6.0 (squeeze) * Modoboa and its prerequisites @@ -32,7 +32,7 @@ If you can't use the vmdk format, you can use `qemu Then, just use your prefered virtualization software (qemu, kvm, virtualbox, etc.) to start the machine. You'll need to configure at least one bridged network interface if you want to be able to play -with *Modoboa*, ie. your machine must be visible from your network. +with Modoboa, ie. your machine must be visible from your network. The default network interface of the machine (``eth0``) is configured to use the DHCP protocol. @@ -49,7 +49,7 @@ root demo the root user demo demo an unpriviliged user ===== ======== ==================== -To connect to *Modoboa*, first connect to the system and retrieve its +To connect to Modoboa, first connect to the system and retrieve its current network address like this:: $ /sbin/ifconfig eth0 @@ -72,4 +72,3 @@ admin@demo.local admin Administrator of the domain *demo.local*. user@demo.local user Simple user. Can access to applications. ================ ======== ============================================ - diff --git a/doc/extending/plugin_api.rst b/doc/extending/plugin_api.rst index b6d2e5f27..a96381405 100644 --- a/doc/extending/plugin_api.rst +++ b/doc/extending/plugin_api.rst @@ -33,12 +33,12 @@ The required glue ***************** To create a new plugin, just start a new django application like -this (into modoboa's directory):: +this (into Modoboa's directory):: $ python manage.py startapp Then, you need to register this application using the provided -API. Just copy/paste the following example into the *__init__.py* file +API. Just copy/paste the following example into the :file:`__init__.py` file of the future extension:: from modoboa.extensions import ModoExtension, exts_pool @@ -72,7 +72,7 @@ of the future extension:: exts_pool.register_extension(MyExtension) Once done, simply add your plugin's module name to the -``INSTALLED_APPS`` variable located inside *settings.py*. Optionaly, +``INSTALLED_APPS`` variable located inside :file:`settings.py`. Optionaly, run ``python manage.py syncdb`` if your plugin provides custom tables and ``python manage.py collectstatic`` to update static files. diff --git a/doc/getting_started/configuration.rst b/doc/getting_started/configuration.rst index cad72e254..efcf39658 100644 --- a/doc/getting_started/configuration.rst +++ b/doc/getting_started/configuration.rst @@ -86,7 +86,7 @@ Custom logo You have the possibility to use a custom logo instead of the default one on the login page. -To do so, open the *settings.py* file and add a +To do so, open the :file:`settings.py` file and add a ``MODOBOA_CUSTOM_LOGO`` variable. This variable must contain the relative URL of your logo under ``MEDIA_URL``. For example:: @@ -107,7 +107,7 @@ Host configuration To manipulate mailboxes on the filesystem, you must allow the user who runs Modoboa to execute commands as the user who owns mailboxes. -To do so, edit the */etc/sudoers* file and add the following inside:: +To do so, edit the :file:`/etc/sudoers` file and add the following inside:: ALL=() NOPASSWD: ALL @@ -121,7 +121,7 @@ Time zone and language Modoboa is available in many languages. -To specify the default language to use, edit the *settings.py* file +To specify the default language to use, edit the :file:`settings.py` file and modify the ``LANGUAGE_CODE`` variable:: LANGUAGE_CODE = 'fr' # or 'en' for english, etc. @@ -143,7 +143,7 @@ Modoboa uses `Django's session framework `_ to store per-user information. -Few parameters need to be set in the *settings.py* configuration +Few parameters need to be set in the :file:`settings.py` configuration file to make Modoboa behave as expected:: SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Default value @@ -151,7 +151,7 @@ file to make Modoboa behave as expected:: This parameter is optional but you must ensure it is set to ``False`` (the default value). -The default configuration file provided by the *modoboa-admin.py* +The default configuration file provided by the ``modoboa-admin.py`` command is properly configured. **** @@ -163,7 +163,7 @@ LDAP Authentication ============== -*Modoboa* supports external LDAP authentication using the following extra components: +Modoboa supports external LDAP authentication using the following extra components: * `Python LDAP client `_ * `Django LDAP authentication backend `_ @@ -172,7 +172,7 @@ If you want to use this feature, you must first install those components:: $ pip install python-ldap django-auth-ldap -Then, all you have to do is to modify the *settings.py* file. Add a +Then, all you have to do is to modify the :file:`settings.py` file. Add a new authentication backend to the `AUTHENTICATION_BACKENDS` variable, like this:: @@ -247,7 +247,7 @@ If you need additional parameters, you will find a detailled documentation `here `_. Once the authentication is properly configured, the users defined in -your LDAP directory will be able to connect to *Modoboa*, the associated +your LDAP directory will be able to connect to Modoboa, the associated domain and mailboxes will be automatically created if needed. .. note:: diff --git a/doc/getting_started/install.rst b/doc/getting_started/install.rst index 3ba00684f..1c4f21d6e 100644 --- a/doc/getting_started/install.rst +++ b/doc/getting_started/install.rst @@ -30,8 +30,8 @@ You can choose between two options: * Use the Python package available on the `PyPI `_ * Download the sources tarball -The easiest one is to install it from the *PyPI*. Just run the -following command and you're done:: +The easiest one is to install it from PyPI. Just run the following +command and you're done:: $ pip install modoboa @@ -51,13 +51,13 @@ Fortunately, all major distributions include a ready-to-use package. On Debian/Ubuntu:: $ apt-get install libcairo2-dev libpango1.0-dev librrd-dev - $ pip install python-rrdtool + $ apt-get install python-rrdtool `virtualenv `_ users ========================================================== -When you deploy an application using *virtualenv*, you may have to -compile some dependencies. For example, *modoboa* relies on *lxml*, +When you deploy an application using virtualenv, you may have to +compile some dependencies. For example, modoboa relies on lxml, which is a C python module. In order to install it, you will need to install the following requirements: @@ -65,9 +65,9 @@ install the following requirements: * libxslt development files * libxml2 development files -On a *Debian* like system, just run the following command:: +On a Debian like system, just run the following command:: - $ apt-get instal python-dev libxml2-dev libxslt-dev + $ apt-get install python-dev libxml2-dev libxslt-dev .. _database: @@ -75,7 +75,7 @@ On a *Debian* like system, just run the following command:: Database ******** -Thanks to *django*, Modoboa supports several databases. Depending on +Thanks to Django, Modoboa supports several databases. Depending on the one you will use, you must install the appropriate python package: * `mysqldb `_ for `MySQL `_ diff --git a/doc/getting_started/plugins.rst b/doc/getting_started/plugins.rst index 5fcfcffb6..cb47c879f 100644 --- a/doc/getting_started/plugins.rst +++ b/doc/getting_started/plugins.rst @@ -50,11 +50,11 @@ This plugin provides a simple management frontend for `amavisd-new The per-domain policies feature only works for new installations. Currently, you can't use modoboa with an existing - database (ie. with data in *users* and *policies* tables). + database (ie. with data in ``users`` and ``policies`` tables). .. note:: - This plugin requires *amavisd-new* version **2.7.0** or higher. If + This plugin requires amavisd-new version **2.7.0** or higher. If you're planning to use the :ref:`selfservice`, you'll need version **2.8.0**. @@ -62,7 +62,7 @@ Database ======== You must tell to Modoboa where it can find the amavis -database. Inside *settings.py*, add a new connection to the +database. Inside :file:`settings.py`, add a new connection to the ``DATABASES`` variable like this:: DATABASES = { @@ -81,7 +81,7 @@ Replace values between ``<>`` with yours. .. note:: - Modoboa doesn't create *amavis* tables. You need to install them + Modoboa doesn't create amavis tables. You need to install them following the `official documentation `_. @@ -106,7 +106,7 @@ Release messages To release messages, first take a look at `this page `_. It -explains how to configure *amavisd-new* to listen somewhere for the +explains how to configure amavisd-new to listen somewhere for the AM.PDP protocol. This protocol is used to send requests. Below is an example of a working configuration:: @@ -126,7 +126,7 @@ Below is an example of a working configuration:: Don't forget to update the ``inet_acl`` list if you plan to release from the network. -Once *amavisd-new* is configured, just tell Modoboa where it can find +Once amavisd-new is configured, just tell Modoboa where it can find the *release server* by modifying the following parameters in the online panel: @@ -212,7 +212,7 @@ the required identifiers. To activate this feature, go the administration panel and set the **Enable self-service mode** parameter to yes. -The last step is to customize the notification messages *amavis* +The last step is to customize the notification messages amavis sends. The most important is to embark a direct link. Take a look at the `README.customize `_ file to learn what you're allowed to do. @@ -229,7 +229,7 @@ Graphical statistics This plugin collects various statistics about emails traffic on your server. It parses a log file to collect information, store it into RRD -files (see `rrdtool `_)and then +files (see `rrdtool `_) and then generates graphics in PNG format. To use it, go to the online parameters panel and adapt the following @@ -273,15 +273,15 @@ Postifx auto-reply messages *************************** This plugin let users define an auto-reply message (*vacation*). It is -based on *postfix* capabilities. +based on Postfix capabilities. The user that executes the autoreply script needs to access -*settings.py*. You must apply proper permissions on this file. For -example, if *settings.py* belongs to *www-data:www-data*, you can add -the *vmail* user to the *www-data* group and set the read permission +:file:`settings.py`. You must apply proper permissions on this file. For +example, if :file:`settings.py` belongs to ``www-data:www-data``, you can add +the ``vmail`` user to the ``www-data`` group and set the read permission for the group. -To make *postfix* use this feature, you need to update your +To make Postfix use this feature, you need to update your configuration files as follows: ``/etc/postfix/main.cf``:: @@ -334,7 +334,7 @@ Two working modes are available: To use this plugin, your hosting setup must include a *ManageSieve* server and your local delivery agent must understand the *Sieve* -language. Don't panic, *Dovecot* supports both :-) (refer to +language. Don't panic, Dovecot supports both :-) (refer to :ref:`dovecot` to know how to enable those features). .. note:: diff --git a/doc/getting_started/upgrade.rst b/doc/getting_started/upgrade.rst index 1cc854e15..5fd9d30cd 100644 --- a/doc/getting_started/upgrade.rst +++ b/doc/getting_started/upgrade.rst @@ -15,6 +15,16 @@ newest versions of Modoboa. Latest version ************** +.. warning:: + + If you use a version **prior to 0.9.5**, please migrate in two + steps: + + #. first migrate to 0.9.5 + #. then migrate to the latest version + + If you try to migrate directly, the operation will fail. + Starting with version 0.9.1, Modoboa comes as a standard django application. Fetch the latest version (see :ref:`get_modoboa`) and install it. @@ -33,13 +43,26 @@ Finally, follow the common procedure:: $ python manage.py syncdb --migrate $ python manage.py collectstatic + +1.0.1: operations on mailboxes +============================== + +The way Modoboa handles **rename** and **delete** operations on +mailboxes has been improved. Make sure to consult :ref:`fs_operations` +and :ref:`Postfix configuration `. Look at the +``smtpd_recipient_restrictions`` setting. + +Run ``modoboa-admin.py postfix_maps --dbtype +`` and compare the files with those that postfix currently +use. Make necessary updates in light of the differences + 1.0.0: production ready, at last ================================ Configuration file update ------------------------- -Several modifications need to be done into *settings.py*. +Several modifications need to be done into :file:`settings.py`. #. Add the following import statement:: @@ -170,9 +193,10 @@ Postfix and Dovecot configuration update It is necessary to update the queries used to retrieve users and mailboxes: -#. Replace all occurences of ``auth_user`` by ``admin_user`` +#. Run ``modoboa-admin.py postfix_maps --dbtype `` and compare the files with those that postfix currently + use. Make necessary updates in light of the differences -#. Into *dovecot-sql.conf*, update the ``user_query`` query, refer to +#. Into :file:`dovecot-sql.conf`, update the ``user_query`` query, refer to :ref:`dovecot_mysql_queries` or :ref:`dovecot_pg_queries` #. Update dovecot's configuration to activate the new :ref:`quota related features ` @@ -189,7 +213,7 @@ may encounter the following issues: #. South fails to migrate ``reversion`` - Due to the admin user model change, the script *0001_initial.py* + Due to the admin user model change, the script :file:`0001_initial.py` may fail. Just deactivate ``reversion`` from ``INSTALLED_APPS`` and run the command again. Once done, reactivate ``reversion`` and run the command one last time. @@ -198,7 +222,7 @@ may encounter the following issues: 0.9.4: administrative panel performance improved ================================================ -#. Edit the *settings.py* file and remove +#. Edit the :file:`settings.py` file and remove ``'django.contrib.auth.backends.ModelBackend'`` from the ``AUTHENTICATION_BACKENDS`` variable @@ -211,10 +235,10 @@ For this version, we recommend to install a new instance (see Then, copy the following content from the old installation to the new one: -* The ``media`` directory +* The :file:`media` directory * The directory containing RRD files if you use the :ref:`stats` plugin -Don't copy the old *settings.py* file, just keep the new one and +Don't copy the old :file:`settings.py` file, just keep the new one and modify it (see :ref:`database` and :ref:`timezone_lang`). Migrate your database (see :ref:`latestversion`). @@ -242,16 +266,16 @@ requires a migration. .. note:: Many files have been renamed/removed for this version. I recommend that you backup important files (*settings.py*, etc.) elsewhere - (ie. */tmp* for example). Then, remove the *modoboa* directory, + (ie. :file:`/tmp` for example). Then, remove the :file:`modoboa` directory, extract the new tarball at the same place, rename the new directory - to *modoboa* and copy the files you've just backup into it. + to :file:`modoboa` and copy the files you've just backup into it. .. note:: If the first super administrator you created is named ``admin``, its password will be changed to ``password`` at the end of this upgrade. Don't forget to modify it! -#. Edit the *settings.py* file and update the following variables +#. Edit the :file:`settings.py` file and update the following variables (just copy/paste their new content):: MIDDLEWARE_CLASSES = ( @@ -308,10 +332,10 @@ requires a migration. $ ./manage.py collectstatic #. If you are using the *stats* extension, please rename the - */static/stats* directory to */media/stats* + :file:`/static/stats` directory to :file:`/media/stats` and change the value of the ``IMG_ROOTDIR`` parameter (go to the adminstration panel) -#. Restart the python instance(s) that serve *Modoboa* +#. Restart the python instance(s) that serve Modoboa #. Log into Modoboa, go to *Modoboa > Extensions*, uncheck all extensions, save. Then, check the extensions you want to use and @@ -321,7 +345,7 @@ requires a migration. (see :ref:`webservers`) #. **For Dovecot users only**, you need to modify the - ``password_query`` (file */etc/dovecot/dovecot-sql.conf* by default + ``password_query`` (file :file:`/etc/dovecot/dovecot-sql.conf` by default on a Debian system) like this:: password_query = SELECT email AS user, password FROM auth_user WHERE email='%u' @@ -329,7 +353,7 @@ requires a migration. 0.8.8: CSV import feature and minor fixes ========================================= -#. Edit the *settings.py* file and add +#. Edit the :file:`settings.py` file and add ``'modoboa.lib.middleware.AjaxLoginRedirect'`` to the ``MIDDLEWARE_CLASSES`` variable like this:: @@ -344,7 +368,7 @@ requires a migration. 'modoboa.extensions.webmail.middleware.WebmailErrorMiddleware', ) -#. Still inside *settings.py*, modify the ``DATABASE_ROUTERS`` +#. Still inside :file:`settings.py`, modify the ``DATABASE_ROUTERS`` variable like this:: DATABASE_ROUTERS = ["modoboa.extensions.amavis_quarantine.dbrouter.AmavisRouter"] @@ -353,7 +377,7 @@ requires a migration. 0.8.7: per-user language selection ================================== -#. Edit the *settings.py* file and add the +#. Edit the :file:`settings.py` file and add the ``'django.middleware.locale.LocaleMiddleware'`` middleware to the ``MIDDLEWARE_CLASSES`` variable like this:: @@ -386,7 +410,7 @@ requires a migration. ========================================================= #. Just update your configuration if you are using the quarantine - plugin. Open *settings.py*, move the database configuration from + plugin. Open :file:`settings.py`, move the database configuration from the ``DB_CONNECTIONS`` variable to the ``DATABASES`` variable, like this:: @@ -408,7 +432,7 @@ requires a migration. DATABASE_ROUTERS = ["modoboa.extensions.amavis_quarantine.dbrouter.AmavisRouter"] -#. Remove the deprecated ``DB_CONNECTIONS`` variable from *settings.py*. +#. Remove the deprecated ``DB_CONNECTIONS`` variable from :file:`settings.py`. 0.8.5: new "Sieve filters" plugin, improved admin app ===================================================== @@ -419,7 +443,7 @@ requires a migration. $ python manage.py migrate admin #. Add ``modoboa.auth`` and ``modoboa.extensions.sievefilters`` to the - ``INSTALLED_APPS`` variable in *settings.py*. + ``INSTALLED_APPS`` variable in :file:`settings.py`. #. Go the *Settings/Extensions* panel, deactivate and activate your extensions, it will update all the symbolic links. @@ -427,7 +451,7 @@ requires a migration. 0.8.4: folders manipulation support (webmail) and bugfixes ========================================================== -#. Update the ``MIDDLEWARE_CLASSES`` variable in *settings.py*:: +#. Update the ``MIDDLEWARE_CLASSES`` variable in :file:`settings.py`:: MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', @@ -442,7 +466,7 @@ requires a migration. extensions, it will update all the symbolic links to the new format. #. Optional: update the ``DATABASES`` and ``TEMPLATE_LOADERS`` - variables in *settings.py* to remove warning messages (appearing with + variables in :file:`settings.py` to remove warning messages (appearing with Django 1.3):: DATABASES = { @@ -464,14 +488,14 @@ requires a migration. 0.8.3: admin application refactoring and more ============================================= -#. Migrate the *admin* application:: +#. Migrate the ``admin`` application:: $ python manage.py migrate admin #. Update SQL queries used in your environnement (see :ref:`postfix` or :ref:`dovecot`). -#. Update *postfix* configuration so that it can handle domain aliases +#. Update Postfix configuration so that it can handle domain aliases (see :ref:`postfix`). @@ -484,9 +508,9 @@ requires a migration. #. Update your config file and add all extensions to ``INSTALLED_APPS`` (even those you are not going to use). -#. Inside the */templates/* directory, remove all symbolic links. -#. Download the latest release of ckeditor and extract it into */static/js/*. It should create a new directory named *ckeditor*. -#. Update the following variables inside *settings.py*:: +#. Inside the :file:`/templates/` directory, remove all symbolic links. +#. Download the latest release of ckeditor and extract it into :file:`/static/js/`. It should create a new directory named ``ckeditor``. +#. Update the following variables inside :file:`settings.py`:: MEDIA_ROOT = os.path.join(MODOBOA_DIR, 'static') MEDIA_URL = '/static/' @@ -500,9 +524,9 @@ requires a migration. 0.8.1 : project renamed ======================= -#. First, rename the *mailng* directory to *modoboa* and copy all the - content from *modoboa-0.8.1* to *modoboa*. -#. Edit *settings.py* and replace all occurences of mailng by +#. First, rename the ``mailng`` directory to ``modoboa`` and copy all the + content from ``modoboa-0.8.1`` to ``modoboa``. +#. Edit :file:`settings.py` and replace all occurences of mailng by modoboa. Make sure you don't modify the ``DATABASE`` section as you're not going to rename your database. #. Rename the ``MAILNG_DIR`` variable to ``MODOBOA_DIR``. @@ -536,7 +560,7 @@ Before you start the migration, make sure you have updated your 'mailng.userprefs', ) -Starting with 0.8, mailng.main doesn't exist anymore. You must remove +Starting with 0.8, ``mailng.main`` doesn't exist anymore. You must remove it from your ``INSTALLED_APPS``. Finally, run the following commands:: diff --git a/doc/integration/imap_and_smtp.rst b/doc/integration/imap_and_smtp.rst index bbcab775e..3838c29ba 100644 --- a/doc/integration/imap_and_smtp.rst +++ b/doc/integration/imap_and_smtp.rst @@ -12,12 +12,12 @@ Modoboa works better with Dovecot 2.0 so the following documentation is suitable for this combination. In this section, we assume dovecot's configuration resides in -*/etc/dovecot*, all pathes will be relative to this directory. +:file:`/etc/dovecot`, all pathes will be relative to this directory. Mailboxes ========= -First, edit the *conf.d/10-mail.conf* and set the ``mail_location`` +First, edit the :file:`conf.d/10-mail.conf` and set the ``mail_location`` variable:: # maildir @@ -45,14 +45,53 @@ Then, edit the ``inbox`` namespace and add the following lines:: It ensures all the special mailboxes will be automaticaly created for new accounts. -.. note:: +.. _fs_operations: + +Operations on the file system +----------------------------- + +Three operation types are considered: + +#. Mailbox creation +#. Mailbox renaming +#. Mailbox deletion + +The first one is managed by Dovecot. The last two ones may be managed +by Modoboa if it can access the file system where the mailboxes are +stored (see :ref:`admin-params` to activate this feature). + +Those operations are treated asynchronously by a cron script. For +example, when you rename an e-mail address through the web UI, the +associated mailbox on the file system is not modified +directly. Instead of that, a *rename* order is created for this +mailbox. The mailbox will be considered unavailable until the order is +not executed (see :ref:`Postfix configuration `). + +Edit the crontab of the user who owns the mailboxes on the file system:: + + $ crontab -u -e + +And add the following line inside:: + + * * * * * python /manage.py handle_mailbox_operations + +.. warning:: + + The cron script must be executed by the system user owning the mailboxes. + +.. warning:: + + The user running the cron script must have access to the + :file:`settings.py` file of the modoboa instance. + +The result of each order is recorded into Modoboa's log. Go to +*Modoboa > Logs* to consult them. - Modoboa is not responsible for mailboxes creation, Dovecot is. Authentication ============== -To make the authentication work, edit the *conf.d/10-auth.conf* and +To make the authentication work, edit the :file:`conf.d/10-auth.conf` and uncomment the following line at the end:: #!include auth-system.conf.ext @@ -64,7 +103,7 @@ uncomment the following line at the end:: #!include auth-static.conf.ext -Then, edit the *conf.d/auth-sql.conf.ext* file and add the following +Then, edit the :file:`conf.d/auth-sql.conf.ext` file and add the following content inside:: passdb sql { @@ -81,13 +120,13 @@ content inside:: Make sure to activate only one backend (per type) inside your configuration (just comment the other ones). -Edit the *dovecot-sql.conf.ext* and modify the configuration according +Edit the :file:`dovecot-sql.conf.ext` and modify the configuration according to your database engine. .. _dovecot_mysql_queries: -*MySQL* users -------------- +MySQL users +----------- :: @@ -105,8 +144,8 @@ to your database engine. .. _dovecot_pg_queries: -*PostgreSQL* users ------------------- +PostgreSQL users +---------------- :: @@ -130,7 +169,7 @@ LDA === The LDA is activated by default but you must define a *postmaster* -address. Open the *conf.d/15-lda.conf* file modify the following line:: +address. Open the :file:`conf.d/15-lda.conf` file modify the following line:: postmaster_address = postmaster@ @@ -143,12 +182,12 @@ Modoboa lets adminstrators define per-domain and/or per-account limits (quota). It also lists the current quota usage of each account. Those features require Dovecot to be configured in a specific way. -Inside *conf.d/10-mail.conf*, add the ``quota`` plugin to the default +Inside :file:`conf.d/10-mail.conf`, add the ``quota`` plugin to the default activated ones:: mail_plugins = quota -Inside *conf.d/10-master.conf*, update the *dict* service to set +Inside :file:`conf.d/10-master.conf`, update the ``dict`` service to set proper permissions:: service dict { @@ -161,7 +200,7 @@ proper permissions:: } } -Inside *conf.d/20-imap.conf*, activate the ``imap_quota`` plugin:: +Inside :file:`conf.d/20-imap.conf`, activate the ``imap_quota`` plugin:: protocol imap { # ... @@ -171,13 +210,13 @@ Inside *conf.d/20-imap.conf*, activate the ``imap_quota`` plugin:: # ... } -Inside *dovecot.conf*, activate the quota SQL dictionary backend:: +Inside :file:`dovecot.conf`, activate the quota SQL dictionary backend:: dict { quota = :/etc/dovecot/dovecot-dict-sql.conf.ext } -Inside *conf.d/90-quota.conf*, activate the *quota dictionary* backend:: +Inside :file:`conf.d/90-quota.conf`, activate the *quota dictionary* backend:: plugin { quota = dict:User quota::proxy::quota @@ -185,7 +224,8 @@ Inside *conf.d/90-quota.conf*, activate the *quota dictionary* backend:: It will tell Dovecot to keep quota usage in the SQL dictionary. -Finally, edit the *dovecot-dict-sql.conf.ext* file and put the following content inside:: +Finally, edit the :file:`dovecot-dict-sql.conf.ext` file and put the +following content inside:: connect = host= dbname= user= password= @@ -208,9 +248,9 @@ Finally, edit the *dovecot-dict-sql.conf.ext* file and put the following content Database schema update ^^^^^^^^^^^^^^^^^^^^^^ -The `admin_quota` table is created by *Django* but unfortunately it -doesn't support `DEFAULT` constraints (it only simulates them when the -ORM is used). As *PostgreSQL* is a bit strict about constraint +The ``admin_quota`` table is created by Django but unfortunately it +doesn't support ``DEFAULT`` constraints (it only simulates them when the +ORM is used). As PostgreSQL is a bit strict about constraint violations, you must execute the following query manually:: db=> ALTER TABLE admin_quota ALTER COLUMN bytes SET DEFAULT 0; @@ -279,8 +319,8 @@ work for Modoboa. You should use the following one instead: CREATE TRIGGER setmboxid AFTER INSERT ON admin_quota FOR EACH ROW EXECUTE PROCEDURE set_mboxid(); -Copy this example into a file (for example: *quota-trigger.sql*) on -server running *postgres* and execute the following commands:: +Copy this example into a file (for example: :file:`quota-trigger.sql`) on +server running postgres and execute the following commands:: $ su - postgres $ psql < /path/to/quota-trigger.sql @@ -293,7 +333,7 @@ For existing installations, *Dovecot* (> 2) offers a command to recalculate the current quota usages. For example, if you want to update all usages, run the following command:: - $ doveadmin quota recalc -A + $ doveadm quota recalc -A Be carefull, it can take a while to execute. @@ -303,7 +343,7 @@ ManageSieve/Sieve Modoboa lets users define filtering rules from the web interface. To do so, it requires *ManageSieve* to be activated on your server. -Inside *conf.d/20-managesieve.conf*, make sure the following lines are +Inside :file:`conf.d/20-managesieve.conf`, make sure the following lines are uncommented:: protocols = $protocols sieve @@ -322,7 +362,7 @@ uncommented:: Messages filtering using Sieve is done by the LDA. -Inside *conf.d/15-lda.conf*, activate the ``sieve`` plugin like this:: +Inside :file:`conf.d/15-lda.conf`, activate the ``sieve`` plugin like this:: protocol lda { # Space separated list of plugins to load (default is global mail_plugins). @@ -330,7 +370,7 @@ Inside *conf.d/15-lda.conf*, activate the ``sieve`` plugin like this:: } Finally, configure the ``sieve`` plugin by editing the -*conf.d/90-sieve.conf* file. Put the follwing content inside:: +:file:`conf.d/90-sieve.conf` file. Put the follwing caontent inside:: plugin { # Location of the active script. When ManageSieve is used this is actually @@ -343,7 +383,7 @@ Finally, configure the ``sieve`` plugin by editing the sieve_dir = ~/sieve } -Restart *Dovecot*. +Restart Dovecot. .. _postfix: @@ -359,20 +399,22 @@ Map files ========= You first need to create configuration files (or map files) that will -be used by *postfix* to lookup into Modoboa tables. +be used by Postfix to lookup into Modoboa tables. To automaticaly generate the requested map files and store them in a directory, run the following command:: $ modoboa-admin.py postfix_maps --dbtype mapfiles -``mapfiles`` is the directory where the files will be stored. Answer the -few questions and you're done. +:file:`mapfiles` is the directory where the files will be +stored. Answer the few questions and you're done. + +.. _postfix_config: Configuration ============= -Use the following configuration in the */etc/postfix/main.cf* file +Use the following configuration in the :file:`/etc/postfix/main.cf` file (this is just one possible configuration):: # Stuff before @@ -393,12 +435,18 @@ Use the following configuration in the */etc/postfix/main.cf* file mysql:/etc/postfix/sql-email2email.cf, mysql:/etc/postfix/sql-catchall-aliases.cf + smtpd_recipient_restrictions = + ... + check_recipient_access mysql:/etc/postfix/maps/sql-maintain.cf + permit_mynetworks + ... + # Stuff after -Then, edit the */etc/postfix/master.cf* file and add the following +Then, edit the :file:`/etc/postfix/master.cf` file and add the following definition at the end:: dovecot unix - n n - - pipe flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient} -Restart *Postfix*. +Restart Postfix. diff --git a/doc/integration/web_servers.rst b/doc/integration/web_servers.rst index ec4911a63..2c2d11185 100644 --- a/doc/integration/web_servers.rst +++ b/doc/integration/web_servers.rst @@ -10,10 +10,19 @@ Web servers Apache2 ******* +.. note:: + + The following instructions are meant to help you get your site up + and running quickly. However it is not possible for the people + contributing documentation to Modoboa to test every single + combination of web server, wsgi server, distribution, etc. So it is + possible that **your** installation of uwsgi or nginx or Apache or + what-have-you works differently. Keep this in mind. + mod_wgsi ======== -First, make sure that *mod_wsgi* is installed on your server. +First, make sure that mod_wsgi is installed on your server. Create a new virtualhost in your Apache configuration and put the following content inside:: @@ -37,20 +46,20 @@ following content inside:: WSGIScriptAlias / /wsgi.py -This is just one possible configuration. +This is just one possible configuration. .. note:: - *Django* 1.3 users, please consult this `page `_, - it contains an example *wsgi.py* file. + Django 1.3 users, please consult this `page `_, + it contains an example :file:`wsgi.py` file. -.. note:: +.. note:: You will certainly need more configuration in order to launch Apache. mod_python ========== -First, make sure that *mod_python* is installed on your server. +First, make sure that mod_python is installed on your server. Create a new virtualhost in your Apache configuration and put the following content inside:: @@ -77,9 +86,9 @@ following content inside:: -This is just one possible configuration. +This is just one possible configuration. -.. note:: +.. note:: You will certainly need more configuration in order to launch Apache. @@ -89,17 +98,28 @@ This is just one possible configuration. Nginx ***** +.. note:: + + The following instructions are meant to help you get your site up + and running quickly. However it is not possible for the people + contributing documentation to Modoboa to test every single + combination of web server, wsgi server, distribution, etc. So it is + possible that **your** installation of uwsgi or nginx or Apache or + what-have-you works differently. Keep this in mind. + +Green Unicorn +============= + `Nginx `_ is a really fast HTTP server. Associated with `Green Unicorn `_, it gives you one of the -best setup to serve python/Django applications. Modoboa's -performances are really good with this configuration. +best setups to serve python/Django applications. Modoboa's +performance is really good with this configuration. -To use this setup, first download and install those softwares -(`Install gunicorn `_ and `install -nginx `_). - -Then, use the following sample *gunicorn* configuration (create a new -file named *gunicorn.conf.py* inside Modoboa's root dir):: +To use this setup, first download and install `nginx +`__ and `gunicorn +`_. Then, use the following sample +gunicorn configuration (create a new file named :file:`gunicorn.conf.py` +inside Modoboa's root dir):: backlog = 2048 bind = "unix:/var/run/gunicorn/modoboa.sock" @@ -113,9 +133,9 @@ file named *gunicorn.conf.py* inside Modoboa's root dir):: To start gunicorn, execute the following commands:: $ cd - $ gunicorn_django -c gunicorn.conf.py + $ gunicorn -c gunicorn.conf.py .wsgi:application -Now the *nginx* part. Just create a new virtual host and use the +Now the nginx part. Just create a new virtual host and use the following configuration:: upstream modoboa { @@ -123,13 +143,19 @@ following configuration:: } server { - listen 443; + listen 443 ssl; + ssl on; + keepalive_timeout 70; + server_name ; root ; access_log /var/log/nginx/.access.log; error_log /var/log/nginx/.error.log; + ssl_certificate ; + ssl_certificate_key ; + location /sitestatic/ { autoindex on; } @@ -143,10 +169,165 @@ following configuration:: proxy_set_header Host $http_host; proxy_redirect off; proxy_set_header X-Forwarded-Protocol ssl; - proxy_pass http://modoboa; + proxy_pass http://modoboa; } } +If you do not plan to use SSL then change the listen directive to +``listen 80;`` and delete each of the following directives:: + + ssl on; + keepalive_timeout 70; + ssl_certificate ; + ssl_certificate_key ; + proxy_set_header X-Forwarded-Protocol ssl; + +If you do plan to use SSL, you'll have to generate a certificate and a +key. `This article +`__ +contains information about how to do it. + Paste this content to your configuration (replace values between -``<>`` with yours), restart *nginx* and enjoy a really fast +``<>`` with yours), restart nginx and enjoy a really fast application! + +uwsgi +===== + +The following setup is meant to get you started quickly. You should +read the documentation of both nginx and uwsgi to understand how to +optimize their configuration for your site. + +The Django documentation includes the following warning regarding +uwsgi: + +.. warning:: + + Some distributions, including Debian and Ubuntu, ship an outdated + version of uWSGI that does not conform to the WSGI + specification. Versions prior to 1.2.6 do not call close on the + response object after handling a request. In those cases the + request_finished signal isn’t sent. This can result in idle + connections to database and memcache servers. + +Use uwsgi 1.2.6 or newer. If you do not, you *will* run into +problems. Modoboa will fail in obscure ways. + +To use this setup, first download and install `nginx +`__ and `uwsgi +`_. + +Here is a sample nginx configuration:: + + server { + listen 443 ssl; + ssl on; + keepalive_timeout 70; + + server_name ; + root ; + + ssl_certificate ; + ssl_certificate_key ; + + access_log /var/log/nginx/.access.log; + error_log /var/log/nginx/.error.log; + + location /sitestatic/ { + autoindex on; + alias ; + } + + # Whether or not Modoboa uses a media directory depends on how + # you configured Modoboa. It does not hurt to have this. + location /media/ { + autoindex on; + alias ; + } + + # This denies access to any file that begins with + # ".ht". Apache's .htaccess and .htpasswd are such files. A + # Modoboa installed from scratch would not contain any such + # files, but you never know what the future holds. + location ~ /\.ht { + deny all; + } + + location / { + include uwsgi_params; + uwsgi_pass ; + uwsgi_param UWSGI_SCRIPT modoboa_server.wsgi:application + uwsgi_param UWSGI_SCHEME https; + } + } + +If you do not plan to use SSL then change the listen directive to +``listen 80;`` and delete each of the following directives:: + + ssl on; + keepalive_timeout 70; + ssl_certificate ; + ssl_certificate_key ; + uwsgi_param UWSGI_SCHEME https; + +If you do plan to use SSL, you'll have to generate a certificate and a +key. `This article +`__ +contains information about how to do it. + +Make sure to replace the ``<...>`` in the sample configuration with +appropriate values. Here are some explanations for the cases that may +not be completely self-explanatory: + +```` + Where Modoboa's :file:`settings.py` resides. This is also where the + :file:`sitestatic` and :file:`media` directories reside. + +```` + This is the URL which will be the root of your Modoboa site at your + domain. For instance, if your Modoboa installation is reachable at + at ``https://foo/modoboa`` then ```` is + ``/modoboa``. In this case you probably also have to set the + ``alias`` directives to point to where Modoboa's sitestatic and + media directories are because otherwise nginx won't be able to find + them. + + If Modoboa is at the root of your domain, then ```` is an empty string and can be deleted from the configuration + above. In this case, you probably do not need the ``alias`` + directives. + +```` + The location where uwsig is listening. It could be a unix domain + socket or an address:port combination. Ubuntu configures uwsgi so + that the port is:: + + unix:/run/uwsgi/app//socket + + where ```` is the name of the application. + +Your uwsgi configuration should be:: + + [uwsgi] + # Not needed when using uwsgi from pip + # plugins = python + chdir = + module = .wsgi:application + master = true + harakiri = 30 + sharedarea = 4 + processes = 4 + vhost = true + no-default-app = true + +The plugins directive should be turned on if you use a uwsgi +installation that requires it. If uwsgi was installed from pip, it +does not require it. In the configuration above: + +```` + The directory where :file:`manage.py` resides. This directory is the + parent of ```` + +```` + The name that you passed to ``modoboa-admin.py deploy`` when you + created your Modoboa instance. diff --git a/modoboa/core/commands/postfix_maps.py b/modoboa/core/commands/postfix_maps.py index 140de1cb2..afe3b57d5 100644 --- a/modoboa/core/commands/postfix_maps.py +++ b/modoboa/core/commands/postfix_maps.py @@ -55,8 +55,8 @@ class AliasesMap(MapFile): class DomainAliasesMailboxesMap(MapFile): filename = 'sql-domain-aliases-mailboxes.cf' - mysql = "SELECT DISTINCT concat(mb.address, '@', dom.name) FROM admin_alias al INNER JOIN admin_domain dom ON dom.id=al.domain_id INNER JOIN admin_domainalias domal ON domal.target_id=dom.id INNER JOIN (admin_alias_mboxes almb, admin_mailbox mb) ON (almb.alias_id=al.id AND almb.mailbox_id=mb.id) WHERE domal.name='%d' AND domal.enabled=1 AND (al.address='%u' OR mb.address='%u')" - postgres = "SELECT DISTINCT mb.address || '@' || dom.name FROM admin_alias al INNER JOIN admin_domain dom ON dom.id=al.domain_id INNER JOIN admin_domainalias domal ON domal.target_id=dom.id INNER JOIN admin_alias_mboxes almb ON almb.alias_id=al.id INNER JOIN admin_mailbox mb ON almb.mailbox_id=mb.id WHERE domal.name='%d' AND domal.enabled AND (al.address='%u' OR mb.address='%u')" + mysql = "(SELECT concat(mb.address, '@', dom.name) FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_mailbox mb ON mb.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled=1 AND mb.address='%u') UNION (SELECT concat(al.address, '@', dom.name) FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_alias al ON al.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled=1 AND al.address='%u')" + postgres = "(SELECT mb.address || '@' || dom.name FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_mailbox mb ON mb.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled AND mb.address='%u') UNION (SELECT al.address || '@' || dom.name FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_alias al ON al.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled AND al.address='%u')" class CatchallAliasesMap(MapFile): @@ -65,6 +65,12 @@ class CatchallAliasesMap(MapFile): postgres = "(SELECT mb.address || '@' || dom.name FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id INNER JOIN admin_alias_mboxes al_mb ON al.id=al_mb.alias_id WHERE al.enabled AND al.address='*' AND dom.name='%d' AND dom.enabled)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.enabled AND al.extmboxes<>'' AND al.address='*' AND dom.name='%d' AND dom.enabled)" +class MaintainMap(MapFile): + filename = 'sql-maintain.cf' + mysql = "SELECT '450 Requested mail action not taken: mailbox unavailable' FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id INNER JOIN admin_mailboxoperation mbop ON mbop.mailbox_id=mb.id WHERE dom.name='%d' AND mb.address='%u' LIMIT 1" + postgres = "SELECT '450 Requested mail action not taken: mailbox unavailable' FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id INNER JOIN admin_mailboxoperation mbop ON mbop.mailbox_id=mb.id WHERE dom.name='%d' AND mb.address='%u' LIMIT 1" + + class TransportMap(MapFile): category = "autoreply" filename = 'sql-transport.cf' diff --git a/modoboa/core/models.py b/modoboa/core/models.py index 035a09b63..7e8b887c8 100644 --- a/modoboa/core/models.py +++ b/modoboa/core/models.py @@ -338,9 +338,9 @@ class User(AbstractBaseUser, PermissionsMixin): events.raiseEvent("AccountImported", user, self, row[7:]) def to_csv(self, csvwriter): - row = ["account", self.username.encode("utf-8"), self.password, + row = ["account", self.username.encode("utf-8"), self.password.encode("utf-8"), self.first_name.encode("utf-8"), self.last_name.encode("utf-8"), - self.is_active, self.group, self.email] + self.is_active, self.group, self.email.encode("utf-8")] row += events.raiseQueryEvent("AccountExported", self) csvwriter.writerow(row) diff --git a/modoboa/extensions/admin/factories.py b/modoboa/extensions/admin/factories.py new file mode 100644 index 000000000..78d1eb4d0 --- /dev/null +++ b/modoboa/extensions/admin/factories.py @@ -0,0 +1,48 @@ +import factory +from django.contrib.auth.models import Group +from . import models + + +class GroupFactory(factory.DjangoModelFactory): + FACTORY_FOR = Group + + name = 'DefaultGroup' + + +class MailboxFactory(factory.DjangoModelFactory): + FACTORY_FOR = models.Mailbox + + quota = 0 + use_domain_quota = True + + +class UserFactory(factory.DjangoModelFactory): + FACTORY_FOR = models.User + + email = factory.LazyAttribute(lambda a: a.username) + password = '{PLAIN}toto' + + mailbox = factory.RelatedFactory( + MailboxFactory, 'user', + address=factory.LazyAttribute( + lambda m: m.user.email.replace('@%s' % m.domain.name, '') + ) + ) + + @factory.post_generation + def groups(self, create, extracted, **kwargs): + if not create: + # Simple build, do nothing. + return + + if extracted: + # A list of groups were passed in, use them + for group in extracted: + self.groups.add(Group.objects.get(name=group)) + + +class DomainFactory(factory.DjangoModelFactory): + FACTORY_FOR = models.Domain + + quota = 10 + enabled = True diff --git a/modoboa/extensions/admin/forms.py b/modoboa/extensions/admin/forms.py index e53f1ce90..f483e6ec5 100644 --- a/modoboa/extensions/admin/forms.py +++ b/modoboa/extensions/admin/forms.py @@ -4,6 +4,7 @@ from django.contrib.auth.models import Group from django.utils.translation import ugettext as _, ugettext_lazy from django.http import QueryDict from modoboa.lib import events, parameters +from modoboa.lib.exceptions import PermDeniedException from modoboa.lib.emailutils import split_mailbox from modoboa.lib.permissions import get_account_roles from modoboa.lib.formutils import ( @@ -78,22 +79,44 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm): return cleaned_data + def update_mailbox_quotas(self, domain): + """Update all quota records associated to this domain + + This method must be called only when a domain gets renamed. As + the primary key used for a quota is an email address, rename a + domain will change all associated email addresses, so it will + change the primary keys used for quotas. The consequence is we + can't issue regular UPDATE queries using the .save() method of + a Quota instance (it will trigger an INSERT as the primary key + has changed). + + So, we use this ugly hack to bypass this behaviour. It is not + perfomant at all as it will generate one query per quota + record to update. + """ + for q in Quota.objects.filter(username__contains="@%s" % self.oldname).values('username'): + username = q['username'].replace('@%s' % self.oldname, '@%s' % domain.name) + Quota.objects.filter(username=q['username']).update(username=username) + def save(self, user, commit=True): + """Custom save method + + Updating a domain may have consequences on other objects + (domain alias, mailbox, quota). The most tricky part concerns + quotas update. + + """ d = super(DomainFormGeneral, self).save(commit=False) if commit: old_mail_homes = None - hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False) - if hm == "yes": - if self.oldname is not None and d.name != self.oldname: - for q in Quota.objects.filter(username__contains="@%s" % self.oldname): - q.username = q.username.replace('@%s' % self.oldname, '@%s' % d.name) - q.save() - old_mail_homes = dict((mb.id, mb.mail_home) for mb in d.mailbox_set.all()) + if self.oldname is not None and d.name != self.oldname: + d.name = self.oldname + old_mail_homes = \ + dict((mb.id, mb.mail_home) for mb in d.mailbox_set.all()) + d.name = self.cleaned_data['name'] d.save() - Mailbox.objects.filter(domain=d, use_domain_quota=True).update(quota=d.quota) - if old_mail_homes is not None: - for mb in d.mailbox_set.all(): - mb.rename_dir(old_mail_homes[mb.id]) + Mailbox.objects.filter(domain=d, use_domain_quota=True) \ + .update(quota=d.quota) for k, v in self.cleaned_data.iteritems(): if not k.startswith("aliases"): continue @@ -113,6 +136,12 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm): if not len(filter(lambda name: self.cleaned_data[name] == dalias.name, self.cleaned_data.keys())): dalias.delete() + + if old_mail_homes is not None: + self.update_mailbox_quotas(d) + for mb in d.mailbox_set.all(): + mb.rename_dir(old_mail_homes[mb.id]) + return d @@ -278,8 +307,6 @@ class AliasForm(forms.ModelForm, DynamicForm): except Domain.DoesNotExist: domain = None if domain is not None: - if not self.user.can_access(domain): - raise PermDeniedException(v) try: rcpt = Alias.objects.get(domain=domain, address=local_part) if rcpt.full_address == self.cleaned_data["email"]: diff --git a/modoboa/extensions/admin/management/__init__.py b/modoboa/extensions/admin/management/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/modoboa/extensions/admin/management/commands/__init__.py b/modoboa/extensions/admin/management/commands/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/modoboa/extensions/admin/management/commands/handle_mailbox_operations.py b/modoboa/extensions/admin/management/commands/handle_mailbox_operations.py new file mode 100644 index 000000000..03b899e37 --- /dev/null +++ b/modoboa/extensions/admin/management/commands/handle_mailbox_operations.py @@ -0,0 +1,92 @@ +import os +import logging +from optparse import make_option +from django.core.management.base import BaseCommand +from modoboa.lib import parameters +from modoboa.lib.sysutils import exec_cmd +from modoboa.admin import AdminConsole +from modoboa.admin.exceptions import AdminError +from modoboa.admin.models import MailboxOperation + + +class OperationError(Exception): + pass + + +class Command(BaseCommand): + help = 'Handles rename and delete operations on mailboxes' + + option_list = BaseCommand.option_list + ( + make_option( + '--pidfile', default='/tmp/handle_mailbox_operations.pid', + help='Path to the file that will contain the PID of this process' + ), + ) + + def __init__(self, *args, **kwargs): + super(Command, self).__init__(*args, **kwargs) + self.logger = logging.getLogger('modoboa.admin') + + def rename_mailbox(self, operation): + if not os.path.exists(operation.argument): + return + new_mail_home = operation.mailbox.mail_home + dirname = os.path.dirname(new_mail_home) + if not os.path.exists(dirname): + try: + os.makedirs(dirname) + except os.error as e: + raise OperationError(str(e)) + code, output = exec_cmd( + "mv %s %s" % (operation.argument, new_mail_home) + ) + if code: + raise OperationError(output) + + def delete_mailbox(self, operation): + if not os.path.exists(operation.argument): + return + code, output = exec_cmd( + "rm -r %s" % operation.argument + ) + if code: + raise OperationError(output) + + def check_pidfile(self, path): + """Check if this command is already running + + :param str path: path to the file containing the PID + :return: a boolean, True means we can go further + """ + if os.path.exists(path): + with open(path) as fp: + pid = fp.read().strip() + code, output = exec_cmd( + "grep handle_mailbox_operations /proc/%s/cmdline" % pid + ) + if not code: + return False + with open(path, 'w') as fp: + print >> fp, os.getpid() + return True + + def handle(self, *args, **options): + AdminConsole().load() + if parameters.get_admin("HANDLE_MAILBOXES") == 'no': + return + if not self.check_pidfile(options['pidfile']): + return + for ope in MailboxOperation.objects.all(): + try: + f = getattr(self, '%s_mailbox' % ope.type) + except AttributeError: + continue + try: + f(ope) + except (OperationError, AdminError) as e: + self.logger.critical('%s failed (reason: %s)', + ope, str(e).encode('utf-8')) + else: + self.logger.info('%s succeed', ope) + ope.delete() + os.unlink(options['pidfile']) diff --git a/modoboa/extensions/admin/migrations/0036_auto__add_mailboxoperation.py b/modoboa/extensions/admin/migrations/0036_auto__add_mailboxoperation.py new file mode 100644 index 000000000..f59c90677 --- /dev/null +++ b/modoboa/extensions/admin/migrations/0036_auto__add_mailboxoperation.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'MailboxOperation' + db.create_table(u'admin_mailboxoperation', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('mailbox', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['admin.Mailbox'], null=True, blank=True)), + ('type', self.gf('django.db.models.fields.CharField')(max_length=20)), + ('argument', self.gf('django.db.models.fields.TextField')()), + )) + db.send_create_signal(u'admin', ['MailboxOperation']) + + + def backwards(self, orm): + # Deleting model 'MailboxOperation' + db.delete_table(u'admin_mailboxoperation') + + + models = { + u'admin.alias': { + 'Meta': {'ordering': "['domain__name', 'address']", 'unique_together': "(('address', 'domain'),)", 'object_name': 'Alias'}, + 'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}), + 'aliases': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['admin.Alias']", 'symmetrical': 'False'}), + 'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.ObjectDates']"}), + 'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.Domain']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'extmboxes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mboxes': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['admin.Mailbox']", 'symmetrical': 'False'}) + }, + u'admin.domain': { + 'Meta': {'ordering': "['name']", 'object_name': 'Domain'}, + 'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.ObjectDates']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), + 'quota': ('django.db.models.fields.IntegerField', [], {}) + }, + u'admin.domainalias': { + 'Meta': {'object_name': 'DomainAlias'}, + 'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.ObjectDates']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), + 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.Domain']"}) + }, + u'admin.extension': { + 'Meta': {'object_name': 'Extension'}, + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + u'admin.mailbox': { + 'Meta': {'object_name': 'Mailbox'}, + 'address': ('django.db.models.fields.CharField', [], {'max_length': '252'}), + 'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.ObjectDates']"}), + 'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.Domain']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'quota': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'use_domain_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.User']"}) + }, + u'admin.mailboxoperation': { + 'Meta': {'object_name': 'MailboxOperation'}, + 'argument': ('django.db.models.fields.TextField', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.Mailbox']", 'null': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '20'}) + }, + u'admin.objectaccess': { + 'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'ObjectAccess'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.User']"}) + }, + u'admin.objectdates': { + 'Meta': {'object_name': 'ObjectDates'}, + 'creation': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modification': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + u'admin.quota': { + 'Meta': {'object_name': 'Quota'}, + 'bytes': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}), + 'mbox': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'quota_value'", 'unique': 'True', 'null': 'True', 'to': u"orm['admin.Mailbox']"}), + 'messages': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'username': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'primary_key': 'True'}) + }, + u'admin.user': { + 'Meta': {'ordering': "['username']", 'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'}) + }, + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + } + } + + complete_apps = ['admin'] \ No newline at end of file diff --git a/modoboa/extensions/admin/models/alias.py b/modoboa/extensions/admin/models/alias.py index 2e83914f6..ada1cfa19 100644 --- a/modoboa/extensions/admin/models/alias.py +++ b/modoboa/extensions/admin/models/alias.py @@ -189,7 +189,7 @@ class Alias(DatesAware): self.save(int_rcpts, ext_rcpts, creator=user) def to_csv(self, csvwriter): - row = [self.type, self.full_address, self.enabled] + row = [self.type, self.full_address.encode("utf-8"), self.enabled] row += self.get_recipients() csvwriter.writerow(row) diff --git a/modoboa/extensions/admin/models/domain.py b/modoboa/extensions/admin/models/domain.py index 99e35f94a..b1eb4ef6a 100644 --- a/modoboa/extensions/admin/models/domain.py +++ b/modoboa/extensions/admin/models/domain.py @@ -7,13 +7,14 @@ from modoboa.lib import events, parameters from modoboa.core.models import ObjectAccess from modoboa.extensions.admin.exceptions import AdminError from .base import DatesAware +from .mailbox import MailboxOperation class DomainManager(Manager): def get_for_admin(self, admin): """Return the domains belonging to this admin - + The result is a ``QuerySet`` object, so this function can be used to fill ``ModelChoiceField`` objects. """ @@ -106,10 +107,6 @@ class Domain(DatesAware): Quota.objects.filter(username__contains='@%s' % self.name).delete() events.raiseEvent("DeleteMailbox", self.mailbox_set.all()) ungrant_access_to_objects(self.mailbox_set.all()) - hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False) - if hm == "yes" and not keepdir: - for mb in self.mailbox_set.all(): - mb.delete_dir() if self.alias_set.count(): events.raiseEvent("MailboxAliasDelete", self.alias_set.all()) ungrant_access_to_objects(self.alias_set.all()) diff --git a/modoboa/extensions/admin/models/mailbox.py b/modoboa/extensions/admin/models/mailbox.py index c254d2106..d0fb15092 100644 --- a/modoboa/extensions/admin/models/mailbox.py +++ b/modoboa/extensions/admin/models/mailbox.py @@ -1,4 +1,5 @@ import os +import pwd import reversion from django.db import models from django.db.models import Q @@ -87,15 +88,27 @@ class Mailbox(DatesAware): @property def mail_home(self): - """ + """Retrieve the home directory of this mailbox. + + The home directory refers to the place on the file system + where the mailbox data is stored. + We ask dovecot to give us this information because there are + several patterns to understand and we don't want to implement + them. """ hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False) if hm is None or hm == "no": return None if self.__mail_home is None: - code, output = exec_cmd("doveadm user %s -f home" % self.full_address, - sudo_user=parameters.get_admin("MAILBOXES_OWNER")) + curuser = pwd.getpwuid(os.getuid()).pw_name + mbowner = parameters.get_admin("MAILBOXES_OWNER") + options = {} + if curuser != mbowner: + options['sudo_user'] = mbowner + code, output = exec_cmd( + "doveadm user %s -f home" % self.full_address, **options + ) if code: raise AdminError(_("Failed to retrieve mailbox location (%s)" % output)) self.__mail_home = output.strip() @@ -105,15 +118,9 @@ class Mailbox(DatesAware): hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False) if hm is None or hm == "no": return - self.__mail_home = None - if not os.path.exists(old_mail_home): - return - code, output = exec_cmd( - "mv %s %s" % (old_mail_home, self.mail_home), - sudo_user=parameters.get_admin("MAILBOXES_OWNER") + MailboxOperation.objects.create( + mailbox=self, type='rename', argument=old_mail_home ) - if code: - raise AdminError(_("Failed to rename mailbox: %s" % output)) def rename(self, address, domain): """Rename the mailbox @@ -125,21 +132,14 @@ class Mailbox(DatesAware): qs = Quota.objects.filter(username=self.full_address) self.address = address self.domain = domain - self.rename_dir(old_mail_home) qs.update(username=self.full_address) + self.rename_dir(old_mail_home) def delete_dir(self): hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False) if hm is None or hm == "no": return - if not os.path.exists(self.mail_home): - return - code, output = exec_cmd( - "rm -r %s" % self.mail_home, - sudo_user=parameters.get_admin("MAILBOXES_OWNER") - ) - if code: - raise AdminError(_("Failed to remove mailbox: %s" % output)) + MailboxOperation.objects.create(type='delete', argument=self.mail_home) def set_quota(self, value=None, override_rules=False): """Set or update quota's value for this mailbox. @@ -250,3 +250,16 @@ class Quota(models.Model): class Meta: app_label = 'admin' + + +class MailboxOperation(models.Model): + mailbox = models.ForeignKey(Mailbox, blank=True, null=True) + type = models.CharField( + max_length=20, choices=(('rename', 'rename'), ('delete', 'delete')) + ) + argument = models.TextField() + + def __str__(self): + if self.type == 'rename': + return 'Rename %s -> %s' % (self.argument, self.mailbox.mail_home) + return 'Delete %s' % self.argument diff --git a/modoboa/extensions/admin/static/admin/css/admin.css b/modoboa/extensions/admin/static/admin/css/admin.css index a28919dd9..2768bf843 100644 --- a/modoboa/extensions/admin/static/admin/css/admin.css +++ b/modoboa/extensions/admin/static/admin/css/admin.css @@ -22,6 +22,10 @@ table .progress { margin-bottom: 0 !important; } +table tbody tr:hover { + background-color: #F9F9F9; +} + .search { width: 85%; -webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px; diff --git a/modoboa/extensions/admin/static/admin/js/admin.js b/modoboa/extensions/admin/static/admin/js/admin.js index 825d645aa..835ea339d 100644 --- a/modoboa/extensions/admin/static/admin/js/admin.js +++ b/modoboa/extensions/admin/static/admin/js/admin.js @@ -114,7 +114,7 @@ Domains.prototype = { : gettext("This operation will remove all data associated to this domain, excepting accounts."); $("a[name=deldomain]").confirm({ - question: gettext("Delete this domain?"), + question: function() { return this.$element.attr('title'); }, method: "POST", warning: warnmsg, checkboxes: deloptions, @@ -240,23 +240,13 @@ Identities.prototype = { $("a.filter").click($.proxy(this.filter_by_tag, this)); $("a[name=delaccount]").confirm({ - question: gettext("Delete this account?"), + question: function() { return this.$element.attr('title'); }, method: "POST", checkboxes: deloptions, success_cb: $.proxy(this.reload_listing, this) }); - $("a[name=deldlist]").confirm({ - question: gettext("Delete this list?"), - method: "DELETE", - success_cb: $.proxy(this.reload_listing, this) - }); - $("a[name=delforward]").confirm({ - question: gettext("Delete this forward?"), - method: "DELETE", - success_cb: $.proxy(this.reload_listing, this) - }); $("a[name=delalias]").confirm({ - question: gettext("Delete this alias?"), + question: function() { return this.$element.attr('title'); }, method: "DELETE", success_cb: $.proxy(this.reload_listing, this) }); diff --git a/modoboa/extensions/admin/templatetags/admin_tags.py b/modoboa/extensions/admin/templatetags/admin_tags.py index 2cc789343..bbc59e552 100644 --- a/modoboa/extensions/admin/templatetags/admin_tags.py +++ b/modoboa/extensions/admin/templatetags/admin_tags.py @@ -119,7 +119,7 @@ def domain_actions(user, domid): actions.append({ "name": "deldomain", "url": reverse("modoboa.extensions.admin.views.domain.deldomain", args=[domid]), - "title": _("Delete the domain"), + "title": _("Delete %s?" % domain.name), "img": "icon-trash" }) return render_actions(actions) @@ -135,30 +135,15 @@ def identity_actions(user, ident): {"name": "delaccount", "url": reverse("modoboa.extensions.admin.views.identity.delaccount", args=[objid]), "img": "icon-trash", - "title": _("Delete this account")}, + "title": _("Delete %s?" % ident.username)}, ] else: - if ident.get_recipients_count() >= 2: - actions = [ - {"name": "deldlist", - "url": reverse("modoboa.extensions.admin.views.alias.deldlist") + "?selection=%s" % objid, - "img": "icon-trash", - "title": _("Delete this distribution list")}, - ] - elif ident.extmboxes != "": - actions = [ - {"name": "delforward", - "url": reverse("modoboa.extensions.admin.views.alias.delforward") + "?selection=%s" % objid, - "img": "icon-trash", - "title": _("Delete this forward")}, - ] - else: - actions = [ - {"name": "delalias", - "url": reverse("modoboa.extensions.admin.views.alias.delalias") + "?selection=%s" % objid, - "img": "icon-trash", - "title": _("Delete this alias")}, - ] + actions = [ + {"name": "delalias", + "url": reverse("modoboa.admin.views.delalias") + "?selection=%s" % objid, + "img": "icon-trash", + "title": _("Delete %s?" % ident.full_address)}, + ] return render_actions(actions) diff --git a/modoboa/extensions/admin/tests.py b/modoboa/extensions/admin/tests.py index 514a79f30..a1db2344c 100644 --- a/modoboa/extensions/admin/tests.py +++ b/modoboa/extensions/admin/tests.py @@ -19,10 +19,15 @@ from modoboa.lib import parameters from modoboa.lib.tests import ModoTestCase from modoboa.extensions.admin.lib import * from modoboa.extensions.admin.models import * +from . import factories class DomainTestCase(ModoTestCase): - fixtures = ["initial_users.json", "test_content.json"] + fixtures = ["initial_users.json"] + + def setUp(self): + super(DomainTestCase, self).setUp() + self.dom = factories.DomainFactory(name='test.com') def test_create(self): """Test the creation of a domain @@ -78,7 +83,10 @@ class DomainTestCase(ModoTestCase): values = { "name": "pouet.com", "quota": 100, "enabled": True } - self.check_ajax_post(reverse("modoboa.admin.views.editdomain", args=[1]), values) + self.check_ajax_post( + reverse("modoboa.admin.views.editdomain", args=[self.dom.id]), + values + ) dom = Domain.objects.get(name="pouet.com") self.assertEqual(dom.name, "pouet.com") self.assertTrue(dom.enabled) @@ -86,13 +94,17 @@ class DomainTestCase(ModoTestCase): def test_delete(self): """Test the removal of a domain """ - self.check_ajax_get(reverse("modoboa.admin.views.deldomain", args=[1]), {}) + self.check_ajax_get(reverse("modoboa.admin.views.deldomain", args=[self.dom.id]), {}) with self.assertRaises(Domain.DoesNotExist): Domain.objects.get(pk=1) class DomainAliasTestCase(ModoTestCase): - fixtures = ["initial_users.json", "test_content.json"] + fixtures = ['initial_users.json'] + + def setUp(self): + super(DomainAliasTestCase, self).setUp() + self.dom = factories.DomainFactory(name='test.com') def test_model(self): dom = Domain.objects.get(name="test.com") @@ -111,16 +123,23 @@ class DomainAliasTestCase(ModoTestCase): dom = Domain.objects.get(name="test.com") values = dict(name=dom.name, quota=dom.quota, enabled=dom.enabled, aliases="domalias.net", aliases_1="domalias.com") - self.check_ajax_post(reverse("modoboa.admin.views.editdomain", args=[1]), values) + self.check_ajax_post(reverse("modoboa.admin.views.editdomain", args=[dom.id]), values) self.assertEqual(dom.domainalias_set.count(), 2) del values["aliases_1"] - self.check_ajax_post(reverse("modoboa.admin.views.editdomain", args=[1]), values) + self.check_ajax_post(reverse("modoboa.admin.views.editdomain", args=[dom.id]), values) self.assertEqual(dom.domainalias_set.count(), 1) class AccountTestCase(ModoTestCase): - fixtures = ["initial_users.json", "test_content.json",] + fixtures = ["initial_users.json"] + + def setUp(self): + super(AccountTestCase, self).setUp() + self.dom = factories.DomainFactory(name="test.com") + self.account = factories.UserFactory( + username="user@test.com", groups=('SimpleUsers',), mailbox__domain=self.dom + ) def test_crud(self): values = dict(username="tester@test.com", first_name="Tester", last_name="Toto", @@ -132,14 +151,14 @@ class AccountTestCase(ModoTestCase): account = User.objects.get(username="tester@test.com") mb = account.mailbox_set.all()[0] self.assertEqual(mb.full_address, "tester@test.com") - self.assertEqual(mb.quota, 100) + self.assertEqual(mb.quota, 10) self.assertEqual(mb.enabled, True) self.assertEqual(mb.quota_value.username, "tester@test.com") self.assertEqual(account.username, mb.full_address) self.assertTrue(account.check_password("toto")) self.assertEqual(account.first_name, "Tester") self.assertEqual(account.last_name, "Toto") - self.assertEqual(mb.domain.mailbox_count, 4) + self.assertEqual(mb.domain.mailbox_count, 2) values["username"] = "pouet@test.com" self.check_ajax_post(reverse("modoboa.admin.views.editaccount", args=[account.id]), values) @@ -173,7 +192,17 @@ class AccountTestCase(ModoTestCase): class AliasTestCase(ModoTestCase): - fixtures = ["initial_users.json", "test_content.json"] + fixtures = ["initial_users.json"] + + def setUp(self): + super(AliasTestCase, self).setUp() + dom = factories.DomainFactory(name="test.com") + factories.UserFactory.create( + username="admin@test.com", groups=('DomainAdmins',), mailbox__domain=dom + ) + factories.UserFactory.create( + username="user@test.com", groups=('SimpleUsers',), mailbox__domain=dom + ) def test_alias(self): user = User.objects.get(username="user@test.com") @@ -208,7 +237,7 @@ class AliasTestCase(ModoTestCase): values) self.assertEqual(dlist.get_recipients_count(), 2) - self.check_ajax_get(reverse("modoboa.admin.views.deldlist") + "?selection=%d" \ + self.check_ajax_get(reverse("modoboa.admin.views.delalias") + "?selection=%d" \ % dlist.id, {}) self.assertRaises(Alias.DoesNotExist, Alias.objects.get, address="all", domain__name="test.com") @@ -224,7 +253,7 @@ class AliasTestCase(ModoTestCase): values) self.assertEqual(fwd.get_recipients_count(), 1) - self.check_ajax_get(reverse("modoboa.admin.views.delforward") + "?selection=%d" \ + self.check_ajax_get(reverse("modoboa.admin.views.delalias") + "?selection=%d" \ % fwd.id, {}) self.assertRaises(Alias.DoesNotExist, Alias.objects.get, address="forward", domain__name="test.com") @@ -245,24 +274,28 @@ class AliasTestCase(ModoTestCase): class PermissionsTestCase(ModoTestCase): - fixtures = ["initial_users.json", "test_content.json"] + fixtures = ["initial_users.json"] def setUp(self): - """ - FIXME: je n'arrive pas à générer des données de test incluant - déjà les permissions (cf. table ObjectAccess). C'est pour - cette raison que j'assigne le domaine test.com ici... - """ super(PermissionsTestCase, self).setUp() - self.user = User.objects.get(username="user@test.com") + dom = factories.DomainFactory(name='test.com') + self.user = factories.UserFactory( + username="user@test.com", groups=('SimpleUsers',), mailbox__domain=dom + ) self.values = dict( username=self.user.username, role="DomainAdmins", is_active=self.user.is_active, email="user@test.com" ) - self.admin = User.objects.get(username="admin@test.com") - dom = Domain.objects.get(name="test.com") + self.admin = factories.UserFactory( + username="admin@test.com", groups=('DomainAdmins',), mailbox__domain=dom + ) dom.add_admin(self.admin) + dom = factories.DomainFactory(name='test2.com') + factories.UserFactory( + username='user@test2.com', groups=('SimpleUsers',), mailbox__domain=dom + ) + def tearDown(self): self.clt.logout() @@ -336,15 +369,31 @@ class PermissionsTestCase(ModoTestCase): self.check_ajax_get(reverse("modoboa.admin.views.delaccount", args=[account.id]), {}, status="ko", respmsg="Permission denied") + def test_domainadmin_dlist_local_domain_not_owned(self): + """Check if a domain admin can use a local mailbox he can't + access as a recipient in a distribution list""" + values = dict( + email="all@test.com", + recipients="user@test.com", + recipients_1="user@test2.com", + enabled=True + ) + self.check_ajax_post(reverse("modoboa.admin.views.newdlist"), values) + class ImportTestCase(ModoTestCase): - fixtures = ["initial_users.json", "test_content.json"] + fixtures = ["initial_users.json"] def setUp(self): super(ImportTestCase, self).setUp() - self.admin = User.objects.get(username="admin@test.com") - dom = Domain.objects.get(name="test.com") + dom = factories.DomainFactory(name="test.com") + self.admin = factories.UserFactory.create( + username="admin@test.com", groups=('DomainAdmins',), mailbox__domain=dom + ) dom.add_admin(self.admin) + factories.UserFactory.create( + username="user@test.com", groups=('SimpleUsers',), mailbox__domain=dom + ) def test_domains_import(self): f = ContentFile(b"""domain; domain1.com; 100; True diff --git a/modoboa/extensions/admin/urls.py b/modoboa/extensions/admin/urls.py index 799d270cf..6f5650814 100644 --- a/modoboa/extensions/admin/urls.py +++ b/modoboa/extensions/admin/urls.py @@ -29,10 +29,7 @@ urlpatterns += patterns( urlpatterns += patterns( 'modoboa.extensions.admin.views.alias', (r'^distriblists/new/$', 'newdlist'), - (r'^distriblists/delete/$', 'deldlist'), - (r'^forwards/new/$', 'newforward'), - (r'^forwards/delete/$', 'delforward'), (r'^aliases/new/$', 'newalias'), (r'^aliases/edit/(?P\d+)/$', 'editalias'), diff --git a/modoboa/extensions/admin/views/alias.py b/modoboa/extensions/admin/views/alias.py index 3201fb57c..809fe17c6 100644 --- a/modoboa/extensions/admin/views/alias.py +++ b/modoboa/extensions/admin/views/alias.py @@ -129,35 +129,25 @@ def editalias(request, alid, tplname="common/generic_modal_form.html"): return render(request, tplname, ctx) -def _del_alias(request, msg, msgs): +@login_required +@permission_required("admin.delete_alias") +@transaction.commit_on_success +def delalias(request): selection = request.GET["selection"].split(",") for alid in selection: alias = Alias.objects.get(pk=alid) if not request.user.can_access(alias): raise PermDeniedException + if alias.type == 'dlist': + msg = "Distribution list deleted" + msgs = "Distribution lists deleted" + elif alias.type == 'forward': + msg = "Forward deleted" + msgs = "Forwards deleted" + else: + msg = "Alias deleted" + msgs = "Aliases deleted" alias.delete() msg = ungettext(msg, msgs, len(selection)) return ajax_simple_response({"status": "ok", "respmsg": msg}) - - -@login_required -@permission_required("admin.delete_alias") -@transaction.commit_on_success -def delalias(request): - return _del_alias(request, "Alias deleted", "Aliases deleted") - - -@login_required -@permission_required("admin.delete_alias") -@transaction.commit_on_success -def deldlist(request): - return _del_alias(request, "Distribution list deleted", - "Distribution lists deleted") - - -@login_required -@permission_required("admin.delete_alias") -@transaction.commit_on_success -def delforward(request): - return _del_alias(request, "Forward deleted", "Forwards deleted") diff --git a/modoboa/extensions/admin/views/domain.py b/modoboa/extensions/admin/views/domain.py index 1fede9a73..737d19bde 100644 --- a/modoboa/extensions/admin/views/domain.py +++ b/modoboa/extensions/admin/views/domain.py @@ -9,7 +9,9 @@ from django.contrib.auth.decorators import ( login_required, permission_required, user_passes_test ) from modoboa.lib import parameters, events -from modoboa.lib.webutils import ajax_simple_response, ajax_response +from modoboa.lib.webutils import ( + ajax_simple_response, ajax_response, _render_to_string +) from modoboa.lib.formutils import CreationWizard from modoboa.lib.exceptions import PermDeniedException from modoboa.lib.templatetags.libextras import pagination_bar @@ -123,6 +125,7 @@ def newdomain(request, tplname="common/wizard_forms.html"): @login_required @permission_required("admin.view_domains") +@transaction.commit_on_success def editdomain(request, dom_id, tplname="admin/editdomainform.html"): domain = Domain.objects.get(pk=dom_id) if not request.user.can_access(domain): @@ -153,15 +156,15 @@ def editdomain(request, dom_id, tplname="admin/editdomainform.html"): error = str(e) else: events.raiseEvent("DomainModified", domain) - return ajax_simple_response({ - "status": "ok", "respmsg": _("Domain modified") - }) + return ajax_simple_response({ + "status": "ok", "respmsg": _("Domain modified") + }) commonctx["tabs"] = form - commonctx["error"] = error - return ajax_response( - request, status="ko", template=tplname, **commonctx - ) + return ajax_simple_response({ + "status": "ko", "respmsg": error, + "content": _render_to_string(request, tplname, commonctx) + }) commonctx["tabs"] = DomainForm(request.user, instances=instances) commonctx["domadmins"] = domadmins diff --git a/modoboa/extensions/admin/views/export.py b/modoboa/extensions/admin/views/export.py index 437e48173..18098f40b 100644 --- a/modoboa/extensions/admin/views/export.py +++ b/modoboa/extensions/admin/views/export.py @@ -1,5 +1,6 @@ import csv import cStringIO +from rfc6266 import build_header from django.http import HttpResponse from django.shortcuts import render from django.core.urlresolvers import reverse @@ -25,7 +26,7 @@ def _export(content, filename): resp = HttpResponse(content) resp["Content-Type"] = "text/csv" resp["Content-Length"] = len(content) - resp["Content-Disposition"] = 'attachment; filename="%s"' % filename + resp["Content-Disposition"] = build_header(filename) return resp diff --git a/modoboa/extensions/amavis/views.py b/modoboa/extensions/amavis/views.py index 52be6b4bd..4ccedf61e 100644 --- a/modoboa/extensions/amavis/views.py +++ b/modoboa/extensions/amavis/views.py @@ -21,17 +21,25 @@ from .lib import selfservice, AMrelease from .sql_listing import SQLlisting, SQLemail, get_wrapper -def __get_current_url(request): +def __back_to_listing(request): + """Return the current listing URL. + + Looks into the user's session and the current request to build the + URL. + + :param request: a ``Request`` object + :return: a string + """ + url = "listing" + params = [] if "page" in request.session: - res = "listing?page=%s" % request.session["page"] - else: - res = "" - params = "&".join(["%s=%s" % (p, request.session[p]) - for p in ["criteria", "pattern"] - if p in request.sessions]) - if params != "": - res += "?%s" % (params) - return res + params += ["page=%s" % request.session["page"]] + + params += ["%s=%s" % (p, request.session[p]) + for p in ["criteria", "pattern"] if p in request.session] + if params: + url += "?%s" % ("&".join(params)) + return url def empty_quarantine(request): @@ -225,7 +233,7 @@ def delete(request, mail_id): "%(count)d messages deleted successfully", len(mail_id)) % {"count": len(mail_id)} return ajax_response(request, respmsg=message, - url=__get_current_url(request)) + url=__back_to_listing(request)) def release_selfservice(request, mail_id): @@ -273,7 +281,7 @@ def release(request, mail_id): "%(count)d requests sent", len(mail_id)) % {"count": len(mail_id)} return ajax_response(request, "ok", respmsg=message, - url=__get_current_url(request)) + url=__back_to_listing(request)) else: msgrcpts = [] wrapper = get_wrapper() @@ -299,7 +307,7 @@ def release(request, mail_id): else: message = error return ajax_response(request, "ko" if error else "ok", respmsg=message, - url=__get_current_url(request)) + url=__back_to_listing(request)) @login_required diff --git a/modoboa/extensions/limits/tests.py b/modoboa/extensions/limits/tests.py index 0c599de10..23e4669e3 100644 --- a/modoboa/extensions/limits/tests.py +++ b/modoboa/extensions/limits/tests.py @@ -1,12 +1,21 @@ from django.core.urlresolvers import reverse from modoboa.lib.tests import ExtTestCase from modoboa.core.models import User +from modoboa.admin import factories class PermissionsTestCase(ExtTestCase): - fixtures = ["initial_users.json", "test_content.json"] + fixtures = ["initial_users.json"] name = "limits" + def setUp(self): + super(PermissionsTestCase, self).setUp() + dom = factories.DomainFactory(name='test.com') + self.admin = factories.UserFactory( + username='admin@test.com', groups=('DomainAdmins',), mailbox__domain=dom + ) + dom.add_admin(self.admin) + def test_domainadmin_deletes_reseller(self): """Check if a domain admin can delete a reseller. @@ -25,7 +34,3 @@ class PermissionsTestCase(ExtTestCase): reverse("modoboa.extensions.admin.views.identity.delaccount", args=[account.id]), {}, status="ko", respmsg="Permission denied" ) - self.check_ajax_get( - reverse("modoboa.extensions.admin.views.identity.delaccount", args=[4]), - {}, status="ko", respmsg="Permission denied" - ) diff --git a/modoboa/extensions/postfix_autoreply/__init__.py b/modoboa/extensions/postfix_autoreply/__init__.py index ff8dd915c..61608c4fc 100644 --- a/modoboa/extensions/postfix_autoreply/__init__.py +++ b/modoboa/extensions/postfix_autoreply/__init__.py @@ -89,10 +89,22 @@ def onCreateDomain(user, domain): transport.save() +@events.observe("DomainModified") +def onDomainModified(domain): + if domain.oldname == domain.name: + return + Transport.objects.filter(domain="autoreply.%s" % domain.oldname) \ + .update(domain="autoreply.%s" % domain.name) + for al in Alias.objects.filter(full_address__contains="@%s" % domain.oldname): + new_address = al.full_address.replace("@%s" % domain.oldname, "@%s" % domain.name) + al.full_address = new_address + al.autoreply_address = "%s@autoreply.%s" % (new_address, domain.name) + al.save() + + @events.observe("DeleteDomain") def onDeleteDomain(domain): - trans = Transport.objects.get(domain="autoreply.%s" % domain.name) - trans.delete() + Transport.objects.filter(domain="autoreply.%s" % domain.name).delete() @events.observe("CreateMailbox") diff --git a/modoboa/extensions/postfix_autoreply/migrations/0003_auto__chg_field_arhistoric_sender.py b/modoboa/extensions/postfix_autoreply/migrations/0003_auto__chg_field_arhistoric_sender.py new file mode 100644 index 000000000..a760497e9 --- /dev/null +++ b/modoboa/extensions/postfix_autoreply/migrations/0003_auto__chg_field_arhistoric_sender.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Changing field 'ARhistoric.sender' + db.alter_column(u'postfix_autoreply_arhistoric', 'sender', self.gf('django.db.models.fields.CharField')(max_length=254)) + + def backwards(self, orm): + + # Changing field 'ARhistoric.sender' + db.alter_column(u'postfix_autoreply_arhistoric', 'sender', self.gf('django.db.models.fields.TextField')()) + + models = { + u'admin.domain': { + 'Meta': {'ordering': "['name']", 'object_name': 'Domain'}, + 'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.ObjectDates']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), + 'quota': ('django.db.models.fields.IntegerField', [], {}) + }, + u'admin.mailbox': { + 'Meta': {'object_name': 'Mailbox'}, + 'address': ('django.db.models.fields.CharField', [], {'max_length': '252'}), + 'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.ObjectDates']"}), + 'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.Domain']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'quota': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'use_domain_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.User']"}) + }, + u'admin.objectaccess': { + 'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'ObjectAccess'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.User']"}) + }, + u'admin.objectdates': { + 'Meta': {'object_name': 'ObjectDates'}, + 'creation': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modification': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + u'admin.user': { + 'Meta': {'ordering': "['username']", 'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'}) + }, + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'postfix_autoreply.alias': { + 'Meta': {'object_name': 'Alias'}, + 'autoreply_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'full_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'postfix_autoreply.arhistoric': { + 'Meta': {'object_name': 'ARhistoric'}, + 'armessage': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['postfix_autoreply.ARmessage']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_sent': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'sender': ('django.db.models.fields.CharField', [], {'max_length': '254'}) + }, + u'postfix_autoreply.armessage': { + 'Meta': {'object_name': 'ARmessage'}, + 'content': ('django.db.models.fields.TextField', [], {}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mbox': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.Mailbox']"}), + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'untildate': ('django.db.models.fields.DateTimeField', [], {}) + }, + u'postfix_autoreply.transport': { + 'Meta': {'object_name': 'Transport'}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'method': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + } + } + + complete_apps = ['postfix_autoreply'] \ No newline at end of file diff --git a/modoboa/extensions/postfix_autoreply/migrations/0004_auto__add_unique_arhistoric_sender_armessage.py b/modoboa/extensions/postfix_autoreply/migrations/0004_auto__add_unique_arhistoric_sender_armessage.py new file mode 100644 index 000000000..25819da9a --- /dev/null +++ b/modoboa/extensions/postfix_autoreply/migrations/0004_auto__add_unique_arhistoric_sender_armessage.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding unique constraint on 'ARhistoric', fields ['sender', 'armessage'] + db.create_unique(u'postfix_autoreply_arhistoric', ['sender', 'armessage_id']) + + + def backwards(self, orm): + # Removing unique constraint on 'ARhistoric', fields ['sender', 'armessage'] + db.delete_unique(u'postfix_autoreply_arhistoric', ['sender', 'armessage_id']) + + + models = { + u'admin.domain': { + 'Meta': {'ordering': "['name']", 'object_name': 'Domain'}, + 'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.ObjectDates']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), + 'quota': ('django.db.models.fields.IntegerField', [], {}) + }, + u'admin.mailbox': { + 'Meta': {'object_name': 'Mailbox'}, + 'address': ('django.db.models.fields.CharField', [], {'max_length': '252'}), + 'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.ObjectDates']"}), + 'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.Domain']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'quota': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'use_domain_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.User']"}) + }, + u'admin.objectaccess': { + 'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'ObjectAccess'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.User']"}) + }, + u'admin.objectdates': { + 'Meta': {'object_name': 'ObjectDates'}, + 'creation': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modification': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + u'admin.user': { + 'Meta': {'ordering': "['username']", 'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'}) + }, + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'postfix_autoreply.alias': { + 'Meta': {'object_name': 'Alias'}, + 'autoreply_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'full_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'postfix_autoreply.arhistoric': { + 'Meta': {'unique_together': "(('armessage', 'sender'),)", 'object_name': 'ARhistoric'}, + 'armessage': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['postfix_autoreply.ARmessage']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_sent': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'sender': ('django.db.models.fields.CharField', [], {'max_length': '254'}) + }, + u'postfix_autoreply.armessage': { + 'Meta': {'object_name': 'ARmessage'}, + 'content': ('django.db.models.fields.TextField', [], {}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mbox': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.Mailbox']"}), + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'untildate': ('django.db.models.fields.DateTimeField', [], {}) + }, + u'postfix_autoreply.transport': { + 'Meta': {'object_name': 'Transport'}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'method': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + } + } + + complete_apps = ['postfix_autoreply'] \ No newline at end of file diff --git a/modoboa/extensions/postfix_autoreply/models.py b/modoboa/extensions/postfix_autoreply/models.py index 5eaaf9e31..db41740e5 100644 --- a/modoboa/extensions/postfix_autoreply/models.py +++ b/modoboa/extensions/postfix_autoreply/models.py @@ -3,6 +3,7 @@ from django.utils.translation import ugettext_lazy as _ from modoboa.extensions.admin.models import Domain, Mailbox + class Transport(models.Model): domain = models.CharField(max_length=300) method = models.CharField(max_length=255) @@ -27,10 +28,13 @@ class ARmessage(models.Model): _('enabled'), help_text=_("Activate/Deactivate your auto reply") ) - untildate = models.DateField() + untildate = models.DateTimeField() class ARhistoric(models.Model): armessage = models.ForeignKey(ARmessage) last_sent = models.DateTimeField(auto_now=True) - sender = models.TextField() + sender = models.CharField(max_length=254) + + class Meta: + unique_together = ("armessage", "sender") diff --git a/modoboa/extensions/sievefilters/forms.py b/modoboa/extensions/sievefilters/forms.py index 34cfd47ca..bcbebd7f4 100644 --- a/modoboa/extensions/sievefilters/forms.py +++ b/modoboa/extensions/sievefilters/forms.py @@ -164,7 +164,7 @@ class FilterForm(forms.Form): for fd in folders: value = fd["path"] if "path" in fd else fd["name"] if parentmb: - ret += [(value, fd["name"].replace("%s." % parentmb, ""))] + ret += [(value, fd["name"].replace("%s%s" % (parentmb, imapc.hdelimiter), ""))] else: ret += [(value, fd["name"])] if "sub" in fd: diff --git a/modoboa/extensions/sievefilters/static/sievefilters/js/jquery.dynfields.js b/modoboa/extensions/sievefilters/static/sievefilters/js/jquery.dynfields.js index 98112a4cc..78c17d1a2 100644 --- a/modoboa/extensions/sievefilters/static/sievefilters/js/jquery.dynfields.js +++ b/modoboa/extensions/sievefilters/static/sievefilters/js/jquery.dynfields.js @@ -178,7 +178,7 @@ value = $this.val(); while (true) { - var id = value.indexOf(".", start); + var id = value.indexOf(options.hdelimiter, start); if (id == -1) { break; } @@ -322,6 +322,7 @@ $.fn.dynaction.defaults = { defaultaction: "fileinto", + hdelimiter: '.', templates: [] }; })(jQuery); \ No newline at end of file diff --git a/modoboa/extensions/sievefilters/static/sievefilters/js/lib.js b/modoboa/extensions/sievefilters/static/sievefilters/js/lib.js index e38092166..7854c0c13 100644 --- a/modoboa/extensions/sievefilters/static/sievefilters/js/lib.js +++ b/modoboa/extensions/sievefilters/static/sievefilters/js/lib.js @@ -44,6 +44,7 @@ function changefs(evt) { function init_filters_list() { $("a[name=togglestate]").click(toggle_filter_state); $("a[name*=movefilter_]").click(move_filter); + $("a[name=removefilter]").click(removefilter); } /* @@ -63,7 +64,6 @@ function loadfs(response) { $("#fsetmenu").remove(); } $("#menu").after($(response.menu)); - $("a[name=removefilter]").click(removefilter); $("a[name=activatefs]").click(activatefs); $("a[name=savefs]").click(savefs); $("a[name=removefs]").click(removefs); diff --git a/modoboa/extensions/sievefilters/templates/sievefilters/index.html b/modoboa/extensions/sievefilters/templates/sievefilters/index.html index 4da8cba6e..2430cafdc 100644 --- a/modoboa/extensions/sievefilters/templates/sievefilters/index.html +++ b/modoboa/extensions/sievefilters/templates/sievefilters/index.html @@ -22,7 +22,8 @@ function filterform_cb() { templates: cond_templates }).data('dyncondition'); var $da = $("#action_0").dynaction({ - templates: action_templates + templates: action_templates, + hdelimiter: '{{ hdelimiter }}' }).data('dynaction'); $("input[name=match_type]").click(function(e) { diff --git a/modoboa/extensions/sievefilters/views.py b/modoboa/extensions/sievefilters/views.py index 6c5999c9f..291f1c0d6 100644 --- a/modoboa/extensions/sievefilters/views.py +++ b/modoboa/extensions/sievefilters/views.py @@ -1,5 +1,6 @@ # coding: utf-8 from sievelib.managesieve import Error +from rfc6266 import build_header from django.shortcuts import render from django.http import HttpResponse from django.template.loader import render_to_string @@ -23,6 +24,8 @@ from templatetags.sfilters_tags import fset_menu @login_required @needs_mailbox() def index(request, tplname="sievefilters/index.html"): + from modoboa.extensions.webmail.imaputils import get_imapconnector + try: sc = SieveClient(user=request.user.username, password=request.session["password"]) @@ -44,6 +47,7 @@ def index(request, tplname="sievefilters/index.html"): "active_script": active_script, "default_script": default_script, "scripts": sorted(scripts), + "hdelimiter": get_imapconnector(request).hdelimiter }) @@ -107,14 +111,19 @@ def submitfilter(request, setname, okmsg, tplname, tplctx, update=False, sc=None if match_type == "all": match_type = "anyof" conditions = [("true",)] + fltname = form.cleaned_data["name"].encode("utf-8") if not update: - fset.addfilter(form.cleaned_data["name"], conditions, actions, + fset.addfilter(fltname, conditions, actions, match_type) else: - fset.updatefilter(request.POST["oldname"], - form.cleaned_data["name"], conditions, actions, - match_type) - sc.pushscript(fset.name, str(fset)) + oldname = request.POST["oldname"].encode("utf-8") + fset.updatefilter( + oldname, fltname, conditions, actions, match_type + ) + try: + sc.pushscript(fset.name, str(fset)) + except SieveClientError as e: + return ajax_response(request, "ko", respmsg=str(e)) return ajax_response(request, respmsg=okmsg, ajaxnav=True) tplctx = build_filter_ctx(tplctx, form) return ajax_response(request, status="ko", template=tplname, **tplctx) @@ -159,6 +168,8 @@ def editfilter(request, setname, fname, tplname="sievefilters/filter.html"): update=True, sc=sc) fset = sc.getscript(setname, format="fset") + if type(fname) is unicode: + fname = fname.encode("utf-8") f = fset.getfilter(fname) form = build_filter_form_from_filter(request, fname, f) ctx = build_filter_ctx(ctx, form) @@ -174,7 +185,7 @@ def removefilter(request, setname, fname): sc = SieveClient(user=request.user.username, password=request.session["password"]) fset = sc.getscript(setname, format="fset") - if fset.removefilter(fname): + if fset.removefilter(fname.encode("utf-8")): sc.pushscript(fset.name, str(fset)) return ajax_response(request, respmsg=_("Filter removed")) return ajax_response(request, "ko", respmsg=_("Failed to remove filter")) @@ -270,9 +281,9 @@ def download_filters_set(request, name): return ajax_response(request, "ko", respmsg=str(e)) resp = HttpResponse(script) - resp["Content-Type"] = "text/plain" + resp["Content-Type"] = "text/plain; charset=utf-8" resp["Content-Length"] = len(script) - resp["Content-Disposition"] = 'attachment; filename="%s.txt"' % name + resp["Content-Disposition"] = build_header('%s.txt' % name) return resp @@ -281,6 +292,8 @@ def download_filters_set(request, name): def toggle_filter_state(request, setname, fname): sc = SieveClient(user=request.user.username, password=request.session["password"]) + if type(fname) is unicode: + fname = fname.encode("utf-8") try: fset = sc.getscript(setname, format="fset") if fset.is_filter_disabled(fname): @@ -309,7 +322,7 @@ def move_filter(request, setname, fname, direction): password=request.session["password"]) try: fset = sc.getscript(setname, format="fset") - fset.movefilter(fname, direction) + fset.movefilter(fname.encode("utf-8"), direction) sc.pushscript(setname, str(fset)) except (SieveClientError), e: return ajax_response(request, "ko", respmsg=str(e)) diff --git a/modoboa/extensions/webmail/fetch_parser.py b/modoboa/extensions/webmail/fetch_parser.py index b049c4de9..97110d753 100644 --- a/modoboa/extensions/webmail/fetch_parser.py +++ b/modoboa/extensions/webmail/fetch_parser.py @@ -10,11 +10,21 @@ retrieve multiple attributes of a message. This simple module tries to fix that *problem*. """ - class ParseError(Exception): pass +class Token(object): + def __init__(self, value): + self.value = value + + +class Literal(Token): + def __init__(self, value): + super(Literal, self).__init__(value) + self.next_token_len = int(self.value[1:-1]) + + def parse_next_token(buf): """Look for the next *token* @@ -26,9 +36,11 @@ def parse_next_token(buf): :return: the position of the token's last caracter into ``buf`` """ end = -1 + klass = Token if buf[0] == '{': # Literal end = buf.find('}') + klass = Literal elif buf[0] == '"': # quoted end = buf.find('"', 1) @@ -39,7 +51,9 @@ def parse_next_token(buf): break if end == -1: raise ParseError("End of buffer reached while looking for a token end") - return end + end += 1 + token = klass(buf[:end]) + return token, end def parse_bodystructure(buf, depth=0, prefix=""): @@ -89,9 +103,13 @@ def parse_bodystructure(buf, depth=0, prefix=""): pos += 1 continue nb_bodystruct = 0 - end = parse_next_token(buf[pos:]) - ret.append(buf[pos:pos + end + 1].strip('"')) - pos += end + 1 + token, end = parse_next_token(buf[pos:]) + pos += end + if isinstance(token, Literal): + ret.append(buf[pos:pos + token.next_token_len].strip('"')) + pos += token.next_token_len + else: + ret.append(token.value.strip('"')) raise ParseError("End of buffer reached while looking for a BODY/BODYSTRUCTURE end") @@ -155,11 +173,10 @@ def parse_fetch_response(data): end = pos + 1 break else: - end = parse_next_token(response) - if response[0] == '{': - datalen = int(response[1:end]) - response = response[end + 1:] - end = datalen + token, end = parse_next_token(response) + if isinstance(token, Literal): + response = response[end:] + end = token.next_token_len msgdef[cmdname] = response[:end] response = response[end + 1:] @@ -201,8 +218,8 @@ if __name__ == "__main__": # (' (("Free Haut Debit" NIL "inscription" "freetelecom.fr")) (("Free Haut Debit" NIL "inscription" "freetelecom.fr")) ((NIL NIL "hautdebit" "freetelecom.fr")) ((NIL NIL "nguyen.antoine" "wanadoo.fr")) NIL NIL NIL "<20061213193125.9DA0919AC@dgroup2-2.proxad.net>") ("text" "plain" ("charset" "iso-8859-1") NIL NIL "8bit" 1428 38 NIL ("inline" NIL) NIL NIL) 76 NIL ("inline" ("filename*" "ISO-8859-1\'\'%5B%49%4E%53%43%52%49%50%54%49%4F%4E%5D%20%52%E9%63%E9%70%74%69%6F%6E%20%64%65%20%76%6F%74%72%65%20%64%6F%73%73%69%65%72%20%64%27%69%6E%73%63%72%69%70%74%69%6F%6E%20%46%72%65%65%20%48%61%75%74%20%44%E9%62%69%74")) NIL NIL) "mixed" ("boundary" "------------040706080908000209030901") NIL NIL NIL) BODY[HEADER.FIELDS (DATE FROM TO CC SUBJECT)] {266}', # 'Date: Tue, 19 Dec 2006 19:50:13 +0100\r\nFrom: Antoine Nguyen \r\nTo: Antoine Nguyen \r\nSubject: [Fwd: [INSCRIPTION] =?ISO-8859-1?Q?R=E9c=E9ption_de_votre_?=\r\n =?ISO-8859-1?Q?dossier_d=27inscription_Free_Haut_D=E9bit=5D?=\r\n\r\n'), ')'] - resp = [('123 (UID 3 BODYSTRUCTURE (((("text" "plain" ("charset" "iso-8859-1") NIL NIL "quoted-printable" 1266 30 NIL NIL NIL NIL)("text" "html" ("charset" "iso-8859-1") NIL NIL "quoted-printable" 8830 227 NIL NIL NIL NIL) "alternative" ("boundary" "_000_152AC7ECD1F8AB43A9AD95DBDDCA3118082C09GKIMA24cmcicfr_") NIL NIL NIL)("image" "png" ("name" "image005.png") "" "image005.png" "base64" 7464 NIL ("inline" ("filename" "image005.png" "size" "5453" "creation-date" "Tue, 06 Sep 2011 13:33:49 GMT" "modification-date" "Tue, 06 Sep 2011 13:33:49 GMT")) NIL NIL)("image" "jpeg" ("name" "image006.jpg") "" "image006.jpg" "base64" 2492 NIL ("inline" ("filename" "image006.jpg" "size" "1819" "creation-date" "Tue, 06 Sep 2011 13:33:49 GMT" "modification-date" "Tue, 06 Sep 2011 13:33:49 GMT")) NIL NIL) "related" ("boundary" "_006_152AC7ECD1F8AB43A9AD95DBDDCA3118082C09GKIMA24cmcicfr_" "type" "multipart/alternative") NIL NIL NIL)("application" "pdf" ("name" "bilan assurance CIC.PDF") NIL "bilan assurance CIC.PDF" "base64" 459532 NIL ("attachment" ("filename" "bilan assurance CIC.PDF" "size" "335811" "creation-date" "Fri, 16 Sep 2011 12:45:23 GMT" "modification-date" "Fri, 16 Sep 2011 12:45:23 GMT")) NIL NIL)(("text" "plain" ("charset" "utf-8") NIL NIL "quoted-printable" 1389 29 NIL NIL NIL NIL)("text" "html" ("charset" "utf-8") NIL NIL "quoted-printable" 1457 27 NIL NIL NIL NIL) "alternative" ("boundary" "===============0775904800==") ("inline" NIL) NIL NIL) "mixed" ("boundary" "_007_152AC7ECD1F8AB43A9AD95DBDDCA3118082C09GKIMA24cmcicfr_") NIL ("fr-FR") NIL)',), ')'] + # resp = [('123 (UID 3 BODYSTRUCTURE (((("text" "plain" ("charset" "iso-8859-1") NIL NIL "quoted-printable" 1266 30 NIL NIL NIL NIL)("text" "html" ("charset" "iso-8859-1") NIL NIL "quoted-printable" 8830 227 NIL NIL NIL NIL) "alternative" ("boundary" "_000_152AC7ECD1F8AB43A9AD95DBDDCA3118082C09GKIMA24cmcicfr_") NIL NIL NIL)("image" "png" ("name" "image005.png") "" "image005.png" "base64" 7464 NIL ("inline" ("filename" "image005.png" "size" "5453" "creation-date" "Tue, 06 Sep 2011 13:33:49 GMT" "modification-date" "Tue, 06 Sep 2011 13:33:49 GMT")) NIL NIL)("image" "jpeg" ("name" "image006.jpg") "" "image006.jpg" "base64" 2492 NIL ("inline" ("filename" "image006.jpg" "size" "1819" "creation-date" "Tue, 06 Sep 2011 13:33:49 GMT" "modification-date" "Tue, 06 Sep 2011 13:33:49 GMT")) NIL NIL) "related" ("boundary" "_006_152AC7ECD1F8AB43A9AD95DBDDCA3118082C09GKIMA24cmcicfr_" "type" "multipart/alternative") NIL NIL NIL)("application" "pdf" ("name" "bilan assurance CIC.PDF") NIL "bilan assurance CIC.PDF" "base64" 459532 NIL ("attachment" ("filename" "bilan assurance CIC.PDF" "size" "335811" "creation-date" "Fri, 16 Sep 2011 12:45:23 GMT" "modification-date" "Fri, 16 Sep 2011 12:45:23 GMT")) NIL NIL)(("text" "plain" ("charset" "utf-8") NIL NIL "quoted-printable" 1389 29 NIL NIL NIL NIL)("text" "html" ("charset" "utf-8") NIL NIL "quoted-printable" 1457 27 NIL NIL NIL NIL) "alternative" ("boundary" "===============0775904800==") ("inline" NIL) NIL NIL) "mixed" ("boundary" "_007_152AC7ECD1F8AB43A9AD95DBDDCA3118082C09GKIMA24cmcicfr_") NIL ("fr-FR") NIL)',), ')'] - resp = [('856 (UID 11111 BODYSTRUCTURE ((("text" "plain" ("charset" "UTF-8") NIL NIL "7bit" 0 0 NIL NIL NIL NIL) "mixed" ("boundary" "----=_Part_407172_3159001.1321948277321") NIL NIL NIL)("application" "octet-stream" ("name" "26274308.pdf") NIL NIL "base64" 14906 NIL ("attachment" ("filename" "(26274308.pdf")) NIL NIL) "mixed" ("boundary" "----=_Part_407171_9686991.1321948277321") NIL NIL NIL)',), ')'] + # resp = [('856 (UID 11111 BODYSTRUCTURE ((("text" "plain" ("charset" "UTF-8") NIL NIL "7bit" 0 0 NIL NIL NIL NIL) "mixed" ("boundary" "----=_Part_407172_3159001.1321948277321") NIL NIL NIL)("application" "octet-stream" ("name" "26274308.pdf") NIL NIL "base64" 14906 NIL ("attachment" ("filename" "(26274308.pdf")) NIL NIL) "mixed" ("boundary" "----=_Part_407171_9686991.1321948277321") NIL NIL NIL)',), ')'] print parse_fetch_response(resp) diff --git a/modoboa/extensions/webmail/imaputils.py b/modoboa/extensions/webmail/imaputils.py index fe68c672c..a5db75fab 100644 --- a/modoboa/extensions/webmail/imaputils.py +++ b/modoboa/extensions/webmail/imaputils.py @@ -151,6 +151,7 @@ class IMAPconnector(object): unseen_pattern = re.compile(r'[^\(]+\(UNSEEN (\d+)\)') def __init__(self, user=None, password=None): + self.__hdelimiter = None self.criterions = [] self.address = parameters.get_admin("IMAP_SERVER") self.port = int(parameters.get_admin("IMAP_PORT")) @@ -225,6 +226,23 @@ class IMAPconnector(object): bodystruct[5], int(bodystruct[6])) return (None, None, 0) + @property + def hdelimiter(self): + """Return the default hierachy delimiter. + + This is a simple way to retrieve the default delimiter (see + http://www.imapwiki.org/ClientImplementation/MailboxList). + + :return: a string + """ + if self.__hdelimiter is None: + data = self._cmd("LIST", "", "") + m = self.list_response_pattern.match(data[0]) + if m is None: + raise WebmailError(_("Failed to retrieve hierarchy delimiter")) + self.__hdelimiter = m.group('delimiter') + return self.__hdelimiter + def refresh(self, user, password): """Check if current connection needs a refresh @@ -383,7 +401,7 @@ class IMAPconnector(object): newmboxes += [descr] if re.search("\%s" % delimiter, name): - parts = name.split(".") + parts = name.split(delimiter) if not "path" in descr: descr["path"] = parts[0] descr["sub"] = [] @@ -397,7 +415,8 @@ class IMAPconnector(object): @capability('LIST-EXTENDED', '_listmboxes_simple') def _listmboxes(self, topmailbox, mailboxes, until_mailbox=None): - pattern = ("%s.%%" % topmailbox.encode("imap4-utf-7")) if len(topmailbox) else "%" + pattern = "%s%s%%" % (topmailbox.encode("imap4-utf-7"), self.hdelimiter) \ + if len(topmailbox) else "%" resp = self._cmd("LIST", "", pattern, "RETURN", "(CHILDREN)") newmboxes = [] for mb in resp: @@ -459,7 +478,7 @@ class IMAPconnector(object): "class": "icon-trash"} ] if until_mailbox: - name, parent = separate_mailbox(until_mailbox) + name, parent = separate_mailbox(until_mailbox, self.hdelimiter) if parent: until_mailbox = parent self._listmboxes(topmailbox, md_mailboxes, until_mailbox) @@ -543,7 +562,7 @@ class IMAPconnector(object): def create_folder(self, name, parent=None): if parent is not None: - name = "%s.%s" % (parent, name) + name = "%s%s%s" % (parent, self.hdelimiter, name) typ, data = self.m.create(self._encode_mbox_name(name)) if typ == "NO": raise WebmailError(data[0]) @@ -667,7 +686,7 @@ def separate_mailbox(fullname, sep="."): If a separator is found in ``fullname``, this function returns the corresponding name and parent mailbox name. """ - if fullname.count("."): + if sep in fullname: parts = fullname.split(sep) name = parts[-1] parent = sep.join(parts[0:len(parts) - 1]) diff --git a/modoboa/extensions/webmail/lib.py b/modoboa/extensions/webmail/lib.py index 8f1bcccb8..62ea9c038 100644 --- a/modoboa/extensions/webmail/lib.py +++ b/modoboa/extensions/webmail/lib.py @@ -6,6 +6,7 @@ from datetime import datetime, timedelta import email import lxml import chardet +from rfc6266 import build_header, parse_headers from django.core.files.uploadhandler import FileUploadHandler, SkipFile from django.utils.translation import ugettext as _, ugettext_lazy from django.conf import settings @@ -29,7 +30,7 @@ class WMtable(tables.Table): "select", cssclass="draggable left", width="2%", defvalue="%spics/grippy.png" % settings.STATIC_URL, header="" - ) + ) flags = tables.ImgColumn("flags", width="4%") withatts = tables.ImgColumn("withatts", width="2%") subject = tables.Column( @@ -216,7 +217,7 @@ class ImapEmail(Email): self.bs = BodyStructure(msg['BODYSTRUCTURE']) data = None - mformat = self.dformat if self.bs.contents.has_key(self.dformat) else fallback_fmt + mformat = self.dformat if self.dformat in self.bs.contents else fallback_fmt if len(self.bs.contents): bodyc = u'' @@ -278,24 +279,30 @@ class ImapEmail(Email): return None def _find_attachments(self): + """Retrieve attachments from the parsed body structure. + + We try to find and decode a file name for each attachment. If + we failed, a generic name will be used (ie. part_1, part_2, ...). + """ for att in self.bs.attachments: attname = "part_%s" % att["pnum"] - params = None - key = None if "params" in att and att["params"] != "NIL": - params = att["params"] - key = "name" - - if key is None and \ - "disposition" in att and len(att["disposition"]) > 1: - params = att["disposition"][1] - key = "filename" - - if key and params: - for pos, value in enumerate(params): - if value == key: - attname = u2u_decode.u2u_decode(params[pos + 1]).strip("\r\t\n") - break + attname = u2u_decode.u2u_decode(att["params"][1]) \ + .strip("\r\t\n") + elif "disposition" in att and len(att["disposition"]) > 1: + for pos, value in enumerate(att["disposition"][1]): + if not value.startswith("filename"): + continue + header = "%s; %s=%s" \ + % (att['disposition'][0], + value, + att["disposition"][1][pos + 1].strip("\r\t\n")) + attname = parse_headers(header).filename_unsafe + if attname is None: + attname = u2u_decode.u2u_decode( + att["disposition"][1][pos + 1] + ).strip("\r\t\n") + break self.attachments[att["pnum"]] = attname def _fetch_inlines(self): @@ -626,7 +633,7 @@ def create_mail_attachment(attdef): res.set_payload(fp.read()) fp.close() Encoders.encode_base64(res) - res.add_header("Content-Disposition", "attachment; filename='%s'" % attdef["fname"]) + res['Content-Disposition'] = build_header(attdef['fname'].decode('utf-8')) return res diff --git a/modoboa/extensions/webmail/static/webmail/css/webmail.css b/modoboa/extensions/webmail/static/webmail/css/webmail.css index 891f9e2c9..82adf1cef 100644 --- a/modoboa/extensions/webmail/static/webmail/css/webmail.css +++ b/modoboa/extensions/webmail/static/webmail/css/webmail.css @@ -16,6 +16,10 @@ body, html { overflow: auto; } +#mboxes_container .nav-list .nav-list { + padding-right: 0; +} + #menubar { position: fixed; left: 215px; diff --git a/modoboa/extensions/webmail/static/webmail/js/webmail.js b/modoboa/extensions/webmail/static/webmail/js/webmail.js index 8d40667f7..8ddd4c5b8 100644 --- a/modoboa/extensions/webmail/static/webmail/js/webmail.js +++ b/modoboa/extensions/webmail/static/webmail/js/webmail.js @@ -15,7 +15,8 @@ Webmail.prototype = { submboxes_url: "", delattachment_url: "", ro_mboxes: ["INBOX"], - trash: "" + trash: "", + hdelimiter: '.' }, initialize: function(options) { @@ -82,7 +83,7 @@ Webmail.prototype = { $(document).on("click", "a[name=forward]", $.proxy(this.reply_loader, this)); $(document).on("click", "a[name=delete]", $.proxy(this.delete_message, this)); $(document).on("click", "a[name=activate_links]", $.proxy(function(e) { this.display_mode(e, "1"); }, this)); - $(document).on("click", "a[name=disable_links]", $.proxy(function(e) { this.disable_mode(e, "0"); }, this)); + $(document).on("click", "a[name=disable_links]", $.proxy(function(e) { this.display_mode(e, "0"); }, this)); $(document).on("click", "a[name=sendmail]", $.proxy(this.sendmail, this)); @@ -217,7 +218,7 @@ Webmail.prototype = { } var $link = $('a[href="' + mailbox + '"]'); - var parts = mailbox.split('.'); + var parts = mailbox.split(this.options.hdelimiter); var dname = " " + parts[parts.length - 1]; var $i = $link.children("i"); @@ -285,7 +286,7 @@ Webmail.prototype = { 'class': "block", href: mailbox }); - var parts = mailbox.split("."); + var parts = mailbox.split(this.options.hdelimiter); var linkcontent = " "; var displayname = linkcontent + parts[parts.length - 1]; @@ -401,18 +402,18 @@ Webmail.prototype = { * to access this mailbox are also loaded) */ load_and_select_mailbox: function(mailbox) { - if (mailbox.indexOf(".") == -1) { + if (mailbox.indexOf(this.options.hdelimiter) == -1) { this.select_mailbox(mailbox); return; } this.reset_mb_selection(); - var parts = mailbox.split("."); + var parts = mailbox.split(this.options.hdelimiter); var curmb = parts[0], lastmb = ""; for (var i = 1; i < parts.length; i++) { lastmb = curmb; - curmb += "." + parts[i]; + curmb += this.options.hdelimiter + parts[i]; var $link = $('a[href="' + curmb + '"]'); var $container = $('li[name="' + lastmb + '"]'); @@ -535,7 +536,7 @@ Webmail.prototype = { return; } $parent = $ul; - mailbox = $parent.attr("name") + "." + mailbox; + mailbox = $parent.attr("name") + this.options.hdelimiter + mailbox; } else { $parent = $("#mboxes_container").children("ul"); } @@ -548,8 +549,8 @@ Webmail.prototype = { * If needed, the mailbox will be moved to its new location. */ rename_mailbox: function(oldname, newname, oldparent, newparent) { - var oldpattern = (oldparent) ? oldparent + "." + oldname : oldname; - var newpattern = (newparent) ? newparent + "." + newparent : newname; + var oldpattern = (oldparent) ? oldparent + this.options.hdelimiter + oldname : oldname; + var newpattern = (newparent) ? newparent + this.options.hdelimiter + newname : newname; var $link = $("#folders").find('a[href="' + oldpattern + '"]'); if (oldname != newname) { @@ -559,14 +560,13 @@ Webmail.prototype = { $link.parent("li").attr("name", newpattern); $link.prepend($i); $link.attr("href", newpattern); - this.navobject.setparam("mbox", newname).update(false, true); + this.navobject.setparam("mbox", newpattern).update(false, true); } if (oldparent != newparent) { - var newlocation = (newparent) ? newparent + "." + newname : newname; this.remove_mbox_from_tree($link.parent("li")); this.add_mailbox_to_tree(newparent, newname); if (this.navobject.getparam("action") == "listmailbox") { - this.navobject.setparam("mbox", newlocation).update(); + this.navobject.setparam("mbox", newpattern).update(); } else { this.select_mailbox("INBOX"); } @@ -709,14 +709,14 @@ Webmail.prototype = { * is clicked) */ compose_loader: function(e) { - var $link = $(e.target); + var $link = get_target(e, 'a'); e.preventDefault(); this.navobject.reset().setparam("action", $link.attr("href")).update(); }, reply_loader: function(e) { - var $link = $(e.target); + var $link = get_target(e, "a"); e.preventDefault(); this.navobject.reset().updateparams($link.attr("href")).update(); }, diff --git a/modoboa/extensions/webmail/templates/webmail/folder.html b/modoboa/extensions/webmail/templates/webmail/folder.html index 717997f59..e0c03b57e 100644 --- a/modoboa/extensions/webmail/templates/webmail/folder.html +++ b/modoboa/extensions/webmail/templates/webmail/folder.html @@ -4,7 +4,7 @@
{% endblock %} diff --git a/modoboa/extensions/webmail/templates/webmail/index.html b/modoboa/extensions/webmail/templates/webmail/index.html index b404f7efc..96c5b588f 100644 --- a/modoboa/extensions/webmail/templates/webmail/index.html +++ b/modoboa/extensions/webmail/templates/webmail/index.html @@ -20,7 +20,8 @@ $(document).ready(function() { deflocation: "{{ deflocation }}", defcallback: "{{ defcallback }}", ro_mboxes: {% tolist ro_mboxes %}, - trash: "{{ trash }}" + trash: "{{ trash }}", + hdelimiter: '{{ hdelimiter }}' }); }); diff --git a/modoboa/extensions/webmail/templatetags/webextras.py b/modoboa/extensions/webmail/templatetags/webextras.py index c7e3f9e7a..93006390b 100644 --- a/modoboa/extensions/webmail/templatetags/webextras.py +++ b/modoboa/extensions/webmail/templatetags/webextras.py @@ -124,7 +124,7 @@ def listmailbox_menu(selection, folder, user): @register.simple_tag -def print_mailboxes(tree, selected=None, withunseen=False, selectonly=False): +def print_mailboxes(tree, selected=None, withunseen=False, selectonly=False, hdelimiter='.'): """Display a tree of mailboxes and sub-mailboxes :param tree: the mailboxes to display @@ -134,7 +134,7 @@ def print_mailboxes(tree, selected=None, withunseen=False, selectonly=False): for mbox in tree: cssclass = "" name = mbox["path"] if "sub" in mbox else mbox["name"] - label = separate_mailbox(mbox["name"])[0] + label = separate_mailbox(mbox["name"], hdelimiter)[0] if selected == name: cssclass = "active" result += "
  • \n" % (name, cssclass) @@ -164,7 +164,7 @@ def print_mailboxes(tree, selected=None, withunseen=False, selectonly=False): if "sub" in mbox and len(mbox["sub"]): result += "\n" + + print_mailboxes(mbox["sub"], selected, withunseen, selectonly, hdelimiter) + "\n" result += "
  • \n" return result diff --git a/modoboa/extensions/webmail/views.py b/modoboa/extensions/webmail/views.py index 09ed1a6af..78f475f0e 100644 --- a/modoboa/extensions/webmail/views.py +++ b/modoboa/extensions/webmail/views.py @@ -1,5 +1,6 @@ # coding: utf-8 import os +from rfc6266 import build_header from django.conf import settings from django.http import HttpResponse from django.shortcuts import render @@ -8,6 +9,7 @@ from django.utils.translation import ugettext as _, ungettext from django.core.urlresolvers import reverse from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.gzip import gzip_page from modoboa.lib import parameters from modoboa.lib.webutils import ( _render_to_string, ajax_response, ajax_simple_response @@ -27,6 +29,7 @@ from templatetags import webextras @login_required @needs_mailbox() +@gzip_page def getattachment(request): """Fetch a message attachment @@ -51,11 +54,15 @@ def getattachment(request): # FIXME : ugly hack, see fetch_parser.py for more explanation # :p if type(disp[1][0]) != dict: - cd = '%s; %s="%s"' % (disp[0], disp[1][0], disp[1][1]) + atype, fieldname, filename = disp[0], disp[1][0], disp[1][1] else: - cd = '%s; %s="%s"' % (disp[0], disp[1][0]['struct'][0], disp[1][0]['struct'][1]) + atype, fieldname, filename = disp[0], disp[1][0]['struct'][0], disp[1][0]['struct'][1] + if fieldname.endswith('*'): + cd = '%s; %s=%s' % (atype, fieldname, filename) + else: + cd = '%s; %s="%s"' % (atype, fieldname, filename) else: - cd = 'attachment; filename="%s"' % request.GET["fname"] + cd = build_header(request.GET["fname"]) resp["Content-Disposition"] = cd resp["Content-Length"] = partdef["size"] return resp @@ -144,7 +151,8 @@ def newfolder(request, tplname="webmail/folder.html"): "action_classes": "submit", "withunseen": False, "selectonly": True, - "mboxes": mbc.getmboxes(request.user)} + "mboxes": mbc.getmboxes(request.user), + "hdelimiter": mbc.hdelimiter} if request.method == "POST": form = FolderForm(request.POST) @@ -176,14 +184,15 @@ def editfolder(request, tplname="webmail/folder.html"): "action_label": _("Update"), "action_classes": "submit", "withunseen": False, - "selectonly": True} + "selectonly": True, + "hdelimiter": mbc.hdelimiter} if request.method == "POST": form = FolderForm(request.POST) if form.is_valid(): pf = request.POST.get("parent_folder", None) ctx["selected"] = pf - oldname, oldparent = separate_mailbox(request.POST["oldname"]) + oldname, oldparent = separate_mailbox(request.POST["oldname"], sep=mbc.hdelimiter) res = dict(status="ok", respmsg=_("Mailbox updated")) if form.cleaned_data["name"] != oldname \ or (pf != oldparent): @@ -205,7 +214,7 @@ def editfolder(request, tplname="webmail/folder.html"): name = request.GET.get("name", None) if name is None: raise WebmailError(_("Invalid request")) - shortname, parent = separate_mailbox(name) + shortname, parent = separate_mailbox(name, sep=mbc.hdelimiter) ctx["mboxes"] = mbc.getmboxes(request.user, until_mailbox=parent) ctx["form"] = FolderForm() ctx["form"].fields["oldname"].initial = name @@ -537,6 +546,7 @@ def index(request): if not request.is_ajax(): request.session["lastaction"] = None imapc = get_imapconnector(request) + response["hdelimiter"] = imapc.hdelimiter response["mboxes"] = render_mboxes_list(request, imapc) imapc.getquota(curmbox) response["refreshrate"] = \ diff --git a/modoboa/lib/emailutils.py b/modoboa/lib/emailutils.py index bc58ea1b3..a10381ffe 100644 --- a/modoboa/lib/emailutils.py +++ b/modoboa/lib/emailutils.py @@ -23,7 +23,7 @@ class EmailAddress(object): return self.fulladdress class Email(object): - def __init__(self, msg, mformat="plain", dformat="plain", links="0"): + def __init__(self, msg, mformat="plain", dformat="plain", links=0): self.attached_map = {} self.contents = {"html" : "", "plain" : ""} self.headers = [] @@ -78,16 +78,16 @@ class Email(object): sometimes, messages embark inline images, which means they must be displayed and not attached. """ - if self.dformat == "html" and self.links != "0" \ - and msg.has_key("Content-Disposition"): + if self.dformat == "html" and self.links \ + and "Content-Disposition" in msg: if msg["Content-Disposition"].startswith("inline"): cid = None - if msg.has_key("Content-ID"): + if "Content-ID" in msg: m = re.match("<(.+)>", msg["Content-ID"]) cid = m is not None and m.group(1) or msg["Content-ID"] fname = msg.get_filename() if fname is None: - if msg.has_key("Content-Location"): + if "Content-Location" in msg: fname = msg["Content-Location"] elif cid is not None: fname = cid @@ -167,9 +167,9 @@ class Email(object): def viewmail_html(self, content, **kwargs): if content is None or content == "": return "" - links = kwargs.has_key("links") and kwargs["links"] or "0" - html = lxml.html.fromstring(content) - if links == "0": + links = kwargs.get("links", 0) + html = lxml.html.fromstring(content) + if not links: html.rewrite_links(lambda x: None) else: html.rewrite_links(self.map_cid) @@ -179,7 +179,6 @@ class Email(object): else: body = lxml.html.tostring(body) body = re.sub("<(/?)body", lambda m: "<%sdiv" % m.group(1), body) - body = Template(body).render(Context({})) return body def split_mailbox(mailbox): diff --git a/modoboa/lib/u2u_decode.py b/modoboa/lib/u2u_decode.py index f09304742..751f1022d 100644 --- a/modoboa/lib/u2u_decode.py +++ b/modoboa/lib/u2u_decode.py @@ -1,45 +1,50 @@ #!/usr/bin/env python -# u2u_decode.py -# unstructured rfc2047 header to unicode -# +# coding: utf-8 +""" +u2u_decode.py + +unstructured rfc2047 header to unicode +""" import re from email.header import decode_header, make_header # check spaces between encoded_words (and strip them) sre = re.compile(r'\?=[ \t]+=\?') # re pat for MIME encoded_word (without trailing spaces) -mre = re.compile(r'=\?[^?]*?\?[bq]\?[^? \t]*?\?=', re.I) +mre = re.compile(r'=\?[^?]*?\?[bq]\?[^?\t]*?\?=', re.I) + + +def clean_spaces(m): + """Replace unencoded spaces in string + + :param str m: a match object + :return: the cleaned string + """ + return m.group(0).replace(" ", "=20") -tre = re.compile('=\?[^?]*\?=') def decode_mime(m): - # substitute matching encoded_word with unicode equiv. - h = decode_header(m.group(0)) + """substitute matching encoded_word with unicode equiv. + """ + h = decode_header(clean_spaces(m)) u = unicode(make_header(h)) return u -def clean_spaces(m): - return m.group(0).replace(" ", "=20") def u2u_decode(s): - # utility function for (final) decoding of mime header - # note: resulting string is in one line (no \n within) - # note2: spaces between enc_words are stripped (see RFC2047) + ur"""utility function for (final) decoding of mime header + + note: resulting string is in one line (no \n within) + note2: spaces between enc_words are stripped (see RFC2047) + + >>> u2u_decode('=?ISO-8859-15?Q?=20Profitez de tous les services en ligne sur impots.gouv.fr?=') + u' Profitez de tous les services en ligne sur impots.gouv.fr' + >>> u2u_decode('=?ISO-8859-1?Q?Accus=E9?= de =?ISO-8859-1?Q?r=E9ception?= de votre annonce') + u'Accus\xe9 de r\xe9ception de votre annonce' + >>> u2u_decode('Sm=?ISO-8859-1?B?9g==?=rg=?ISO-8859-1?B?5Q==?=sbord') + u'Sm\xf6rg\xe5sbord' + """ s = ''.join(s.splitlines()) s = sre.sub('?==?', s) - s = tre.sub(clean_spaces, s) u = mre.sub(decode_mime, s) return u - -if __name__ == '__main__': - import sys - if len(sys.argv) > 1: - s = sys.argv[1] - else: - s = """[Apache-Users 7784] ServerAlias =?ISO-2022-JP?B?GyRAGyRCJEsbKEI=?=:( - =?ISO-2022-JP?B?GyRCJTMlbSVzGyhC?=)=?ISO-2022-JP?B?GyRCJHI7SBsoQg==?= - =?ISO-2022-JP?B?GyRAGyRCTVEkOSRrJEg1c0YwJCwkKiQrJDckJBsoQg==?=""" - s = 'Sm=?ISO-8859-1?B?9g==?=rg=?ISO-8859-1?B?5Q==?=sbord' - u = u2u_decode(s) - print u - diff --git a/modoboa/locale/de/LC_MESSAGES/django.po b/modoboa/locale/de/LC_MESSAGES/django.po index 588099c21..2a5e03aa8 100644 --- a/modoboa/locale/de/LC_MESSAGES/django.po +++ b/modoboa/locale/de/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Modoboa-0.9\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-06-01 16:35+0200\n" +"POT-Creation-Date: 2013-09-20 22:30+0200\n" "PO-Revision-Date: 2013-05-24 22:37+0100\n" "Last-Translator: Patrick Ben Koetter \n" "Language-Team: DE \n" @@ -28,8 +28,8 @@ msgstr "Verwaltungskonsole" msgid "Web based console to manage domains, accounts and aliases" msgstr "Webinterface zur Verwaltung von Domains, Mailkonten und -aliasen" -#: admin/__init__.py:16 admin/forms.py:179 admin/forms.py:614 -#: admin/views.py:93 admin/views.py:441 +#: admin/__init__.py:16 admin/forms.py:211 admin/forms.py:652 +#: admin/views.py:94 admin/views.py:447 #: extensions/postfix_autoreply/app_settings.py:11 #: extensions/sievefilters/app_settings.py:50 #: extensions/stats/app_settings.py:11 extensions/webmail/app_settings.py:11 @@ -248,15 +248,24 @@ msgstr "Standard Top-Redirect" msgid "The default redirection used when no application is specified" msgstr "Die Standardumleitung wenn kein Programm angegeben wurde" -#: admin/app_settings.py:230 +#: admin/app_settings.py:213 +msgid "Key must be either 16, 24, or 32 bytes long" +msgstr "" + +#: admin/app_settings.py:222 +#, fuzzy +msgid "Invalid syntax" +msgstr "Ungültige Zeile" + +#: admin/app_settings.py:245 msgid "This field is required" msgstr "Dieses Feld ist erforderlich" -#: admin/forms.py:16 admin/forms.py:459 admin/tables.py:18 +#: admin/forms.py:20 admin/forms.py:497 admin/tables.py:18 msgid "Alias(es)" msgstr "Aliase" -#: admin/forms.py:18 +#: admin/forms.py:22 msgid "" "Alias(es) of this domain. Indicate only one name per input, press ENTER to " "add a new input." @@ -265,23 +274,23 @@ msgstr "" "Eingabefeld an. Bestätigen Sie mit ENTER, um ein neues Eingabefeld zu " "erhalten." -#: admin/forms.py:55 +#: admin/forms.py:59 msgid "An alias with this name already exists" msgstr "Ein Alias mit diesem Namen existiert bereits" -#: admin/forms.py:69 +#: admin/forms.py:73 msgid "A domain with this name already exists" msgstr "Eine Domäne mit diesem Namen existiert bereits" -#: admin/forms.py:114 +#: admin/forms.py:146 msgid "Create a domain administrator" msgstr "Domänen-Administrator erstellen" -#: admin/forms.py:116 +#: admin/forms.py:148 msgid "Automatically create an administrator for this domain" msgstr "Automatisch Administrator für diese Domain anlegen" -#: admin/forms.py:120 admin/tables.py:12 admin/tables.py:47 +#: admin/forms.py:152 admin/tables.py:12 admin/tables.py:47 #: admin/templates/admin/editdomainform.html:13 #: admin/templates/admin/identities_table.html:5 #: admin/templates/admin/information.html:8 @@ -290,7 +299,7 @@ msgstr "Automatisch Administrator für diese Domain anlegen" msgid "Name" msgstr "Name" -#: admin/forms.py:122 +#: admin/forms.py:154 msgid "" "The administrator's name. Don't include the domain's name here, it will be " "automatically appended." @@ -298,28 +307,28 @@ msgstr "" "Name des Administrators. Geben Sie nicht den Domainnamen mit an. Er wird " "automatisch hinzugefügt." -#: admin/forms.py:128 +#: admin/forms.py:160 msgid "Create aliases" msgstr "Aliase erstellen" -#: admin/forms.py:130 +#: admin/forms.py:162 msgid "Automatically create standard aliases for this domain" msgstr "Automatisch Standard-Aliase für Domain anlegen" -#: admin/forms.py:143 +#: admin/forms.py:175 msgid "Invalid format" msgstr "Ungültiges Format" -#: admin/forms.py:155 +#: admin/forms.py:187 #, python-format msgid "User '%s' already exists" msgstr "Identität %s existiert bereits" -#: admin/forms.py:203 +#: admin/forms.py:235 msgid "Email address" msgstr "E-Mail Adresse" -#: admin/forms.py:204 +#: admin/forms.py:236 msgid "" "The distribution list address. Use the '*' character to create a 'catchall' " "address (ex: *@domain.tld)." @@ -327,11 +336,11 @@ msgstr "" "Adresse einer Verteilerliste. Geben Sie '*' an, um einen 'catchall'-Alias " "(Bsp: *@example.com) zu erstellen." -#: admin/forms.py:207 +#: admin/forms.py:239 msgid "Recipients" msgstr "Empfänger" -#: admin/forms.py:208 +#: admin/forms.py:240 msgid "" "Mailbox(es) this alias will point to. Indicate only one address per input, " "press ENTER to add a new input." @@ -339,111 +348,110 @@ msgstr "" "Mailboxen auf die der Alias verweist. Geben Sie jeweils nur eine Adresse ein " "und bestätigen Sie mit ENTER." -#: admin/forms.py:246 admin/forms.py:504 admin/forms.py:530 -#: admin/models.py:1147 +#: admin/forms.py:278 admin/forms.py:542 admin/forms.py:568 msgid "Domain does not exist" msgstr "Domain existiert nicht" -#: admin/forms.py:248 +#: admin/forms.py:280 msgid "You don't have access to this domain" msgstr "Der Zugriff auf diese Domain ist ihnen nicht gestattet" -#: admin/forms.py:268 +#: admin/forms.py:300 msgid "Invalid mailbox" msgstr "Ungültige Mailbox" -#: admin/forms.py:284 +#: admin/forms.py:316 admin/models.py:1202 #, python-format msgid "Local recipient %s not found" msgstr "Lokaler Empfänger %s nicht gefunden" -#: admin/forms.py:286 admin/forms.py:292 +#: admin/forms.py:318 admin/forms.py:324 #, python-format msgid "Recipient %s already present" msgstr "Empfänger %s existiert bereits" -#: admin/forms.py:297 +#: admin/forms.py:329 msgid "No recipient defined" msgstr "Keine Empfänger angegeben" -#: admin/forms.py:311 extensions/webmail/forms.py:19 +#: admin/forms.py:343 extensions/webmail/forms.py:19 msgid "Select a file" msgstr "Wählen Sie eine Datei" -#: admin/forms.py:313 admin/forms.py:341 +#: admin/forms.py:345 admin/forms.py:373 msgid "Separator" msgstr "Separator" -#: admin/forms.py:316 +#: admin/forms.py:348 msgid "Continue on error" msgstr "Bei Fehler fortfahren" -#: admin/forms.py:317 +#: admin/forms.py:349 msgid "Don't treat duplicated objects as error" msgstr "Doppelte Objekte nicht als Fehler behandeln" -#: admin/forms.py:332 +#: admin/forms.py:364 msgid "Crypt passwords" msgstr "Passworte verschlüsseln" -#: admin/forms.py:333 +#: admin/forms.py:365 msgid "Check this option if passwords contained in your file are not crypted" msgstr "Auswählen wenn Kennwörter in Datei nicht verschlüsselt sind" -#: admin/forms.py:339 +#: admin/forms.py:371 msgid "File name" msgstr "Dateiname" -#: admin/forms.py:371 admin/templates/admin/editdomainform.html:13 +#: admin/forms.py:403 admin/templates/admin/editdomainform.html:13 #: auth/forms.py:7 msgid "Username" msgstr "Benutzername" -#: admin/forms.py:373 +#: admin/forms.py:405 msgid "Role" msgstr "Rolle" -#: admin/forms.py:374 admin/forms.py:401 +#: admin/forms.py:406 admin/forms.py:433 msgid "Choose" msgstr "Auswählen" -#: admin/forms.py:375 +#: admin/forms.py:407 msgid "What level of permission this user will have" msgstr "Rechte, die der Benutzer haben wird" -#: admin/forms.py:377 auth/forms.py:11 +#: admin/forms.py:409 auth/forms.py:11 msgid "Password" msgstr "Passwort" -#: admin/forms.py:379 userprefs/forms.py:18 +#: admin/forms.py:411 userprefs/forms.py:18 msgid "Confirmation" msgstr "Bestätigung" -#: admin/forms.py:381 +#: admin/forms.py:413 msgid "Enter the same password as above, for verification." msgstr "Kennwort bestätigen" -#: admin/forms.py:392 +#: admin/forms.py:424 msgid "Enabled" msgstr "Aktiviert" -#: admin/forms.py:434 +#: admin/forms.py:471 msgid "The two password fields didn't match." msgstr "Die angegebenen Kennworte stimmen nicht überein" -#: admin/forms.py:440 +#: admin/forms.py:477 msgid "You can't disable your own account" msgstr "Sie können Ihr eigenes Konto nicht deaktivieren" -#: admin/forms.py:450 +#: admin/forms.py:488 msgid "E-mail" msgstr "E-Mail" -#: admin/forms.py:452 +#: admin/forms.py:490 msgid "Quota" msgstr "Quota" -#: admin/forms.py:454 +#: admin/forms.py:492 msgid "" "Quota in MB for this mailbox. Define a custom value or use domain's default " "one. Leave empty to define an unlimited value (not allowed for domain " @@ -453,7 +461,7 @@ msgstr "" "Sie den Standardwert der Domain. Lassen Sie das Feld leer für unbegrenztes " "Quota - Domänen-Administratoren ist dies nicht gestattet." -#: admin/forms.py:461 +#: admin/forms.py:499 msgid "" "Alias(es) of this mailbox. Indicate only one address per input, press ENTER " "to add a new input. Use the '*' character to create a 'catchall' alias (ex: " @@ -463,132 +471,132 @@ msgstr "" "an. Bestätigen Sie mit ENTER um die Eingabe zu bestätigen. Geben Sie '*' an, " "um einen 'catchall'-Alias (Bsp: *@example.com) zu erstellen." -#: admin/forms.py:512 +#: admin/forms.py:550 #, python-format msgid "Mailbox %s already exists" msgstr "Mailbox %s existiert bereits" -#: admin/forms.py:572 +#: admin/forms.py:610 msgid "Domain(s)" msgstr "Domain(s)" -#: admin/forms.py:574 +#: admin/forms.py:612 msgid "Domain(s) that user administrates" msgstr "Domänen, die dieser Anwender administriert" -#: admin/forms.py:616 admin/views.py:444 +#: admin/forms.py:654 admin/views.py:450 msgid "Mail" msgstr "E-Mail" -#: admin/forms.py:618 +#: admin/forms.py:656 msgid "Permissions" msgstr "Berechtigungen" -#: admin/models.py:78 +#: admin/models.py:80 msgid "You can't delete your own account" msgstr "Sie können Ihr eigenes Konto nicht entfernen" -#: admin/models.py:159 +#: admin/models.py:161 msgid "Failed to update password: LDAP module not installed" msgstr "Konnte Kennwort nicht aktualisieren: LDAP-Modul nicht installiert" -#: admin/models.py:165 +#: admin/models.py:167 #, python-format msgid "Failed to update password: %s" msgstr "Konnte Kennwort nicht aktualisieren: %s" -#: admin/models.py:192 +#: admin/models.py:194 msgid "account" msgstr "Konto" -#: admin/models.py:494 admin/models.py:720 admin/models.py:782 +#: admin/models.py:496 admin/models.py:733 admin/models.py:795 msgid "Invalid line" msgstr "Ungültige Zeile" -#: admin/models.py:498 +#: admin/models.py:500 msgid "You can't import an account with a role greater than yours" msgstr "Sie können kein Konto einer höheren Rolle importieren" -#: admin/models.py:518 +#: admin/models.py:506 +#, python-format +msgid "The simple user '%s' must have a valid email address" +msgstr "" + +#: admin/models.py:510 +#, python-format +msgid "username and email fields must not differ for '%s'" +msgstr "" + +#: admin/models.py:534 #, python-format msgid "Account import failed (%s): domain does not exist" msgstr "Kann Konto nicht importieren (%s): Die Domain existiert nicht" -#: admin/models.py:607 admin/models.py:733 +#: admin/models.py:624 admin/models.py:746 msgid "name" msgstr "Name" -#: admin/models.py:608 +#: admin/models.py:625 msgid "The domain name" msgstr "Name der Domäne" -#: admin/models.py:610 +#: admin/models.py:627 msgid "Default quota in MB applied to mailboxes" msgstr "Standard-Quota für Mailboxen (in MB)" -#: admin/models.py:613 admin/models.py:740 admin/models.py:1020 -#: admin/models.py:1181 extensions/postfix_autoreply/models.py:19 +#: admin/models.py:630 admin/models.py:753 admin/models.py:1045 +#: admin/models.py:1217 extensions/postfix_autoreply/models.py:27 msgid "enabled" msgstr "aktiviert" -#: admin/models.py:614 +#: admin/models.py:631 msgid "Check to activate this domain" msgstr "Auswählen, um diese Domäne zu aktivieren" -#: admin/models.py:734 +#: admin/models.py:747 msgid "The alias name" msgstr "Der Alias-Name" -#: admin/models.py:736 +#: admin/models.py:749 msgid "target" msgstr "Ziel" -#: admin/models.py:737 +#: admin/models.py:750 msgid "The domain this alias points to" msgstr "Domäne auf die dieser Alias verweist" -#: admin/models.py:741 admin/models.py:1021 +#: admin/models.py:754 admin/models.py:1046 msgid "Check to activate this alias" msgstr "Auswählen um den Alias zu aktivieren" -#: admin/models.py:788 +#: admin/models.py:801 #, python-format msgid "Unknown domain %s" msgstr "Unbekannte Domain %s" -#: admin/models.py:805 admin/models.py:1006 +#: admin/models.py:818 admin/models.py:1031 msgid "address" msgstr "Adresse" -#: admin/models.py:806 +#: admin/models.py:819 msgid "Mailbox address (without the @domain.tld part)" msgstr "Mailbox-Adresse (ohne den @domain.tld-Anteil)" -#: admin/models.py:852 +#: admin/models.py:877 #, python-format msgid "Failed to retrieve mailbox location (%s)" msgstr "Konnte Speicherort der Mailbox (%s) nicht bestimmen" -#: admin/models.py:868 -#, python-format -msgid "Failed to rename mailbox: %s" -msgstr "Mailbox konnte nicht umbenannt werden: %s" - -#: admin/models.py:894 -#, python-format -msgid "Failed to remove mailbox: %s" -msgstr "Konnte Mailbox nicht entfernen: %s" - -#: admin/models.py:909 +#: admin/models.py:921 #, python-format msgid "Quota is greater than the allowed domain's limit (%dM)" msgstr "Das Quota ist größer als das maximale Quota der Domain (%dM)" -#: admin/models.py:914 +#: admin/models.py:926 msgid "A quota is required" msgstr "Ein Quota ist erforderlich" -#: admin/models.py:1007 +#: admin/models.py:1032 msgid "" "The alias address (without the domain part). For a 'catch-all' address, just " "enter an * character." @@ -596,57 +604,57 @@ msgstr "" "Die Alias-Adresse (ohne den Domain-Anteil). Geben sie für eine Adresse an, " "die alles annimmt, * an." -#: admin/models.py:1011 +#: admin/models.py:1036 msgid "mailboxes" msgstr "Mailboxen" -#: admin/models.py:1012 +#: admin/models.py:1037 msgid "The mailboxes this alias points to" msgstr "Mailbox auf den dieser Alias verweist" -#: admin/models.py:1016 +#: admin/models.py:1041 msgid "The aliases this alias points to" msgstr "Aliase auf die dieser Alias verweist" -#: admin/models.py:1064 +#: admin/models.py:1089 msgid "distribution list" msgstr "Verteilerliste" -#: admin/models.py:1065 +#: admin/models.py:1090 msgid "forward" msgstr "Weiterleitung" -#: admin/models.py:1066 +#: admin/models.py:1091 msgid "alias" msgstr "Alias" -#: admin/models.py:1142 +#: admin/models.py:1170 #, python-format msgid "Invalid line: %s" msgstr "Ungültige Zeile: %s" -#: admin/models.py:1167 -#, python-format -msgid "Mailbox %s does not exist" -msgstr "Mailbox %s existiert nicht" +#: admin/models.py:1175 +#, fuzzy, python-format +msgid "Domain '%s' does not exist" +msgstr "Domain existiert nicht" -#: admin/models.py:1182 +#: admin/models.py:1218 msgid "Check to enable this extension" msgstr "Auswählen, um diese Erweiterung zu aktivieren" -#: admin/models.py:1282 +#: admin/models.py:1318 msgid "added" msgstr "hinzugefügt" -#: admin/models.py:1285 +#: admin/models.py:1321 msgid "modified" msgstr "verändert" -#: admin/models.py:1288 +#: admin/models.py:1324 msgid "deleted" msgstr "entfernt" -#: admin/models.py:1290 +#: admin/models.py:1326 #, python-format msgid "%(object)s '%(name)s' %(action)s by user %(user)s" msgstr "%(object)s '%(name)s' %(action)s der Identität %(user)s" @@ -656,7 +664,7 @@ msgid "Edit domain" msgstr "Domäne bearbeiten" #: admin/tables.py:21 admin/templates/admin/identities_table.html:8 -#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:79 +#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:83 #: extensions/sievefilters/templates/sievefilters/filter.html:17 #: extensions/sievefilters/templates/sievefilters/guieditor.html:5 #: extensions/webmail/templatetags/webextras.py:97 @@ -671,143 +679,143 @@ msgstr "Version" msgid "Description" msgstr "Beschreibung" -#: admin/views.py:87 +#: admin/views.py:88 msgid "New domain" msgstr "Neue Domäne" -#: admin/views.py:88 admin/views.py:97 admin/views.py:225 admin/views.py:438 -#: admin/views.py:445 extensions/sievefilters/views.py:120 -#: extensions/sievefilters/views.py:187 extensions/webmail/views.py:131 +#: admin/views.py:89 admin/views.py:98 admin/views.py:228 admin/views.py:444 +#: admin/views.py:451 extensions/sievefilters/views.py:129 +#: extensions/sievefilters/views.py:198 extensions/webmail/views.py:136 msgid "Create" msgstr "Erstellen" -#: admin/views.py:94 admin/views.py:442 +#: admin/views.py:95 admin/views.py:448 msgid "Next" msgstr "Nächstes" -#: admin/views.py:96 +#: admin/views.py:97 msgid "Options" msgstr "optionen" -#: admin/views.py:98 admin/views.py:446 +#: admin/views.py:99 admin/views.py:452 msgid "Previous" msgstr "Vorheriges" -#: admin/views.py:111 +#: admin/views.py:112 msgid "Domain created" msgstr "Domäne erstellt." -#: admin/views.py:144 admin/views.py:282 admin/views.py:492 +#: admin/views.py:146 admin/views.py:285 admin/views.py:498 #: extensions/postfix_autoreply/templates/postfix_autoreply/autoreply.html:9 -#: extensions/sievefilters/views.py:139 extensions/webmail/views.py:162 +#: extensions/sievefilters/views.py:148 extensions/webmail/views.py:168 #: userprefs/templates/userprefs/forward.html:8 #: userprefs/templates/userprefs/profile.html:8 msgid "Update" msgstr "Aktualisieren" -#: admin/views.py:160 +#: admin/views.py:162 msgid "Domain modified" msgstr "Domäne verändert" -#: admin/views.py:186 +#: admin/views.py:189 msgid "You can't delete your own domain" msgstr "Sie können Ihre eigene Domäne nicht löschen" -#: admin/views.py:189 +#: admin/views.py:192 msgid "Domain deleted" msgid_plural "Domains deleted" msgstr[0] "Domäne gelöscht" msgstr[1] "Domänen gelöscht" -#: admin/views.py:204 +#: admin/views.py:207 msgid "Alias with this name already exists" msgstr "Ein Alias mit diesem Namen existiert bereits" -#: admin/views.py:247 +#: admin/views.py:250 msgid "New distribution list" msgstr "Neue Verteilerliste" -#: admin/views.py:248 +#: admin/views.py:251 msgid "Distribution list created" msgstr "Verteilerliste erstellt" -#: admin/views.py:257 +#: admin/views.py:260 msgid "New alias" msgstr "Neuer Alias" -#: admin/views.py:258 +#: admin/views.py:261 msgid "Alias created" msgstr "Alias erstellt" -#: admin/views.py:267 +#: admin/views.py:270 msgid "New forward" msgstr "Neue Weiterleitung" -#: admin/views.py:268 +#: admin/views.py:271 msgid "Forward created" msgstr "Weiterleitung erstellt" -#: admin/views.py:286 +#: admin/views.py:289 msgid "Distribution list modified" msgstr "Verteilerliste verändert" -#: admin/views.py:288 +#: admin/views.py:291 msgid "Forward modified" msgstr "Weiterleitung verändert" -#: admin/views.py:290 +#: admin/views.py:293 msgid "Alias modified" msgstr "Alias verändert" -#: admin/views.py:403 admin/views.py:541 admin/views.py:546 -#: extensions/amavis/views.py:195 extensions/amavis/views.py:201 -#: extensions/amavis/views.py:234 extensions/amavis/views.py:238 -#: extensions/amavis/views.py:240 extensions/webmail/views.py:36 -#: extensions/webmail/views.py:64 extensions/webmail/views.py:77 -#: extensions/webmail/views.py:93 extensions/webmail/views.py:109 -#: extensions/webmail/views.py:193 extensions/webmail/views.py:419 -#: extensions/webmail/views.py:430 extensions/webmail/views.py:457 +#: admin/views.py:402 admin/views.py:545 admin/views.py:550 +#: extensions/amavis/views.py:204 extensions/amavis/views.py:210 +#: extensions/amavis/views.py:243 extensions/amavis/views.py:247 +#: extensions/amavis/views.py:249 extensions/webmail/views.py:41 +#: extensions/webmail/views.py:68 extensions/webmail/views.py:81 +#: extensions/webmail/views.py:98 extensions/webmail/views.py:114 +#: extensions/webmail/views.py:200 extensions/webmail/views.py:427 +#: extensions/webmail/views.py:438 extensions/webmail/views.py:465 #: lib/formutils.py:32 lib/formutils.py:37 msgid "Invalid request" msgstr "Ungültige Anfrage" -#: admin/views.py:435 +#: admin/views.py:441 msgid "New account" msgstr "Neues Konto" -#: admin/views.py:459 +#: admin/views.py:465 msgid "Account created" msgstr "Konto erstellt" -#: admin/views.py:507 +#: admin/views.py:513 msgid "Account updated" msgstr "Konto aktualisiert" -#: admin/views.py:531 +#: admin/views.py:535 msgid "Account deleted" msgid_plural "Accounts deleted" msgstr[0] "Konto gelöscht" msgstr[1] "Konten gelöscht" -#: admin/views.py:586 +#: admin/views.py:590 msgid "Parameters saved" msgstr "Parameter gespeichert" -#: admin/views.py:632 +#: admin/views.py:636 msgid "Modifications applied." msgstr "Änderungen übernommen." -#: admin/views.py:740 +#: admin/views.py:743 #, python-format msgid "Object already exists: %s" msgstr "Objekt existiert bereits: %s" -#: admin/views.py:742 +#: admin/views.py:745 #, python-format msgid "%d objects imported successfully" msgstr "%d Objekte erfolgreich importiert" -#: admin/views.py:760 +#: admin/views.py:763 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
      \n" @@ -835,25 +843,25 @@ msgstr "" "\n" "

      Ein anderes Zeichen als Separator ist gestattet.

      \n" -#: admin/views.py:772 +#: admin/views.py:775 msgid "Import identities" msgstr "Identitäten importieren" -#: admin/views.py:773 admin/views.py:843 admin/templatetags/admin_extras.py:87 +#: admin/views.py:776 admin/views.py:846 admin/templatetags/admin_extras.py:87 #: admin/templatetags/admin_extras.py:144 msgid "Import" msgstr "Importiere" -#: admin/views.py:803 +#: admin/views.py:806 msgid "Export identities" msgstr "Identitäten exportieren" -#: admin/views.py:804 admin/views.py:860 admin/templatetags/admin_extras.py:93 +#: admin/views.py:807 admin/views.py:863 admin/templatetags/admin_extras.py:93 #: admin/templatetags/admin_extras.py:150 msgid "Export" msgstr "Exportiere" -#: admin/views.py:832 +#: admin/views.py:835 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
        \n" @@ -873,11 +881,11 @@ msgstr "" "vorhergehenden sein.

        \n" "

        Ein anderes Zeichen als Trenner ist gestattet.

        \n" -#: admin/views.py:842 +#: admin/views.py:845 msgid "Import domains" msgstr "Domains importieren" -#: admin/views.py:859 +#: admin/views.py:862 msgid "Export domains" msgstr "Domains exportieren" @@ -950,7 +958,7 @@ msgid "Tags" msgstr "Tags" #: admin/templates/admin/importform.html:5 -#: admin/templatetags/admin_extras.py:305 +#: admin/templatetags/admin_extras.py:290 msgid "Help" msgstr "Hilfe" @@ -997,7 +1005,7 @@ msgid "Previously on Modoboa..." msgstr "Vorher auf Modoboa…" #: admin/templates/admin/logs.html:6 extensions/amavis/sql_listing.py:25 -#: extensions/webmail/lib.py:37 extensions/webmail/lib.py:406 +#: extensions/webmail/lib.py:38 extensions/webmail/lib.py:411 msgid "Date" msgstr "Datum" @@ -1100,34 +1108,21 @@ msgid "View the domain's identities" msgstr "Domain-Identitäten anzeigen" #: admin/templatetags/admin_extras.py:178 -msgid "Delete the domain" -msgstr "Domain entfernen" - #: admin/templatetags/admin_extras.py:194 -msgid "Delete this account" -msgstr "Dieses Konto löschen" +#: admin/templatetags/admin_extras.py:201 +#, fuzzy, python-format +msgid "Delete %s?" +msgstr "Löschen" -#: admin/templatetags/admin_extras.py:202 -msgid "Delete this distribution list" -msgstr "Diese Verteilerliste löschen" - -#: admin/templatetags/admin_extras.py:209 -msgid "Delete this forward" -msgstr "Weiterleitung entfernen" - -#: admin/templatetags/admin_extras.py:216 -msgid "Delete this alias" -msgstr " Alias entfernen" - -#: admin/templatetags/admin_extras.py:238 +#: admin/templatetags/admin_extras.py:223 msgid "Remove this permission" msgstr "Berechtigung entfernen" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "Yes" msgstr "Ja" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "No" msgstr "Nein" @@ -1136,13 +1131,13 @@ msgstr "Nein" msgid "User '%s' successfully logged in" msgstr "Identität '%s' hat sich erfolgreich angemeldet" -#: auth/views.py:41 +#: auth/views.py:44 msgid "Your username and password didn't match. Please try again." msgstr "" "Ihr Benutzername und Passwort stimmen nicht überein. Bitte versuchen Sie es " "noch einmal." -#: auth/views.py:64 +#: auth/views.py:67 #, python-format msgid "User '%s' logged out" msgstr "Identität '%s' hat sich abgemeldet" @@ -1202,16 +1197,16 @@ msgstr "Einfache amavis Management Oberfläche" msgid "Quarantine" msgstr "Quarantäne" -#: extensions/amavis/__init__.py:127 +#: extensions/amavis/__init__.py:129 msgid "pending requests" msgstr "Offene Anfragen" -#: extensions/amavis/__init__.py:144 +#: extensions/amavis/__init__.py:149 #, python-format msgid "%d pending requests" msgstr "%d offene Anfragen" -#: extensions/amavis/__init__.py:156 +#: extensions/amavis/__init__.py:161 msgid "Content filter" msgstr "Inhaltsfilter" @@ -1331,12 +1326,12 @@ msgid "Virus filter" msgstr "Virusfilter" #: extensions/amavis/models.py:94 extensions/amavis/models.py:102 -#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:268 +#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:281 msgid "yes" msgstr "Ja" #: extensions/amavis/models.py:95 extensions/amavis/models.py:103 -#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:272 +#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:285 msgid "no" msgstr "Nein" @@ -1384,13 +1379,13 @@ msgstr "" "Betreff:-Zeile einer Spam-Nachricht mit dem angegebenen Text ergänzen. " "Wählen Sie 'Standard' für den systemweiten Standard." -#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:36 +#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:37 msgid "From" msgstr "Von" #: extensions/amavis/sql_listing.py:24 extensions/sievefilters/forms.py:68 -#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:35 -#: extensions/webmail/lib.py:404 templates/common/email_searchbar.html:6 +#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:36 +#: extensions/webmail/lib.py:409 templates/common/email_searchbar.html:6 msgid "Subject" msgstr "Betreff" @@ -1400,37 +1395,37 @@ msgstr "Betreff" msgid "To" msgstr "An" -#: extensions/amavis/views.py:34 +#: extensions/amavis/views.py:43 msgid "Empty quarantine" msgstr "Quarantäne leeren" -#: extensions/amavis/views.py:202 +#: extensions/amavis/views.py:211 msgid "Message deleted" msgstr "Nachricht gelöscht" -#: extensions/amavis/views.py:223 +#: extensions/amavis/views.py:232 #, python-format msgid "%(count)d message deleted successfully" msgid_plural "%(count)d messages deleted successfully" msgstr[0] "%(count)d Nachricht erfolgreich gelöscht" msgstr[1] "%(count)d Nachrichten erfolgreich gelöscht" -#: extensions/amavis/views.py:243 +#: extensions/amavis/views.py:252 msgid "Request sent" msgstr "Anfrage gesendet" -#: extensions/amavis/views.py:249 +#: extensions/amavis/views.py:258 msgid "Message released" msgstr "Nachricht freigegeben" -#: extensions/amavis/views.py:271 +#: extensions/amavis/views.py:280 #, python-format msgid "%(count)d request sent" msgid_plural "%(count)d requests sent" msgstr[0] "%(count)d Anfrage gesendet" msgstr[1] "%(count)d Anfragen gesendet" -#: extensions/amavis/views.py:295 +#: extensions/amavis/views.py:304 #, python-format msgid "%(count)d message released successfully" msgid_plural "%(count)d messages released successfully" @@ -1557,7 +1552,7 @@ msgstr "Grenzwerte" msgid "Reseller" msgstr "Reseller" -#: extensions/limits/__init__.py:96 +#: extensions/limits/__init__.py:94 msgid "Resources" msgstr "Ressourcen" @@ -1683,23 +1678,23 @@ msgstr "Aktivieren Sie ihre automatisierte Antwort bis zu diesem Datum" msgid "This date is over" msgstr "Das Datum ist vorbei" -#: extensions/postfix_autoreply/models.py:15 +#: extensions/postfix_autoreply/models.py:19 msgid "subject" msgstr "Betreff" -#: extensions/postfix_autoreply/models.py:16 +#: extensions/postfix_autoreply/models.py:20 msgid "The subject that will appear in sent emails" msgstr "Der Betreff, der in den versendeten Nachrichten verwendet wird" -#: extensions/postfix_autoreply/models.py:17 +#: extensions/postfix_autoreply/models.py:23 msgid "content" msgstr "Inhalt" -#: extensions/postfix_autoreply/models.py:18 +#: extensions/postfix_autoreply/models.py:24 msgid "The content that will appear in sent emails" msgstr "Der Inhalt, der in den versendeten Nachrichten verwendet wird" -#: extensions/postfix_autoreply/models.py:20 +#: extensions/postfix_autoreply/models.py:28 msgid "Activate/Deactivate your auto reply" msgstr "Aktivieren/Deaktivieren Sie die automatisierte Antwort" @@ -1837,53 +1832,53 @@ msgstr "" msgid "Not enough space on server" msgstr "Kein weiterer Platz auf Server verfügbar" -#: extensions/sievefilters/views.py:64 +#: extensions/sievefilters/views.py:68 msgid "Failed to retrieve filters set" msgstr "Konnte Filter-Satz nicht laden" -#: extensions/sievefilters/views.py:117 +#: extensions/sievefilters/views.py:126 #: extensions/sievefilters/templatetags/sfilters_tags.py:33 msgid "New filter" msgstr "Neuer Filter" -#: extensions/sievefilters/views.py:124 +#: extensions/sievefilters/views.py:133 msgid "Filter created" msgstr "Filter erstellt" -#: extensions/sievefilters/views.py:136 +#: extensions/sievefilters/views.py:145 #: extensions/sievefilters/templatetags/sfilters_tags.py:77 msgid "Edit filter" msgstr "Filter bearbeiten" -#: extensions/sievefilters/views.py:145 +#: extensions/sievefilters/views.py:154 msgid "Filter modified" msgstr "Filter verändert" -#: extensions/sievefilters/views.py:165 +#: extensions/sievefilters/views.py:176 msgid "Filter removed" msgstr "Filter entfernt" -#: extensions/sievefilters/views.py:166 +#: extensions/sievefilters/views.py:177 msgid "Failed to remove filter" msgstr "Konnte Filter nicht entfernen" -#: extensions/sievefilters/views.py:180 +#: extensions/sievefilters/views.py:191 msgid "Filters set saved" msgstr "Filter-Satz gespeichert" -#: extensions/sievefilters/views.py:185 +#: extensions/sievefilters/views.py:196 msgid "Create a new filters set" msgstr "Neuen Filter-Satz erstellen" -#: extensions/sievefilters/views.py:208 +#: extensions/sievefilters/views.py:219 msgid "Filters set created" msgstr "Filter erstellt" -#: extensions/sievefilters/views.py:229 +#: extensions/sievefilters/views.py:240 msgid "Filters set deleted" msgstr "Filter entfernt" -#: extensions/sievefilters/views.py:241 +#: extensions/sievefilters/views.py:252 msgid "Filters set activated" msgstr "Filter-Satz aktiviert" @@ -1899,15 +1894,15 @@ msgstr "Aktiv" msgid "No filter defined yet" msgstr "Noch keine Filter definiert" -#: extensions/sievefilters/templates/sievefilters/index.html:55 +#: extensions/sievefilters/templates/sievefilters/index.html:56 msgid "Filter sets" msgstr "Filter-Sätze" -#: extensions/sievefilters/templates/sievefilters/index.html:59 +#: extensions/sievefilters/templates/sievefilters/index.html:60 msgid "active" msgstr "aktiv" -#: extensions/sievefilters/templates/sievefilters/index.html:73 +#: extensions/sievefilters/templates/sievefilters/index.html:74 msgid "" "No filters set defined yet. You must create one in order to define filters." msgstr "" @@ -2226,84 +2221,89 @@ msgstr "Server-Antwort" msgid "Cci" msgstr "Cci" -#: extensions/webmail/imaputils.py:259 +#: extensions/webmail/imaputils.py:237 +#, fuzzy +msgid "Failed to retrieve hierarchy delimiter" +msgstr "Konnte Filter-Satz nicht laden" + +#: extensions/webmail/imaputils.py:278 #, python-format msgid "Connection to IMAP server failed: %s" msgstr "Verbindung zu IMAP-Server fehlgeschlagen: %s" -#: extensions/webmail/lib.py:353 +#: extensions/webmail/lib.py:358 msgid "wrote:" msgstr "schrieb:" -#: extensions/webmail/lib.py:418 extensions/webmail/lib.py:422 +#: extensions/webmail/lib.py:423 extensions/webmail/lib.py:427 msgid "Original message" msgstr "Gesendete Nachrichten" -#: extensions/webmail/views.py:81 +#: extensions/webmail/views.py:86 #, python-format msgid "%(count)d message deleted" msgid_plural "%(count)d messages deleted" msgstr[0] "%(count)d Nachricht gelöscht" msgstr[1] "%(count)d Nachrichten gelöscht" -#: extensions/webmail/views.py:98 +#: extensions/webmail/views.py:103 msgid "Unknown action" msgstr "Unbekannte Aktion" -#: extensions/webmail/views.py:111 lib/email_listing.py:137 +#: extensions/webmail/views.py:116 lib/email_listing.py:137 msgid "Empty mailbox" msgstr "Mailbox leer" -#: extensions/webmail/views.py:128 -#: extensions/webmail/templatetags/webextras.py:169 +#: extensions/webmail/views.py:133 +#: extensions/webmail/templatetags/webextras.py:170 msgid "Create a new mailbox" msgstr "Neue Mailbox erstellen" -#: extensions/webmail/views.py:143 +#: extensions/webmail/views.py:149 msgid "Mailbox created" msgstr "Mailbox erstellt." -#: extensions/webmail/views.py:159 +#: extensions/webmail/views.py:165 msgid "Edit mailbox" msgstr "Mailbox bearbeiten" -#: extensions/webmail/views.py:173 +#: extensions/webmail/views.py:180 msgid "Mailbox updated" msgstr "Mailbox aktualisiert" -#: extensions/webmail/views.py:207 extensions/webmail/views.py:388 -#: extensions/webmail/views.py:497 +#: extensions/webmail/views.py:214 extensions/webmail/views.py:396 +#: extensions/webmail/views.py:505 msgid "Bad request" msgstr "Fehlerhafte Anfrage" -#: extensions/webmail/views.py:238 +#: extensions/webmail/views.py:246 msgid "Failed to save attachment: " msgstr "Konnte Anhang nicht speichern" -#: extensions/webmail/views.py:241 +#: extensions/webmail/views.py:249 #, python-format msgid "Attachment is too big (limit: %s)" msgstr "Anhang ist zu groß (Limit: %s)" -#: extensions/webmail/views.py:247 +#: extensions/webmail/views.py:255 #: extensions/webmail/templates/webmail/compose.html:15 #: extensions/webmail/templates/webmail/headers.html:4 msgid "Attachments" msgstr "Dateianhänge" -#: extensions/webmail/views.py:263 +#: extensions/webmail/views.py:271 msgid "Bad query" msgstr "Fehlerhafte Anfrage" -#: extensions/webmail/views.py:273 +#: extensions/webmail/views.py:281 msgid "Failed to remove attachment: " msgstr "Konnte Anhang nicht entfernen:" -#: extensions/webmail/views.py:278 +#: extensions/webmail/views.py:286 msgid "Unknown attachment" msgstr "Unbekannter Anhang" -#: extensions/webmail/views.py:493 +#: extensions/webmail/views.py:501 msgid "Undefined action" msgstr "Undefinierte Aktion" @@ -2334,7 +2334,7 @@ msgstr[1] "%(counter)s Dateien" msgid "Parent mailbox" msgstr "Eltern-Mailbox" -#: extensions/webmail/templates/webmail/index.html:36 +#: extensions/webmail/templates/webmail/index.html:38 msgid "Mailbox quota" msgstr "Mailbox Quota" @@ -2396,15 +2396,15 @@ msgstr "Als ungelesen" msgid "Compress folder" msgstr "Ordner komprimieren" -#: extensions/webmail/templatetags/webextras.py:109 +#: extensions/webmail/templatetags/webextras.py:110 msgid "Empty folder" msgstr "Leerer Ordner" -#: extensions/webmail/templatetags/webextras.py:177 +#: extensions/webmail/templatetags/webextras.py:178 msgid "Edit the selected mailbox" msgstr "Ausgewählte Mailbox bearbeiten" -#: extensions/webmail/templatetags/webextras.py:182 +#: extensions/webmail/templatetags/webextras.py:183 msgid "Remove the selected mailbox" msgstr "Markierte Mailbox entfernen" @@ -2458,7 +2458,7 @@ msgstr "Die angeforderte Seite existiert nicht" msgid "An internal error occured." msgstr "Ein interne Fehler ist aufgetreten" -#: templates/nlayout.html:56 +#: templates/nlayout.html:62 msgid "Powered by Modoboa" msgstr "Powered by Modoboa" @@ -2492,11 +2492,11 @@ msgstr "Schliessen" msgid "Welcome to Modoboa" msgstr "Willkommen zu Modoboa" -#: templates/registration/login.html:33 +#: templates/registration/login.html:34 msgid "Remember me" msgstr "Erinnere mich" -#: templates/registration/login.html:35 +#: templates/registration/login.html:36 msgid "Log in" msgstr "Anmelden" @@ -2512,7 +2512,7 @@ msgstr "Anwenderspezifische Einstellungen" msgid "Prefered language" msgstr "Bevorzugte Sprache" -#: userprefs/app_settings.py:26 +#: userprefs/app_settings.py:27 msgid "Prefered language to display pages" msgstr "Bevorzugte Sprache für Seitendarstellung" @@ -2603,6 +2603,30 @@ msgstr "Aktualisieren sie ihre persönlichen Daten" msgid "Logout" msgstr "Logout" +#~ msgid "Failed to rename mailbox: %s" +#~ msgstr "Mailbox konnte nicht umbenannt werden: %s" + +#~ msgid "Failed to remove mailbox: %s" +#~ msgstr "Konnte Mailbox nicht entfernen: %s" + +#~ msgid "Mailbox %s does not exist" +#~ msgstr "Mailbox %s existiert nicht" + +#~ msgid "Delete the domain" +#~ msgstr "Domain entfernen" + +#~ msgid "Delete this account" +#~ msgstr "Dieses Konto löschen" + +#~ msgid "Delete this distribution list" +#~ msgstr "Diese Verteilerliste löschen" + +#~ msgid "Delete this forward" +#~ msgstr "Weiterleitung entfernen" + +#~ msgid "Delete this alias" +#~ msgstr " Alias entfernen" + #~ msgid "Path to the root directory where messages are stored" #~ msgstr "Pfad zum root-Verzeichnis unterhalb dessen E-Mails abgelegt werden" diff --git a/modoboa/locale/en/LC_MESSAGES/django.po b/modoboa/locale/en/LC_MESSAGES/django.po index 1fb68f940..30fda01ce 100644 --- a/modoboa/locale/en/LC_MESSAGES/django.po +++ b/modoboa/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-06-01 16:35+0200\n" +"POT-Creation-Date: 2013-09-20 22:30+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -25,8 +25,8 @@ msgstr "" msgid "Web based console to manage domains, accounts and aliases" msgstr "" -#: admin/__init__.py:16 admin/forms.py:179 admin/forms.py:614 -#: admin/views.py:93 admin/views.py:441 +#: admin/__init__.py:16 admin/forms.py:211 admin/forms.py:652 +#: admin/views.py:94 admin/views.py:447 #: extensions/postfix_autoreply/app_settings.py:11 #: extensions/sievefilters/app_settings.py:50 #: extensions/stats/app_settings.py:11 extensions/webmail/app_settings.py:11 @@ -236,37 +236,45 @@ msgstr "" msgid "The default redirection used when no application is specified" msgstr "" -#: admin/app_settings.py:230 +#: admin/app_settings.py:213 +msgid "Key must be either 16, 24, or 32 bytes long" +msgstr "" + +#: admin/app_settings.py:222 +msgid "Invalid syntax" +msgstr "" + +#: admin/app_settings.py:245 msgid "This field is required" msgstr "" -#: admin/forms.py:16 admin/forms.py:459 admin/tables.py:18 +#: admin/forms.py:20 admin/forms.py:497 admin/tables.py:18 msgid "Alias(es)" msgstr "" -#: admin/forms.py:18 +#: admin/forms.py:22 msgid "" "Alias(es) of this domain. Indicate only one name per input, press ENTER to " "add a new input." msgstr "" -#: admin/forms.py:55 +#: admin/forms.py:59 msgid "An alias with this name already exists" msgstr "" -#: admin/forms.py:69 +#: admin/forms.py:73 msgid "A domain with this name already exists" msgstr "" -#: admin/forms.py:114 +#: admin/forms.py:146 msgid "Create a domain administrator" msgstr "" -#: admin/forms.py:116 +#: admin/forms.py:148 msgid "Automatically create an administrator for this domain" msgstr "" -#: admin/forms.py:120 admin/tables.py:12 admin/tables.py:47 +#: admin/forms.py:152 admin/tables.py:12 admin/tables.py:47 #: admin/templates/admin/editdomainform.html:13 #: admin/templates/admin/identities_table.html:5 #: admin/templates/admin/information.html:8 @@ -275,349 +283,348 @@ msgstr "" msgid "Name" msgstr "" -#: admin/forms.py:122 +#: admin/forms.py:154 msgid "" "The administrator's name. Don't include the domain's name here, it will be " "automatically appended." msgstr "" -#: admin/forms.py:128 +#: admin/forms.py:160 msgid "Create aliases" msgstr "" -#: admin/forms.py:130 +#: admin/forms.py:162 msgid "Automatically create standard aliases for this domain" msgstr "" -#: admin/forms.py:143 +#: admin/forms.py:175 msgid "Invalid format" msgstr "" -#: admin/forms.py:155 +#: admin/forms.py:187 #, python-format msgid "User '%s' already exists" msgstr "" -#: admin/forms.py:203 +#: admin/forms.py:235 msgid "Email address" msgstr "" -#: admin/forms.py:204 +#: admin/forms.py:236 msgid "" "The distribution list address. Use the '*' character to create a 'catchall' " "address (ex: *@domain.tld)." msgstr "" -#: admin/forms.py:207 +#: admin/forms.py:239 msgid "Recipients" msgstr "" -#: admin/forms.py:208 +#: admin/forms.py:240 msgid "" "Mailbox(es) this alias will point to. Indicate only one address per input, " "press ENTER to add a new input." msgstr "" -#: admin/forms.py:246 admin/forms.py:504 admin/forms.py:530 -#: admin/models.py:1147 +#: admin/forms.py:278 admin/forms.py:542 admin/forms.py:568 msgid "Domain does not exist" msgstr "" -#: admin/forms.py:248 +#: admin/forms.py:280 msgid "You don't have access to this domain" msgstr "" -#: admin/forms.py:268 +#: admin/forms.py:300 msgid "Invalid mailbox" msgstr "" -#: admin/forms.py:284 +#: admin/forms.py:316 admin/models.py:1202 #, python-format msgid "Local recipient %s not found" msgstr "" -#: admin/forms.py:286 admin/forms.py:292 +#: admin/forms.py:318 admin/forms.py:324 #, python-format msgid "Recipient %s already present" msgstr "" -#: admin/forms.py:297 +#: admin/forms.py:329 msgid "No recipient defined" msgstr "" -#: admin/forms.py:311 extensions/webmail/forms.py:19 +#: admin/forms.py:343 extensions/webmail/forms.py:19 msgid "Select a file" msgstr "" -#: admin/forms.py:313 admin/forms.py:341 +#: admin/forms.py:345 admin/forms.py:373 msgid "Separator" msgstr "" -#: admin/forms.py:316 +#: admin/forms.py:348 msgid "Continue on error" msgstr "" -#: admin/forms.py:317 +#: admin/forms.py:349 msgid "Don't treat duplicated objects as error" msgstr "" -#: admin/forms.py:332 +#: admin/forms.py:364 msgid "Crypt passwords" msgstr "" -#: admin/forms.py:333 +#: admin/forms.py:365 msgid "Check this option if passwords contained in your file are not crypted" msgstr "" -#: admin/forms.py:339 +#: admin/forms.py:371 msgid "File name" msgstr "" -#: admin/forms.py:371 admin/templates/admin/editdomainform.html:13 +#: admin/forms.py:403 admin/templates/admin/editdomainform.html:13 #: auth/forms.py:7 msgid "Username" msgstr "" -#: admin/forms.py:373 +#: admin/forms.py:405 msgid "Role" msgstr "" -#: admin/forms.py:374 admin/forms.py:401 +#: admin/forms.py:406 admin/forms.py:433 msgid "Choose" msgstr "" -#: admin/forms.py:375 +#: admin/forms.py:407 msgid "What level of permission this user will have" msgstr "" -#: admin/forms.py:377 auth/forms.py:11 +#: admin/forms.py:409 auth/forms.py:11 msgid "Password" msgstr "" -#: admin/forms.py:379 userprefs/forms.py:18 +#: admin/forms.py:411 userprefs/forms.py:18 msgid "Confirmation" msgstr "" -#: admin/forms.py:381 +#: admin/forms.py:413 msgid "Enter the same password as above, for verification." msgstr "" -#: admin/forms.py:392 +#: admin/forms.py:424 msgid "Enabled" msgstr "" -#: admin/forms.py:434 +#: admin/forms.py:471 msgid "The two password fields didn't match." msgstr "" -#: admin/forms.py:440 +#: admin/forms.py:477 msgid "You can't disable your own account" msgstr "" -#: admin/forms.py:450 +#: admin/forms.py:488 msgid "E-mail" msgstr "" -#: admin/forms.py:452 +#: admin/forms.py:490 msgid "Quota" msgstr "" -#: admin/forms.py:454 +#: admin/forms.py:492 msgid "" "Quota in MB for this mailbox. Define a custom value or use domain's default " "one. Leave empty to define an unlimited value (not allowed for domain " "administrators)." msgstr "" -#: admin/forms.py:461 +#: admin/forms.py:499 msgid "" "Alias(es) of this mailbox. Indicate only one address per input, press ENTER " "to add a new input. Use the '*' character to create a 'catchall' alias (ex: " "*@domain.tld)." msgstr "" -#: admin/forms.py:512 +#: admin/forms.py:550 #, python-format msgid "Mailbox %s already exists" msgstr "" -#: admin/forms.py:572 +#: admin/forms.py:610 msgid "Domain(s)" msgstr "" -#: admin/forms.py:574 +#: admin/forms.py:612 msgid "Domain(s) that user administrates" msgstr "" -#: admin/forms.py:616 admin/views.py:444 +#: admin/forms.py:654 admin/views.py:450 msgid "Mail" msgstr "" -#: admin/forms.py:618 +#: admin/forms.py:656 msgid "Permissions" msgstr "" -#: admin/models.py:78 +#: admin/models.py:80 msgid "You can't delete your own account" msgstr "" -#: admin/models.py:159 +#: admin/models.py:161 msgid "Failed to update password: LDAP module not installed" msgstr "" -#: admin/models.py:165 +#: admin/models.py:167 #, python-format msgid "Failed to update password: %s" msgstr "" -#: admin/models.py:192 +#: admin/models.py:194 msgid "account" msgstr "" -#: admin/models.py:494 admin/models.py:720 admin/models.py:782 +#: admin/models.py:496 admin/models.py:733 admin/models.py:795 msgid "Invalid line" msgstr "" -#: admin/models.py:498 +#: admin/models.py:500 msgid "You can't import an account with a role greater than yours" msgstr "" -#: admin/models.py:518 +#: admin/models.py:506 +#, python-format +msgid "The simple user '%s' must have a valid email address" +msgstr "" + +#: admin/models.py:510 +#, python-format +msgid "username and email fields must not differ for '%s'" +msgstr "" + +#: admin/models.py:534 #, python-format msgid "Account import failed (%s): domain does not exist" msgstr "" -#: admin/models.py:607 admin/models.py:733 +#: admin/models.py:624 admin/models.py:746 msgid "name" msgstr "" -#: admin/models.py:608 +#: admin/models.py:625 msgid "The domain name" msgstr "" -#: admin/models.py:610 +#: admin/models.py:627 msgid "Default quota in MB applied to mailboxes" msgstr "" -#: admin/models.py:613 admin/models.py:740 admin/models.py:1020 -#: admin/models.py:1181 extensions/postfix_autoreply/models.py:19 +#: admin/models.py:630 admin/models.py:753 admin/models.py:1045 +#: admin/models.py:1217 extensions/postfix_autoreply/models.py:27 msgid "enabled" msgstr "" -#: admin/models.py:614 +#: admin/models.py:631 msgid "Check to activate this domain" msgstr "" -#: admin/models.py:734 +#: admin/models.py:747 msgid "The alias name" msgstr "" -#: admin/models.py:736 +#: admin/models.py:749 msgid "target" msgstr "" -#: admin/models.py:737 +#: admin/models.py:750 msgid "The domain this alias points to" msgstr "" -#: admin/models.py:741 admin/models.py:1021 +#: admin/models.py:754 admin/models.py:1046 msgid "Check to activate this alias" msgstr "" -#: admin/models.py:788 +#: admin/models.py:801 #, python-format msgid "Unknown domain %s" msgstr "" -#: admin/models.py:805 admin/models.py:1006 +#: admin/models.py:818 admin/models.py:1031 msgid "address" msgstr "" -#: admin/models.py:806 +#: admin/models.py:819 msgid "Mailbox address (without the @domain.tld part)" msgstr "" -#: admin/models.py:852 +#: admin/models.py:877 #, python-format msgid "Failed to retrieve mailbox location (%s)" msgstr "" -#: admin/models.py:868 -#, python-format -msgid "Failed to rename mailbox: %s" -msgstr "" - -#: admin/models.py:894 -#, python-format -msgid "Failed to remove mailbox: %s" -msgstr "" - -#: admin/models.py:909 +#: admin/models.py:921 #, python-format msgid "Quota is greater than the allowed domain's limit (%dM)" msgstr "" -#: admin/models.py:914 +#: admin/models.py:926 msgid "A quota is required" msgstr "" -#: admin/models.py:1007 +#: admin/models.py:1032 msgid "" "The alias address (without the domain part). For a 'catch-all' address, just " "enter an * character." msgstr "" -#: admin/models.py:1011 +#: admin/models.py:1036 msgid "mailboxes" msgstr "" -#: admin/models.py:1012 +#: admin/models.py:1037 msgid "The mailboxes this alias points to" msgstr "" -#: admin/models.py:1016 +#: admin/models.py:1041 msgid "The aliases this alias points to" msgstr "" -#: admin/models.py:1064 +#: admin/models.py:1089 msgid "distribution list" msgstr "" -#: admin/models.py:1065 +#: admin/models.py:1090 msgid "forward" msgstr "" -#: admin/models.py:1066 +#: admin/models.py:1091 msgid "alias" msgstr "" -#: admin/models.py:1142 +#: admin/models.py:1170 #, python-format msgid "Invalid line: %s" msgstr "" -#: admin/models.py:1167 +#: admin/models.py:1175 #, python-format -msgid "Mailbox %s does not exist" +msgid "Domain '%s' does not exist" msgstr "" -#: admin/models.py:1182 +#: admin/models.py:1218 msgid "Check to enable this extension" msgstr "" -#: admin/models.py:1282 +#: admin/models.py:1318 msgid "added" msgstr "" -#: admin/models.py:1285 +#: admin/models.py:1321 msgid "modified" msgstr "" -#: admin/models.py:1288 +#: admin/models.py:1324 msgid "deleted" msgstr "" -#: admin/models.py:1290 +#: admin/models.py:1326 #, python-format msgid "%(object)s '%(name)s' %(action)s by user %(user)s" msgstr "" @@ -627,7 +634,7 @@ msgid "Edit domain" msgstr "" #: admin/tables.py:21 admin/templates/admin/identities_table.html:8 -#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:79 +#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:83 #: extensions/sievefilters/templates/sievefilters/filter.html:17 #: extensions/sievefilters/templates/sievefilters/guieditor.html:5 #: extensions/webmail/templatetags/webextras.py:97 @@ -642,143 +649,143 @@ msgstr "" msgid "Description" msgstr "" -#: admin/views.py:87 +#: admin/views.py:88 msgid "New domain" msgstr "" -#: admin/views.py:88 admin/views.py:97 admin/views.py:225 admin/views.py:438 -#: admin/views.py:445 extensions/sievefilters/views.py:120 -#: extensions/sievefilters/views.py:187 extensions/webmail/views.py:131 +#: admin/views.py:89 admin/views.py:98 admin/views.py:228 admin/views.py:444 +#: admin/views.py:451 extensions/sievefilters/views.py:129 +#: extensions/sievefilters/views.py:198 extensions/webmail/views.py:136 msgid "Create" msgstr "" -#: admin/views.py:94 admin/views.py:442 +#: admin/views.py:95 admin/views.py:448 msgid "Next" msgstr "" -#: admin/views.py:96 +#: admin/views.py:97 msgid "Options" msgstr "" -#: admin/views.py:98 admin/views.py:446 +#: admin/views.py:99 admin/views.py:452 msgid "Previous" msgstr "" -#: admin/views.py:111 +#: admin/views.py:112 msgid "Domain created" msgstr "" -#: admin/views.py:144 admin/views.py:282 admin/views.py:492 +#: admin/views.py:146 admin/views.py:285 admin/views.py:498 #: extensions/postfix_autoreply/templates/postfix_autoreply/autoreply.html:9 -#: extensions/sievefilters/views.py:139 extensions/webmail/views.py:162 +#: extensions/sievefilters/views.py:148 extensions/webmail/views.py:168 #: userprefs/templates/userprefs/forward.html:8 #: userprefs/templates/userprefs/profile.html:8 msgid "Update" msgstr "" -#: admin/views.py:160 +#: admin/views.py:162 msgid "Domain modified" msgstr "" -#: admin/views.py:186 +#: admin/views.py:189 msgid "You can't delete your own domain" msgstr "" -#: admin/views.py:189 +#: admin/views.py:192 msgid "Domain deleted" msgid_plural "Domains deleted" msgstr[0] "" msgstr[1] "" -#: admin/views.py:204 +#: admin/views.py:207 msgid "Alias with this name already exists" msgstr "" -#: admin/views.py:247 +#: admin/views.py:250 msgid "New distribution list" msgstr "" -#: admin/views.py:248 +#: admin/views.py:251 msgid "Distribution list created" msgstr "" -#: admin/views.py:257 +#: admin/views.py:260 msgid "New alias" msgstr "" -#: admin/views.py:258 +#: admin/views.py:261 msgid "Alias created" msgstr "" -#: admin/views.py:267 +#: admin/views.py:270 msgid "New forward" msgstr "" -#: admin/views.py:268 +#: admin/views.py:271 msgid "Forward created" msgstr "" -#: admin/views.py:286 +#: admin/views.py:289 msgid "Distribution list modified" msgstr "" -#: admin/views.py:288 +#: admin/views.py:291 msgid "Forward modified" msgstr "" -#: admin/views.py:290 +#: admin/views.py:293 msgid "Alias modified" msgstr "" -#: admin/views.py:403 admin/views.py:541 admin/views.py:546 -#: extensions/amavis/views.py:195 extensions/amavis/views.py:201 -#: extensions/amavis/views.py:234 extensions/amavis/views.py:238 -#: extensions/amavis/views.py:240 extensions/webmail/views.py:36 -#: extensions/webmail/views.py:64 extensions/webmail/views.py:77 -#: extensions/webmail/views.py:93 extensions/webmail/views.py:109 -#: extensions/webmail/views.py:193 extensions/webmail/views.py:419 -#: extensions/webmail/views.py:430 extensions/webmail/views.py:457 +#: admin/views.py:402 admin/views.py:545 admin/views.py:550 +#: extensions/amavis/views.py:204 extensions/amavis/views.py:210 +#: extensions/amavis/views.py:243 extensions/amavis/views.py:247 +#: extensions/amavis/views.py:249 extensions/webmail/views.py:41 +#: extensions/webmail/views.py:68 extensions/webmail/views.py:81 +#: extensions/webmail/views.py:98 extensions/webmail/views.py:114 +#: extensions/webmail/views.py:200 extensions/webmail/views.py:427 +#: extensions/webmail/views.py:438 extensions/webmail/views.py:465 #: lib/formutils.py:32 lib/formutils.py:37 msgid "Invalid request" msgstr "" -#: admin/views.py:435 +#: admin/views.py:441 msgid "New account" msgstr "" -#: admin/views.py:459 +#: admin/views.py:465 msgid "Account created" msgstr "" -#: admin/views.py:507 +#: admin/views.py:513 msgid "Account updated" msgstr "" -#: admin/views.py:531 +#: admin/views.py:535 msgid "Account deleted" msgid_plural "Accounts deleted" msgstr[0] "" msgstr[1] "" -#: admin/views.py:586 +#: admin/views.py:590 msgid "Parameters saved" msgstr "" -#: admin/views.py:632 +#: admin/views.py:636 msgid "Modifications applied." msgstr "" -#: admin/views.py:740 +#: admin/views.py:743 #, python-format msgid "Object already exists: %s" msgstr "" -#: admin/views.py:742 +#: admin/views.py:745 #, python-format msgid "%d objects imported successfully" msgstr "" -#: admin/views.py:760 +#: admin/views.py:763 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
          \n" @@ -794,25 +801,25 @@ msgid "" "

          You can use a different character as separator.

          \n" msgstr "" -#: admin/views.py:772 +#: admin/views.py:775 msgid "Import identities" msgstr "" -#: admin/views.py:773 admin/views.py:843 admin/templatetags/admin_extras.py:87 +#: admin/views.py:776 admin/views.py:846 admin/templatetags/admin_extras.py:87 #: admin/templatetags/admin_extras.py:144 msgid "Import" msgstr "" -#: admin/views.py:803 +#: admin/views.py:806 msgid "Export identities" msgstr "" -#: admin/views.py:804 admin/views.py:860 admin/templatetags/admin_extras.py:93 +#: admin/views.py:807 admin/views.py:863 admin/templatetags/admin_extras.py:93 #: admin/templatetags/admin_extras.py:150 msgid "Export" msgstr "" -#: admin/views.py:832 +#: admin/views.py:835 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
            \n" @@ -824,11 +831,11 @@ msgid "" "

            You can use a different character as separator.

            \n" msgstr "" -#: admin/views.py:842 +#: admin/views.py:845 msgid "Import domains" msgstr "" -#: admin/views.py:859 +#: admin/views.py:862 msgid "Export domains" msgstr "" @@ -901,7 +908,7 @@ msgid "Tags" msgstr "" #: admin/templates/admin/importform.html:5 -#: admin/templatetags/admin_extras.py:305 +#: admin/templatetags/admin_extras.py:290 msgid "Help" msgstr "" @@ -948,7 +955,7 @@ msgid "Previously on Modoboa..." msgstr "" #: admin/templates/admin/logs.html:6 extensions/amavis/sql_listing.py:25 -#: extensions/webmail/lib.py:37 extensions/webmail/lib.py:406 +#: extensions/webmail/lib.py:38 extensions/webmail/lib.py:411 msgid "Date" msgstr "" @@ -1051,34 +1058,21 @@ msgid "View the domain's identities" msgstr "" #: admin/templatetags/admin_extras.py:178 -msgid "Delete the domain" -msgstr "" - #: admin/templatetags/admin_extras.py:194 -msgid "Delete this account" +#: admin/templatetags/admin_extras.py:201 +#, python-format +msgid "Delete %s?" msgstr "" -#: admin/templatetags/admin_extras.py:202 -msgid "Delete this distribution list" -msgstr "" - -#: admin/templatetags/admin_extras.py:209 -msgid "Delete this forward" -msgstr "" - -#: admin/templatetags/admin_extras.py:216 -msgid "Delete this alias" -msgstr "" - -#: admin/templatetags/admin_extras.py:238 +#: admin/templatetags/admin_extras.py:223 msgid "Remove this permission" msgstr "" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "Yes" msgstr "" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "No" msgstr "" @@ -1087,11 +1081,11 @@ msgstr "" msgid "User '%s' successfully logged in" msgstr "" -#: auth/views.py:41 +#: auth/views.py:44 msgid "Your username and password didn't match. Please try again." msgstr "" -#: auth/views.py:64 +#: auth/views.py:67 #, python-format msgid "User '%s' logged out" msgstr "" @@ -1137,16 +1131,16 @@ msgstr "" msgid "Quarantine" msgstr "" -#: extensions/amavis/__init__.py:127 +#: extensions/amavis/__init__.py:129 msgid "pending requests" msgstr "" -#: extensions/amavis/__init__.py:144 +#: extensions/amavis/__init__.py:149 #, python-format msgid "%d pending requests" msgstr "" -#: extensions/amavis/__init__.py:156 +#: extensions/amavis/__init__.py:161 msgid "Content filter" msgstr "" @@ -1261,12 +1255,12 @@ msgid "Virus filter" msgstr "" #: extensions/amavis/models.py:94 extensions/amavis/models.py:102 -#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:268 +#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:281 msgid "yes" msgstr "" #: extensions/amavis/models.py:95 extensions/amavis/models.py:103 -#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:272 +#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:285 msgid "no" msgstr "" @@ -1306,13 +1300,13 @@ msgid "" "settings." msgstr "" -#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:36 +#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:37 msgid "From" msgstr "" #: extensions/amavis/sql_listing.py:24 extensions/sievefilters/forms.py:68 -#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:35 -#: extensions/webmail/lib.py:404 templates/common/email_searchbar.html:6 +#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:36 +#: extensions/webmail/lib.py:409 templates/common/email_searchbar.html:6 msgid "Subject" msgstr "" @@ -1322,37 +1316,37 @@ msgstr "" msgid "To" msgstr "" -#: extensions/amavis/views.py:34 +#: extensions/amavis/views.py:43 msgid "Empty quarantine" msgstr "" -#: extensions/amavis/views.py:202 +#: extensions/amavis/views.py:211 msgid "Message deleted" msgstr "" -#: extensions/amavis/views.py:223 +#: extensions/amavis/views.py:232 #, python-format msgid "%(count)d message deleted successfully" msgid_plural "%(count)d messages deleted successfully" msgstr[0] "" msgstr[1] "" -#: extensions/amavis/views.py:243 +#: extensions/amavis/views.py:252 msgid "Request sent" msgstr "" -#: extensions/amavis/views.py:249 +#: extensions/amavis/views.py:258 msgid "Message released" msgstr "" -#: extensions/amavis/views.py:271 +#: extensions/amavis/views.py:280 #, python-format msgid "%(count)d request sent" msgid_plural "%(count)d requests sent" msgstr[0] "" msgstr[1] "" -#: extensions/amavis/views.py:295 +#: extensions/amavis/views.py:304 #, python-format msgid "%(count)d message released successfully" msgid_plural "%(count)d messages released successfully" @@ -1473,7 +1467,7 @@ msgstr "" msgid "Reseller" msgstr "" -#: extensions/limits/__init__.py:96 +#: extensions/limits/__init__.py:94 msgid "Resources" msgstr "" @@ -1592,23 +1586,23 @@ msgstr "" msgid "This date is over" msgstr "" -#: extensions/postfix_autoreply/models.py:15 +#: extensions/postfix_autoreply/models.py:19 msgid "subject" msgstr "" -#: extensions/postfix_autoreply/models.py:16 +#: extensions/postfix_autoreply/models.py:20 msgid "The subject that will appear in sent emails" msgstr "" -#: extensions/postfix_autoreply/models.py:17 +#: extensions/postfix_autoreply/models.py:23 msgid "content" msgstr "" -#: extensions/postfix_autoreply/models.py:18 +#: extensions/postfix_autoreply/models.py:24 msgid "The content that will appear in sent emails" msgstr "" -#: extensions/postfix_autoreply/models.py:20 +#: extensions/postfix_autoreply/models.py:28 msgid "Activate/Deactivate your auto reply" msgstr "" @@ -1742,53 +1736,53 @@ msgstr "" msgid "Not enough space on server" msgstr "" -#: extensions/sievefilters/views.py:64 +#: extensions/sievefilters/views.py:68 msgid "Failed to retrieve filters set" msgstr "" -#: extensions/sievefilters/views.py:117 +#: extensions/sievefilters/views.py:126 #: extensions/sievefilters/templatetags/sfilters_tags.py:33 msgid "New filter" msgstr "" -#: extensions/sievefilters/views.py:124 +#: extensions/sievefilters/views.py:133 msgid "Filter created" msgstr "" -#: extensions/sievefilters/views.py:136 +#: extensions/sievefilters/views.py:145 #: extensions/sievefilters/templatetags/sfilters_tags.py:77 msgid "Edit filter" msgstr "" -#: extensions/sievefilters/views.py:145 +#: extensions/sievefilters/views.py:154 msgid "Filter modified" msgstr "" -#: extensions/sievefilters/views.py:165 +#: extensions/sievefilters/views.py:176 msgid "Filter removed" msgstr "" -#: extensions/sievefilters/views.py:166 +#: extensions/sievefilters/views.py:177 msgid "Failed to remove filter" msgstr "" -#: extensions/sievefilters/views.py:180 +#: extensions/sievefilters/views.py:191 msgid "Filters set saved" msgstr "" -#: extensions/sievefilters/views.py:185 +#: extensions/sievefilters/views.py:196 msgid "Create a new filters set" msgstr "" -#: extensions/sievefilters/views.py:208 +#: extensions/sievefilters/views.py:219 msgid "Filters set created" msgstr "" -#: extensions/sievefilters/views.py:229 +#: extensions/sievefilters/views.py:240 msgid "Filters set deleted" msgstr "" -#: extensions/sievefilters/views.py:241 +#: extensions/sievefilters/views.py:252 msgid "Filters set activated" msgstr "" @@ -1804,15 +1798,15 @@ msgstr "" msgid "No filter defined yet" msgstr "" -#: extensions/sievefilters/templates/sievefilters/index.html:55 +#: extensions/sievefilters/templates/sievefilters/index.html:56 msgid "Filter sets" msgstr "" -#: extensions/sievefilters/templates/sievefilters/index.html:59 +#: extensions/sievefilters/templates/sievefilters/index.html:60 msgid "active" msgstr "" -#: extensions/sievefilters/templates/sievefilters/index.html:73 +#: extensions/sievefilters/templates/sievefilters/index.html:74 msgid "" "No filters set defined yet. You must create one in order to define filters." msgstr "" @@ -2127,84 +2121,88 @@ msgstr "" msgid "Cci" msgstr "" -#: extensions/webmail/imaputils.py:259 +#: extensions/webmail/imaputils.py:237 +msgid "Failed to retrieve hierarchy delimiter" +msgstr "" + +#: extensions/webmail/imaputils.py:278 #, python-format msgid "Connection to IMAP server failed: %s" msgstr "" -#: extensions/webmail/lib.py:353 +#: extensions/webmail/lib.py:358 msgid "wrote:" msgstr "" -#: extensions/webmail/lib.py:418 extensions/webmail/lib.py:422 +#: extensions/webmail/lib.py:423 extensions/webmail/lib.py:427 msgid "Original message" msgstr "" -#: extensions/webmail/views.py:81 +#: extensions/webmail/views.py:86 #, python-format msgid "%(count)d message deleted" msgid_plural "%(count)d messages deleted" msgstr[0] "" msgstr[1] "" -#: extensions/webmail/views.py:98 +#: extensions/webmail/views.py:103 msgid "Unknown action" msgstr "" -#: extensions/webmail/views.py:111 lib/email_listing.py:137 +#: extensions/webmail/views.py:116 lib/email_listing.py:137 msgid "Empty mailbox" msgstr "" -#: extensions/webmail/views.py:128 -#: extensions/webmail/templatetags/webextras.py:169 +#: extensions/webmail/views.py:133 +#: extensions/webmail/templatetags/webextras.py:170 msgid "Create a new mailbox" msgstr "" -#: extensions/webmail/views.py:143 +#: extensions/webmail/views.py:149 msgid "Mailbox created" msgstr "" -#: extensions/webmail/views.py:159 +#: extensions/webmail/views.py:165 msgid "Edit mailbox" msgstr "" -#: extensions/webmail/views.py:173 +#: extensions/webmail/views.py:180 msgid "Mailbox updated" msgstr "" -#: extensions/webmail/views.py:207 extensions/webmail/views.py:388 -#: extensions/webmail/views.py:497 +#: extensions/webmail/views.py:214 extensions/webmail/views.py:396 +#: extensions/webmail/views.py:505 msgid "Bad request" msgstr "" -#: extensions/webmail/views.py:238 +#: extensions/webmail/views.py:246 msgid "Failed to save attachment: " msgstr "" -#: extensions/webmail/views.py:241 +#: extensions/webmail/views.py:249 #, python-format msgid "Attachment is too big (limit: %s)" msgstr "" -#: extensions/webmail/views.py:247 +#: extensions/webmail/views.py:255 #: extensions/webmail/templates/webmail/compose.html:15 #: extensions/webmail/templates/webmail/headers.html:4 msgid "Attachments" msgstr "" -#: extensions/webmail/views.py:263 +#: extensions/webmail/views.py:271 msgid "Bad query" msgstr "" -#: extensions/webmail/views.py:273 +#: extensions/webmail/views.py:281 msgid "Failed to remove attachment: " msgstr "" -#: extensions/webmail/views.py:278 +#: extensions/webmail/views.py:286 msgid "Unknown attachment" msgstr "" -#: extensions/webmail/views.py:493 +#: extensions/webmail/views.py:501 msgid "Undefined action" msgstr "" @@ -2235,7 +2233,7 @@ msgstr[1] "" msgid "Parent mailbox" msgstr "" -#: extensions/webmail/templates/webmail/index.html:36 +#: extensions/webmail/templates/webmail/index.html:38 msgid "Mailbox quota" msgstr "" @@ -2297,15 +2295,15 @@ msgstr "" msgid "Compress folder" msgstr "" -#: extensions/webmail/templatetags/webextras.py:109 +#: extensions/webmail/templatetags/webextras.py:110 msgid "Empty folder" msgstr "" -#: extensions/webmail/templatetags/webextras.py:177 +#: extensions/webmail/templatetags/webextras.py:178 msgid "Edit the selected mailbox" msgstr "" -#: extensions/webmail/templatetags/webextras.py:182 +#: extensions/webmail/templatetags/webextras.py:183 msgid "Remove the selected mailbox" msgstr "" @@ -2359,7 +2357,7 @@ msgstr "" msgid "An internal error occured." msgstr "" -#: templates/nlayout.html:56 +#: templates/nlayout.html:62 msgid "Powered by Modoboa" msgstr "" @@ -2393,11 +2391,11 @@ msgstr "" msgid "Welcome to Modoboa" msgstr "" -#: templates/registration/login.html:33 +#: templates/registration/login.html:34 msgid "Remember me" msgstr "" -#: templates/registration/login.html:35 +#: templates/registration/login.html:36 msgid "Log in" msgstr "" @@ -2413,7 +2411,7 @@ msgstr "" msgid "Prefered language" msgstr "" -#: userprefs/app_settings.py:26 +#: userprefs/app_settings.py:27 msgid "Prefered language to display pages" msgstr "" diff --git a/modoboa/locale/es/LC_MESSAGES/django.po b/modoboa/locale/es/LC_MESSAGES/django.po index eac45d1bf..3457ecc93 100644 --- a/modoboa/locale/es/LC_MESSAGES/django.po +++ b/modoboa/locale/es/LC_MESSAGES/django.po @@ -1,22 +1,23 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Pedro Gracia , 2011-2013 # Pedro Gracia , 2010-2011 msgid "" msgstr "" "Project-Id-Version: Modoboa\n" -"Report-Msgid-Bugs-To: http://dev.modoboa.org/\n" -"POT-Creation-Date: 2013-06-01 16:35+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-09-20 22:30+0200\n" "PO-Revision-Date: 2013-06-03 16:33+0000\n" "Last-Translator: Pedro Gracia \n" -"Language-Team: Spanish (http://www.transifex.com/projects/p/modoboa/language/es/)\n" +"Language-Team: Spanish (http://www.transifex.com/projects/p/modoboa/language/" +"es/)\n" +"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: admin/__init__.py:9 @@ -27,8 +28,8 @@ msgstr "Consola de administración" msgid "Web based console to manage domains, accounts and aliases" msgstr "Consola web para administrar dominios, cuentas y alias" -#: admin/__init__.py:16 admin/forms.py:179 admin/forms.py:614 -#: admin/views.py:93 admin/views.py:441 +#: admin/__init__.py:16 admin/forms.py:211 admin/forms.py:652 +#: admin/views.py:94 admin/views.py:447 #: extensions/postfix_autoreply/app_settings.py:11 #: extensions/sievefilters/app_settings.py:50 #: extensions/stats/app_settings.py:11 extensions/webmail/app_settings.py:11 @@ -122,7 +123,9 @@ msgstr "Unir a DN" msgid "" "The distinguished name to use when binding to the LDAP server. Leave empty " "for an anonymous bind" -msgstr "El nombre distinguido a usar cuando nos unimos al servidor LDAP. Dejar vació para una unión anónima" +msgstr "" +"El nombre distinguido a usar cuando nos unimos al servidor LDAP. Dejar vació " +"para una unión anónima" #: admin/app_settings.py:97 msgid "Bind password" @@ -130,7 +133,8 @@ msgstr "Unir contraseña" #: admin/app_settings.py:99 msgid "The password to use when binding to the LDAP server (with 'Bind DN')" -msgstr "La contraseña a usar cuando nos unimos al servidor LDAP (con 'Unir a DN')" +msgstr "" +"La contraseña a usar cuando nos unimos al servidor LDAP (con 'Unir a DN')" #: admin/app_settings.py:105 msgid "Search base" @@ -148,7 +152,9 @@ msgstr "Filtro de búsqueda" msgid "" "An optional filter string (e.g. '(objectClass=person)'). In order to be " "valid, it must be enclosed in parentheses." -msgstr "Una cadena de filtro opcional (p.e. '(objectClass=person)'). Para que sea válido tiene que ser encerrado entre paréntesis." +msgstr "" +"Una cadena de filtro opcional (p.e. '(objectClass=person)'). Para que sea " +"válido tiene que ser encerrado entre paréntesis." #: admin/app_settings.py:119 msgid "User DN template" @@ -159,7 +165,9 @@ msgstr "Plantilla DN del usuario" msgid "" "The template used to construct a user's DN. It should contain one " "placeholder (ie. %(user)s)" -msgstr "La plantilla usada para contriunr un DN de usuario. Debería contener una cadena reemplazables (p.e. %(user)s)" +msgstr "" +"La plantilla usada para contriunr un DN de usuario. Debería contener una " +"cadena reemplazables (p.e. %(user)s)" #: admin/app_settings.py:126 msgid "Password attribute" @@ -192,7 +200,9 @@ msgstr "Manejar mailboxes en el sistema de fichero" msgid "" "Rename or remove mailboxes on the filesystem when they get renamed or " "removed within Modoboa" -msgstr "Renombrar o eliminar mailboxes en el sistema de ficheros cuando sean renombrados o eliminados dentro de Modoboa" +msgstr "" +"Renombrar o eliminar mailboxes en el sistema de ficheros cuando sean " +"renombrados o eliminados dentro de Modoboa" #: admin/app_settings.py:146 msgid "Mailboxes ower" @@ -236,39 +246,51 @@ msgstr "Redirección principal por defecto" #: admin/app_settings.py:175 msgid "The default redirection used when no application is specified" -msgstr "La redirección que será usada cuando ninguna aplicación sea especificada." +msgstr "" +"La redirección que será usada cuando ninguna aplicación sea especificada." -#: admin/app_settings.py:230 +#: admin/app_settings.py:213 +msgid "Key must be either 16, 24, or 32 bytes long" +msgstr "" + +#: admin/app_settings.py:222 +#, fuzzy +msgid "Invalid syntax" +msgstr "Línea inválida" + +#: admin/app_settings.py:245 msgid "This field is required" msgstr "Este campo es obligatorio" -#: admin/forms.py:16 admin/forms.py:459 admin/tables.py:18 +#: admin/forms.py:20 admin/forms.py:497 admin/tables.py:18 msgid "Alias(es)" msgstr "Alias" -#: admin/forms.py:18 +#: admin/forms.py:22 msgid "" "Alias(es) of this domain. Indicate only one name per input, press ENTER to " "add a new input." -msgstr "Alia(s) de este dominio. Indique únicamente un nombre por entrada, presione ENTER para añadir una nueva entrada." +msgstr "" +"Alia(s) de este dominio. Indique únicamente un nombre por entrada, presione " +"ENTER para añadir una nueva entrada." -#: admin/forms.py:55 +#: admin/forms.py:59 msgid "An alias with this name already exists" msgstr "Ya existe un alias con este nombre" -#: admin/forms.py:69 +#: admin/forms.py:73 msgid "A domain with this name already exists" msgstr "Ya existe un dominio con este nombre" -#: admin/forms.py:114 +#: admin/forms.py:146 msgid "Create a domain administrator" msgstr "Crear un administrador del dominio" -#: admin/forms.py:116 +#: admin/forms.py:148 msgid "Automatically create an administrator for this domain" msgstr "Automáticamente crear una administrador para este dominio" -#: admin/forms.py:120 admin/tables.py:12 admin/tables.py:47 +#: admin/forms.py:152 admin/tables.py:12 admin/tables.py:47 #: admin/templates/admin/editdomainform.html:13 #: admin/templates/admin/identities_table.html:5 #: admin/templates/admin/information.html:8 @@ -277,349 +299,364 @@ msgstr "Automáticamente crear una administrador para este dominio" msgid "Name" msgstr "Nombre" -#: admin/forms.py:122 +#: admin/forms.py:154 msgid "" "The administrator's name. Don't include the domain's name here, it will be " "automatically appended." -msgstr "El nombre del administrador. No incluya el nombre del dominio aquí, será añadido automáticamente." +msgstr "" +"El nombre del administrador. No incluya el nombre del dominio aquí, será " +"añadido automáticamente." -#: admin/forms.py:128 +#: admin/forms.py:160 msgid "Create aliases" msgstr "Crear alias" -#: admin/forms.py:130 +#: admin/forms.py:162 msgid "Automatically create standard aliases for this domain" msgstr "Automáticamente crear alias estándar para este dominio" -#: admin/forms.py:143 +#: admin/forms.py:175 msgid "Invalid format" msgstr "Formato inválido" -#: admin/forms.py:155 +#: admin/forms.py:187 #, python-format msgid "User '%s' already exists" msgstr "El usuario '%s' ya existe" -#: admin/forms.py:203 +#: admin/forms.py:235 msgid "Email address" msgstr "Dirección de email" -#: admin/forms.py:204 +#: admin/forms.py:236 msgid "" "The distribution list address. Use the '*' character to create a 'catchall' " "address (ex: *@domain.tld)." -msgstr "La dirección de la lista de distribución. Use el carácter '*' para crear una dirección 'catchall' (recogerlos todos, ej. *@domain.tld)" +msgstr "" +"La dirección de la lista de distribución. Use el carácter '*' para crear una " +"dirección 'catchall' (recogerlos todos, ej. *@domain.tld)" -#: admin/forms.py:207 +#: admin/forms.py:239 msgid "Recipients" msgstr "Destinatarios" -#: admin/forms.py:208 +#: admin/forms.py:240 msgid "" "Mailbox(es) this alias will point to. Indicate only one address per input, " "press ENTER to add a new input." -msgstr "Mailbox(es) a los que apuntará este alias. Indique únicamente una dirección por entrada, presione ENTER para añadir una nueva entrada." +msgstr "" +"Mailbox(es) a los que apuntará este alias. Indique únicamente una dirección " +"por entrada, presione ENTER para añadir una nueva entrada." -#: admin/forms.py:246 admin/forms.py:504 admin/forms.py:530 -#: admin/models.py:1147 +#: admin/forms.py:278 admin/forms.py:542 admin/forms.py:568 msgid "Domain does not exist" msgstr "El dominio no existe" -#: admin/forms.py:248 +#: admin/forms.py:280 msgid "You don't have access to this domain" msgstr "No tienes acceso a este dominio" -#: admin/forms.py:268 +#: admin/forms.py:300 msgid "Invalid mailbox" msgstr "mailbox inválido" -#: admin/forms.py:284 +#: admin/forms.py:316 admin/models.py:1202 #, python-format msgid "Local recipient %s not found" msgstr "Destinatario local %s no encontrado" -#: admin/forms.py:286 admin/forms.py:292 +#: admin/forms.py:318 admin/forms.py:324 #, python-format msgid "Recipient %s already present" msgstr "EL destinatario %s ya existe" -#: admin/forms.py:297 +#: admin/forms.py:329 msgid "No recipient defined" msgstr "No ha puesto destinatario" -#: admin/forms.py:311 extensions/webmail/forms.py:19 +#: admin/forms.py:343 extensions/webmail/forms.py:19 msgid "Select a file" msgstr "Seleccione un fichero" -#: admin/forms.py:313 admin/forms.py:341 +#: admin/forms.py:345 admin/forms.py:373 msgid "Separator" msgstr "Separador" -#: admin/forms.py:316 +#: admin/forms.py:348 msgid "Continue on error" msgstr "Continúe en error." -#: admin/forms.py:317 +#: admin/forms.py:349 msgid "Don't treat duplicated objects as error" msgstr "No tratar objetos duplicados como error" -#: admin/forms.py:332 +#: admin/forms.py:364 msgid "Crypt passwords" msgstr "Contraseñas cifradas" -#: admin/forms.py:333 +#: admin/forms.py:365 msgid "Check this option if passwords contained in your file are not crypted" -msgstr "Marque esta opción si las contraseñas que contiene su fichero no están cifradas" +msgstr "" +"Marque esta opción si las contraseñas que contiene su fichero no están " +"cifradas" -#: admin/forms.py:339 +#: admin/forms.py:371 msgid "File name" msgstr "Nombre del fichero" -#: admin/forms.py:371 admin/templates/admin/editdomainform.html:13 +#: admin/forms.py:403 admin/templates/admin/editdomainform.html:13 #: auth/forms.py:7 msgid "Username" msgstr "Nombre de usuario" -#: admin/forms.py:373 +#: admin/forms.py:405 msgid "Role" msgstr "Rol" -#: admin/forms.py:374 admin/forms.py:401 +#: admin/forms.py:406 admin/forms.py:433 msgid "Choose" msgstr "Elija" -#: admin/forms.py:375 +#: admin/forms.py:407 msgid "What level of permission this user will have" msgstr "Qué nivel de permiso tendrá este usuario" -#: admin/forms.py:377 auth/forms.py:11 +#: admin/forms.py:409 auth/forms.py:11 msgid "Password" msgstr "Contraseña" -#: admin/forms.py:379 userprefs/forms.py:18 +#: admin/forms.py:411 userprefs/forms.py:18 msgid "Confirmation" msgstr "Confirmación" -#: admin/forms.py:381 +#: admin/forms.py:413 msgid "Enter the same password as above, for verification." msgstr "Introduzca la misma contraseña que arriba, para verificación." -#: admin/forms.py:392 +#: admin/forms.py:424 msgid "Enabled" msgstr "Activado" -#: admin/forms.py:434 +#: admin/forms.py:471 msgid "The two password fields didn't match." msgstr "Las contraseñas no concuerdan" -#: admin/forms.py:440 +#: admin/forms.py:477 msgid "You can't disable your own account" msgstr "No puede deshabilitar su propia cuenta" -#: admin/forms.py:450 +#: admin/forms.py:488 msgid "E-mail" msgstr "Email" -#: admin/forms.py:452 +#: admin/forms.py:490 msgid "Quota" msgstr "Cuota" -#: admin/forms.py:454 +#: admin/forms.py:492 msgid "" "Quota in MB for this mailbox. Define a custom value or use domain's default " "one. Leave empty to define an unlimited value (not allowed for domain " "administrators)." -msgstr "Cuota en MB para este mailbox. Defina un valor por defecto o use el del dominio por defecto. Déjelo vacío para definir un valor ilimitado (no permitido para los administradores del dominio)" +msgstr "" +"Cuota en MB para este mailbox. Defina un valor por defecto o use el del " +"dominio por defecto. Déjelo vacío para definir un valor ilimitado (no " +"permitido para los administradores del dominio)" -#: admin/forms.py:461 +#: admin/forms.py:499 msgid "" "Alias(es) of this mailbox. Indicate only one address per input, press ENTER " "to add a new input. Use the '*' character to create a 'catchall' alias (ex: " "*@domain.tld)." -msgstr "Alias de este mailbox. Indique sólo una dirección por entrada, presione ENTER para añadir una nueva entrada. Use el carácter '*' para crear una dirección 'catchall' (recogerlos todos, ej. *@domain.tld)" +msgstr "" +"Alias de este mailbox. Indique sólo una dirección por entrada, presione " +"ENTER para añadir una nueva entrada. Use el carácter '*' para crear una " +"dirección 'catchall' (recogerlos todos, ej. *@domain.tld)" -#: admin/forms.py:512 +#: admin/forms.py:550 #, python-format msgid "Mailbox %s already exists" msgstr "El mailbox %s ya existe" -#: admin/forms.py:572 +#: admin/forms.py:610 msgid "Domain(s)" msgstr "Dominio(s)" -#: admin/forms.py:574 +#: admin/forms.py:612 msgid "Domain(s) that user administrates" msgstr "Dominio(s) que el usuario administra" -#: admin/forms.py:616 admin/views.py:444 +#: admin/forms.py:654 admin/views.py:450 msgid "Mail" msgstr "Correo" -#: admin/forms.py:618 +#: admin/forms.py:656 msgid "Permissions" msgstr "Permisos" -#: admin/models.py:78 +#: admin/models.py:80 msgid "You can't delete your own account" msgstr "No puede eliminar su propia cuenta" -#: admin/models.py:159 +#: admin/models.py:161 msgid "Failed to update password: LDAP module not installed" msgstr "Falló al actualizar la contraseña: módulo LDAP no instalado" -#: admin/models.py:165 +#: admin/models.py:167 #, python-format msgid "Failed to update password: %s" msgstr "Falló la actualización de la contraseña: %s" -#: admin/models.py:192 +#: admin/models.py:194 msgid "account" msgstr "cuenta" -#: admin/models.py:494 admin/models.py:720 admin/models.py:782 +#: admin/models.py:496 admin/models.py:733 admin/models.py:795 msgid "Invalid line" msgstr "Línea inválida" -#: admin/models.py:498 +#: admin/models.py:500 msgid "You can't import an account with a role greater than yours" msgstr "No puede importar una cuenta con un rol mayor que el suyo" -#: admin/models.py:518 +#: admin/models.py:506 +#, python-format +msgid "The simple user '%s' must have a valid email address" +msgstr "" + +#: admin/models.py:510 +#, python-format +msgid "username and email fields must not differ for '%s'" +msgstr "" + +#: admin/models.py:534 #, python-format msgid "Account import failed (%s): domain does not exist" msgstr "Falló la importación de la cuenta (%s): el dominio no existe" -#: admin/models.py:607 admin/models.py:733 +#: admin/models.py:624 admin/models.py:746 msgid "name" msgstr "nombre" -#: admin/models.py:608 +#: admin/models.py:625 msgid "The domain name" msgstr "Nombre del dominio" -#: admin/models.py:610 +#: admin/models.py:627 msgid "Default quota in MB applied to mailboxes" msgstr "Cuota por defecto en MB que se aplicará a los mailboxes" -#: admin/models.py:613 admin/models.py:740 admin/models.py:1020 -#: admin/models.py:1181 extensions/postfix_autoreply/models.py:19 +#: admin/models.py:630 admin/models.py:753 admin/models.py:1045 +#: admin/models.py:1217 extensions/postfix_autoreply/models.py:27 msgid "enabled" msgstr "activado" -#: admin/models.py:614 +#: admin/models.py:631 msgid "Check to activate this domain" msgstr "Marcar para activar este dominio" -#: admin/models.py:734 +#: admin/models.py:747 msgid "The alias name" msgstr "Nombre del alias" -#: admin/models.py:736 +#: admin/models.py:749 msgid "target" msgstr "objetivo" -#: admin/models.py:737 +#: admin/models.py:750 msgid "The domain this alias points to" msgstr "El dominio al que este alias apunta" -#: admin/models.py:741 admin/models.py:1021 +#: admin/models.py:754 admin/models.py:1046 msgid "Check to activate this alias" msgstr "Marcar para activar este alias" -#: admin/models.py:788 +#: admin/models.py:801 #, python-format msgid "Unknown domain %s" msgstr "Dominio desconocido %s" -#: admin/models.py:805 admin/models.py:1006 +#: admin/models.py:818 admin/models.py:1031 msgid "address" msgstr "dirección" -#: admin/models.py:806 +#: admin/models.py:819 msgid "Mailbox address (without the @domain.tld part)" msgstr "Dirección del mailbox (sin la parte @dominio.tld)" -#: admin/models.py:852 +#: admin/models.py:877 #, python-format msgid "Failed to retrieve mailbox location (%s)" msgstr "Fallo al recuperar la localización del mailbox (%s)" -#: admin/models.py:868 -#, python-format -msgid "Failed to rename mailbox: %s" -msgstr "Fallo al renombrar el mailbox: %s" - -#: admin/models.py:894 -#, python-format -msgid "Failed to remove mailbox: %s" -msgstr "Fallo al eliminar el mailbox: %s" - -#: admin/models.py:909 +#: admin/models.py:921 #, python-format msgid "Quota is greater than the allowed domain's limit (%dM)" msgstr "La cuota es mayor que el límite permitido para el dominio (%dM)" -#: admin/models.py:914 +#: admin/models.py:926 msgid "A quota is required" msgstr "Una cuota es obligatoria" -#: admin/models.py:1007 +#: admin/models.py:1032 msgid "" -"The alias address (without the domain part). For a 'catch-all' address, just" -" enter an * character." -msgstr "La dirección del alias (sin la parte del dominio). Para una dirección que lo recoja todo, ponga un asterisco (*)." +"The alias address (without the domain part). For a 'catch-all' address, just " +"enter an * character." +msgstr "" +"La dirección del alias (sin la parte del dominio). Para una dirección que lo " +"recoja todo, ponga un asterisco (*)." -#: admin/models.py:1011 +#: admin/models.py:1036 msgid "mailboxes" msgstr "mailboxes" -#: admin/models.py:1012 +#: admin/models.py:1037 msgid "The mailboxes this alias points to" msgstr "Los 'mailboxes' de este alias apuntan a" -#: admin/models.py:1016 +#: admin/models.py:1041 msgid "The aliases this alias points to" msgstr "Los alias de este alias apuntan a" -#: admin/models.py:1064 +#: admin/models.py:1089 msgid "distribution list" msgstr "Lista de distribución" -#: admin/models.py:1065 +#: admin/models.py:1090 msgid "forward" msgstr "reenvío" -#: admin/models.py:1066 +#: admin/models.py:1091 msgid "alias" msgstr "alias" -#: admin/models.py:1142 +#: admin/models.py:1170 #, python-format msgid "Invalid line: %s" msgstr "Línea inválida: %s" -#: admin/models.py:1167 -#, python-format -msgid "Mailbox %s does not exist" -msgstr "El mailbox %s no existe" +#: admin/models.py:1175 +#, fuzzy, python-format +msgid "Domain '%s' does not exist" +msgstr "El dominio no existe" -#: admin/models.py:1182 +#: admin/models.py:1218 msgid "Check to enable this extension" msgstr "Marcar para activar esta extensión" -#: admin/models.py:1282 +#: admin/models.py:1318 msgid "added" msgstr "añadido" -#: admin/models.py:1285 +#: admin/models.py:1321 msgid "modified" msgstr "modificado" -#: admin/models.py:1288 +#: admin/models.py:1324 msgid "deleted" msgstr "eliminado" -#: admin/models.py:1290 +#: admin/models.py:1326 #, python-format msgid "%(object)s '%(name)s' %(action)s by user %(user)s" msgstr "%(object)s '%(name)s' %(action)s por el usuario %(user)s" @@ -629,7 +666,7 @@ msgid "Edit domain" msgstr "Editar el dominio" #: admin/tables.py:21 admin/templates/admin/identities_table.html:8 -#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:79 +#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:83 #: extensions/sievefilters/templates/sievefilters/filter.html:17 #: extensions/sievefilters/templates/sievefilters/guieditor.html:5 #: extensions/webmail/templatetags/webextras.py:97 @@ -644,190 +681,212 @@ msgstr "Versión" msgid "Description" msgstr "Descripción" -#: admin/views.py:87 +#: admin/views.py:88 msgid "New domain" msgstr "Nuevo dominio" -#: admin/views.py:88 admin/views.py:97 admin/views.py:225 admin/views.py:438 -#: admin/views.py:445 extensions/sievefilters/views.py:120 -#: extensions/sievefilters/views.py:187 extensions/webmail/views.py:131 +#: admin/views.py:89 admin/views.py:98 admin/views.py:228 admin/views.py:444 +#: admin/views.py:451 extensions/sievefilters/views.py:129 +#: extensions/sievefilters/views.py:198 extensions/webmail/views.py:136 msgid "Create" msgstr "Crear" -#: admin/views.py:94 admin/views.py:442 +#: admin/views.py:95 admin/views.py:448 msgid "Next" msgstr "Siguiente" -#: admin/views.py:96 +#: admin/views.py:97 msgid "Options" msgstr "Opciones" -#: admin/views.py:98 admin/views.py:446 +#: admin/views.py:99 admin/views.py:452 msgid "Previous" msgstr "Anterior" -#: admin/views.py:111 +#: admin/views.py:112 msgid "Domain created" msgstr "Dominio creado" -#: admin/views.py:144 admin/views.py:282 admin/views.py:492 +#: admin/views.py:146 admin/views.py:285 admin/views.py:498 #: extensions/postfix_autoreply/templates/postfix_autoreply/autoreply.html:9 -#: extensions/sievefilters/views.py:139 extensions/webmail/views.py:162 +#: extensions/sievefilters/views.py:148 extensions/webmail/views.py:168 #: userprefs/templates/userprefs/forward.html:8 #: userprefs/templates/userprefs/profile.html:8 msgid "Update" msgstr "Actualizar" -#: admin/views.py:160 +#: admin/views.py:162 msgid "Domain modified" msgstr "Dominio modificado" -#: admin/views.py:186 +#: admin/views.py:189 msgid "You can't delete your own domain" msgstr "No puedo eliminar su propio dominio" -#: admin/views.py:189 +#: admin/views.py:192 msgid "Domain deleted" msgid_plural "Domains deleted" msgstr[0] "Dominio eliminado" msgstr[1] "Dominios eliminados" -#: admin/views.py:204 +#: admin/views.py:207 msgid "Alias with this name already exists" msgstr "Ya existe un alias con este nombre" -#: admin/views.py:247 +#: admin/views.py:250 msgid "New distribution list" msgstr "Nueva lista de distribución" -#: admin/views.py:248 +#: admin/views.py:251 msgid "Distribution list created" msgstr "Lista de distribución creada" -#: admin/views.py:257 +#: admin/views.py:260 msgid "New alias" msgstr "Nuevo alias" -#: admin/views.py:258 +#: admin/views.py:261 msgid "Alias created" msgstr "Alias creado" -#: admin/views.py:267 +#: admin/views.py:270 msgid "New forward" msgstr "Nuevo reenvío" -#: admin/views.py:268 +#: admin/views.py:271 msgid "Forward created" msgstr "Reenvío creado" -#: admin/views.py:286 +#: admin/views.py:289 msgid "Distribution list modified" msgstr "Lista de distribución modificada" -#: admin/views.py:288 +#: admin/views.py:291 msgid "Forward modified" msgstr "Reenvío modificado" -#: admin/views.py:290 +#: admin/views.py:293 msgid "Alias modified" msgstr "Alias modificado" -#: admin/views.py:403 admin/views.py:541 admin/views.py:546 -#: extensions/amavis/views.py:195 extensions/amavis/views.py:201 -#: extensions/amavis/views.py:234 extensions/amavis/views.py:238 -#: extensions/amavis/views.py:240 extensions/webmail/views.py:36 -#: extensions/webmail/views.py:64 extensions/webmail/views.py:77 -#: extensions/webmail/views.py:93 extensions/webmail/views.py:109 -#: extensions/webmail/views.py:193 extensions/webmail/views.py:419 -#: extensions/webmail/views.py:430 extensions/webmail/views.py:457 +#: admin/views.py:402 admin/views.py:545 admin/views.py:550 +#: extensions/amavis/views.py:204 extensions/amavis/views.py:210 +#: extensions/amavis/views.py:243 extensions/amavis/views.py:247 +#: extensions/amavis/views.py:249 extensions/webmail/views.py:41 +#: extensions/webmail/views.py:68 extensions/webmail/views.py:81 +#: extensions/webmail/views.py:98 extensions/webmail/views.py:114 +#: extensions/webmail/views.py:200 extensions/webmail/views.py:427 +#: extensions/webmail/views.py:438 extensions/webmail/views.py:465 #: lib/formutils.py:32 lib/formutils.py:37 msgid "Invalid request" msgstr "Petición inválida" -#: admin/views.py:435 +#: admin/views.py:441 msgid "New account" msgstr "Nueva cuenta" -#: admin/views.py:459 +#: admin/views.py:465 msgid "Account created" msgstr "Cuenta creada" -#: admin/views.py:507 +#: admin/views.py:513 msgid "Account updated" msgstr "Cuenta actualizada" -#: admin/views.py:531 +#: admin/views.py:535 msgid "Account deleted" msgid_plural "Accounts deleted" msgstr[0] "Cuenta eliminada" msgstr[1] "Cuentas eliminadas" -#: admin/views.py:586 +#: admin/views.py:590 msgid "Parameters saved" msgstr "Parámetros guardados" -#: admin/views.py:632 +#: admin/views.py:636 msgid "Modifications applied." msgstr "Modificaciones aplicadas." -#: admin/views.py:740 +#: admin/views.py:743 #, python-format msgid "Object already exists: %s" msgstr "El objeto ya existe: %s" -#: admin/views.py:742 +#: admin/views.py:745 #, python-format msgid "%d objects imported successfully" msgstr "%d objetos importados con éxito" -#: admin/views.py:760 +#: admin/views.py:763 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
              \n" -"
            • account; loginname; password; first name; last name; enabled; group; address[, domain, ...]
            • \n" +"
            • account; loginname; password; first name; last name; enabled; group; " +"address[, domain, ...]
            • \n" "
            • alias; address; enabled; internal recipient
            • \n" "
            • forward; address; enabled; external recipient
            • \n" "
            • dlist; address; enabled; recipient; recipient; ...
            • \n" "
            \n" -"

            The first element of each line is mandatory and must be equal to one of the previous values.

            \n" +"

            The first element of each line is mandatory and must be equal to one of " +"the previous values.

            \n" "\n" "

            You can use a different character as separator.

            \n" -msgstr "Importe un fichero CSV dónde las líneas respetan uno de los siguientes formatos:\n
              \n
            • account; loginname; password; first name; last name; enabled; group; address[, domain, ...]
            • ⏎\n
            • alias; address; enabled; internal recipient
            • ⏎\n
            • forward; address; enabled; external recipient
            • ⏎\n
            • dlist; address; enabled; recipient; recipient; ...
            • ⏎\n
            ⏎\n

            El primer elemento de cada línea es obligatorio y debe ser igual al de los valores previos.

            \n\n

            Puede usar un carácter diferente como separador.

            \n" +msgstr "" +"Importe un fichero CSV dónde las líneas respetan uno de los siguientes " +"formatos:\n" +"
              \n" +"
            • account; loginname; password; first name; last name; enabled; group; " +"address[, domain, ...]
            • ⏎\n" +"
            • alias; address; enabled; internal recipient
            • ⏎\n" +"
            • forward; address; enabled; external recipient
            • ⏎\n" +"
            • dlist; address; enabled; recipient; recipient; ...
            • ⏎\n" +"
            ⏎\n" +"

            El primer elemento de cada línea es obligatorio y debe ser igual al de " +"los valores previos.

            \n" +"\n" +"

            Puede usar un carácter diferente como separador.

            \n" -#: admin/views.py:772 +#: admin/views.py:775 msgid "Import identities" msgstr "Importar identidades" -#: admin/views.py:773 admin/views.py:843 admin/templatetags/admin_extras.py:87 +#: admin/views.py:776 admin/views.py:846 admin/templatetags/admin_extras.py:87 #: admin/templatetags/admin_extras.py:144 msgid "Import" msgstr "Importar" -#: admin/views.py:803 +#: admin/views.py:806 msgid "Export identities" msgstr "Exportar identidades" -#: admin/views.py:804 admin/views.py:860 admin/templatetags/admin_extras.py:93 +#: admin/views.py:807 admin/views.py:863 admin/templatetags/admin_extras.py:93 #: admin/templatetags/admin_extras.py:150 msgid "Export" msgstr "Exportar" -#: admin/views.py:832 +#: admin/views.py:835 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
              \n" "
            • domain; name; quota; enabled
            • \n" "
            • domainalias; name; targeted domain; enabled
            • \n" "
            \n" -"

            The first element of each line is mandatory and must be equal to one of the previous values.

            \n" +"

            The first element of each line is mandatory and must be equal to one of " +"the previous values.

            \n" "

            You can use a different character as separator.

            \n" -msgstr "Provea un fichero CSV dónde las líneas respetan uno de los siguientes formatos:⏎
              ⏎
            • dominio; nombre; cuota; activado
            • ⏎
            • aliasdeldominio; nombre; dominio objetivo; activado
            • ⏎
            ⏎

            El primer elemento de cada línea es obligatorio y debe ser igual a uno de los valores anteriores.

            ⏎

            Puede usar un carácter diferente como separador.

            ⏎\n" +msgstr "" +"Provea un fichero CSV dónde las líneas respetan uno de los siguientes " +"formatos:⏎
              ⏎
            • dominio; nombre; cuota; activado
            • ⏎ " +"
            • aliasdeldominio; nombre; dominio objetivo; activado
            • ⏎ ⏎

              El primer elemento de cada línea es obligatorio y debe ser igual a " +"uno de los valores anteriores.

              ⏎

              Puede usar un carácter diferente como " +"separador.

              ⏎\n" -#: admin/views.py:842 +#: admin/views.py:845 msgid "Import domains" msgstr "Importar dominios" -#: admin/views.py:859 +#: admin/views.py:862 msgid "Export domains" msgstr "Exportar dominios" @@ -900,7 +959,7 @@ msgid "Tags" msgstr "Tags" #: admin/templates/admin/importform.html:5 -#: admin/templatetags/admin_extras.py:305 +#: admin/templatetags/admin_extras.py:290 msgid "Help" msgstr "Ayuda" @@ -947,7 +1006,7 @@ msgid "Previously on Modoboa..." msgstr "Anteriormente en Modoboa..." #: admin/templates/admin/logs.html:6 extensions/amavis/sql_listing.py:25 -#: extensions/webmail/lib.py:37 extensions/webmail/lib.py:406 +#: extensions/webmail/lib.py:38 extensions/webmail/lib.py:411 msgid "Date" msgstr "Fecha" @@ -1050,34 +1109,21 @@ msgid "View the domain's identities" msgstr "Ver las identidades del dominio" #: admin/templatetags/admin_extras.py:178 -msgid "Delete the domain" -msgstr "Eliminar el dominio" - #: admin/templatetags/admin_extras.py:194 -msgid "Delete this account" -msgstr "Eliminar esta cuenta" +#: admin/templatetags/admin_extras.py:201 +#, fuzzy, python-format +msgid "Delete %s?" +msgstr "Eliminar" -#: admin/templatetags/admin_extras.py:202 -msgid "Delete this distribution list" -msgstr "Eliminar esta lista de distribución" - -#: admin/templatetags/admin_extras.py:209 -msgid "Delete this forward" -msgstr "Eliminar este reenvío" - -#: admin/templatetags/admin_extras.py:216 -msgid "Delete this alias" -msgstr "Eliminar este alias" - -#: admin/templatetags/admin_extras.py:238 +#: admin/templatetags/admin_extras.py:223 msgid "Remove this permission" msgstr "Eliminar este permiso" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "Yes" msgstr "Sí" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "No" msgstr "No " @@ -1086,11 +1132,13 @@ msgstr "No " msgid "User '%s' successfully logged in" msgstr "Usuario '%s' ha entrado con éxito" -#: auth/views.py:41 +#: auth/views.py:44 msgid "Your username and password didn't match. Please try again." -msgstr "Su nombre de usuario y contraseña no concuerdan. Por favor, inténtelo de nuevo." +msgstr "" +"Su nombre de usuario y contraseña no concuerdan. Por favor, inténtelo de " +"nuevo." -#: auth/views.py:64 +#: auth/views.py:67 #, python-format msgid "User '%s' logged out" msgstr "Usuario '%s' ha salido" @@ -1116,15 +1164,32 @@ msgid "" "\n" "

              Welcome to the online demo!

              \n" "

              Warning: the demo's concent is resetted every two hours.

              \n" -"

              To try the demo, the following users are available (username/password):

              \n" +"

              To try the demo, the following users are available (username/password):

              \n" "
                \n" "
              • A super administrator : admin/password
              • \n" "
              • A domain administrator : admin@demo.local/admin
              • \n" "
              • A simple user : user@demo.local/user
              • \n" "
              \n" "

              Please report any issue or give any suggestion to \n" -" the mailing list.

              \n" -msgstr "\n

              ¡Bienvendio a la demo!

              \n

              Aviso: el contenido de la demo será inicializado cada dos horas.

              \n

              Para probar la demo están disponibles los siguientes usuarios (usuario/contraseña):

              \n
                \n
              • Un super administrador : admin/password
              • \n
              • Un administrador de dominio : admin@demo.local/admin
              • \n
              • Un usuario normal : user@demo.local/user
              • \n
              \n

              Por favor, informe de cualquier incidencia o denos cualquier sugerencia a \n la lista de correo.

              \n" +" the " +"mailing list.

              \n" +msgstr "" +"\n" +"

              ¡Bienvendio a la demo!

              \n" +"

              Aviso: el contenido de la demo será inicializado cada dos horas.\n" +"

              Para probar la demo están disponibles los siguientes usuarios (usuario/" +"contraseña):

              \n" +"
                \n" +"
              • Un super administrador : admin/password
              • \n" +"
              • Un administrador de dominio : admin@demo.local/admin
              • \n" +"
              • Un usuario normal : user@demo.local/user
              • \n" +"
              \n" +"

              Por favor, informe de cualquier incidencia o denos cualquier sugerencia " +"a \n" +" la lista " +"de correo.

              \n" #: extensions/amavis/__init__.py:22 msgid "Simple amavis management frontend" @@ -1134,16 +1199,16 @@ msgstr "Panel de gestión sencilla para amavis" msgid "Quarantine" msgstr "Cuarentena" -#: extensions/amavis/__init__.py:127 +#: extensions/amavis/__init__.py:129 msgid "pending requests" msgstr "Peticiones pendientes" -#: extensions/amavis/__init__.py:144 +#: extensions/amavis/__init__.py:149 #, python-format msgid "%d pending requests" msgstr "%d peticiones pendientes" -#: extensions/amavis/__init__.py:156 +#: extensions/amavis/__init__.py:161 msgid "Content filter" msgstr "Filtro de contenido" @@ -1157,7 +1222,9 @@ msgstr "Tiempo máximo del mensaje" #: extensions/amavis/app_settings.py:16 msgid "Quarantine messages maximum age (in days) before deletion" -msgstr "Máxima edad (en días) de los mensajes de cuarentena antes de proceder a su eliminación" +msgstr "" +"Máxima edad (en días) de los mensajes de cuarentena antes de proceder a su " +"eliminación" #: extensions/amavis/app_settings.py:19 msgid "Messages releasing" @@ -1169,7 +1236,9 @@ msgstr "Eliminar mensajes publicados" #: extensions/amavis/app_settings.py:24 msgid "Remove messages marked as released while cleaning up the database" -msgstr "Eliminar los mensajes marcados como publicados cuando se haga limpieza de la base de datos" +msgstr "" +"Eliminar los mensajes marcados como publicados cuando se haga limpieza de la " +"base de datos" #: extensions/amavis/app_settings.py:28 msgid "Amavis connection mode" @@ -1258,12 +1327,12 @@ msgid "Virus filter" msgstr "Filtro de virus" #: extensions/amavis/models.py:94 extensions/amavis/models.py:102 -#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:268 +#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:281 msgid "yes" msgstr "sí" #: extensions/amavis/models.py:95 extensions/amavis/models.py:103 -#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:272 +#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:285 msgid "no" msgstr "no" @@ -1275,7 +1344,9 @@ msgstr "Por defecto" #: extensions/amavis/models.py:98 msgid "Bypass virus checks or not. Choose 'default' to use global settings." -msgstr "Saltarse la comprobación de virus o no. Elija 'Por defecto' para usar la configuración global." +msgstr "" +"Saltarse la comprobación de virus o no. Elija 'Por defecto' para usar la " +"configuración global." #: extensions/amavis/models.py:101 msgid "Spam filter" @@ -1283,7 +1354,9 @@ msgstr "Filtro de spam" #: extensions/amavis/models.py:106 msgid "Bypass spam checks or not. Choose 'default' to use global settings." -msgstr "Saltarse la comprobación de spam o no. Elija 'Por defecto' para usar la configuración global." +msgstr "" +"Saltarse la comprobación de spam o no. Elija 'Por defecto' para usar la " +"configuración global." #: extensions/amavis/models.py:109 msgid "Banned filter" @@ -1291,7 +1364,9 @@ msgstr "Filtro de expulsados" #: extensions/amavis/models.py:114 msgid "Bypass banned checks or not. Choose 'default' to use global settings." -msgstr "Saltarse la comprobación de expulsados o no. Elija 'Por defecto' para usar la configuración global." +msgstr "" +"Saltarse la comprobación de expulsados o no. Elija 'Por defecto' para usar " +"la configuración global." #: extensions/amavis/models.py:144 msgid "Spam marker" @@ -1299,17 +1374,19 @@ msgstr "Marcador de spam" #: extensions/amavis/models.py:146 msgid "" -"Modify spam subject using the specified text. Choose 'default' to use global" -" settings." -msgstr "Modificar el asunto del spam usando el texto especificado. Elija 'por defecto' para usar la configuración global." +"Modify spam subject using the specified text. Choose 'default' to use global " +"settings." +msgstr "" +"Modificar el asunto del spam usando el texto especificado. Elija 'por " +"defecto' para usar la configuración global." -#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:36 +#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:37 msgid "From" msgstr "Desde" #: extensions/amavis/sql_listing.py:24 extensions/sievefilters/forms.py:68 -#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:35 -#: extensions/webmail/lib.py:404 templates/common/email_searchbar.html:6 +#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:36 +#: extensions/webmail/lib.py:409 templates/common/email_searchbar.html:6 msgid "Subject" msgstr "Tema" @@ -1319,37 +1396,37 @@ msgstr "Tema" msgid "To" msgstr "A" -#: extensions/amavis/views.py:34 +#: extensions/amavis/views.py:43 msgid "Empty quarantine" msgstr "Vaciar cuarentena" -#: extensions/amavis/views.py:202 +#: extensions/amavis/views.py:211 msgid "Message deleted" msgstr "Mensaje eliminado" -#: extensions/amavis/views.py:223 +#: extensions/amavis/views.py:232 #, python-format msgid "%(count)d message deleted successfully" msgid_plural "%(count)d messages deleted successfully" msgstr[0] "%(count)d mensaje eliminado correctamente" msgstr[1] "%(count)d mensajes eliminados correctamente" -#: extensions/amavis/views.py:243 +#: extensions/amavis/views.py:252 msgid "Request sent" msgstr "Petición enviada" -#: extensions/amavis/views.py:249 +#: extensions/amavis/views.py:258 msgid "Message released" msgstr "Mensaje publicado" -#: extensions/amavis/views.py:271 +#: extensions/amavis/views.py:280 #, python-format msgid "%(count)d request sent" msgid_plural "%(count)d requests sent" msgstr[0] "%(count)d petición enviada" msgstr[1] "%(count)d peticiones enviadas" -#: extensions/amavis/views.py:295 +#: extensions/amavis/views.py:304 #, python-format msgid "%(count)d message released successfully" msgid_plural "%(count)d messages released successfully" @@ -1384,8 +1461,12 @@ msgid "" msgid_plural "" "\n" "%(counter)s release requests are pending for action.\n" -msgstr[0] "\n%(counter)s petición de publicación está pendiente de acción.\n" -msgstr[1] "\n%(counter)s peticiones de publicación están pendiente de acción.\n" +msgstr[0] "" +"\n" +"%(counter)s petición de publicación está pendiente de acción.\n" +msgstr[1] "" +"\n" +"%(counter)s peticiones de publicación están pendiente de acción.\n" #: extensions/amavis/templates/amavis/notifications/pending_requests.html:6 msgid "Sketch:" @@ -1460,7 +1541,8 @@ msgstr "Mal MIME" #: extensions/limits/__init__.py:23 msgid "" "Per administrator resources to limit the number of objects they can create" -msgstr "Recursos por administrador para limitar el número de objetos que pueden crear" +msgstr "" +"Recursos por administrador para limitar el número de objetos que pueden crear" #: extensions/limits/__init__.py:54 msgid "Limits" @@ -1470,7 +1552,7 @@ msgstr "Límites" msgid "Reseller" msgstr "Revendedor" -#: extensions/limits/__init__.py:96 +#: extensions/limits/__init__.py:94 msgid "Resources" msgstr "Recursos" @@ -1484,9 +1566,10 @@ msgid "Domain admins" msgstr "Administradores del dominio" #: extensions/limits/app_settings.py:15 -msgid "" -"Maximum number of allowed domain administrators for a new administrator" -msgstr "Número máximo de dominios permitido de administradores para un nuevo administrador" +msgid "Maximum number of allowed domain administrators for a new administrator" +msgstr "" +"Número máximo de dominios permitido de administradores para un nuevo " +"administrador" #: extensions/limits/app_settings.py:21 msgid "Maximum number of allowed domains for a new administrator" @@ -1494,7 +1577,8 @@ msgstr "Número máximo de dominios permitidos para un nuevo administrador" #: extensions/limits/app_settings.py:27 msgid "Maximum number of allowed domain aliases for a new administrator" -msgstr "Número máximo permitido de alias de dominio para un nuevo administrador" +msgstr "" +"Número máximo permitido de alias de dominio para un nuevo administrador" #: extensions/limits/app_settings.py:33 msgid "Maximum number of allowed mailboxes for a new administrator" @@ -1506,7 +1590,8 @@ msgstr "Número máxido de alias permitidos para un nuevo administrador" #: extensions/limits/forms.py:13 msgid "Maximum number of domain administrators this user can create" -msgstr "Número máximo de administradores de dominio que este usuario puede crear" +msgstr "" +"Número máximo de administradores de dominio que este usuario puede crear" #: extensions/limits/forms.py:17 msgid "Maximum number of domains this user can create" @@ -1590,23 +1675,23 @@ msgstr "Activar su autorespuesta hasta esta fecha" msgid "This date is over" msgstr "Esta fecha ha pasado" -#: extensions/postfix_autoreply/models.py:15 +#: extensions/postfix_autoreply/models.py:19 msgid "subject" msgstr "asunto" -#: extensions/postfix_autoreply/models.py:16 +#: extensions/postfix_autoreply/models.py:20 msgid "The subject that will appear in sent emails" msgstr "El asunto que aparecerán en los correos enviados" -#: extensions/postfix_autoreply/models.py:17 +#: extensions/postfix_autoreply/models.py:23 msgid "content" msgstr "contenido" -#: extensions/postfix_autoreply/models.py:18 +#: extensions/postfix_autoreply/models.py:24 msgid "The content that will appear in sent emails" msgstr "El contenido que aparecerá en los emails enviados" -#: extensions/postfix_autoreply/models.py:20 +#: extensions/postfix_autoreply/models.py:28 msgid "Activate/Deactivate your auto reply" msgstr "Activar/desactivar su autorespuesta" @@ -1616,7 +1701,8 @@ msgstr "El mensaje de autorespuesta se ha actualizado correctamente." #: extensions/postfix_autoreply/templates/postfix_autoreply/autoreply.html:2 msgid "Define a message to automatically send when you are off" -msgstr "Defina el mensaje que automáticamente se enviará cuando esté desconectado" +msgstr "" +"Defina el mensaje que automáticamente se enviará cuando esté desconectado" #: extensions/sievefilters/__init__.py:12 msgid "Plugin to easily create server-side filters" @@ -1740,53 +1826,53 @@ msgstr "La conexión al servidor MANAGESIEVE falló, verifique su configuración msgid "Not enough space on server" msgstr "No hay suficiente espacio en el servidor" -#: extensions/sievefilters/views.py:64 +#: extensions/sievefilters/views.py:68 msgid "Failed to retrieve filters set" msgstr "Fallo en la recuperación de un conjunto de filtros" -#: extensions/sievefilters/views.py:117 +#: extensions/sievefilters/views.py:126 #: extensions/sievefilters/templatetags/sfilters_tags.py:33 msgid "New filter" msgstr "Nuevo filtro" -#: extensions/sievefilters/views.py:124 +#: extensions/sievefilters/views.py:133 msgid "Filter created" msgstr "Filtro creado" -#: extensions/sievefilters/views.py:136 +#: extensions/sievefilters/views.py:145 #: extensions/sievefilters/templatetags/sfilters_tags.py:77 msgid "Edit filter" msgstr "Editar filtro" -#: extensions/sievefilters/views.py:145 +#: extensions/sievefilters/views.py:154 msgid "Filter modified" msgstr "Filtro modificado" -#: extensions/sievefilters/views.py:165 +#: extensions/sievefilters/views.py:176 msgid "Filter removed" msgstr "Filtro eliminado" -#: extensions/sievefilters/views.py:166 +#: extensions/sievefilters/views.py:177 msgid "Failed to remove filter" msgstr "La eliminación del filtro falló" -#: extensions/sievefilters/views.py:180 +#: extensions/sievefilters/views.py:191 msgid "Filters set saved" msgstr "Filtros guardados" -#: extensions/sievefilters/views.py:185 +#: extensions/sievefilters/views.py:196 msgid "Create a new filters set" msgstr "Crear un nuevo conjunto de filtros" -#: extensions/sievefilters/views.py:208 +#: extensions/sievefilters/views.py:219 msgid "Filters set created" msgstr "Conjunto de filtros creado" -#: extensions/sievefilters/views.py:229 +#: extensions/sievefilters/views.py:240 msgid "Filters set deleted" msgstr "Conjunto de filtros eliminado" -#: extensions/sievefilters/views.py:241 +#: extensions/sievefilters/views.py:252 msgid "Filters set activated" msgstr "Conjunto de filtros activado" @@ -1802,18 +1888,20 @@ msgstr "Activo" msgid "No filter defined yet" msgstr "No hay un filtro definido aún" -#: extensions/sievefilters/templates/sievefilters/index.html:55 +#: extensions/sievefilters/templates/sievefilters/index.html:56 msgid "Filter sets" msgstr "Conjunto de filtros" -#: extensions/sievefilters/templates/sievefilters/index.html:59 +#: extensions/sievefilters/templates/sievefilters/index.html:60 msgid "active" msgstr "activo" -#: extensions/sievefilters/templates/sievefilters/index.html:73 +#: extensions/sievefilters/templates/sievefilters/index.html:74 msgid "" "No filters set defined yet. You must create one in order to define filters." -msgstr "No hay un conjunto de filtros definido aún. Debe crear uno para poder definir filtros." +msgstr "" +"No hay un conjunto de filtros definido aún. Debe crear uno para poder " +"definir filtros." #: extensions/sievefilters/templatetags/sfilters_tags.py:16 msgid "New filters set" @@ -2125,84 +2213,89 @@ msgstr "Respuesta del servidor" msgid "Cci" msgstr "Cco" -#: extensions/webmail/imaputils.py:259 +#: extensions/webmail/imaputils.py:237 +#, fuzzy +msgid "Failed to retrieve hierarchy delimiter" +msgstr "Fallo en la recuperación de un conjunto de filtros" + +#: extensions/webmail/imaputils.py:278 #, python-format msgid "Connection to IMAP server failed: %s" msgstr "Falló la conexión con el servidor IMAP: %s" -#: extensions/webmail/lib.py:353 +#: extensions/webmail/lib.py:358 msgid "wrote:" msgstr "escribió:" -#: extensions/webmail/lib.py:418 extensions/webmail/lib.py:422 +#: extensions/webmail/lib.py:423 extensions/webmail/lib.py:427 msgid "Original message" msgstr "Mensaje original" -#: extensions/webmail/views.py:81 +#: extensions/webmail/views.py:86 #, python-format msgid "%(count)d message deleted" msgid_plural "%(count)d messages deleted" msgstr[0] "%(count)d mensaje eliminado" msgstr[1] "%(count)d mensajes eliminados" -#: extensions/webmail/views.py:98 +#: extensions/webmail/views.py:103 msgid "Unknown action" msgstr "Acción desconocida" -#: extensions/webmail/views.py:111 lib/email_listing.py:137 +#: extensions/webmail/views.py:116 lib/email_listing.py:137 msgid "Empty mailbox" msgstr "Mailbox vacío" -#: extensions/webmail/views.py:128 -#: extensions/webmail/templatetags/webextras.py:169 +#: extensions/webmail/views.py:133 +#: extensions/webmail/templatetags/webextras.py:170 msgid "Create a new mailbox" msgstr "Crear un nuevo mailbox" -#: extensions/webmail/views.py:143 +#: extensions/webmail/views.py:149 msgid "Mailbox created" msgstr "Mailbox creado." -#: extensions/webmail/views.py:159 +#: extensions/webmail/views.py:165 msgid "Edit mailbox" msgstr "Editar el mailbox" -#: extensions/webmail/views.py:173 +#: extensions/webmail/views.py:180 msgid "Mailbox updated" msgstr "Mailbox actualizado" -#: extensions/webmail/views.py:207 extensions/webmail/views.py:388 -#: extensions/webmail/views.py:497 +#: extensions/webmail/views.py:214 extensions/webmail/views.py:396 +#: extensions/webmail/views.py:505 msgid "Bad request" msgstr "Petición incorrecta" -#: extensions/webmail/views.py:238 +#: extensions/webmail/views.py:246 msgid "Failed to save attachment: " msgstr "Fallo al guardar el adjunto:" -#: extensions/webmail/views.py:241 +#: extensions/webmail/views.py:249 #, python-format msgid "Attachment is too big (limit: %s)" msgstr "EL adjunto es demasiado grande (límite: %s)" -#: extensions/webmail/views.py:247 +#: extensions/webmail/views.py:255 #: extensions/webmail/templates/webmail/compose.html:15 #: extensions/webmail/templates/webmail/headers.html:4 msgid "Attachments" msgstr "Adjuntos" -#: extensions/webmail/views.py:263 +#: extensions/webmail/views.py:271 msgid "Bad query" msgstr "Consulta errónea" -#: extensions/webmail/views.py:273 +#: extensions/webmail/views.py:281 msgid "Failed to remove attachment: " msgstr "Fallo al eliminar el adjunto:" -#: extensions/webmail/views.py:278 +#: extensions/webmail/views.py:286 msgid "Unknown attachment" msgstr "Adjunto desconocido" -#: extensions/webmail/views.py:493 +#: extensions/webmail/views.py:501 msgid "Undefined action" msgstr "Acción no definida" @@ -2233,7 +2326,7 @@ msgstr[1] "%(counter)s ficheros" msgid "Parent mailbox" msgstr "Mailbox padre" -#: extensions/webmail/templates/webmail/index.html:36 +#: extensions/webmail/templates/webmail/index.html:38 msgid "Mailbox quota" msgstr "Cuota del mailbox" @@ -2295,15 +2388,15 @@ msgstr "Como no leído" msgid "Compress folder" msgstr "Comprimir la carpeta" -#: extensions/webmail/templatetags/webextras.py:109 +#: extensions/webmail/templatetags/webextras.py:110 msgid "Empty folder" msgstr "Vaciar la carpeta" -#: extensions/webmail/templatetags/webextras.py:177 +#: extensions/webmail/templatetags/webextras.py:178 msgid "Edit the selected mailbox" msgstr "Editar el mailbox seleccionado" -#: extensions/webmail/templatetags/webextras.py:182 +#: extensions/webmail/templatetags/webextras.py:183 msgid "Remove the selected mailbox" msgstr "Eliminar el mailbox seleccionado" @@ -2357,7 +2450,7 @@ msgstr "La página pedida no existe." msgid "An internal error occured." msgstr "Ocurrió un error interno." -#: templates/nlayout.html:56 +#: templates/nlayout.html:62 msgid "Powered by Modoboa" msgstr "Tecnología Modoboa" @@ -2391,11 +2484,11 @@ msgstr "Cerrar" msgid "Welcome to Modoboa" msgstr "Bienvenido a Modoboa" -#: templates/registration/login.html:33 +#: templates/registration/login.html:34 msgid "Remember me" msgstr "Recuerdame" -#: templates/registration/login.html:35 +#: templates/registration/login.html:36 msgid "Log in" msgstr "Entrar" @@ -2411,7 +2504,7 @@ msgstr "Configuración por usuario" msgid "Prefered language" msgstr "Idioma preferido" -#: userprefs/app_settings.py:26 +#: userprefs/app_settings.py:27 msgid "Prefered language to display pages" msgstr "Idioma preferido para mostrar las páginas" @@ -2451,7 +2544,9 @@ msgstr "Reenvía mensajes y guarda copias en su mailbox local" msgid "" "You can't define a forward to a local destination. Please ask your " "administrator to create an alias instead." -msgstr "No puede definir un reenvío a un destino local. Por favor, pregunte a su administrador para crear un alias en su lugar." +msgstr "" +"No puede definir un reenvío a un destino local. Por favor, pregunte a su " +"administrador para crear un alias en su lugar." #: userprefs/views.py:32 msgid "You need a mailbox in order to define a forward" @@ -2499,3 +2594,27 @@ msgstr "Actualizar su información personal" #: userprefs/templatetags/uprefs_extras.py:57 msgid "Logout" msgstr "Salir" + +#~ msgid "Failed to rename mailbox: %s" +#~ msgstr "Fallo al renombrar el mailbox: %s" + +#~ msgid "Failed to remove mailbox: %s" +#~ msgstr "Fallo al eliminar el mailbox: %s" + +#~ msgid "Mailbox %s does not exist" +#~ msgstr "El mailbox %s no existe" + +#~ msgid "Delete the domain" +#~ msgstr "Eliminar el dominio" + +#~ msgid "Delete this account" +#~ msgstr "Eliminar esta cuenta" + +#~ msgid "Delete this distribution list" +#~ msgstr "Eliminar esta lista de distribución" + +#~ msgid "Delete this forward" +#~ msgstr "Eliminar este reenvío" + +#~ msgid "Delete this alias" +#~ msgstr "Eliminar este alias" diff --git a/modoboa/locale/fr/LC_MESSAGES/django.po b/modoboa/locale/fr/LC_MESSAGES/django.po index 40f10043d..bed98c974 100644 --- a/modoboa/locale/fr/LC_MESSAGES/django.po +++ b/modoboa/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: modoboa-1.0.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-06-01 16:35+0200\n" +"POT-Creation-Date: 2013-09-20 22:30+0200\n" "PO-Revision-Date: 2011-01-07 10:00+100\n" "Last-Translator: Antoine Nguyen \n" "Language-Team: FR \n" @@ -25,8 +25,8 @@ msgstr "Console d'administration" msgid "Web based console to manage domains, accounts and aliases" msgstr "Console web pour gérer les domains, comptes et alias" -#: admin/__init__.py:16 admin/forms.py:179 admin/forms.py:614 -#: admin/views.py:93 admin/views.py:441 +#: admin/__init__.py:16 admin/forms.py:211 admin/forms.py:652 +#: admin/views.py:94 admin/views.py:447 #: extensions/postfix_autoreply/app_settings.py:11 #: extensions/sievefilters/app_settings.py:50 #: extensions/stats/app_settings.py:11 extensions/webmail/app_settings.py:11 @@ -250,15 +250,23 @@ msgid "The default redirection used when no application is specified" msgstr "" "La redirection appliquée par défaut quand aucune application n'est spécifiée" -#: admin/app_settings.py:230 +#: admin/app_settings.py:213 +msgid "Key must be either 16, 24, or 32 bytes long" +msgstr "La longueur d'une clé doit être de 16, 24 ou 32 octets" + +#: admin/app_settings.py:222 +msgid "Invalid syntax" +msgstr "Syntaxe invalide" + +#: admin/app_settings.py:245 msgid "This field is required" msgstr "Ce champ est requis" -#: admin/forms.py:16 admin/forms.py:459 admin/tables.py:18 +#: admin/forms.py:20 admin/forms.py:497 admin/tables.py:18 msgid "Alias(es)" msgstr "Alias" -#: admin/forms.py:18 +#: admin/forms.py:22 msgid "" "Alias(es) of this domain. Indicate only one name per input, press ENTER to " "add a new input." @@ -266,23 +274,23 @@ msgstr "" "Alias de ce domaine. Indiquer seulement un nom par champ, appuyer sur ENTREE " "pour ajouter un nouveau champ." -#: admin/forms.py:55 +#: admin/forms.py:59 msgid "An alias with this name already exists" msgstr "Un alias de ce nom existe déjà" -#: admin/forms.py:69 +#: admin/forms.py:73 msgid "A domain with this name already exists" msgstr "Un domaine de ce nom existe déjà" -#: admin/forms.py:114 +#: admin/forms.py:146 msgid "Create a domain administrator" msgstr "Créer un administrateur de domaine" -#: admin/forms.py:116 +#: admin/forms.py:148 msgid "Automatically create an administrator for this domain" msgstr "Créer automatiquement un administrateur pour ce domaine" -#: admin/forms.py:120 admin/tables.py:12 admin/tables.py:47 +#: admin/forms.py:152 admin/tables.py:12 admin/tables.py:47 #: admin/templates/admin/editdomainform.html:13 #: admin/templates/admin/identities_table.html:5 #: admin/templates/admin/information.html:8 @@ -291,7 +299,7 @@ msgstr "Créer automatiquement un administrateur pour ce domaine" msgid "Name" msgstr "Nom" -#: admin/forms.py:122 +#: admin/forms.py:154 msgid "" "The administrator's name. Don't include the domain's name here, it will be " "automatically appended." @@ -299,28 +307,28 @@ msgstr "" "Le nom de l'administrateur. Ne pas include un nom de domaine ici, il sera " "ajouté automatiquement." -#: admin/forms.py:128 +#: admin/forms.py:160 msgid "Create aliases" msgstr "Créer des alias" -#: admin/forms.py:130 +#: admin/forms.py:162 msgid "Automatically create standard aliases for this domain" msgstr "Créer automatiquement des alias standard pour ce domaine" -#: admin/forms.py:143 +#: admin/forms.py:175 msgid "Invalid format" msgstr "Format invalide" -#: admin/forms.py:155 +#: admin/forms.py:187 #, python-format msgid "User '%s' already exists" msgstr "L'utilisateur '%s' existe déjà" -#: admin/forms.py:203 +#: admin/forms.py:235 msgid "Email address" msgstr "Adresse email" -#: admin/forms.py:204 +#: admin/forms.py:236 msgid "" "The distribution list address. Use the '*' character to create a 'catchall' " "address (ex: *@domain.tld)." @@ -328,11 +336,11 @@ msgstr "" "L'adresse de la liste de distribution. Utiliser le caractère '*' pour créer " "une adresse 'attrape tout' (ex: *@domain.tld)." -#: admin/forms.py:207 +#: admin/forms.py:239 msgid "Recipients" msgstr "Destinataires" -#: admin/forms.py:208 +#: admin/forms.py:240 msgid "" "Mailbox(es) this alias will point to. Indicate only one address per input, " "press ENTER to add a new input." @@ -340,113 +348,112 @@ msgstr "" "Destinataire(s) de cet alias. Indiquer seulement une adresse par champ, " "appuyer sur ENTREE pour ajouter un nouveau champ." -#: admin/forms.py:246 admin/forms.py:504 admin/forms.py:530 -#: admin/models.py:1147 +#: admin/forms.py:278 admin/forms.py:542 admin/forms.py:568 msgid "Domain does not exist" msgstr "Domain inexistant" -#: admin/forms.py:248 +#: admin/forms.py:280 msgid "You don't have access to this domain" msgstr "Vous n'avez pas accès à ce domaine" -#: admin/forms.py:268 +#: admin/forms.py:300 msgid "Invalid mailbox" msgstr "Boite aux lettres invalide" -#: admin/forms.py:284 +#: admin/forms.py:316 admin/models.py:1202 #, python-format msgid "Local recipient %s not found" msgstr "Destinataire local %s introuvable" -#: admin/forms.py:286 admin/forms.py:292 +#: admin/forms.py:318 admin/forms.py:324 #, python-format msgid "Recipient %s already present" msgstr "Destinataire %s déjà présent" -#: admin/forms.py:297 +#: admin/forms.py:329 msgid "No recipient defined" msgstr "Aucune destinataire défini" -#: admin/forms.py:311 extensions/webmail/forms.py:19 +#: admin/forms.py:343 extensions/webmail/forms.py:19 msgid "Select a file" msgstr "Sélectionner un fichier" -#: admin/forms.py:313 admin/forms.py:341 +#: admin/forms.py:345 admin/forms.py:373 msgid "Separator" msgstr "Séparateur" -#: admin/forms.py:316 +#: admin/forms.py:348 msgid "Continue on error" msgstr "Continuer en cas d'erreur" -#: admin/forms.py:317 +#: admin/forms.py:349 msgid "Don't treat duplicated objects as error" msgstr "Ne pas traiter les objets dupliqués comme des erreurs" -#: admin/forms.py:332 +#: admin/forms.py:364 msgid "Crypt passwords" msgstr "Chiffrer les mots de passe" -#: admin/forms.py:333 +#: admin/forms.py:365 msgid "Check this option if passwords contained in your file are not crypted" msgstr "" "Cocher cette option si les mots de passe contenus dans votre fichier ne sont " "pas chiffrés" -#: admin/forms.py:339 +#: admin/forms.py:371 msgid "File name" msgstr "Nom du fichier" -#: admin/forms.py:371 admin/templates/admin/editdomainform.html:13 +#: admin/forms.py:403 admin/templates/admin/editdomainform.html:13 #: auth/forms.py:7 msgid "Username" msgstr "Nom d'utilisateur" -#: admin/forms.py:373 +#: admin/forms.py:405 msgid "Role" msgstr "Rôle" -#: admin/forms.py:374 admin/forms.py:401 +#: admin/forms.py:406 admin/forms.py:433 msgid "Choose" msgstr "Choisir" -#: admin/forms.py:375 +#: admin/forms.py:407 msgid "What level of permission this user will have" msgstr "Quel niveau de permission cet utilisateur aura" -#: admin/forms.py:377 auth/forms.py:11 +#: admin/forms.py:409 auth/forms.py:11 msgid "Password" msgstr "Mot de passe" -#: admin/forms.py:379 userprefs/forms.py:18 +#: admin/forms.py:411 userprefs/forms.py:18 msgid "Confirmation" msgstr "Confirmation" -#: admin/forms.py:381 +#: admin/forms.py:413 msgid "Enter the same password as above, for verification." msgstr "Entrer le même mot de passe, pour vérification." -#: admin/forms.py:392 +#: admin/forms.py:424 msgid "Enabled" msgstr "Activé" -#: admin/forms.py:434 +#: admin/forms.py:471 msgid "The two password fields didn't match." msgstr "Les deux mots de passe ne correspondent pas." -#: admin/forms.py:440 +#: admin/forms.py:477 msgid "You can't disable your own account" msgstr "Vous ne pouvez pas désactiver votre propre compte" -#: admin/forms.py:450 +#: admin/forms.py:488 msgid "E-mail" msgstr "E-mail" -#: admin/forms.py:452 +#: admin/forms.py:490 msgid "Quota" msgstr "Quota" -#: admin/forms.py:454 +#: admin/forms.py:492 msgid "" "Quota in MB for this mailbox. Define a custom value or use domain's default " "one. Leave empty to define an unlimited value (not allowed for domain " @@ -456,7 +463,7 @@ msgstr "" "valeur par défaut du domaine. Laisser vide pour définir une valeur illimitée " "(interdit pour les admins. de domaine)." -#: admin/forms.py:461 +#: admin/forms.py:499 msgid "" "Alias(es) of this mailbox. Indicate only one address per input, press ENTER " "to add a new input. Use the '*' character to create a 'catchall' alias (ex: " @@ -466,133 +473,133 @@ msgstr "" "ENTREE pour ajouter un nouveau champ. Utiliser le caractère '*' pour créer " "une adresse 'attrape tout' (ex: *@domain.tld)." -#: admin/forms.py:512 +#: admin/forms.py:550 #, python-format msgid "Mailbox %s already exists" msgstr "La boite %s existe déjà" -#: admin/forms.py:572 +#: admin/forms.py:610 msgid "Domain(s)" msgstr "Domaine(s)" -#: admin/forms.py:574 +#: admin/forms.py:612 msgid "Domain(s) that user administrates" msgstr "Domaine(s) que cet utilisateur administre" -#: admin/forms.py:616 admin/views.py:444 +#: admin/forms.py:654 admin/views.py:450 msgid "Mail" msgstr "Courrier" -#: admin/forms.py:618 +#: admin/forms.py:656 msgid "Permissions" msgstr "Permissions" -#: admin/models.py:78 +#: admin/models.py:80 msgid "You can't delete your own account" msgstr "Vous ne pouvez pas supprimer votre propre compte" -#: admin/models.py:159 +#: admin/models.py:161 msgid "Failed to update password: LDAP module not installed" msgstr "" "Echec de la mise à jour du mot de passe : le module LDAP n'est pas installé" -#: admin/models.py:165 +#: admin/models.py:167 #, python-format msgid "Failed to update password: %s" msgstr "Echec de la mise à jour du mot de passe : %s" -#: admin/models.py:192 +#: admin/models.py:194 msgid "account" msgstr "compte" -#: admin/models.py:494 admin/models.py:720 admin/models.py:782 +#: admin/models.py:496 admin/models.py:733 admin/models.py:795 msgid "Invalid line" msgstr "Ligne invalide" -#: admin/models.py:498 +#: admin/models.py:500 msgid "You can't import an account with a role greater than yours" msgstr "Vous ne pouvez pas importer un compte avec un rôle supérieur au votre" -#: admin/models.py:518 +#: admin/models.py:506 +#, python-format +msgid "The simple user '%s' must have a valid email address" +msgstr "L'utilisateur simple '%s' doit avoir une adresse email valide" + +#: admin/models.py:510 +#, python-format +msgid "username and email fields must not differ for '%s'" +msgstr "Les champs username et email de '%s' ne doivent pas différer" + +#: admin/models.py:534 #, python-format msgid "Account import failed (%s): domain does not exist" msgstr "L'import du compte a échoué (%s): le domaine n'existe pas" -#: admin/models.py:607 admin/models.py:733 +#: admin/models.py:624 admin/models.py:746 msgid "name" msgstr "Nom" -#: admin/models.py:608 +#: admin/models.py:625 msgid "The domain name" msgstr "Le nom du domaine" -#: admin/models.py:610 +#: admin/models.py:627 msgid "Default quota in MB applied to mailboxes" msgstr "Quota par défaut en Mo appliqué aux boites aux lettres" -#: admin/models.py:613 admin/models.py:740 admin/models.py:1020 -#: admin/models.py:1181 extensions/postfix_autoreply/models.py:19 +#: admin/models.py:630 admin/models.py:753 admin/models.py:1045 +#: admin/models.py:1217 extensions/postfix_autoreply/models.py:27 msgid "enabled" msgstr "Activé" -#: admin/models.py:614 +#: admin/models.py:631 msgid "Check to activate this domain" msgstr "Cocher pour activer ce domaine" -#: admin/models.py:734 +#: admin/models.py:747 msgid "The alias name" msgstr "Le nom de l'alias" -#: admin/models.py:736 +#: admin/models.py:749 msgid "target" msgstr "cible" -#: admin/models.py:737 +#: admin/models.py:750 msgid "The domain this alias points to" msgstr "Le domaine vers lequel cet alias pointe" -#: admin/models.py:741 admin/models.py:1021 +#: admin/models.py:754 admin/models.py:1046 msgid "Check to activate this alias" msgstr "Cocher pour activer cet alias" -#: admin/models.py:788 +#: admin/models.py:801 #, python-format msgid "Unknown domain %s" msgstr "Domain %s inconnu" -#: admin/models.py:805 admin/models.py:1006 +#: admin/models.py:818 admin/models.py:1031 msgid "address" msgstr "Adresse" -#: admin/models.py:806 +#: admin/models.py:819 msgid "Mailbox address (without the @domain.tld part)" msgstr "Adresse de la boite aux lettres (sans la partie @domain.tld)" -#: admin/models.py:852 +#: admin/models.py:877 #, python-format msgid "Failed to retrieve mailbox location (%s)" msgstr "Impossible de récuperer l'emplacement de la boite (%s)" -#: admin/models.py:868 -#, python-format -msgid "Failed to rename mailbox: %s" -msgstr "Impossible de renommer la boite : %s" - -#: admin/models.py:894 -#, python-format -msgid "Failed to remove mailbox: %s" -msgstr "Impossible de supprimer la boite : %s" - -#: admin/models.py:909 +#: admin/models.py:921 #, python-format msgid "Quota is greater than the allowed domain's limit (%dM)" msgstr "Le quota est supérieur à la limité autorisée pour le domaine (%dM)" -#: admin/models.py:914 +#: admin/models.py:926 msgid "A quota is required" msgstr "Un quota est requis" -#: admin/models.py:1007 +#: admin/models.py:1032 msgid "" "The alias address (without the domain part). For a 'catch-all' address, just " "enter an * character." @@ -600,57 +607,57 @@ msgstr "" "L'adresse de l'alias (sans la partie domaine). Pour une adresse 'attrape-" "tout', entrer juste un caractère *." -#: admin/models.py:1011 +#: admin/models.py:1036 msgid "mailboxes" msgstr "Boites aux lettres" -#: admin/models.py:1012 +#: admin/models.py:1037 msgid "The mailboxes this alias points to" msgstr "Les boites aux lettres sur lesquelles pointe cet alias" -#: admin/models.py:1016 +#: admin/models.py:1041 msgid "The aliases this alias points to" msgstr "Les alias vers lesquels pointe cet alias" -#: admin/models.py:1064 +#: admin/models.py:1089 msgid "distribution list" msgstr "liste de distribution" -#: admin/models.py:1065 +#: admin/models.py:1090 msgid "forward" msgstr "transfert" -#: admin/models.py:1066 +#: admin/models.py:1091 msgid "alias" msgstr "alias" -#: admin/models.py:1142 +#: admin/models.py:1170 #, python-format msgid "Invalid line: %s" msgstr "Ligne invalide : %s" -#: admin/models.py:1167 +#: admin/models.py:1175 #, python-format -msgid "Mailbox %s does not exist" -msgstr "La boite %s n'existe pas" +msgid "Domain '%s' does not exist" +msgstr "Domain '%s' inexistant" -#: admin/models.py:1182 +#: admin/models.py:1218 msgid "Check to enable this extension" msgstr "Cocher pour activer cette extension" -#: admin/models.py:1282 +#: admin/models.py:1318 msgid "added" msgstr "ajouté" -#: admin/models.py:1285 +#: admin/models.py:1321 msgid "modified" msgstr "modifié" -#: admin/models.py:1288 +#: admin/models.py:1324 msgid "deleted" msgstr "Supprimé" -#: admin/models.py:1290 +#: admin/models.py:1326 #, python-format msgid "%(object)s '%(name)s' %(action)s by user %(user)s" msgstr "%(object)s '%(name)s' %(action)s par l'utilisateur %(user)s" @@ -660,7 +667,7 @@ msgid "Edit domain" msgstr "Editer le domaine" #: admin/tables.py:21 admin/templates/admin/identities_table.html:8 -#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:79 +#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:83 #: extensions/sievefilters/templates/sievefilters/filter.html:17 #: extensions/sievefilters/templates/sievefilters/guieditor.html:5 #: extensions/webmail/templatetags/webextras.py:97 @@ -675,143 +682,143 @@ msgstr "Version" msgid "Description" msgstr "Description" -#: admin/views.py:87 +#: admin/views.py:88 msgid "New domain" msgstr "Nouveau domaine" -#: admin/views.py:88 admin/views.py:97 admin/views.py:225 admin/views.py:438 -#: admin/views.py:445 extensions/sievefilters/views.py:120 -#: extensions/sievefilters/views.py:187 extensions/webmail/views.py:131 +#: admin/views.py:89 admin/views.py:98 admin/views.py:228 admin/views.py:444 +#: admin/views.py:451 extensions/sievefilters/views.py:129 +#: extensions/sievefilters/views.py:198 extensions/webmail/views.py:136 msgid "Create" msgstr "Créer" -#: admin/views.py:94 admin/views.py:442 +#: admin/views.py:95 admin/views.py:448 msgid "Next" msgstr "Suivante" -#: admin/views.py:96 +#: admin/views.py:97 msgid "Options" msgstr "Options" -#: admin/views.py:98 admin/views.py:446 +#: admin/views.py:99 admin/views.py:452 msgid "Previous" msgstr "Précédente" -#: admin/views.py:111 +#: admin/views.py:112 msgid "Domain created" msgstr "Domaine créé" -#: admin/views.py:144 admin/views.py:282 admin/views.py:492 +#: admin/views.py:146 admin/views.py:285 admin/views.py:498 #: extensions/postfix_autoreply/templates/postfix_autoreply/autoreply.html:9 -#: extensions/sievefilters/views.py:139 extensions/webmail/views.py:162 +#: extensions/sievefilters/views.py:148 extensions/webmail/views.py:168 #: userprefs/templates/userprefs/forward.html:8 #: userprefs/templates/userprefs/profile.html:8 msgid "Update" msgstr "Mettre à jour" -#: admin/views.py:160 +#: admin/views.py:162 msgid "Domain modified" msgstr "Domaine modifié" -#: admin/views.py:186 +#: admin/views.py:189 msgid "You can't delete your own domain" msgstr "Vous ne pouvez pas supprimer votre propre domaine" -#: admin/views.py:189 +#: admin/views.py:192 msgid "Domain deleted" msgid_plural "Domains deleted" msgstr[0] "Domaine supprimé" msgstr[1] "Domaines supprimés" -#: admin/views.py:204 +#: admin/views.py:207 msgid "Alias with this name already exists" msgstr "Un alias de ce nom existe déjà" -#: admin/views.py:247 +#: admin/views.py:250 msgid "New distribution list" msgstr "Nouvelle liste de distribution" -#: admin/views.py:248 +#: admin/views.py:251 msgid "Distribution list created" msgstr "Liste de distribution créée" -#: admin/views.py:257 +#: admin/views.py:260 msgid "New alias" msgstr "Nouvel alias" -#: admin/views.py:258 +#: admin/views.py:261 msgid "Alias created" msgstr "Alias créé" -#: admin/views.py:267 +#: admin/views.py:270 msgid "New forward" msgstr "Nouveau transfert" -#: admin/views.py:268 +#: admin/views.py:271 msgid "Forward created" msgstr "Transfert créé" -#: admin/views.py:286 +#: admin/views.py:289 msgid "Distribution list modified" msgstr "Liste de distribution modifiée" -#: admin/views.py:288 +#: admin/views.py:291 msgid "Forward modified" msgstr "Transfert modifié" -#: admin/views.py:290 +#: admin/views.py:293 msgid "Alias modified" msgstr "Alias modifié" -#: admin/views.py:403 admin/views.py:541 admin/views.py:546 -#: extensions/amavis/views.py:195 extensions/amavis/views.py:201 -#: extensions/amavis/views.py:234 extensions/amavis/views.py:238 -#: extensions/amavis/views.py:240 extensions/webmail/views.py:36 -#: extensions/webmail/views.py:64 extensions/webmail/views.py:77 -#: extensions/webmail/views.py:93 extensions/webmail/views.py:109 -#: extensions/webmail/views.py:193 extensions/webmail/views.py:419 -#: extensions/webmail/views.py:430 extensions/webmail/views.py:457 +#: admin/views.py:402 admin/views.py:545 admin/views.py:550 +#: extensions/amavis/views.py:204 extensions/amavis/views.py:210 +#: extensions/amavis/views.py:243 extensions/amavis/views.py:247 +#: extensions/amavis/views.py:249 extensions/webmail/views.py:41 +#: extensions/webmail/views.py:68 extensions/webmail/views.py:81 +#: extensions/webmail/views.py:98 extensions/webmail/views.py:114 +#: extensions/webmail/views.py:200 extensions/webmail/views.py:427 +#: extensions/webmail/views.py:438 extensions/webmail/views.py:465 #: lib/formutils.py:32 lib/formutils.py:37 msgid "Invalid request" msgstr "Requête invalide" -#: admin/views.py:435 +#: admin/views.py:441 msgid "New account" msgstr "Nouveau compte" -#: admin/views.py:459 +#: admin/views.py:465 msgid "Account created" msgstr "Compte créé" -#: admin/views.py:507 +#: admin/views.py:513 msgid "Account updated" msgstr "Compte mis à jour" -#: admin/views.py:531 +#: admin/views.py:535 msgid "Account deleted" msgid_plural "Accounts deleted" msgstr[0] "Compte supprimé" msgstr[1] "Comptes supprimés" -#: admin/views.py:586 +#: admin/views.py:590 msgid "Parameters saved" msgstr "Paramètres enregistrés" -#: admin/views.py:632 +#: admin/views.py:636 msgid "Modifications applied." msgstr "Modifications appliquées." -#: admin/views.py:740 +#: admin/views.py:743 #, python-format msgid "Object already exists: %s" msgstr "L'objet existe déjà : %s" -#: admin/views.py:742 +#: admin/views.py:745 #, python-format msgid "%d objects imported successfully" msgstr "%d objets importés avec succès" -#: admin/views.py:760 +#: admin/views.py:763 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
                \n" @@ -839,25 +846,25 @@ msgstr "" "\n" "

                Vous pouvez utiliser un caractère différent comme séparateur.

                \n" -#: admin/views.py:772 +#: admin/views.py:775 msgid "Import identities" msgstr "Importer des identités" -#: admin/views.py:773 admin/views.py:843 admin/templatetags/admin_extras.py:87 +#: admin/views.py:776 admin/views.py:846 admin/templatetags/admin_extras.py:87 #: admin/templatetags/admin_extras.py:144 msgid "Import" msgstr "Importer" -#: admin/views.py:803 +#: admin/views.py:806 msgid "Export identities" msgstr "Export d'identités" -#: admin/views.py:804 admin/views.py:860 admin/templatetags/admin_extras.py:93 +#: admin/views.py:807 admin/views.py:863 admin/templatetags/admin_extras.py:93 #: admin/templatetags/admin_extras.py:150 msgid "Export" msgstr "Exporter" -#: admin/views.py:832 +#: admin/views.py:835 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
                  \n" @@ -877,11 +884,11 @@ msgstr "" "l'une des valeurs précédentes.

                  \n" "

                  Vous pouvez utiliser un caractère différent comme séparateur.

                  \n" -#: admin/views.py:842 +#: admin/views.py:845 msgid "Import domains" msgstr "Importer des domaines" -#: admin/views.py:859 +#: admin/views.py:862 msgid "Export domains" msgstr "Export de domaines" @@ -954,7 +961,7 @@ msgid "Tags" msgstr "Tags" #: admin/templates/admin/importform.html:5 -#: admin/templatetags/admin_extras.py:305 +#: admin/templatetags/admin_extras.py:290 msgid "Help" msgstr "Aide" @@ -1001,7 +1008,7 @@ msgid "Previously on Modoboa..." msgstr "Précédemment dans Modoboa..." #: admin/templates/admin/logs.html:6 extensions/amavis/sql_listing.py:25 -#: extensions/webmail/lib.py:37 extensions/webmail/lib.py:406 +#: extensions/webmail/lib.py:38 extensions/webmail/lib.py:411 msgid "Date" msgstr "Date" @@ -1104,34 +1111,21 @@ msgid "View the domain's identities" msgstr "Voir les identités du domaine" #: admin/templatetags/admin_extras.py:178 -msgid "Delete the domain" -msgstr "Supprimer ce domaine" - #: admin/templatetags/admin_extras.py:194 -msgid "Delete this account" -msgstr "Supprimer ce compte" +#: admin/templatetags/admin_extras.py:201 +#, python-format +msgid "Delete %s?" +msgstr "Supprimer %s ?" -#: admin/templatetags/admin_extras.py:202 -msgid "Delete this distribution list" -msgstr "Supprimer cette liste de distribution" - -#: admin/templatetags/admin_extras.py:209 -msgid "Delete this forward" -msgstr "Supprimer ce transfert" - -#: admin/templatetags/admin_extras.py:216 -msgid "Delete this alias" -msgstr "Supprimer cet alias" - -#: admin/templatetags/admin_extras.py:238 +#: admin/templatetags/admin_extras.py:223 msgid "Remove this permission" msgstr "Supprimer cette permission" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "Yes" msgstr "Oui" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "No" msgstr "Non" @@ -1140,13 +1134,13 @@ msgstr "Non" msgid "User '%s' successfully logged in" msgstr "Utiliseur '%s' connecté avec succès" -#: auth/views.py:41 +#: auth/views.py:44 msgid "Your username and password didn't match. Please try again." msgstr "" "Votre nom d'utilisateur et mot de passe ne correspondent pas. Veuillez " "réessayer." -#: auth/views.py:64 +#: auth/views.py:67 #, python-format msgid "User '%s' logged out" msgstr "Utilisateur '%s' déconnecté" @@ -1206,16 +1200,16 @@ msgstr "Interface simplifiée pour la gestion d'amavis" msgid "Quarantine" msgstr "Quarantaine" -#: extensions/amavis/__init__.py:127 +#: extensions/amavis/__init__.py:129 msgid "pending requests" msgstr "requêtes en attente" -#: extensions/amavis/__init__.py:144 +#: extensions/amavis/__init__.py:149 #, python-format msgid "%d pending requests" msgstr "%d requêtes en attente" -#: extensions/amavis/__init__.py:156 +#: extensions/amavis/__init__.py:161 msgid "Content filter" msgstr "Filtrage de contenu" @@ -1332,12 +1326,12 @@ msgid "Virus filter" msgstr "Filtrage des virus" #: extensions/amavis/models.py:94 extensions/amavis/models.py:102 -#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:268 +#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:281 msgid "yes" msgstr "oui" #: extensions/amavis/models.py:95 extensions/amavis/models.py:103 -#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:272 +#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:285 msgid "no" msgstr "non" @@ -1385,13 +1379,13 @@ msgstr "" "Modifier le sujet du spam en utilisant le texte spécifié. Choisir 'défaut' " "pour utiliser les paramètres globaux." -#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:36 +#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:37 msgid "From" msgstr "De" #: extensions/amavis/sql_listing.py:24 extensions/sievefilters/forms.py:68 -#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:35 -#: extensions/webmail/lib.py:404 templates/common/email_searchbar.html:6 +#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:36 +#: extensions/webmail/lib.py:409 templates/common/email_searchbar.html:6 msgid "Subject" msgstr "Sujet" @@ -1401,37 +1395,37 @@ msgstr "Sujet" msgid "To" msgstr "A" -#: extensions/amavis/views.py:34 +#: extensions/amavis/views.py:43 msgid "Empty quarantine" msgstr "Quarantaine vide" -#: extensions/amavis/views.py:202 +#: extensions/amavis/views.py:211 msgid "Message deleted" msgstr "Message supprimé" -#: extensions/amavis/views.py:223 +#: extensions/amavis/views.py:232 #, python-format msgid "%(count)d message deleted successfully" msgid_plural "%(count)d messages deleted successfully" msgstr[0] "%(count)d message supprimé correctement" msgstr[1] "%(count)d messages supprimés correctement" -#: extensions/amavis/views.py:243 +#: extensions/amavis/views.py:252 msgid "Request sent" msgstr "Requête envoyée" -#: extensions/amavis/views.py:249 +#: extensions/amavis/views.py:258 msgid "Message released" msgstr "Message relâché" -#: extensions/amavis/views.py:271 +#: extensions/amavis/views.py:280 #, python-format msgid "%(count)d request sent" msgid_plural "%(count)d requests sent" msgstr[0] "%(count)d requête envoyée" msgstr[1] "%(count)d requêtes envoyées" -#: extensions/amavis/views.py:295 +#: extensions/amavis/views.py:304 #, python-format msgid "%(count)d message released successfully" msgid_plural "%(count)d messages released successfully" @@ -1558,7 +1552,7 @@ msgstr "Limites" msgid "Reseller" msgstr "Revendeur" -#: extensions/limits/__init__.py:96 +#: extensions/limits/__init__.py:94 msgid "Resources" msgstr "Ressources" @@ -1679,23 +1673,23 @@ msgstr "Activer votre réponse automatique jusqu'à cette date" msgid "This date is over" msgstr "Cette date est dépassée" -#: extensions/postfix_autoreply/models.py:15 +#: extensions/postfix_autoreply/models.py:19 msgid "subject" msgstr "sujet" -#: extensions/postfix_autoreply/models.py:16 +#: extensions/postfix_autoreply/models.py:20 msgid "The subject that will appear in sent emails" msgstr "Le sujet qui apparaitra dans les emails envoyés" -#: extensions/postfix_autoreply/models.py:17 +#: extensions/postfix_autoreply/models.py:23 msgid "content" msgstr "contenu" -#: extensions/postfix_autoreply/models.py:18 +#: extensions/postfix_autoreply/models.py:24 msgid "The content that will appear in sent emails" msgstr "Le contenu qui apparaitra dans les emails envoyés" -#: extensions/postfix_autoreply/models.py:20 +#: extensions/postfix_autoreply/models.py:28 msgid "Activate/Deactivate your auto reply" msgstr "Activer/Désactiver votre réponse automatique" @@ -1830,53 +1824,53 @@ msgstr "" msgid "Not enough space on server" msgstr "Pas assez d'espace sur le serveur" -#: extensions/sievefilters/views.py:64 +#: extensions/sievefilters/views.py:68 msgid "Failed to retrieve filters set" msgstr "Impossible de récuperer le jeu de filtres" -#: extensions/sievefilters/views.py:117 +#: extensions/sievefilters/views.py:126 #: extensions/sievefilters/templatetags/sfilters_tags.py:33 msgid "New filter" msgstr "Nouveau filtre" -#: extensions/sievefilters/views.py:124 +#: extensions/sievefilters/views.py:133 msgid "Filter created" msgstr "Filtre créé" -#: extensions/sievefilters/views.py:136 +#: extensions/sievefilters/views.py:145 #: extensions/sievefilters/templatetags/sfilters_tags.py:77 msgid "Edit filter" msgstr "Editer le filtre" -#: extensions/sievefilters/views.py:145 +#: extensions/sievefilters/views.py:154 msgid "Filter modified" msgstr "Filtre modifié" -#: extensions/sievefilters/views.py:165 +#: extensions/sievefilters/views.py:176 msgid "Filter removed" msgstr "Filtre supprimé" -#: extensions/sievefilters/views.py:166 +#: extensions/sievefilters/views.py:177 msgid "Failed to remove filter" msgstr "Impossible de supprimer le filtre" -#: extensions/sievefilters/views.py:180 +#: extensions/sievefilters/views.py:191 msgid "Filters set saved" msgstr "Jeu de filtres sauvegardé" -#: extensions/sievefilters/views.py:185 +#: extensions/sievefilters/views.py:196 msgid "Create a new filters set" msgstr "Créer un nouveau jeu de filtres" -#: extensions/sievefilters/views.py:208 +#: extensions/sievefilters/views.py:219 msgid "Filters set created" msgstr "Jeu de filtres créé" -#: extensions/sievefilters/views.py:229 +#: extensions/sievefilters/views.py:240 msgid "Filters set deleted" msgstr "Jeu de filtres supprimé" -#: extensions/sievefilters/views.py:241 +#: extensions/sievefilters/views.py:252 msgid "Filters set activated" msgstr "Jeu de filtres activé" @@ -1892,15 +1886,15 @@ msgstr "Actif" msgid "No filter defined yet" msgstr "Aucun filtre défini." -#: extensions/sievefilters/templates/sievefilters/index.html:55 +#: extensions/sievefilters/templates/sievefilters/index.html:56 msgid "Filter sets" msgstr "Jeux de filtres" -#: extensions/sievefilters/templates/sievefilters/index.html:59 +#: extensions/sievefilters/templates/sievefilters/index.html:60 msgid "active" msgstr "actif" -#: extensions/sievefilters/templates/sievefilters/index.html:73 +#: extensions/sievefilters/templates/sievefilters/index.html:74 msgid "" "No filters set defined yet. You must create one in order to define filters." msgstr "" @@ -2218,84 +2212,88 @@ msgstr "Réponse du serveur" msgid "Cci" msgstr "Cci" -#: extensions/webmail/imaputils.py:259 +#: extensions/webmail/imaputils.py:237 +msgid "Failed to retrieve hierarchy delimiter" +msgstr "Impossible de récuperer le séparateur de hiérarchie" + +#: extensions/webmail/imaputils.py:278 #, python-format msgid "Connection to IMAP server failed: %s" msgstr "La connexion au serveur IMAP a échoué : %s" -#: extensions/webmail/lib.py:353 +#: extensions/webmail/lib.py:358 msgid "wrote:" msgstr "a écrit :" -#: extensions/webmail/lib.py:418 extensions/webmail/lib.py:422 +#: extensions/webmail/lib.py:423 extensions/webmail/lib.py:427 msgid "Original message" msgstr "Message original" -#: extensions/webmail/views.py:81 +#: extensions/webmail/views.py:86 #, python-format msgid "%(count)d message deleted" msgid_plural "%(count)d messages deleted" msgstr[0] "%(count)d message supprimé" msgstr[1] "%(count)d messages supprimés" -#: extensions/webmail/views.py:98 +#: extensions/webmail/views.py:103 msgid "Unknown action" msgstr "Action inconnue" -#: extensions/webmail/views.py:111 lib/email_listing.py:137 +#: extensions/webmail/views.py:116 lib/email_listing.py:137 msgid "Empty mailbox" msgstr "Boite aux lettre vide" -#: extensions/webmail/views.py:128 -#: extensions/webmail/templatetags/webextras.py:169 +#: extensions/webmail/views.py:133 +#: extensions/webmail/templatetags/webextras.py:170 msgid "Create a new mailbox" msgstr "Créer une nouvelle boite aux lettres" -#: extensions/webmail/views.py:143 +#: extensions/webmail/views.py:149 msgid "Mailbox created" msgstr "Boite aux lettres créée" -#: extensions/webmail/views.py:159 +#: extensions/webmail/views.py:165 msgid "Edit mailbox" msgstr "Editer la boite aux lettres" -#: extensions/webmail/views.py:173 +#: extensions/webmail/views.py:180 msgid "Mailbox updated" msgstr "Boite aux lettres mise à jour" -#: extensions/webmail/views.py:207 extensions/webmail/views.py:388 -#: extensions/webmail/views.py:497 +#: extensions/webmail/views.py:214 extensions/webmail/views.py:396 +#: extensions/webmail/views.py:505 msgid "Bad request" msgstr "Mauvaise requête" -#: extensions/webmail/views.py:238 +#: extensions/webmail/views.py:246 msgid "Failed to save attachment: " msgstr "Impossible d'enregistrer la pièce jointe : " -#: extensions/webmail/views.py:241 +#: extensions/webmail/views.py:249 #, python-format msgid "Attachment is too big (limit: %s)" msgstr "Pièce jointe trop grosse (limite : %s)" -#: extensions/webmail/views.py:247 +#: extensions/webmail/views.py:255 #: extensions/webmail/templates/webmail/compose.html:15 #: extensions/webmail/templates/webmail/headers.html:4 msgid "Attachments" msgstr "Pièces jointes" -#: extensions/webmail/views.py:263 +#: extensions/webmail/views.py:271 msgid "Bad query" msgstr "Mauvaise requête" -#: extensions/webmail/views.py:273 +#: extensions/webmail/views.py:281 msgid "Failed to remove attachment: " msgstr "Impossible de supprimer la pièce jointe :" -#: extensions/webmail/views.py:278 +#: extensions/webmail/views.py:286 msgid "Unknown attachment" msgstr "Pièce jointe inconnue" -#: extensions/webmail/views.py:493 +#: extensions/webmail/views.py:501 msgid "Undefined action" msgstr "Action indéfinie" @@ -2326,7 +2324,7 @@ msgstr[1] "%(counter)s fichiers" msgid "Parent mailbox" msgstr "Boite aux lettres parente" -#: extensions/webmail/templates/webmail/index.html:36 +#: extensions/webmail/templates/webmail/index.html:38 msgid "Mailbox quota" msgstr "Quota de la boite aux lettres" @@ -2388,15 +2386,15 @@ msgstr "Comme non lus" msgid "Compress folder" msgstr "Compresser ce dossier" -#: extensions/webmail/templatetags/webextras.py:109 +#: extensions/webmail/templatetags/webextras.py:110 msgid "Empty folder" msgstr "Vider ce dossier" -#: extensions/webmail/templatetags/webextras.py:177 +#: extensions/webmail/templatetags/webextras.py:178 msgid "Edit the selected mailbox" msgstr "Editer la boite aux lettres sélectionnée" -#: extensions/webmail/templatetags/webextras.py:182 +#: extensions/webmail/templatetags/webextras.py:183 msgid "Remove the selected mailbox" msgstr "Supprimer la boite aux lettres sélectionnée" @@ -2450,7 +2448,7 @@ msgstr "La page demandée n'existe pas." msgid "An internal error occured." msgstr "Une erreur interne est survenue" -#: templates/nlayout.html:56 +#: templates/nlayout.html:62 msgid "Powered by Modoboa" msgstr "Propulsé par Modoboa" @@ -2484,11 +2482,11 @@ msgstr "Fermer" msgid "Welcome to Modoboa" msgstr "Bienvenue dans Modoboa" -#: templates/registration/login.html:33 +#: templates/registration/login.html:34 msgid "Remember me" msgstr "Se souvenir de moi" -#: templates/registration/login.html:35 +#: templates/registration/login.html:36 msgid "Log in" msgstr "Se connecter" @@ -2504,7 +2502,7 @@ msgstr "Paramètres par utilisateur" msgid "Prefered language" msgstr "Langage préféré" -#: userprefs/app_settings.py:26 +#: userprefs/app_settings.py:27 msgid "Prefered language to display pages" msgstr "Langage préféré pour afficher les pages" diff --git a/modoboa/locale/it/LC_MESSAGES/django.po b/modoboa/locale/it/LC_MESSAGES/django.po index f7bc75730..36373ed17 100644 --- a/modoboa/locale/it/LC_MESSAGES/django.po +++ b/modoboa/locale/it/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-06-27 17:24+0200\n" +"POT-Creation-Date: 2013-09-20 22:30+0200\n" "PO-Revision-Date: 2013-06-28 17:03+0200\n" "Last-Translator: Giancarlo Gaifas \n" "Language-Team: ITALIANO \n" @@ -25,8 +25,8 @@ msgstr "Interfaccia amministrativa" msgid "Web based console to manage domains, accounts and aliases" msgstr "Interfaccia web per l'amministrazione di domini, account e alias" -#: admin/__init__.py:16 admin/forms.py:180 admin/forms.py:615 -#: admin/views.py:93 admin/views.py:453 +#: admin/__init__.py:16 admin/forms.py:211 admin/forms.py:652 +#: admin/views.py:94 admin/views.py:447 #: extensions/postfix_autoreply/app_settings.py:11 #: extensions/sievefilters/app_settings.py:50 #: extensions/stats/app_settings.py:11 extensions/webmail/app_settings.py:11 @@ -56,7 +56,8 @@ msgstr "Schema password predefinito" #: admin/app_settings.py:50 msgid "Scheme used to crypt mailbox passwords" -msgstr "Schema utilizzato per la criptazione delle password delle caselle di posta" +msgstr "" +"Schema utilizzato per la criptazione delle password delle caselle di posta" #: admin/app_settings.py:54 msgid "Secret key" @@ -120,7 +121,9 @@ msgstr "collega DN" msgid "" "The distinguished name to use when binding to the LDAP server. Leave empty " "for an anonymous bind" -msgstr "Nome particolare da usare quando ci si collega al server LDAP. Lasciare vuoto per un collegamento anonimo" +msgstr "" +"Nome particolare da usare quando ci si collega al server LDAP. Lasciare " +"vuoto per un collegamento anonimo" #: admin/app_settings.py:97 msgid "Bind password" @@ -128,7 +131,9 @@ msgstr "Password del collegamento" #: admin/app_settings.py:99 msgid "The password to use when binding to the LDAP server (with 'Bind DN')" -msgstr "La password da utilizzare quando ci si collega al server LDAP (con 'Collega DN')" +msgstr "" +"La password da utilizzare quando ci si collega al server LDAP (con 'Collega " +"DN')" #: admin/app_settings.py:105 msgid "Search base" @@ -146,7 +151,9 @@ msgstr "Filtro ricerca" msgid "" "An optional filter string (e.g. '(objectClass=person)'). In order to be " "valid, it must be enclosed in parentheses." -msgstr "Stringa di filtraggio opzionale (p.es '(objectClass=person)'). Per essere valida deve essere racchiusa tra parentesi." +msgstr "" +"Stringa di filtraggio opzionale (p.es '(objectClass=person)'). Per essere " +"valida deve essere racchiusa tra parentesi." #: admin/app_settings.py:119 msgid "User DN template" @@ -157,7 +164,9 @@ msgstr "Modello DN dell'utente" msgid "" "The template used to construct a user's DN. It should contain one " "placeholder (ie. %(user)s)" -msgstr "Il modello utilizzato per comporre un DN dell'utente. Deve contenere un segnaposto (p.es. %(user)s)" +msgstr "" +"Il modello utilizzato per comporre un DN dell'utente. Deve contenere un " +"segnaposto (p.es. %(user)s)" #: admin/app_settings.py:126 msgid "Password attribute" @@ -190,7 +199,9 @@ msgstr "Gestione delle caselle di posta nel filsystem" msgid "" "Rename or remove mailboxes on the filesystem when they get renamed or " "removed within Modoboa" -msgstr "Rinomina o rimuovi le caselle di posta nel filsystem quando sono rinominate o rimosse in Modoboa" +msgstr "" +"Rinomina o rimuovi le caselle di posta nel filsystem quando sono rinominate " +"o rimosse in Modoboa" #: admin/app_settings.py:146 msgid "Mailboxes ower" @@ -206,7 +217,8 @@ msgstr "Rimozione automatica dell'account" #: admin/app_settings.py:154 msgid "When a mailbox is removed, also remove the associated account" -msgstr "Quando una casella postale viene rimossa rimuovi anche l'account associato" +msgstr "" +"Quando una casella postale viene rimossa rimuovi anche l'account associato" #: admin/app_settings.py:157 admin/templates/admin/editdomainform.html:7 msgid "Miscellaneous" @@ -234,43 +246,51 @@ msgstr "Reindirizzamento principale predefinito" #: admin/app_settings.py:175 msgid "The default redirection used when no application is specified" -msgstr "Redirezione predefinita utilizzata quando non è specificata alcuna applicazione" +msgstr "" +"Redirezione predefinita utilizzata quando non è specificata alcuna " +"applicazione" -#: admin/app_settings.py:215 +#: admin/app_settings.py:213 +msgid "Key must be either 16, 24, or 32 bytes long" +msgstr "" + +#: admin/app_settings.py:222 msgid "Invalid syntax" msgstr "Sintassi errata" -#: admin/app_settings.py:238 +#: admin/app_settings.py:245 msgid "This field is required" msgstr "Questo campo è obbligatorio" -#: admin/forms.py:17 admin/forms.py:460 admin/tables.py:18 +#: admin/forms.py:20 admin/forms.py:497 admin/tables.py:18 msgid "Alias(es)" msgstr "Alias" -#: admin/forms.py:19 +#: admin/forms.py:22 msgid "" "Alias(es) of this domain. Indicate only one name per input, press ENTER to " "add a new input." -msgstr "Alias per questo dominio. Inserire un solo nome alla volta, premere INVIO per aggiungere un nuovo elemento" +msgstr "" +"Alias per questo dominio. Inserire un solo nome alla volta, premere INVIO " +"per aggiungere un nuovo elemento" -#: admin/forms.py:56 +#: admin/forms.py:59 msgid "An alias with this name already exists" msgstr "Esiste già un alias con questo nome" -#: admin/forms.py:70 +#: admin/forms.py:73 msgid "A domain with this name already exists" msgstr "Esiste già un dominio con questo nome" -#: admin/forms.py:115 +#: admin/forms.py:146 msgid "Create a domain administrator" msgstr "Crea un amministratore di dominio" -#: admin/forms.py:117 +#: admin/forms.py:148 msgid "Automatically create an administrator for this domain" msgstr "Crea automaticamente un amministratore per questo dominio" -#: admin/forms.py:121 admin/tables.py:12 admin/tables.py:47 +#: admin/forms.py:152 admin/tables.py:12 admin/tables.py:47 #: admin/templates/admin/editdomainform.html:13 #: admin/templates/admin/identities_table.html:5 #: admin/templates/admin/information.html:8 @@ -279,348 +299,362 @@ msgstr "Crea automaticamente un amministratore per questo dominio" msgid "Name" msgstr "Nome" -#: admin/forms.py:123 +#: admin/forms.py:154 msgid "" "The administrator's name. Don't include the domain's name here, it will be " "automatically appended." -msgstr "Il nome dell'amministratore. Non includere il nome del dominio, verrà aggiunto automaticamente." +msgstr "" +"Il nome dell'amministratore. Non includere il nome del dominio, verrà " +"aggiunto automaticamente." -#: admin/forms.py:129 +#: admin/forms.py:160 msgid "Create aliases" msgstr "Crea alias" -#: admin/forms.py:131 +#: admin/forms.py:162 msgid "Automatically create standard aliases for this domain" msgstr "Crea automaticamente gli alias standard per questo dominio" -#: admin/forms.py:144 +#: admin/forms.py:175 msgid "Invalid format" msgstr "Formato non valido" -#: admin/forms.py:156 +#: admin/forms.py:187 #, python-format msgid "User '%s' already exists" msgstr "L'utente '%s' esiste già" -#: admin/forms.py:204 +#: admin/forms.py:235 msgid "Email address" msgstr "Indirizzo email" -#: admin/forms.py:205 +#: admin/forms.py:236 msgid "" "The distribution list address. Use the '*' character to create a 'catchall' " "address (ex: *@domain.tld)." msgstr "Elenco degli indirizzi di smistamento" -#: admin/forms.py:208 +#: admin/forms.py:239 msgid "Recipients" msgstr "Destinatari" -#: admin/forms.py:209 +#: admin/forms.py:240 msgid "" "Mailbox(es) this alias will point to. Indicate only one address per input, " "press ENTER to add a new input." -msgstr "Casella(e) di posta a cui l'alias punterà. Inserire un solo indirizzo alla volta, premere INVIO per aggiungere un nuovo elemento." +msgstr "" +"Casella(e) di posta a cui l'alias punterà. Inserire un solo indirizzo alla " +"volta, premere INVIO per aggiungere un nuovo elemento." -#: admin/forms.py:247 admin/forms.py:505 admin/forms.py:531 +#: admin/forms.py:278 admin/forms.py:542 admin/forms.py:568 msgid "Domain does not exist" msgstr "Il dominio non esiste" -#: admin/forms.py:249 +#: admin/forms.py:280 msgid "You don't have access to this domain" msgstr "Non hai accesso a questo dominio" -#: admin/forms.py:269 +#: admin/forms.py:300 msgid "Invalid mailbox" msgstr "Casella di posta non valida" -#: admin/forms.py:285 admin/models.py:1175 +#: admin/forms.py:316 admin/models.py:1202 #, python-format msgid "Local recipient %s not found" msgstr "Il destinatario locale %s non è stato trovato" -#: admin/forms.py:287 admin/forms.py:293 +#: admin/forms.py:318 admin/forms.py:324 #, python-format msgid "Recipient %s already present" msgstr "Il destinatario %s è già esistente" -#: admin/forms.py:298 +#: admin/forms.py:329 msgid "No recipient defined" msgstr "Non è stato definito un destinatario" -#: admin/forms.py:312 extensions/webmail/forms.py:19 +#: admin/forms.py:343 extensions/webmail/forms.py:19 msgid "Select a file" msgstr "Seleziona un file" -#: admin/forms.py:314 admin/forms.py:342 +#: admin/forms.py:345 admin/forms.py:373 msgid "Separator" msgstr "Separatore" -#: admin/forms.py:317 +#: admin/forms.py:348 msgid "Continue on error" msgstr "Continuare in caso di errore" -#: admin/forms.py:318 +#: admin/forms.py:349 msgid "Don't treat duplicated objects as error" msgstr "Non considerare errore gli oggetti duplicati" -#: admin/forms.py:333 +#: admin/forms.py:364 msgid "Crypt passwords" msgstr "Cripta le password" -#: admin/forms.py:334 +#: admin/forms.py:365 msgid "Check this option if passwords contained in your file are not crypted" -msgstr "Seleziona questa opzione se le password contenute nel file non sono criptate" +msgstr "" +"Seleziona questa opzione se le password contenute nel file non sono criptate" -#: admin/forms.py:340 +#: admin/forms.py:371 msgid "File name" msgstr "Nome del file" -#: admin/forms.py:372 admin/templates/admin/editdomainform.html:13 +#: admin/forms.py:403 admin/templates/admin/editdomainform.html:13 #: auth/forms.py:7 msgid "Username" msgstr "Nome utente" -#: admin/forms.py:374 +#: admin/forms.py:405 msgid "Role" msgstr "Ruolo" -#: admin/forms.py:375 admin/forms.py:402 +#: admin/forms.py:406 admin/forms.py:433 msgid "Choose" msgstr "Scegli" -#: admin/forms.py:376 +#: admin/forms.py:407 msgid "What level of permission this user will have" msgstr "Il livello di permessi che avrà questo utente" -#: admin/forms.py:378 auth/forms.py:11 +#: admin/forms.py:409 auth/forms.py:11 msgid "Password" msgstr "Password" -#: admin/forms.py:380 userprefs/forms.py:18 +#: admin/forms.py:411 userprefs/forms.py:18 msgid "Confirmation" msgstr "Conferma" -#: admin/forms.py:382 +#: admin/forms.py:413 msgid "Enter the same password as above, for verification." -msgstr "Inserisci la medesima password che hai inserito sopra, per la verifica." +msgstr "" +"Inserisci la medesima password che hai inserito sopra, per la verifica." -#: admin/forms.py:393 +#: admin/forms.py:424 msgid "Enabled" msgstr "Abilitato" -#: admin/forms.py:435 +#: admin/forms.py:471 msgid "The two password fields didn't match." msgstr "Le password nei due campi non corrispondono" -#: admin/forms.py:441 +#: admin/forms.py:477 msgid "You can't disable your own account" msgstr "Tu non puoi disabilitare il tuo account" -#: admin/forms.py:451 +#: admin/forms.py:488 msgid "E-mail" msgstr "E-mail" -#: admin/forms.py:453 +#: admin/forms.py:490 msgid "Quota" msgstr "Quota" -#: admin/forms.py:455 +#: admin/forms.py:492 msgid "" "Quota in MB for this mailbox. Define a custom value or use domain's default " "one. Leave empty to define an unlimited value (not allowed for domain " "administrators)." -msgstr "Quota in MB per questo account. Stabilire un valore personalizzato o usare quello predefinito. Lasciare vuoto per non impostare limiti (non consentito per gli amministratori di dominio)." +msgstr "" +"Quota in MB per questo account. Stabilire un valore personalizzato o usare " +"quello predefinito. Lasciare vuoto per non impostare limiti (non consentito " +"per gli amministratori di dominio)." -#: admin/forms.py:462 +#: admin/forms.py:499 msgid "" "Alias(es) of this mailbox. Indicate only one address per input, press ENTER " "to add a new input. Use the '*' character to create a 'catchall' alias (ex: " "*@domain.tld)." -msgstr "Alias per questa casella di posta. Inserire un solo indirizzo alla volta, premere INVIO per aggiungere un nuovo elemento. Utilizzare il carattere '*' per creare un alias 'prenditutto' (p.es.: *@dominio.org)." +msgstr "" +"Alias per questa casella di posta. Inserire un solo indirizzo alla volta, " +"premere INVIO per aggiungere un nuovo elemento. Utilizzare il carattere '*' " +"per creare un alias 'prenditutto' (p.es.: *@dominio.org)." -#: admin/forms.py:513 +#: admin/forms.py:550 #, python-format msgid "Mailbox %s already exists" msgstr "La casella di posta %s esiste già" -#: admin/forms.py:573 +#: admin/forms.py:610 msgid "Domain(s)" msgstr "Dominio(i)" -#: admin/forms.py:575 +#: admin/forms.py:612 msgid "Domain(s) that user administrates" msgstr "Dominio(i) amministrato(i) dall'utente" -#: admin/forms.py:617 admin/views.py:456 +#: admin/forms.py:654 admin/views.py:450 msgid "Mail" msgstr "Posta" -#: admin/forms.py:619 +#: admin/forms.py:656 msgid "Permissions" msgstr "Permessi" -#: admin/models.py:78 +#: admin/models.py:80 msgid "You can't delete your own account" msgstr "Non puoi cancellare il tuo account" -#: admin/models.py:159 +#: admin/models.py:161 msgid "Failed to update password: LDAP module not installed" msgstr "Aggiornamento della password fallito: il modulo LDAP non è installato" -#: admin/models.py:165 +#: admin/models.py:167 #, python-format msgid "Failed to update password: %s" msgstr "Aggiornamento della password fallito: %s" -#: admin/models.py:192 +#: admin/models.py:194 msgid "account" msgstr "account" -#: admin/models.py:494 admin/models.py:720 admin/models.py:782 +#: admin/models.py:496 admin/models.py:733 admin/models.py:795 msgid "Invalid line" msgstr "Riga non valida" -#: admin/models.py:498 +#: admin/models.py:500 msgid "You can't import an account with a role greater than yours" msgstr "Non puoi importare un account con un ruolo superiore al tuo" -#: admin/models.py:518 +#: admin/models.py:506 +#, python-format +msgid "The simple user '%s' must have a valid email address" +msgstr "" + +#: admin/models.py:510 +#, python-format +msgid "username and email fields must not differ for '%s'" +msgstr "" + +#: admin/models.py:534 #, python-format msgid "Account import failed (%s): domain does not exist" msgstr "Importazione dell'account fallito (%s): il dominio non esiste" -#: admin/models.py:607 admin/models.py:733 +#: admin/models.py:624 admin/models.py:746 msgid "name" msgstr "nome" -#: admin/models.py:608 +#: admin/models.py:625 msgid "The domain name" msgstr "Il nome del dominio" -#: admin/models.py:610 +#: admin/models.py:627 msgid "Default quota in MB applied to mailboxes" msgstr "Quota in MB predefinita applicata alle caselle di posta" -#: admin/models.py:613 admin/models.py:740 admin/models.py:1020 -#: admin/models.py:1190 extensions/postfix_autoreply/models.py:19 +#: admin/models.py:630 admin/models.py:753 admin/models.py:1045 +#: admin/models.py:1217 extensions/postfix_autoreply/models.py:27 msgid "enabled" msgstr "Attivato" -#: admin/models.py:614 +#: admin/models.py:631 msgid "Check to activate this domain" msgstr "Seleziona per attivare questo dominio" -#: admin/models.py:734 +#: admin/models.py:747 msgid "The alias name" msgstr "Il nome dell'alias" -#: admin/models.py:736 +#: admin/models.py:749 msgid "target" msgstr "destinazione" -#: admin/models.py:737 +#: admin/models.py:750 msgid "The domain this alias points to" msgstr "Il dominio a cui punta questo alias" -#: admin/models.py:741 admin/models.py:1021 +#: admin/models.py:754 admin/models.py:1046 msgid "Check to activate this alias" msgstr "Seleziona per attivare questo alias" -#: admin/models.py:788 +#: admin/models.py:801 #, python-format msgid "Unknown domain %s" msgstr "Dominio sconosciuto %s" -#: admin/models.py:805 admin/models.py:1006 +#: admin/models.py:818 admin/models.py:1031 msgid "address" msgstr "indirizzo" -#: admin/models.py:806 +#: admin/models.py:819 msgid "Mailbox address (without the @domain.tld part)" msgstr "Indirizzo della casella di posta (senza la parte @dominio.org)" -#: admin/models.py:852 +#: admin/models.py:877 #, python-format msgid "Failed to retrieve mailbox location (%s)" msgstr "Impossibile recuperare la posizione della casella di posta (%s)" -#: admin/models.py:868 -#, python-format -msgid "Failed to rename mailbox: %s" -msgstr "Impossibile rinominare la casella di posta: %s" - -#: admin/models.py:894 -#, python-format -msgid "Failed to remove mailbox: %s" -msgstr "Impossibile rimuovere la casella di posta: %s" - -#: admin/models.py:909 +#: admin/models.py:921 #, python-format msgid "Quota is greater than the allowed domain's limit (%dM)" msgstr "La quota è maggiore del limite stabilito per il dominio (%dM)" -#: admin/models.py:914 +#: admin/models.py:926 msgid "A quota is required" msgstr "È richiesta una quota" -#: admin/models.py:1007 +#: admin/models.py:1032 msgid "" "The alias address (without the domain part). For a 'catch-all' address, just " "enter an * character." -msgstr "L'indirizzo alternativo (senza la parte del dominio). Per un indirizzo 'prenditutto' inserisci un carattere '*'." +msgstr "" +"L'indirizzo alternativo (senza la parte del dominio). Per un indirizzo " +"'prenditutto' inserisci un carattere '*'." -#: admin/models.py:1011 +#: admin/models.py:1036 msgid "mailboxes" msgstr "caselle di posta" -#: admin/models.py:1012 +#: admin/models.py:1037 msgid "The mailboxes this alias points to" msgstr "Le caselle di posta a cui punta questo alias" -#: admin/models.py:1016 +#: admin/models.py:1041 msgid "The aliases this alias points to" msgstr "Gli alias a cui questo alias puntano" -#: admin/models.py:1064 +#: admin/models.py:1089 msgid "distribution list" msgstr "elenco di smistamento" -#: admin/models.py:1065 +#: admin/models.py:1090 msgid "forward" msgstr "inoltra" -#: admin/models.py:1066 +#: admin/models.py:1091 msgid "alias" msgstr "alias" -#: admin/models.py:1145 +#: admin/models.py:1170 #, python-format msgid "Invalid line: %s" msgstr "Riga non valida: %s" -#: admin/models.py:1150 +#: admin/models.py:1175 #, python-format msgid "Domain '%s' does not exist" msgstr "Il dominio '%s' non esiste" -#: admin/models.py:1191 +#: admin/models.py:1218 msgid "Check to enable this extension" msgstr "Seleziona per abilitare questa estensione" -#: admin/models.py:1291 +#: admin/models.py:1318 msgid "added" msgstr "aggiunto" -#: admin/models.py:1294 +#: admin/models.py:1321 msgid "modified" msgstr "modificato" -#: admin/models.py:1297 +#: admin/models.py:1324 msgid "deleted" msgstr "cancellato" -#: admin/models.py:1299 +#: admin/models.py:1326 #, python-format msgid "%(object)s '%(name)s' %(action)s by user %(user)s" msgstr "%(object)s '%(name)s' %(action)s dell'utente %(user)s" @@ -630,7 +664,7 @@ msgid "Edit domain" msgstr "Modifica dominio" #: admin/tables.py:21 admin/templates/admin/identities_table.html:8 -#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:79 +#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:83 #: extensions/sievefilters/templates/sievefilters/filter.html:17 #: extensions/sievefilters/templates/sievefilters/guieditor.html:5 #: extensions/webmail/templatetags/webextras.py:97 @@ -645,143 +679,143 @@ msgstr "Versione" msgid "Description" msgstr "Descrizione" -#: admin/views.py:87 +#: admin/views.py:88 msgid "New domain" msgstr "Nuovo dominio" -#: admin/views.py:88 admin/views.py:97 admin/views.py:224 admin/views.py:450 -#: admin/views.py:457 extensions/sievefilters/views.py:120 -#: extensions/sievefilters/views.py:187 extensions/webmail/views.py:133 +#: admin/views.py:89 admin/views.py:98 admin/views.py:228 admin/views.py:444 +#: admin/views.py:451 extensions/sievefilters/views.py:129 +#: extensions/sievefilters/views.py:198 extensions/webmail/views.py:136 msgid "Create" msgstr "Crea" -#: admin/views.py:94 admin/views.py:454 +#: admin/views.py:95 admin/views.py:448 msgid "Next" msgstr "Successivo" -#: admin/views.py:96 +#: admin/views.py:97 msgid "Options" msgstr "Opzioni" -#: admin/views.py:98 admin/views.py:458 +#: admin/views.py:99 admin/views.py:452 msgid "Previous" msgstr "Precedente" -#: admin/views.py:111 +#: admin/views.py:112 msgid "Domain created" msgstr "Dominio creato" -#: admin/views.py:144 admin/views.py:281 admin/views.py:504 +#: admin/views.py:146 admin/views.py:285 admin/views.py:498 #: extensions/postfix_autoreply/templates/postfix_autoreply/autoreply.html:9 -#: extensions/sievefilters/views.py:139 extensions/webmail/views.py:164 +#: extensions/sievefilters/views.py:148 extensions/webmail/views.py:168 #: userprefs/templates/userprefs/forward.html:8 #: userprefs/templates/userprefs/profile.html:8 msgid "Update" msgstr "Aggiorna" -#: admin/views.py:160 +#: admin/views.py:162 msgid "Domain modified" msgstr "Dominio modificato" -#: admin/views.py:185 +#: admin/views.py:189 msgid "You can't delete your own domain" msgstr "Non puoi cancellare il tuo dominio" -#: admin/views.py:188 +#: admin/views.py:192 msgid "Domain deleted" msgid_plural "Domains deleted" msgstr[0] "Dominio cancellato" msgstr[1] "Domini cancellati" -#: admin/views.py:203 +#: admin/views.py:207 msgid "Alias with this name already exists" msgstr "Un alias con questo nome esiste già" -#: admin/views.py:246 +#: admin/views.py:250 msgid "New distribution list" msgstr "Nuovo elenco di smistamento" -#: admin/views.py:247 +#: admin/views.py:251 msgid "Distribution list created" msgstr "Elenco di smistamento creato" -#: admin/views.py:256 +#: admin/views.py:260 msgid "New alias" msgstr "Nuovo alias" -#: admin/views.py:257 +#: admin/views.py:261 msgid "Alias created" msgstr "Alias creato" -#: admin/views.py:266 +#: admin/views.py:270 msgid "New forward" msgstr "Nuovo inoltro" -#: admin/views.py:267 +#: admin/views.py:271 msgid "Forward created" msgstr "Inoltro creato" -#: admin/views.py:285 +#: admin/views.py:289 msgid "Distribution list modified" msgstr "Elenco di smistamento modificato" -#: admin/views.py:287 +#: admin/views.py:291 msgid "Forward modified" msgstr "Inoltro modificato" -#: admin/views.py:289 +#: admin/views.py:293 msgid "Alias modified" msgstr "Alias modificato" -#: admin/views.py:408 admin/views.py:551 admin/views.py:556 -#: extensions/amavis/views.py:195 extensions/amavis/views.py:201 -#: extensions/amavis/views.py:234 extensions/amavis/views.py:238 -#: extensions/amavis/views.py:240 extensions/webmail/views.py:37 -#: extensions/webmail/views.py:65 extensions/webmail/views.py:78 -#: extensions/webmail/views.py:95 extensions/webmail/views.py:111 -#: extensions/webmail/views.py:195 extensions/webmail/views.py:422 -#: extensions/webmail/views.py:433 extensions/webmail/views.py:460 +#: admin/views.py:402 admin/views.py:545 admin/views.py:550 +#: extensions/amavis/views.py:204 extensions/amavis/views.py:210 +#: extensions/amavis/views.py:243 extensions/amavis/views.py:247 +#: extensions/amavis/views.py:249 extensions/webmail/views.py:41 +#: extensions/webmail/views.py:68 extensions/webmail/views.py:81 +#: extensions/webmail/views.py:98 extensions/webmail/views.py:114 +#: extensions/webmail/views.py:200 extensions/webmail/views.py:427 +#: extensions/webmail/views.py:438 extensions/webmail/views.py:465 #: lib/formutils.py:32 lib/formutils.py:37 msgid "Invalid request" msgstr "Richiesta non valida" -#: admin/views.py:447 +#: admin/views.py:441 msgid "New account" msgstr "Nuovo account" -#: admin/views.py:471 +#: admin/views.py:465 msgid "Account created" msgstr "Account creato" -#: admin/views.py:519 +#: admin/views.py:513 msgid "Account updated" msgstr "Account aggiornato" -#: admin/views.py:541 +#: admin/views.py:535 msgid "Account deleted" msgid_plural "Accounts deleted" msgstr[0] "Account cancellato" msgstr[1] "Account cancellati" -#: admin/views.py:596 +#: admin/views.py:590 msgid "Parameters saved" msgstr "Parametri salvati" -#: admin/views.py:642 +#: admin/views.py:636 msgid "Modifications applied." msgstr "Modifiche applicate" -#: admin/views.py:749 +#: admin/views.py:743 #, python-format msgid "Object already exists: %s" msgstr "L'oggetto esiste già: %s" -#: admin/views.py:751 +#: admin/views.py:745 #, python-format msgid "%d objects imported successfully" msgstr "%d oggetti importati correttamente" -#: admin/views.py:769 +#: admin/views.py:763 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
                    \n" @@ -798,34 +832,37 @@ msgid "" msgstr "" "Fornire un file CSV le cui righe rispettino uno dei seguenti formati:\n" "
                      \n" -"
                    • account; loginname; password; nome; cognome; abilitato; group; indirizzo[, dominio, ...]
                    • \n" +"
                    • account; loginname; password; nome; cognome; abilitato; group; " +"indirizzo[, dominio, ...]
                    • \n" "
                    • alias; indirizzo; abilitato; destinatario interno
                    • \n" "
                    • forward; indirizzo; abilitato; destinatario esterno
                    • \n" -"
                    • dlist; indirizzo; abilitato; destinatario; destinatario; ...
                    • \n" +"
                    • dlist; indirizzo; abilitato; destinatario; destinatario; ...\n" "
                    \n" -"

                    Il primo elemento di ogni riga è obbligatorio e deve essere uguale a quello dei valori precedenti.

                    \n" +"

                    Il primo elemento di ogni riga è obbligatorio e deve essere uguale a " +"quello dei valori precedenti.

                    \n" "\n" "

                    Come separatore puoi utilizzare un carattere diverso.

                    \n" -#: admin/views.py:781 +#: admin/views.py:775 msgid "Import identities" msgstr "Identità di importazione" -#: admin/views.py:782 admin/views.py:852 admin/templatetags/admin_extras.py:87 +#: admin/views.py:776 admin/views.py:846 admin/templatetags/admin_extras.py:87 #: admin/templatetags/admin_extras.py:144 msgid "Import" msgstr "Importa" -#: admin/views.py:812 +#: admin/views.py:806 msgid "Export identities" msgstr "Identità di esportazione" -#: admin/views.py:813 admin/views.py:869 admin/templatetags/admin_extras.py:93 +#: admin/views.py:807 admin/views.py:863 admin/templatetags/admin_extras.py:93 #: admin/templatetags/admin_extras.py:150 msgid "Export" msgstr "Esporta" -#: admin/views.py:841 +#: admin/views.py:835 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
                      \n" @@ -841,15 +878,16 @@ msgstr "" "
                    • dominio; nome; quota; abilitato
                    • \n" "
                    • aliasdominio; nome; dominio target; abilitato
                    • \n" "
                    \n" -"

                    Il primo elemento di ogni riga è obbligatorio e deve essere uguale a quello dei valori precedenti.

                    \n" +"

                    Il primo elemento di ogni riga è obbligatorio e deve essere uguale a " +"quello dei valori precedenti.

                    \n" "\n" "

                    Come separatore puoi utilizzare un carattere diverso.

                    \n" -#: admin/views.py:851 +#: admin/views.py:845 msgid "Import domains" msgstr "Importa domini" -#: admin/views.py:868 +#: admin/views.py:862 msgid "Export domains" msgstr "Esporta domini" @@ -922,7 +960,7 @@ msgid "Tags" msgstr "Tag" #: admin/templates/admin/importform.html:5 -#: admin/templatetags/admin_extras.py:305 +#: admin/templatetags/admin_extras.py:290 msgid "Help" msgstr "Aiuto" @@ -969,7 +1007,7 @@ msgid "Previously on Modoboa..." msgstr "Precedentemente su Modoboa ..." #: admin/templates/admin/logs.html:6 extensions/amavis/sql_listing.py:25 -#: extensions/webmail/lib.py:37 extensions/webmail/lib.py:406 +#: extensions/webmail/lib.py:38 extensions/webmail/lib.py:411 msgid "Date" msgstr "Data" @@ -1072,34 +1110,21 @@ msgid "View the domain's identities" msgstr "Visualizza le identita del dominio" #: admin/templatetags/admin_extras.py:178 -msgid "Delete the domain" -msgstr "Cancella il dominio" - #: admin/templatetags/admin_extras.py:194 -msgid "Delete this account" -msgstr "Cancella questo account" +#: admin/templatetags/admin_extras.py:201 +#, fuzzy, python-format +msgid "Delete %s?" +msgstr "Elimina" -#: admin/templatetags/admin_extras.py:202 -msgid "Delete this distribution list" -msgstr "Cancella l'elenco di smistamento" - -#: admin/templatetags/admin_extras.py:209 -msgid "Delete this forward" -msgstr "Cancella questo inoltro" - -#: admin/templatetags/admin_extras.py:216 -msgid "Delete this alias" -msgstr "Cancella questo alias" - -#: admin/templatetags/admin_extras.py:238 +#: admin/templatetags/admin_extras.py:223 msgid "Remove this permission" msgstr "Rimuovi questo permesso" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "Yes" msgstr "Si" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "No" msgstr "No" @@ -1151,8 +1176,10 @@ msgid "" msgstr "" "\n" "

                    Benvenuti alla demo online!

                    \n" -"

                    Attenzione: il contenuto della demo viene rinnovato ogni due ore.

                    \n" -"

                    Per provare la demo sono disponibili i seguenti utenti (username/passwordAttenzione: il contenuto della demo viene rinnovato ogni due ore.\n" +"

                    Per provare la demo sono disponibili i seguenti utenti (username/" +"password):

                    \n" "
                      \n" "
                    • Un super amministratore : admin/password
                    • \n" @@ -1206,7 +1233,8 @@ msgstr "Rimozione dei messaggi rilasciati" #: extensions/amavis/app_settings.py:24 msgid "Remove messages marked as released while cleaning up the database" -msgstr "Rimuovi i messaggi marcati come rilasciati durante la pulizia del database" +msgstr "" +"Rimuovi i messaggi marcati come rilasciati durante la pulizia del database" #: extensions/amavis/app_settings.py:28 msgid "Amavis connection mode" @@ -1295,12 +1323,12 @@ msgid "Virus filter" msgstr "Filtro virus" #: extensions/amavis/models.py:94 extensions/amavis/models.py:102 -#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:268 +#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:281 msgid "yes" msgstr "si" #: extensions/amavis/models.py:95 extensions/amavis/models.py:103 -#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:272 +#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:285 msgid "no" msgstr "no" @@ -1312,7 +1340,9 @@ msgstr "predefinito" #: extensions/amavis/models.py:98 msgid "Bypass virus checks or not. Choose 'default' to use global settings." -msgstr "Aggirare il controllo virus o no. Scegliere 'predefinito' per utilizzare le impostazioni globali." +msgstr "" +"Aggirare il controllo virus o no. Scegliere 'predefinito' per utilizzare le " +"impostazioni globali." #: extensions/amavis/models.py:101 msgid "Spam filter" @@ -1320,7 +1350,9 @@ msgstr "Filtro spam" #: extensions/amavis/models.py:106 msgid "Bypass spam checks or not. Choose 'default' to use global settings." -msgstr "Aggirare il controllo spam o no. Scegliere 'predefinito' per utilizzare le impostazioni globali." +msgstr "" +"Aggirare il controllo spam o no. Scegliere 'predefinito' per utilizzare le " +"impostazioni globali." #: extensions/amavis/models.py:109 msgid "Banned filter" @@ -1328,7 +1360,9 @@ msgstr "Filtro banned" #: extensions/amavis/models.py:114 msgid "Bypass banned checks or not. Choose 'default' to use global settings." -msgstr "Aggirare il controllo banned o no. Scegliere 'predefinito' per utilizzare le impostazioni globali." +msgstr "" +"Aggirare il controllo banned o no. Scegliere 'predefinito' per utilizzare le " +"impostazioni globali." #: extensions/amavis/models.py:144 msgid "Spam marker" @@ -1338,15 +1372,17 @@ msgstr "Contrassegno spam" msgid "" "Modify spam subject using the specified text. Choose 'default' to use global " "settings." -msgstr "Modifica dell'oggetto spam utilizzando un testo specifico. Scegliere 'predefinito' per utilizzare le impostazioni globali." +msgstr "" +"Modifica dell'oggetto spam utilizzando un testo specifico. Scegliere " +"'predefinito' per utilizzare le impostazioni globali." -#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:36 +#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:37 msgid "From" msgstr "Da" #: extensions/amavis/sql_listing.py:24 extensions/sievefilters/forms.py:68 -#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:35 -#: extensions/webmail/lib.py:404 templates/common/email_searchbar.html:6 +#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:36 +#: extensions/webmail/lib.py:409 templates/common/email_searchbar.html:6 msgid "Subject" msgstr "Oggetto" @@ -1356,37 +1392,37 @@ msgstr "Oggetto" msgid "To" msgstr "A" -#: extensions/amavis/views.py:34 +#: extensions/amavis/views.py:43 msgid "Empty quarantine" msgstr "Svuota quarantena" -#: extensions/amavis/views.py:202 +#: extensions/amavis/views.py:211 msgid "Message deleted" msgstr "Messaggio eliminato" -#: extensions/amavis/views.py:223 +#: extensions/amavis/views.py:232 #, python-format msgid "%(count)d message deleted successfully" msgid_plural "%(count)d messages deleted successfully" msgstr[0] "%(count)d messaggio eliminato con successo" msgstr[1] "%(count)d messaggi eliminati con successo" -#: extensions/amavis/views.py:243 +#: extensions/amavis/views.py:252 msgid "Request sent" msgstr "Request inviata" -#: extensions/amavis/views.py:249 +#: extensions/amavis/views.py:258 msgid "Message released" msgstr "Messaggio rilasciato" -#: extensions/amavis/views.py:271 +#: extensions/amavis/views.py:280 #, python-format msgid "%(count)d request sent" msgid_plural "%(count)d requests sent" msgstr[0] "%(count)d request inviata" msgstr[1] "%(count)d request inviate" -#: extensions/amavis/views.py:295 +#: extensions/amavis/views.py:304 #, python-format msgid "%(count)d message released successfully" msgid_plural "%(count)d messages released successfully" @@ -1421,8 +1457,12 @@ msgid "" msgid_plural "" "\n" "%(counter)s release requests are pending for action.\n" -msgstr[0] "\n%(counter)s richiesta di rilascio è in attesa di azioni\n" -msgstr[1] "\n%(counter)s richieste di rilascio sono in attesa di azioni\n" +msgstr[0] "" +"\n" +"%(counter)s richiesta di rilascio è in attesa di azioni\n" +msgstr[1] "" +"\n" +"%(counter)s richieste di rilascio sono in attesa di azioni\n" #: extensions/amavis/templates/amavis/notifications/pending_requests.html:6 msgid "Sketch:" @@ -1497,7 +1537,9 @@ msgstr "MIME errato" #: extensions/limits/__init__.py:23 msgid "" "Per administrator resources to limit the number of objects they can create" -msgstr "Risorse per amministratore. Limitazione del numero di oggetti che possono creare " +msgstr "" +"Risorse per amministratore. Limitazione del numero di oggetti che possono " +"creare " #: extensions/limits/__init__.py:54 msgid "Limits" @@ -1522,7 +1564,9 @@ msgstr "Amministratori di domini" #: extensions/limits/app_settings.py:15 msgid "Maximum number of allowed domain administrators for a new administrator" -msgstr "Numero massimo di amministratori di domini consentiti per un nuovo amministratore" +msgstr "" +"Numero massimo di amministratori di domini consentiti per un nuovo " +"amministratore" #: extensions/limits/app_settings.py:21 msgid "Maximum number of allowed domains for a new administrator" @@ -1530,11 +1574,13 @@ msgstr "Numero massimo di domini consentiti per un nuovo amministratore" #: extensions/limits/app_settings.py:27 msgid "Maximum number of allowed domain aliases for a new administrator" -msgstr "Numero massimo di alias di dominio consentiti per un nuovo amministratore" +msgstr "" +"Numero massimo di alias di dominio consentiti per un nuovo amministratore" #: extensions/limits/app_settings.py:33 msgid "Maximum number of allowed mailboxes for a new administrator" -msgstr "Numero massimo di caselle di posta consentite per un nuovo amministratore" +msgstr "" +"Numero massimo di caselle di posta consentite per un nuovo amministratore" #: extensions/limits/app_settings.py:39 msgid "Maximum number of allowed aliases for a new administrator" @@ -1542,7 +1588,8 @@ msgstr "Numero massimo di alias consentiti per un nuovo amministratore" #: extensions/limits/forms.py:13 msgid "Maximum number of domain administrators this user can create" -msgstr "Numero massimo di amministratori di dominio che questo utente può creare" +msgstr "" +"Numero massimo di amministratori di dominio che questo utente può creare" #: extensions/limits/forms.py:17 msgid "Maximum number of domains this user can create" @@ -1558,7 +1605,8 @@ msgstr "Numero massimo di caselle di posta che questo utente può creare" #: extensions/limits/forms.py:29 msgid "Maximum number of mailbox aliases this user can create" -msgstr "Numero massimo di alias di caselle di posta che questo utente può creare" +msgstr "" +"Numero massimo di alias di caselle di posta che questo utente può creare" #: extensions/limits/forms.py:46 msgid "Invalid limit" @@ -1612,7 +1660,9 @@ msgstr "Tempo massimo della risposta automatica" #: extensions/postfix_autoreply/app_settings.py:16 msgid "Timeout in seconds between two auto-replies to the same recipient" -msgstr "Tempo massimo in secondi tra due risposte automatiche al medesimo destinatario" +msgstr "" +"Tempo massimo in secondi tra due risposte automatiche al medesimo " +"destinatario" #: extensions/postfix_autoreply/forms.py:9 msgid "Until" @@ -1626,23 +1676,23 @@ msgstr "Attiva la tua risposta automatica fino a questa data" msgid "This date is over" msgstr "Questa data è passata" -#: extensions/postfix_autoreply/models.py:15 +#: extensions/postfix_autoreply/models.py:19 msgid "subject" msgstr "oggetto" -#: extensions/postfix_autoreply/models.py:16 +#: extensions/postfix_autoreply/models.py:20 msgid "The subject that will appear in sent emails" msgstr "L'oggetto che apparirà nelle mail inviate" -#: extensions/postfix_autoreply/models.py:17 +#: extensions/postfix_autoreply/models.py:23 msgid "content" msgstr "contenuto" -#: extensions/postfix_autoreply/models.py:18 +#: extensions/postfix_autoreply/models.py:24 msgid "The content that will appear in sent emails" msgstr "Il contenuto che apparirà nelle mail inviate" -#: extensions/postfix_autoreply/models.py:20 +#: extensions/postfix_autoreply/models.py:28 msgid "Activate/Deactivate your auto reply" msgstr "Attiva/disattiva la tua risposta automatica" @@ -1770,59 +1820,60 @@ msgstr "Ridireziona il messaggio a" #: extensions/sievefilters/lib.py:37 msgid "Connection to MANAGESIEVE server failed, check your configuration" -msgstr "Connessione al server MANAGESIEVE fallita, controlla la tua configurazione" +msgstr "" +"Connessione al server MANAGESIEVE fallita, controlla la tua configurazione" #: extensions/sievefilters/lib.py:82 msgid "Not enough space on server" msgstr "Non c'è spazio sufficiente nel server" -#: extensions/sievefilters/views.py:64 +#: extensions/sievefilters/views.py:68 msgid "Failed to retrieve filters set" msgstr "Recupero delle impostazioni di filtro fallito" -#: extensions/sievefilters/views.py:117 +#: extensions/sievefilters/views.py:126 #: extensions/sievefilters/templatetags/sfilters_tags.py:33 msgid "New filter" msgstr "Nuovo filtro" -#: extensions/sievefilters/views.py:124 +#: extensions/sievefilters/views.py:133 msgid "Filter created" msgstr "Filtro creato" -#: extensions/sievefilters/views.py:136 +#: extensions/sievefilters/views.py:145 #: extensions/sievefilters/templatetags/sfilters_tags.py:77 msgid "Edit filter" msgstr "Modifica filtro" -#: extensions/sievefilters/views.py:145 +#: extensions/sievefilters/views.py:154 msgid "Filter modified" msgstr "Filtro modificato" -#: extensions/sievefilters/views.py:165 +#: extensions/sievefilters/views.py:176 msgid "Filter removed" msgstr "Filtro eliminato" -#: extensions/sievefilters/views.py:166 +#: extensions/sievefilters/views.py:177 msgid "Failed to remove filter" msgstr "Rimozione del filtro fallita" -#: extensions/sievefilters/views.py:180 +#: extensions/sievefilters/views.py:191 msgid "Filters set saved" msgstr "Gruppo filtri salvato" -#: extensions/sievefilters/views.py:185 +#: extensions/sievefilters/views.py:196 msgid "Create a new filters set" msgstr "Crea un nuovo gruppo di filtri" -#: extensions/sievefilters/views.py:208 +#: extensions/sievefilters/views.py:219 msgid "Filters set created" msgstr "Gruppo filtri creato" -#: extensions/sievefilters/views.py:229 +#: extensions/sievefilters/views.py:240 msgid "Filters set deleted" msgstr "Gruppo filtri eliminato" -#: extensions/sievefilters/views.py:241 +#: extensions/sievefilters/views.py:252 msgid "Filters set activated" msgstr "Gruppo filtri attivato" @@ -1838,18 +1889,20 @@ msgstr "Attivo" msgid "No filter defined yet" msgstr "Non ci sono ancora filtri definiti" -#: extensions/sievefilters/templates/sievefilters/index.html:55 +#: extensions/sievefilters/templates/sievefilters/index.html:56 msgid "Filter sets" msgstr "Impostazioni dei filtri" -#: extensions/sievefilters/templates/sievefilters/index.html:59 +#: extensions/sievefilters/templates/sievefilters/index.html:60 msgid "active" msgstr "attivo" -#: extensions/sievefilters/templates/sievefilters/index.html:73 +#: extensions/sievefilters/templates/sievefilters/index.html:74 msgid "" "No filters set defined yet. You must create one in order to define filters." -msgstr "Non è ancora stato definito alcun gruppo di filtri. Devi crearne uno per definire dei filtri" +msgstr "" +"Non è ancora stato definito alcun gruppo di filtri. Devi crearne uno per " +"definire dei filtri" #: extensions/sievefilters/templatetags/sfilters_tags.py:16 msgid "New filters set" @@ -2031,7 +2084,8 @@ msgstr "Dimensione massima degli allegati" #: extensions/webmail/app_settings.py:16 msgid "Maximum attachment size in bytes (or KB, MB, GB if specified)" -msgstr "Dimensione massima degli allegati in bytes (o KB, MB, GB se specificato)" +msgstr "" +"Dimensione massima degli allegati in bytes (o KB, MB, GB se specificato)" #: extensions/webmail/app_settings.py:19 msgid "IMAP settings" @@ -2087,7 +2141,8 @@ msgstr "Modalità di visualizzazione del messaggio predefinita" #: extensions/webmail/app_settings.py:79 msgid "The default mode used when displaying a message" -msgstr "La modalità di visualizzazione predefinita quando viene mostrato il messaggio" +msgstr "" +"La modalità di visualizzazione predefinita quando viene mostrato il messaggio" #: extensions/webmail/app_settings.py:85 msgid "Enable HTML links display" @@ -2161,84 +2216,89 @@ msgstr "Risposta del server" msgid "Cci" msgstr "Cci" -#: extensions/webmail/imaputils.py:259 +#: extensions/webmail/imaputils.py:237 +#, fuzzy +msgid "Failed to retrieve hierarchy delimiter" +msgstr "Recupero delle impostazioni di filtro fallito" + +#: extensions/webmail/imaputils.py:278 #, python-format msgid "Connection to IMAP server failed: %s" msgstr "Connessione al server IMAP fallita: %s" -#: extensions/webmail/lib.py:353 +#: extensions/webmail/lib.py:358 msgid "wrote:" msgstr "scritto:" -#: extensions/webmail/lib.py:418 extensions/webmail/lib.py:422 +#: extensions/webmail/lib.py:423 extensions/webmail/lib.py:427 msgid "Original message" msgstr "Messaggio originale" -#: extensions/webmail/views.py:83 +#: extensions/webmail/views.py:86 #, python-format msgid "%(count)d message deleted" msgid_plural "%(count)d messages deleted" msgstr[0] "%(count)d messaggio cancellato" msgstr[1] "%(count)d messaggi cancellati" -#: extensions/webmail/views.py:100 +#: extensions/webmail/views.py:103 msgid "Unknown action" msgstr "Azione sconosciuta" -#: extensions/webmail/views.py:113 lib/email_listing.py:137 +#: extensions/webmail/views.py:116 lib/email_listing.py:137 msgid "Empty mailbox" msgstr "Casella di posta vuota" -#: extensions/webmail/views.py:130 +#: extensions/webmail/views.py:133 #: extensions/webmail/templatetags/webextras.py:170 msgid "Create a new mailbox" msgstr "Crea una nuova casella di posta" -#: extensions/webmail/views.py:145 +#: extensions/webmail/views.py:149 msgid "Mailbox created" msgstr "Casella di posta creata" -#: extensions/webmail/views.py:161 +#: extensions/webmail/views.py:165 msgid "Edit mailbox" msgstr "Modifica casella di posta" -#: extensions/webmail/views.py:175 +#: extensions/webmail/views.py:180 msgid "Mailbox updated" msgstr "Casella di posta aggiornata" -#: extensions/webmail/views.py:209 extensions/webmail/views.py:391 -#: extensions/webmail/views.py:500 +#: extensions/webmail/views.py:214 extensions/webmail/views.py:396 +#: extensions/webmail/views.py:505 msgid "Bad request" msgstr "Richiesta sbagliata" -#: extensions/webmail/views.py:241 +#: extensions/webmail/views.py:246 msgid "Failed to save attachment: " msgstr "Salvataggio allegato fallito: " -#: extensions/webmail/views.py:244 +#: extensions/webmail/views.py:249 #, python-format msgid "Attachment is too big (limit: %s)" msgstr "L'allegato è troppo grande (limite: %s)" -#: extensions/webmail/views.py:250 +#: extensions/webmail/views.py:255 #: extensions/webmail/templates/webmail/compose.html:15 #: extensions/webmail/templates/webmail/headers.html:4 msgid "Attachments" msgstr "Allegati" -#: extensions/webmail/views.py:266 +#: extensions/webmail/views.py:271 msgid "Bad query" msgstr "Domanda sbagliata" -#: extensions/webmail/views.py:276 +#: extensions/webmail/views.py:281 msgid "Failed to remove attachment: " msgstr "Rimozione allegato fallita: " -#: extensions/webmail/views.py:281 +#: extensions/webmail/views.py:286 msgid "Unknown attachment" msgstr "Allegato sconosciuto" -#: extensions/webmail/views.py:496 +#: extensions/webmail/views.py:501 msgid "Undefined action" msgstr "Azione non definita" @@ -2269,7 +2329,7 @@ msgstr[1] "%(counter)s file" msgid "Parent mailbox" msgstr "Casella di posta principale" -#: extensions/webmail/templates/webmail/index.html:37 +#: extensions/webmail/templates/webmail/index.html:38 msgid "Mailbox quota" msgstr "Quota casella di posta" @@ -2447,7 +2507,7 @@ msgstr "Impostazioni per-utente" msgid "Prefered language" msgstr "Lingua preferita" -#: userprefs/app_settings.py:26 +#: userprefs/app_settings.py:27 msgid "Prefered language to display pages" msgstr "Lingua preferita per mostrare le pagine" @@ -2481,13 +2541,16 @@ msgstr "Mantieni copie locali" #: userprefs/forms.py:67 msgid "Forward messages and store copies into your local mailbox" -msgstr "Inoltra i messaggi e memorizza le copie nella tua casella di posta locale" +msgstr "" +"Inoltra i messaggi e memorizza le copie nella tua casella di posta locale" #: userprefs/forms.py:84 msgid "" "You can't define a forward to a local destination. Please ask your " "administrator to create an alias instead." -msgstr "Non puoi definire l'inoltro con destinazione una cartella locale. Chiedi piuttosto all'amministratore di creare un alias." +msgstr "" +"Non puoi definire l'inoltro con destinazione una cartella locale. Chiedi " +"piuttosto all'amministratore di creare un alias." #: userprefs/views.py:32 msgid "You need a mailbox in order to define a forward" @@ -2535,3 +2598,24 @@ msgstr "Aggiorna le informazioni personali" #: userprefs/templatetags/uprefs_extras.py:57 msgid "Logout" msgstr "Esci" + +#~ msgid "Failed to rename mailbox: %s" +#~ msgstr "Impossibile rinominare la casella di posta: %s" + +#~ msgid "Failed to remove mailbox: %s" +#~ msgstr "Impossibile rimuovere la casella di posta: %s" + +#~ msgid "Delete the domain" +#~ msgstr "Cancella il dominio" + +#~ msgid "Delete this account" +#~ msgstr "Cancella questo account" + +#~ msgid "Delete this distribution list" +#~ msgstr "Cancella l'elenco di smistamento" + +#~ msgid "Delete this forward" +#~ msgstr "Cancella questo inoltro" + +#~ msgid "Delete this alias" +#~ msgstr "Cancella questo alias" diff --git a/modoboa/locale/pt_PT/LC_MESSAGES/django.po b/modoboa/locale/pt_PT/LC_MESSAGES/django.po index a5de42e61..a160de8a6 100644 --- a/modoboa/locale/pt_PT/LC_MESSAGES/django.po +++ b/modoboa/locale/pt_PT/LC_MESSAGES/django.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # mikec , 2012 # mikec , 2013 @@ -10,15 +10,16 @@ msgid "" msgstr "" "Project-Id-Version: Modoboa\n" -"Report-Msgid-Bugs-To: http://dev.modoboa.org/\n" -"POT-Creation-Date: 2013-06-01 16:35+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-09-20 22:30+0200\n" "PO-Revision-Date: 2013-06-21 13:19+0000\n" "Last-Translator: mikec \n" -"Language-Team: Portuguese (Portugal) (http://www.transifex.com/projects/p/modoboa/language/pt_PT/)\n" +"Language-Team: Portuguese (Portugal) (http://www.transifex.com/projects/p/" +"modoboa/language/pt_PT/)\n" +"Language: pt_PT\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: pt_PT\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: admin/__init__.py:9 @@ -29,8 +30,8 @@ msgstr "Consola de Administração" msgid "Web based console to manage domains, accounts and aliases" msgstr "Consola baseada na web para gestão de domínios, contas e aliases" -#: admin/__init__.py:16 admin/forms.py:179 admin/forms.py:614 -#: admin/views.py:93 admin/views.py:441 +#: admin/__init__.py:16 admin/forms.py:211 admin/forms.py:652 +#: admin/views.py:94 admin/views.py:447 #: extensions/postfix_autoreply/app_settings.py:11 #: extensions/sievefilters/app_settings.py:50 #: extensions/stats/app_settings.py:11 extensions/webmail/app_settings.py:11 @@ -124,7 +125,9 @@ msgstr "\"Bind DN\"" msgid "" "The distinguished name to use when binding to the LDAP server. Leave empty " "for an anonymous bind" -msgstr "O nome único usado para fazer o \"bind\" ao servidor LDAP. Deixar vario para \"bind\" anónimo" +msgstr "" +"O nome único usado para fazer o \"bind\" ao servidor LDAP. Deixar vario " +"para \"bind\" anónimo" #: admin/app_settings.py:97 msgid "Bind password" @@ -132,7 +135,8 @@ msgstr "Password para bind" #: admin/app_settings.py:99 msgid "The password to use when binding to the LDAP server (with 'Bind DN')" -msgstr "A password usada para fazer o \"bind\" ao servidor LDAP (com 'Bind DN')" +msgstr "" +"A password usada para fazer o \"bind\" ao servidor LDAP (com 'Bind DN')" #: admin/app_settings.py:105 msgid "Search base" @@ -150,7 +154,9 @@ msgstr "Filtro de pesquisa" msgid "" "An optional filter string (e.g. '(objectClass=person)'). In order to be " "valid, it must be enclosed in parentheses." -msgstr "Um filtro opcional (ex: '(objetClass=person)'). Tem de estar entre parênteses para ser válido" +msgstr "" +"Um filtro opcional (ex: '(objetClass=person)'). Tem de estar entre " +"parênteses para ser válido" #: admin/app_settings.py:119 msgid "User DN template" @@ -161,7 +167,9 @@ msgstr "Template DN de utilizador" msgid "" "The template used to construct a user's DN. It should contain one " "placeholder (ie. %(user)s)" -msgstr "O template usado para construir o DN (nome único). Deve apenas conter um 'placeholder' (ex: %(user)s) " +msgstr "" +"O template usado para construir o DN (nome único). Deve apenas conter um " +"'placeholder' (ex: %(user)s) " #: admin/app_settings.py:126 msgid "Password attribute" @@ -194,7 +202,9 @@ msgstr "Lidar com caixas de correio no sistema de ficheiros" msgid "" "Rename or remove mailboxes on the filesystem when they get renamed or " "removed within Modoboa" -msgstr "Renomear ou remover as caixas de correio no sistema de ficheiros quando estas são renomeadas no Modoboa" +msgstr "" +"Renomear ou remover as caixas de correio no sistema de ficheiros quando " +"estas são renomeadas no Modoboa" #: admin/app_settings.py:146 msgid "Mailboxes ower" @@ -210,7 +220,8 @@ msgstr "Remoção automática de conta" #: admin/app_settings.py:154 msgid "When a mailbox is removed, also remove the associated account" -msgstr "Ao remover uma caixa de correio estará também a remover a conta associada" +msgstr "" +"Ao remover uma caixa de correio estará também a remover a conta associada" #: admin/app_settings.py:157 admin/templates/admin/editdomainform.html:7 msgid "Miscellaneous" @@ -238,39 +249,52 @@ msgstr "Redirecionamento pré-definido" #: admin/app_settings.py:175 msgid "The default redirection used when no application is specified" -msgstr "O redirecionamento padrão usado quando nenhuma aplicação se encontra especificada" +msgstr "" +"O redirecionamento padrão usado quando nenhuma aplicação se encontra " +"especificada" -#: admin/app_settings.py:230 +#: admin/app_settings.py:213 +msgid "Key must be either 16, 24, or 32 bytes long" +msgstr "" + +#: admin/app_settings.py:222 +#, fuzzy +msgid "Invalid syntax" +msgstr "Linha inválida" + +#: admin/app_settings.py:245 msgid "This field is required" msgstr "Este campo é obrigatório" -#: admin/forms.py:16 admin/forms.py:459 admin/tables.py:18 +#: admin/forms.py:20 admin/forms.py:497 admin/tables.py:18 msgid "Alias(es)" msgstr "Alias(es)" -#: admin/forms.py:18 +#: admin/forms.py:22 msgid "" "Alias(es) of this domain. Indicate only one name per input, press ENTER to " "add a new input." -msgstr "Alias(es) deste domínio. Indicar apenas um nome por entrada, pressionar ENTER para acrescentar uma nova entrada." +msgstr "" +"Alias(es) deste domínio. Indicar apenas um nome por entrada, pressionar " +"ENTER para acrescentar uma nova entrada." -#: admin/forms.py:55 +#: admin/forms.py:59 msgid "An alias with this name already exists" msgstr "Já existe um alias com este nome" -#: admin/forms.py:69 +#: admin/forms.py:73 msgid "A domain with this name already exists" msgstr "Este nome de domínio já existe" -#: admin/forms.py:114 +#: admin/forms.py:146 msgid "Create a domain administrator" msgstr "Criar um administrador de domínio" -#: admin/forms.py:116 +#: admin/forms.py:148 msgid "Automatically create an administrator for this domain" msgstr "Criar automaticamente um administrador para este domínio" -#: admin/forms.py:120 admin/tables.py:12 admin/tables.py:47 +#: admin/forms.py:152 admin/tables.py:12 admin/tables.py:47 #: admin/templates/admin/editdomainform.html:13 #: admin/templates/admin/identities_table.html:5 #: admin/templates/admin/information.html:8 @@ -279,349 +303,362 @@ msgstr "Criar automaticamente um administrador para este domínio" msgid "Name" msgstr "Nome" -#: admin/forms.py:122 +#: admin/forms.py:154 msgid "" "The administrator's name. Don't include the domain's name here, it will be " "automatically appended." -msgstr "O nome do administrador. Não inclua o nome do domínio já que este será automaticamente anexado." +msgstr "" +"O nome do administrador. Não inclua o nome do domínio já que este será " +"automaticamente anexado." -#: admin/forms.py:128 +#: admin/forms.py:160 msgid "Create aliases" msgstr " Criar aliases" -#: admin/forms.py:130 +#: admin/forms.py:162 msgid "Automatically create standard aliases for this domain" msgstr "Criar automaticamente aliases para este domínio" -#: admin/forms.py:143 +#: admin/forms.py:175 msgid "Invalid format" msgstr "Formato inválido" -#: admin/forms.py:155 +#: admin/forms.py:187 #, python-format msgid "User '%s' already exists" msgstr "O utilizador '%s' já existe" -#: admin/forms.py:203 +#: admin/forms.py:235 msgid "Email address" msgstr "Endereço de e-mail" -#: admin/forms.py:204 +#: admin/forms.py:236 msgid "" "The distribution list address. Use the '*' character to create a 'catchall' " "address (ex: *@domain.tld)." -msgstr "Os endereços da lista de distribuição. Use o '*' para criar um endereço 'catchall' (Ex: *@domain.tld)." +msgstr "" +"Os endereços da lista de distribuição. Use o '*' para criar um endereço " +"'catchall' (Ex: *@domain.tld)." -#: admin/forms.py:207 +#: admin/forms.py:239 msgid "Recipients" msgstr "Destinatários" -#: admin/forms.py:208 +#: admin/forms.py:240 msgid "" "Mailbox(es) this alias will point to. Indicate only one address per input, " "press ENTER to add a new input." -msgstr "Caixa(s) de correio para o qual este 'alias' aponta. Indicar apenas um endereço por entrada, pressionar ENTER para acrescentar uma nova entrada." +msgstr "" +"Caixa(s) de correio para o qual este 'alias' aponta. Indicar apenas um " +"endereço por entrada, pressionar ENTER para acrescentar uma nova entrada." -#: admin/forms.py:246 admin/forms.py:504 admin/forms.py:530 -#: admin/models.py:1147 +#: admin/forms.py:278 admin/forms.py:542 admin/forms.py:568 msgid "Domain does not exist" msgstr "O domínio não existe" -#: admin/forms.py:248 +#: admin/forms.py:280 msgid "You don't have access to this domain" msgstr "Não tem acesso a este domínio" -#: admin/forms.py:268 +#: admin/forms.py:300 msgid "Invalid mailbox" msgstr "Caixa de correio inválida" -#: admin/forms.py:284 +#: admin/forms.py:316 admin/models.py:1202 #, python-format msgid "Local recipient %s not found" msgstr "O destinatário local %s não foi encontrado" -#: admin/forms.py:286 admin/forms.py:292 +#: admin/forms.py:318 admin/forms.py:324 #, python-format msgid "Recipient %s already present" msgstr "O destinatário %s já existe" -#: admin/forms.py:297 +#: admin/forms.py:329 msgid "No recipient defined" msgstr "Sem destinatário definido" -#: admin/forms.py:311 extensions/webmail/forms.py:19 +#: admin/forms.py:343 extensions/webmail/forms.py:19 msgid "Select a file" msgstr "Escolha um ficheiro" -#: admin/forms.py:313 admin/forms.py:341 +#: admin/forms.py:345 admin/forms.py:373 msgid "Separator" msgstr "Separador" -#: admin/forms.py:316 +#: admin/forms.py:348 msgid "Continue on error" msgstr "Continua com erro" -#: admin/forms.py:317 +#: admin/forms.py:349 msgid "Don't treat duplicated objects as error" msgstr "Não tratar objetos duplicados como erro" -#: admin/forms.py:332 +#: admin/forms.py:364 msgid "Crypt passwords" msgstr "Passwords encriptadas" -#: admin/forms.py:333 +#: admin/forms.py:365 msgid "Check this option if passwords contained in your file are not crypted" msgstr "Marque esta opção se as senhas contidas no arquivo não são encriptadas" -#: admin/forms.py:339 +#: admin/forms.py:371 msgid "File name" msgstr "Nome do ficheiro" -#: admin/forms.py:371 admin/templates/admin/editdomainform.html:13 +#: admin/forms.py:403 admin/templates/admin/editdomainform.html:13 #: auth/forms.py:7 msgid "Username" msgstr "Nome de Utilizador" -#: admin/forms.py:373 +#: admin/forms.py:405 msgid "Role" msgstr "Papel" -#: admin/forms.py:374 admin/forms.py:401 +#: admin/forms.py:406 admin/forms.py:433 msgid "Choose" msgstr "Escolher" -#: admin/forms.py:375 +#: admin/forms.py:407 msgid "What level of permission this user will have" msgstr "Que nível de permissões terá o utilizador" -#: admin/forms.py:377 auth/forms.py:11 +#: admin/forms.py:409 auth/forms.py:11 msgid "Password" msgstr "Password" -#: admin/forms.py:379 userprefs/forms.py:18 +#: admin/forms.py:411 userprefs/forms.py:18 msgid "Confirmation" msgstr "Confirmação" -#: admin/forms.py:381 +#: admin/forms.py:413 msgid "Enter the same password as above, for verification." msgstr "Repita a password acima, para verificação." -#: admin/forms.py:392 +#: admin/forms.py:424 msgid "Enabled" msgstr "Ativo" -#: admin/forms.py:434 +#: admin/forms.py:471 msgid "The two password fields didn't match." msgstr "Os dois campos de password não são idênticos." -#: admin/forms.py:440 +#: admin/forms.py:477 msgid "You can't disable your own account" msgstr "Não pode desativar a sua própria conta" -#: admin/forms.py:450 +#: admin/forms.py:488 msgid "E-mail" msgstr "E-mail" -#: admin/forms.py:452 +#: admin/forms.py:490 msgid "Quota" msgstr "Quota" -#: admin/forms.py:454 +#: admin/forms.py:492 msgid "" "Quota in MB for this mailbox. Define a custom value or use domain's default " "one. Leave empty to define an unlimited value (not allowed for domain " "administrators)." -msgstr "Quota em MB para esta caixa de correio. Definir uma valor personalizado ou usar o valor predefinido pelo domínio. Deixar em branco para definir uma valor ilimitado (não permitido para administradores do domínio)." +msgstr "" +"Quota em MB para esta caixa de correio. Definir uma valor personalizado ou " +"usar o valor predefinido pelo domínio. Deixar em branco para definir uma " +"valor ilimitado (não permitido para administradores do domínio)." -#: admin/forms.py:461 +#: admin/forms.py:499 msgid "" "Alias(es) of this mailbox. Indicate only one address per input, press ENTER " "to add a new input. Use the '*' character to create a 'catchall' alias (ex: " "*@domain.tld)." -msgstr "Alias(es) desta caixa de correio. Indique apenas um endereço por entrada, clique ENTER para adicionar uma nova entrada. Use o '*' para criar um alias 'catchall' (ex: *@domain.tld)." +msgstr "" +"Alias(es) desta caixa de correio. Indique apenas um endereço por entrada, " +"clique ENTER para adicionar uma nova entrada. Use o '*' para criar um alias " +"'catchall' (ex: *@domain.tld)." -#: admin/forms.py:512 +#: admin/forms.py:550 #, python-format msgid "Mailbox %s already exists" msgstr "Caixa de correio %s já existe" -#: admin/forms.py:572 +#: admin/forms.py:610 msgid "Domain(s)" msgstr "Domínio(s)" -#: admin/forms.py:574 +#: admin/forms.py:612 msgid "Domain(s) that user administrates" msgstr "Domínio(s) administrado pelo utilizador" -#: admin/forms.py:616 admin/views.py:444 +#: admin/forms.py:654 admin/views.py:450 msgid "Mail" msgstr "Correio" -#: admin/forms.py:618 +#: admin/forms.py:656 msgid "Permissions" msgstr "Permissões" -#: admin/models.py:78 +#: admin/models.py:80 msgid "You can't delete your own account" msgstr "Não pode apagar a sua própria conta" -#: admin/models.py:159 +#: admin/models.py:161 msgid "Failed to update password: LDAP module not installed" msgstr "Falha ao actualizar password: Modulo LDAP não instalado" -#: admin/models.py:165 +#: admin/models.py:167 #, python-format msgid "Failed to update password: %s" msgstr "Falha ao actualizar a password: %s" -#: admin/models.py:192 +#: admin/models.py:194 msgid "account" msgstr "conta" -#: admin/models.py:494 admin/models.py:720 admin/models.py:782 +#: admin/models.py:496 admin/models.py:733 admin/models.py:795 msgid "Invalid line" msgstr "Linha inválida" -#: admin/models.py:498 +#: admin/models.py:500 msgid "You can't import an account with a role greater than yours" msgstr "Não é possível importa uma conta com permissões superiores" -#: admin/models.py:518 +#: admin/models.py:506 +#, python-format +msgid "The simple user '%s' must have a valid email address" +msgstr "" + +#: admin/models.py:510 +#, python-format +msgid "username and email fields must not differ for '%s'" +msgstr "" + +#: admin/models.py:534 #, python-format msgid "Account import failed (%s): domain does not exist" msgstr "Importação da conta falhou (%s): domínio não existe" -#: admin/models.py:607 admin/models.py:733 +#: admin/models.py:624 admin/models.py:746 msgid "name" msgstr "nome" -#: admin/models.py:608 +#: admin/models.py:625 msgid "The domain name" msgstr "O nome do domínio" -#: admin/models.py:610 +#: admin/models.py:627 msgid "Default quota in MB applied to mailboxes" msgstr "Quota em MB aplicada por defeito às caixas de correio" -#: admin/models.py:613 admin/models.py:740 admin/models.py:1020 -#: admin/models.py:1181 extensions/postfix_autoreply/models.py:19 +#: admin/models.py:630 admin/models.py:753 admin/models.py:1045 +#: admin/models.py:1217 extensions/postfix_autoreply/models.py:27 msgid "enabled" msgstr "ativo" -#: admin/models.py:614 +#: admin/models.py:631 msgid "Check to activate this domain" msgstr "Marcar para ativar este domínio" -#: admin/models.py:734 +#: admin/models.py:747 msgid "The alias name" msgstr "O nome do 'alias'" -#: admin/models.py:736 +#: admin/models.py:749 msgid "target" msgstr "alvo" -#: admin/models.py:737 +#: admin/models.py:750 msgid "The domain this alias points to" msgstr "O domínio para o qual este alias irá apontar" -#: admin/models.py:741 admin/models.py:1021 +#: admin/models.py:754 admin/models.py:1046 msgid "Check to activate this alias" msgstr "Marcar para ativar este alias" -#: admin/models.py:788 +#: admin/models.py:801 #, python-format msgid "Unknown domain %s" msgstr "Domínio desconhecido: %s" -#: admin/models.py:805 admin/models.py:1006 +#: admin/models.py:818 admin/models.py:1031 msgid "address" msgstr "endereços" -#: admin/models.py:806 +#: admin/models.py:819 msgid "Mailbox address (without the @domain.tld part)" msgstr "Endereços das caixas de correio (sem a parte @domain.tld)" -#: admin/models.py:852 +#: admin/models.py:877 #, python-format msgid "Failed to retrieve mailbox location (%s)" msgstr "Falha ao recuperar a localização da caixa de correio (%s)" -#: admin/models.py:868 -#, python-format -msgid "Failed to rename mailbox: %s" -msgstr "Falha ao renomear a caixa de correio: %s" - -#: admin/models.py:894 -#, python-format -msgid "Failed to remove mailbox: %s" -msgstr "Falha ao remover a caixa de correio:%s" - -#: admin/models.py:909 +#: admin/models.py:921 #, python-format msgid "Quota is greater than the allowed domain's limit (%dM)" msgstr "A quota excede o limite permitido pelo domínio (%dM)" -#: admin/models.py:914 +#: admin/models.py:926 msgid "A quota is required" msgstr "É necessário uma quota" -#: admin/models.py:1007 +#: admin/models.py:1032 msgid "" -"The alias address (without the domain part). For a 'catch-all' address, just" -" enter an * character." -msgstr "O endereço do alias (sem a parte do domínio). Para um endereço 'cath-all', digite apenas o caractere *" +"The alias address (without the domain part). For a 'catch-all' address, just " +"enter an * character." +msgstr "" +"O endereço do alias (sem a parte do domínio). Para um endereço 'cath-all', " +"digite apenas o caractere *" -#: admin/models.py:1011 +#: admin/models.py:1036 msgid "mailboxes" msgstr "caixas de correio" -#: admin/models.py:1012 +#: admin/models.py:1037 msgid "The mailboxes this alias points to" msgstr "As caixas de correio para onde este alias irá apontar" -#: admin/models.py:1016 +#: admin/models.py:1041 msgid "The aliases this alias points to" msgstr "Este 'aliases' aponta para" -#: admin/models.py:1064 +#: admin/models.py:1089 msgid "distribution list" msgstr "lista de distribuição" -#: admin/models.py:1065 +#: admin/models.py:1090 msgid "forward" msgstr "reencaminhar" -#: admin/models.py:1066 +#: admin/models.py:1091 msgid "alias" msgstr "alias" -#: admin/models.py:1142 +#: admin/models.py:1170 #, python-format msgid "Invalid line: %s" msgstr "Linha inválida: %s" -#: admin/models.py:1167 -#, python-format -msgid "Mailbox %s does not exist" -msgstr "Caixa de correio %s não existe" +#: admin/models.py:1175 +#, fuzzy, python-format +msgid "Domain '%s' does not exist" +msgstr "O domínio não existe" -#: admin/models.py:1182 +#: admin/models.py:1218 msgid "Check to enable this extension" msgstr "Marque para ativar esta extensão" -#: admin/models.py:1282 +#: admin/models.py:1318 msgid "added" msgstr "acrescentado" -#: admin/models.py:1285 +#: admin/models.py:1321 msgid "modified" msgstr "modificado" -#: admin/models.py:1288 +#: admin/models.py:1324 msgid "deleted" msgstr "apagado" -#: admin/models.py:1290 +#: admin/models.py:1326 #, python-format msgid "%(object)s '%(name)s' %(action)s by user %(user)s" msgstr "%(object)s '%(name)s' %(action)s pelo utilizador %(user)s" @@ -631,7 +668,7 @@ msgid "Edit domain" msgstr "Editar domínio" #: admin/tables.py:21 admin/templates/admin/identities_table.html:8 -#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:79 +#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:83 #: extensions/sievefilters/templates/sievefilters/filter.html:17 #: extensions/sievefilters/templates/sievefilters/guieditor.html:5 #: extensions/webmail/templatetags/webextras.py:97 @@ -646,190 +683,210 @@ msgstr "Versão" msgid "Description" msgstr "Descrição" -#: admin/views.py:87 +#: admin/views.py:88 msgid "New domain" msgstr "Novo domínio" -#: admin/views.py:88 admin/views.py:97 admin/views.py:225 admin/views.py:438 -#: admin/views.py:445 extensions/sievefilters/views.py:120 -#: extensions/sievefilters/views.py:187 extensions/webmail/views.py:131 +#: admin/views.py:89 admin/views.py:98 admin/views.py:228 admin/views.py:444 +#: admin/views.py:451 extensions/sievefilters/views.py:129 +#: extensions/sievefilters/views.py:198 extensions/webmail/views.py:136 msgid "Create" msgstr "Criar" -#: admin/views.py:94 admin/views.py:442 +#: admin/views.py:95 admin/views.py:448 msgid "Next" msgstr "Seguinte" -#: admin/views.py:96 +#: admin/views.py:97 msgid "Options" msgstr "Opções" -#: admin/views.py:98 admin/views.py:446 +#: admin/views.py:99 admin/views.py:452 msgid "Previous" msgstr "Anterior" -#: admin/views.py:111 +#: admin/views.py:112 msgid "Domain created" msgstr "Domínio criado" -#: admin/views.py:144 admin/views.py:282 admin/views.py:492 +#: admin/views.py:146 admin/views.py:285 admin/views.py:498 #: extensions/postfix_autoreply/templates/postfix_autoreply/autoreply.html:9 -#: extensions/sievefilters/views.py:139 extensions/webmail/views.py:162 +#: extensions/sievefilters/views.py:148 extensions/webmail/views.py:168 #: userprefs/templates/userprefs/forward.html:8 #: userprefs/templates/userprefs/profile.html:8 msgid "Update" msgstr "Actualizar" -#: admin/views.py:160 +#: admin/views.py:162 msgid "Domain modified" msgstr "Domínio alterado" -#: admin/views.py:186 +#: admin/views.py:189 msgid "You can't delete your own domain" msgstr "Não é possível eliminar o seu próprio domínio" -#: admin/views.py:189 +#: admin/views.py:192 msgid "Domain deleted" msgid_plural "Domains deleted" msgstr[0] "Domínio criado" msgstr[1] "Domínios eliminados" -#: admin/views.py:204 +#: admin/views.py:207 msgid "Alias with this name already exists" msgstr "Já existe um 'alias' com este nome" -#: admin/views.py:247 +#: admin/views.py:250 msgid "New distribution list" msgstr "Nova lista de distribuição" -#: admin/views.py:248 +#: admin/views.py:251 msgid "Distribution list created" msgstr "A lista de distribuição foi criada" -#: admin/views.py:257 +#: admin/views.py:260 msgid "New alias" msgstr "Novo 'alias'" -#: admin/views.py:258 +#: admin/views.py:261 msgid "Alias created" msgstr "Alias criado" -#: admin/views.py:267 +#: admin/views.py:270 msgid "New forward" msgstr "Novo reencaminhamento" -#: admin/views.py:268 +#: admin/views.py:271 msgid "Forward created" msgstr "Reencaminhamento criado" -#: admin/views.py:286 +#: admin/views.py:289 msgid "Distribution list modified" msgstr "Lista de distribuição modificada" -#: admin/views.py:288 +#: admin/views.py:291 msgid "Forward modified" msgstr "Reencaminhamento modificado" -#: admin/views.py:290 +#: admin/views.py:293 msgid "Alias modified" msgstr "'Alias' modificado" -#: admin/views.py:403 admin/views.py:541 admin/views.py:546 -#: extensions/amavis/views.py:195 extensions/amavis/views.py:201 -#: extensions/amavis/views.py:234 extensions/amavis/views.py:238 -#: extensions/amavis/views.py:240 extensions/webmail/views.py:36 -#: extensions/webmail/views.py:64 extensions/webmail/views.py:77 -#: extensions/webmail/views.py:93 extensions/webmail/views.py:109 -#: extensions/webmail/views.py:193 extensions/webmail/views.py:419 -#: extensions/webmail/views.py:430 extensions/webmail/views.py:457 +#: admin/views.py:402 admin/views.py:545 admin/views.py:550 +#: extensions/amavis/views.py:204 extensions/amavis/views.py:210 +#: extensions/amavis/views.py:243 extensions/amavis/views.py:247 +#: extensions/amavis/views.py:249 extensions/webmail/views.py:41 +#: extensions/webmail/views.py:68 extensions/webmail/views.py:81 +#: extensions/webmail/views.py:98 extensions/webmail/views.py:114 +#: extensions/webmail/views.py:200 extensions/webmail/views.py:427 +#: extensions/webmail/views.py:438 extensions/webmail/views.py:465 #: lib/formutils.py:32 lib/formutils.py:37 msgid "Invalid request" msgstr "Pedido inválido" -#: admin/views.py:435 +#: admin/views.py:441 msgid "New account" msgstr "Nova conta" -#: admin/views.py:459 +#: admin/views.py:465 msgid "Account created" msgstr "Conta criada" -#: admin/views.py:507 +#: admin/views.py:513 msgid "Account updated" msgstr "Conta actualizada" -#: admin/views.py:531 +#: admin/views.py:535 msgid "Account deleted" msgid_plural "Accounts deleted" msgstr[0] "Conta eliminada" msgstr[1] "Contas eliminadas" -#: admin/views.py:586 +#: admin/views.py:590 msgid "Parameters saved" msgstr "Parâmetros salvos" -#: admin/views.py:632 +#: admin/views.py:636 msgid "Modifications applied." msgstr "Alterações efectuadas." -#: admin/views.py:740 +#: admin/views.py:743 #, python-format msgid "Object already exists: %s" msgstr "Este objeto já existe: %s" -#: admin/views.py:742 +#: admin/views.py:745 #, python-format msgid "%d objects imported successfully" msgstr "%d objetos importados com sucesso" -#: admin/views.py:760 +#: admin/views.py:763 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
                        \n" -"
                      • account; loginname; password; first name; last name; enabled; group; address[, domain, ...]
                      • \n" +"
                      • account; loginname; password; first name; last name; enabled; group; " +"address[, domain, ...]
                      • \n" "
                      • alias; address; enabled; internal recipient
                      • \n" "
                      • forward; address; enabled; external recipient
                      • \n" "
                      • dlist; address; enabled; recipient; recipient; ...
                      • \n" "
                      \n" -"

                      The first element of each line is mandatory and must be equal to one of the previous values.

                      \n" +"

                      The first element of each line is mandatory and must be equal to one of " +"the previous values.

                      \n" "\n" "

                      You can use a different character as separator.

                      \n" -msgstr "Forneça um ficheiro CSV cujas linhas respeitem um dos seguintes formatos:⏎\n
                        ⏎\n
                      • account; loginname; password; first name; last name; enabled; group; address[, domain, ...]
                      • ⏎\n
                      • alias; address; enabled; internal recipient
                      • ⏎\n
                      • forward; address; enabled; external recipient
                      • ⏎\n
                      • dlist; address; enabled; recipient; recipient; ...
                      • ⏎\n
                      ⏎\n

                      O primeiro elemento de cada linha é obrigatório e deve ser igual a um dos valores anteriores..

                      ⏎\n⏎\n

                      Pode utilizar um caractere diferente como separador.

                      ⏎\n" +msgstr "" +"Forneça um ficheiro CSV cujas linhas respeitem um dos seguintes formatos:⏎\n" +"
                        ⏎\n" +"
                      • account; loginname; password; first name; last name; enabled; group; " +"address[, domain, ...]
                      • ⏎\n" +"
                      • alias; address; enabled; internal recipient
                      • ⏎\n" +"
                      • forward; address; enabled; external recipient
                      • ⏎\n" +"
                      • dlist; address; enabled; recipient; recipient; ...
                      • ⏎\n" +"
                      ⏎\n" +"

                      O primeiro elemento de cada linha é obrigatório e deve ser igual a um dos " +"valores anteriores..

                      ⏎\n" +"⏎\n" +"

                      Pode utilizar um caractere diferente como separador.

                      ⏎\n" -#: admin/views.py:772 +#: admin/views.py:775 msgid "Import identities" msgstr "Importar identidades" -#: admin/views.py:773 admin/views.py:843 admin/templatetags/admin_extras.py:87 +#: admin/views.py:776 admin/views.py:846 admin/templatetags/admin_extras.py:87 #: admin/templatetags/admin_extras.py:144 msgid "Import" msgstr "Importar" -#: admin/views.py:803 +#: admin/views.py:806 msgid "Export identities" msgstr "Exportar identidades" -#: admin/views.py:804 admin/views.py:860 admin/templatetags/admin_extras.py:93 +#: admin/views.py:807 admin/views.py:863 admin/templatetags/admin_extras.py:93 #: admin/templatetags/admin_extras.py:150 msgid "Export" msgstr "Exportar" -#: admin/views.py:832 +#: admin/views.py:835 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
                        \n" "
                      • domain; name; quota; enabled
                      • \n" "
                      • domainalias; name; targeted domain; enabled
                      • \n" "
                      \n" -"

                      The first element of each line is mandatory and must be equal to one of the previous values.

                      \n" +"

                      The first element of each line is mandatory and must be equal to one of " +"the previous values.

                      \n" "

                      You can use a different character as separator.

                      \n" -msgstr "Forneça um ficheiro CSV cujas linhas respeitem um dos seguintes formatos:⏎
                        ⏎
                      • domain; name; quota; enabled
                      • ⏎
                      • domainalias; name; targeted domain; enabled
                      • ⏎
                      ⏎

                      O primeiro elemento de cada linha é obrigatório e deve ser igual a um dos valores anteriores.

                      ⏎

                      Pode utilizar um caractere diferente como separador.

                      ⏎\n" +msgstr "" +"Forneça um ficheiro CSV cujas linhas respeitem um dos seguintes formatos:⏎ " +"
                        ⏎
                      • domain; name; quota; enabled
                      • ⏎
                      • domainalias; " +"name; targeted domain; enabled
                      • ⏎
                      ⏎

                      O primeiro elemento de " +"cada linha é obrigatório e deve ser igual a um dos valores anteriores.

                      ⏎ " +"

                      Pode utilizar um caractere diferente como separador.

                      ⏎\n" -#: admin/views.py:842 +#: admin/views.py:845 msgid "Import domains" msgstr "Importar domínios" -#: admin/views.py:859 +#: admin/views.py:862 msgid "Export domains" msgstr "Exportar domínios" @@ -902,7 +959,7 @@ msgid "Tags" msgstr "Tags" #: admin/templates/admin/importform.html:5 -#: admin/templatetags/admin_extras.py:305 +#: admin/templatetags/admin_extras.py:290 msgid "Help" msgstr "Ajuda" @@ -949,7 +1006,7 @@ msgid "Previously on Modoboa..." msgstr "Anteriormente no Modoboa..." #: admin/templates/admin/logs.html:6 extensions/amavis/sql_listing.py:25 -#: extensions/webmail/lib.py:37 extensions/webmail/lib.py:406 +#: extensions/webmail/lib.py:38 extensions/webmail/lib.py:411 msgid "Date" msgstr "Data" @@ -1052,34 +1109,21 @@ msgid "View the domain's identities" msgstr "Visualizar as identidades do domínio" #: admin/templatetags/admin_extras.py:178 -msgid "Delete the domain" -msgstr "Apagar o domínio" - #: admin/templatetags/admin_extras.py:194 -msgid "Delete this account" -msgstr "Apagar esta conta" +#: admin/templatetags/admin_extras.py:201 +#, fuzzy, python-format +msgid "Delete %s?" +msgstr "Eliminar" -#: admin/templatetags/admin_extras.py:202 -msgid "Delete this distribution list" -msgstr "Apagar esta lista de distribuição" - -#: admin/templatetags/admin_extras.py:209 -msgid "Delete this forward" -msgstr "Apagar este reencaminhamento" - -#: admin/templatetags/admin_extras.py:216 -msgid "Delete this alias" -msgstr "Apagar este 'alias'" - -#: admin/templatetags/admin_extras.py:238 +#: admin/templatetags/admin_extras.py:223 msgid "Remove this permission" msgstr "Remover esta permissão" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "Yes" msgstr "Sim" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "No" msgstr "Não" @@ -1088,11 +1132,11 @@ msgstr "Não" msgid "User '%s' successfully logged in" msgstr "O utilizador '%s' fez login com sucesso" -#: auth/views.py:41 +#: auth/views.py:44 msgid "Your username and password didn't match. Please try again." msgstr "O seu nome de utilizador" -#: auth/views.py:64 +#: auth/views.py:67 #, python-format msgid "User '%s' logged out" msgstr "O utilizador '%s' fez logout" @@ -1118,15 +1162,31 @@ msgid "" "\n" "

                      Welcome to the online demo!

                      \n" "

                      Warning: the demo's concent is resetted every two hours.

                      \n" -"

                      To try the demo, the following users are available (username/password):

                      \n" +"

                      To try the demo, the following users are available (username/password):

                      \n" "
                        \n" "
                      • A super administrator : admin/password
                      • \n" "
                      • A domain administrator : admin@demo.local/admin
                      • \n" "
                      • A simple user : user@demo.local/user
                      • \n" "
                      \n" "

                      Please report any issue or give any suggestion to \n" -" the mailing list.

                      \n" -msgstr "\n

                      Bem-vindo à demo online!

                      \n

                      Aviso: os conteúdos desta demo são limpos a cada duas horas.

                      \n

                      Para experimentar a demo, estão disponíveis os seguintes utilizadores (username/password):

                      \n
                        \n
                      • Super administrador: admin/password
                      • \n
                      • Administrador de domínio: admin@demo.local/admin
                      • \n
                      • Utilizador básico: user@demo.local/user
                      • \n
                      \n

                      Para reportar qualquer problema ou apresentar uma sugestão, utilize o seguinte link \n mailing list.

                      \n" +" the " +"mailing list.

                      \n" +msgstr "" +"\n" +"

                      Bem-vindo à demo online!

                      \n" +"

                      Aviso: os conteúdos desta demo são limpos a cada duas horas.

                      \n" +"

                      Para experimentar a demo, estão disponíveis os seguintes utilizadores " +"(username/password):

                      \n" +"
                        \n" +"
                      • Super administrador: admin/password
                      • \n" +"
                      • Administrador de domínio: admin@demo.local/admin
                      • \n" +"
                      • Utilizador básico: user@demo.local/user
                      • \n" +"
                      \n" +"

                      Para reportar qualquer problema ou apresentar uma sugestão, utilize o " +"seguinte link \n" +" mailing " +"list.

                      \n" #: extensions/amavis/__init__.py:22 msgid "Simple amavis management frontend" @@ -1136,16 +1196,16 @@ msgstr "Interface de gestão básica do amavis" msgid "Quarantine" msgstr "Quarentena" -#: extensions/amavis/__init__.py:127 +#: extensions/amavis/__init__.py:129 msgid "pending requests" msgstr "pedidos pendentes" -#: extensions/amavis/__init__.py:144 +#: extensions/amavis/__init__.py:149 #, python-format msgid "%d pending requests" msgstr "%d pedidos pendentes" -#: extensions/amavis/__init__.py:156 +#: extensions/amavis/__init__.py:161 msgid "Content filter" msgstr "Filtro de conteúdo" @@ -1159,7 +1219,9 @@ msgstr "Idade maxima da messagem" #: extensions/amavis/app_settings.py:16 msgid "Quarantine messages maximum age (in days) before deletion" -msgstr "Tempo máximo que as mensagens ficam na quarentena (em dias) até serem eliminadas" +msgstr "" +"Tempo máximo que as mensagens ficam na quarentena (em dias) até serem " +"eliminadas" #: extensions/amavis/app_settings.py:19 msgid "Messages releasing" @@ -1171,7 +1233,9 @@ msgstr "Remover mensagens libertadas" #: extensions/amavis/app_settings.py:24 msgid "Remove messages marked as released while cleaning up the database" -msgstr "Remova as mensagens, marcadas como enviadas, durante a limpeza da base de dados" +msgstr "" +"Remova as mensagens, marcadas como enviadas, durante a limpeza da base de " +"dados" #: extensions/amavis/app_settings.py:28 msgid "Amavis connection mode" @@ -1260,12 +1324,12 @@ msgid "Virus filter" msgstr "Filtro de vírus" #: extensions/amavis/models.py:94 extensions/amavis/models.py:102 -#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:268 +#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:281 msgid "yes" msgstr "sim" #: extensions/amavis/models.py:95 extensions/amavis/models.py:103 -#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:272 +#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:285 msgid "no" msgstr "não" @@ -1277,7 +1341,9 @@ msgstr "predifinido" #: extensions/amavis/models.py:98 msgid "Bypass virus checks or not. Choose 'default' to use global settings." -msgstr "Ignorar a verificação de vírus ou não. Escolher 'predefinido' para utilizar as definições gerais." +msgstr "" +"Ignorar a verificação de vírus ou não. Escolher 'predefinido' para utilizar " +"as definições gerais." #: extensions/amavis/models.py:101 msgid "Spam filter" @@ -1285,7 +1351,9 @@ msgstr "Filtro de spam" #: extensions/amavis/models.py:106 msgid "Bypass spam checks or not. Choose 'default' to use global settings." -msgstr "Ignorar filtros de spam ou não. Escolher 'predefinido' para utilizar as definições gerais." +msgstr "" +"Ignorar filtros de spam ou não. Escolher 'predefinido' para utilizar as " +"definições gerais." #: extensions/amavis/models.py:109 msgid "Banned filter" @@ -1293,7 +1361,9 @@ msgstr "Ficheiros proibidos" #: extensions/amavis/models.py:114 msgid "Bypass banned checks or not. Choose 'default' to use global settings." -msgstr "Ignorar a verificação de ficheiros proibidos. Escolher 'predefinido' para utilizar as definições gerais." +msgstr "" +"Ignorar a verificação de ficheiros proibidos. Escolher 'predefinido' para " +"utilizar as definições gerais." #: extensions/amavis/models.py:144 msgid "Spam marker" @@ -1301,17 +1371,19 @@ msgstr "Marcador spam" #: extensions/amavis/models.py:146 msgid "" -"Modify spam subject using the specified text. Choose 'default' to use global" -" settings." -msgstr "Modifique o assunto de spam usando o texto especificado. Escolha 'default' para usar as configurações globais." +"Modify spam subject using the specified text. Choose 'default' to use global " +"settings." +msgstr "" +"Modifique o assunto de spam usando o texto especificado. Escolha 'default' " +"para usar as configurações globais." -#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:36 +#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:37 msgid "From" msgstr "De" #: extensions/amavis/sql_listing.py:24 extensions/sievefilters/forms.py:68 -#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:35 -#: extensions/webmail/lib.py:404 templates/common/email_searchbar.html:6 +#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:36 +#: extensions/webmail/lib.py:409 templates/common/email_searchbar.html:6 msgid "Subject" msgstr "Assunto" @@ -1321,37 +1393,37 @@ msgstr "Assunto" msgid "To" msgstr "Para" -#: extensions/amavis/views.py:34 +#: extensions/amavis/views.py:43 msgid "Empty quarantine" msgstr "Quarentena vazia" -#: extensions/amavis/views.py:202 +#: extensions/amavis/views.py:211 msgid "Message deleted" msgstr "Mensagem apagada" -#: extensions/amavis/views.py:223 +#: extensions/amavis/views.py:232 #, python-format msgid "%(count)d message deleted successfully" msgid_plural "%(count)d messages deleted successfully" msgstr[0] "%(count)d mensagem eliminada com sucesso" msgstr[1] "%(count)d mensagens eliminadas com sucesso" -#: extensions/amavis/views.py:243 +#: extensions/amavis/views.py:252 msgid "Request sent" msgstr "Pedido enviado" -#: extensions/amavis/views.py:249 +#: extensions/amavis/views.py:258 msgid "Message released" msgstr "Mensagem libertada" -#: extensions/amavis/views.py:271 +#: extensions/amavis/views.py:280 #, python-format msgid "%(count)d request sent" msgid_plural "%(count)d requests sent" msgstr[0] "%(count)d pedido enviado" msgstr[1] "%(count)d pedidos enviados" -#: extensions/amavis/views.py:295 +#: extensions/amavis/views.py:304 #, python-format msgid "%(count)d message released successfully" msgid_plural "%(count)d messages released successfully" @@ -1386,8 +1458,12 @@ msgid "" msgid_plural "" "\n" "%(counter)s release requests are pending for action.\n" -msgstr[0] "\n%(counter)s pedido de libertação pendente\n" -msgstr[1] "\n%(counter)s pedidos de libertação pendentes\n" +msgstr[0] "" +"\n" +"%(counter)s pedido de libertação pendente\n" +msgstr[1] "" +"\n" +"%(counter)s pedidos de libertação pendentes\n" #: extensions/amavis/templates/amavis/notifications/pending_requests.html:6 msgid "Sketch:" @@ -1472,7 +1548,7 @@ msgstr "Limites" msgid "Reseller" msgstr "Revendedor" -#: extensions/limits/__init__.py:96 +#: extensions/limits/__init__.py:94 msgid "Resources" msgstr "Recursos" @@ -1486,9 +1562,10 @@ msgid "Domain admins" msgstr "Administradores de domínio" #: extensions/limits/app_settings.py:15 -msgid "" -"Maximum number of allowed domain administrators for a new administrator" -msgstr "Número máximo permitido de administradores de domínio para um novo administrador" +msgid "Maximum number of allowed domain administrators for a new administrator" +msgstr "" +"Número máximo permitido de administradores de domínio para um novo " +"administrador" #: extensions/limits/app_settings.py:21 msgid "Maximum number of allowed domains for a new administrator" @@ -1496,7 +1573,8 @@ msgstr "Número máximo permitido de domínios para novo administrador" #: extensions/limits/app_settings.py:27 msgid "Maximum number of allowed domain aliases for a new administrator" -msgstr "Número máximo permitido de aliases de domínio para um novo administrador" +msgstr "" +"Número máximo permitido de aliases de domínio para um novo administrador" #: extensions/limits/app_settings.py:33 msgid "Maximum number of allowed mailboxes for a new administrator" @@ -1508,7 +1586,8 @@ msgstr "Número máximo de aliases permitidas para um novo administrador" #: extensions/limits/forms.py:13 msgid "Maximum number of domain administrators this user can create" -msgstr "Número máximo de administradores de domínio que este utilizador pode criar" +msgstr "" +"Número máximo de administradores de domínio que este utilizador pode criar" #: extensions/limits/forms.py:17 msgid "Maximum number of domains this user can create" @@ -1524,7 +1603,8 @@ msgstr "Número máximo de caixas de correio que este utilizador por criar" #: extensions/limits/forms.py:29 msgid "Maximum number of mailbox aliases this user can create" -msgstr "Número máximo de aliases para caixas de correio que este utilizador por criar" +msgstr "" +"Número máximo de aliases para caixas de correio que este utilizador por criar" #: extensions/limits/forms.py:46 msgid "Invalid limit" @@ -1578,7 +1658,9 @@ msgstr "Tempo limite de resposta automática" #: extensions/postfix_autoreply/app_settings.py:16 msgid "Timeout in seconds between two auto-replies to the same recipient" -msgstr "Tempo limite em segundos entre duas respostas automáticas para o mesmo destinatário" +msgstr "" +"Tempo limite em segundos entre duas respostas automáticas para o mesmo " +"destinatário" #: extensions/postfix_autoreply/forms.py:9 msgid "Until" @@ -1592,23 +1674,23 @@ msgstr "Ativar o seu aviso de ausência até esta data" msgid "This date is over" msgstr "Esta data ultrapassa" -#: extensions/postfix_autoreply/models.py:15 +#: extensions/postfix_autoreply/models.py:19 msgid "subject" msgstr "assunto" -#: extensions/postfix_autoreply/models.py:16 +#: extensions/postfix_autoreply/models.py:20 msgid "The subject that will appear in sent emails" msgstr "O assunto que irá constar nos e-mails enviados" -#: extensions/postfix_autoreply/models.py:17 +#: extensions/postfix_autoreply/models.py:23 msgid "content" msgstr "conteúdo" -#: extensions/postfix_autoreply/models.py:18 +#: extensions/postfix_autoreply/models.py:24 msgid "The content that will appear in sent emails" msgstr "O conteúdo que irá constar nos e-mails enviados" -#: extensions/postfix_autoreply/models.py:20 +#: extensions/postfix_autoreply/models.py:28 msgid "Activate/Deactivate your auto reply" msgstr "Ativar/desativar repostas automáticas" @@ -1742,53 +1824,53 @@ msgstr "Ligação ao servidor MANAGESIEVE falhou, valide a configuração" msgid "Not enough space on server" msgstr "Espaço insuficiente no servidor" -#: extensions/sievefilters/views.py:64 +#: extensions/sievefilters/views.py:68 msgid "Failed to retrieve filters set" msgstr "Falha ao recuperar os filtros definidos" -#: extensions/sievefilters/views.py:117 +#: extensions/sievefilters/views.py:126 #: extensions/sievefilters/templatetags/sfilters_tags.py:33 msgid "New filter" msgstr "Novo filtro" -#: extensions/sievefilters/views.py:124 +#: extensions/sievefilters/views.py:133 msgid "Filter created" msgstr "Filtro criado" -#: extensions/sievefilters/views.py:136 +#: extensions/sievefilters/views.py:145 #: extensions/sievefilters/templatetags/sfilters_tags.py:77 msgid "Edit filter" msgstr "Editar filtro" -#: extensions/sievefilters/views.py:145 +#: extensions/sievefilters/views.py:154 msgid "Filter modified" msgstr "Filtro modificado" -#: extensions/sievefilters/views.py:165 +#: extensions/sievefilters/views.py:176 msgid "Filter removed" msgstr "Filtro removido" -#: extensions/sievefilters/views.py:166 +#: extensions/sievefilters/views.py:177 msgid "Failed to remove filter" msgstr "Falha ao remover filtro" -#: extensions/sievefilters/views.py:180 +#: extensions/sievefilters/views.py:191 msgid "Filters set saved" msgstr "Grupo de filtros guardado" -#: extensions/sievefilters/views.py:185 +#: extensions/sievefilters/views.py:196 msgid "Create a new filters set" msgstr "Criar novo grupo de filtros" -#: extensions/sievefilters/views.py:208 +#: extensions/sievefilters/views.py:219 msgid "Filters set created" msgstr "Grupo de filtros criado" -#: extensions/sievefilters/views.py:229 +#: extensions/sievefilters/views.py:240 msgid "Filters set deleted" msgstr "Grupo de filtros eliminado" -#: extensions/sievefilters/views.py:241 +#: extensions/sievefilters/views.py:252 msgid "Filters set activated" msgstr "Grupo de filtros ativado" @@ -1804,18 +1886,19 @@ msgstr "Ativo" msgid "No filter defined yet" msgstr "Ainda não existe nenhum filtro definido" -#: extensions/sievefilters/templates/sievefilters/index.html:55 +#: extensions/sievefilters/templates/sievefilters/index.html:56 msgid "Filter sets" msgstr "Grupos de filtros" -#: extensions/sievefilters/templates/sievefilters/index.html:59 +#: extensions/sievefilters/templates/sievefilters/index.html:60 msgid "active" msgstr "ativo" -#: extensions/sievefilters/templates/sievefilters/index.html:73 +#: extensions/sievefilters/templates/sievefilters/index.html:74 msgid "" "No filters set defined yet. You must create one in order to define filters." -msgstr "Não existem grupos de filtros. Terá de criar um para poder definir filtros." +msgstr "" +"Não existem grupos de filtros. Terá de criar um para poder definir filtros." #: extensions/sievefilters/templatetags/sfilters_tags.py:16 msgid "New filters set" @@ -2127,84 +2210,89 @@ msgstr "Resposta do servidor" msgid "Cci" msgstr "Cci" -#: extensions/webmail/imaputils.py:259 +#: extensions/webmail/imaputils.py:237 +#, fuzzy +msgid "Failed to retrieve hierarchy delimiter" +msgstr "Falha ao recuperar os filtros definidos" + +#: extensions/webmail/imaputils.py:278 #, python-format msgid "Connection to IMAP server failed: %s" msgstr "A ligação ao servidor IMAP falhou: %s" -#: extensions/webmail/lib.py:353 +#: extensions/webmail/lib.py:358 msgid "wrote:" msgstr "escreveu:" -#: extensions/webmail/lib.py:418 extensions/webmail/lib.py:422 +#: extensions/webmail/lib.py:423 extensions/webmail/lib.py:427 msgid "Original message" msgstr "Mensagem original" -#: extensions/webmail/views.py:81 +#: extensions/webmail/views.py:86 #, python-format msgid "%(count)d message deleted" msgid_plural "%(count)d messages deleted" msgstr[0] "%(count)d mensagens eliminadas" msgstr[1] "%(count)d mensagens eliminadas" -#: extensions/webmail/views.py:98 +#: extensions/webmail/views.py:103 msgid "Unknown action" msgstr "Acção desconhecida" -#: extensions/webmail/views.py:111 lib/email_listing.py:137 +#: extensions/webmail/views.py:116 lib/email_listing.py:137 msgid "Empty mailbox" msgstr "Caixa de correio vazia" -#: extensions/webmail/views.py:128 -#: extensions/webmail/templatetags/webextras.py:169 +#: extensions/webmail/views.py:133 +#: extensions/webmail/templatetags/webextras.py:170 msgid "Create a new mailbox" msgstr "Criar nova caixa de correio" -#: extensions/webmail/views.py:143 +#: extensions/webmail/views.py:149 msgid "Mailbox created" msgstr "Caixa de correio criada" -#: extensions/webmail/views.py:159 +#: extensions/webmail/views.py:165 msgid "Edit mailbox" msgstr "Editar caixa de correio" -#: extensions/webmail/views.py:173 +#: extensions/webmail/views.py:180 msgid "Mailbox updated" msgstr "Caixa de correio actualizada" -#: extensions/webmail/views.py:207 extensions/webmail/views.py:388 -#: extensions/webmail/views.py:497 +#: extensions/webmail/views.py:214 extensions/webmail/views.py:396 +#: extensions/webmail/views.py:505 msgid "Bad request" msgstr "Pedido inválido" -#: extensions/webmail/views.py:238 +#: extensions/webmail/views.py:246 msgid "Failed to save attachment: " msgstr "Falha ao salvar o anexo:" -#: extensions/webmail/views.py:241 +#: extensions/webmail/views.py:249 #, python-format msgid "Attachment is too big (limit: %s)" msgstr "Anexo demasiado grande (limite %s)" -#: extensions/webmail/views.py:247 +#: extensions/webmail/views.py:255 #: extensions/webmail/templates/webmail/compose.html:15 #: extensions/webmail/templates/webmail/headers.html:4 msgid "Attachments" msgstr "Anexos" -#: extensions/webmail/views.py:263 +#: extensions/webmail/views.py:271 msgid "Bad query" msgstr "Pesquisa inválida" -#: extensions/webmail/views.py:273 +#: extensions/webmail/views.py:281 msgid "Failed to remove attachment: " msgstr "Falha ao remover os anexos:" -#: extensions/webmail/views.py:278 +#: extensions/webmail/views.py:286 msgid "Unknown attachment" msgstr "Anexo desconhecido" -#: extensions/webmail/views.py:493 +#: extensions/webmail/views.py:501 msgid "Undefined action" msgstr "Ação indefinida" @@ -2235,7 +2323,7 @@ msgstr[1] "%(counter)s ficheiros" msgid "Parent mailbox" msgstr "Caixa de correio principal" -#: extensions/webmail/templates/webmail/index.html:36 +#: extensions/webmail/templates/webmail/index.html:38 msgid "Mailbox quota" msgstr "Quota da caixa de correio" @@ -2297,15 +2385,15 @@ msgstr "Como não lidas" msgid "Compress folder" msgstr "Comprimir pasta" -#: extensions/webmail/templatetags/webextras.py:109 +#: extensions/webmail/templatetags/webextras.py:110 msgid "Empty folder" msgstr "Esvaziar pasta" -#: extensions/webmail/templatetags/webextras.py:177 +#: extensions/webmail/templatetags/webextras.py:178 msgid "Edit the selected mailbox" msgstr "Editar caixa de correio selecionada" -#: extensions/webmail/templatetags/webextras.py:182 +#: extensions/webmail/templatetags/webextras.py:183 msgid "Remove the selected mailbox" msgstr "Eliminar caixa de correio selecionada" @@ -2359,7 +2447,7 @@ msgstr "A página solicitada não existe." msgid "An internal error occured." msgstr "Ocorreu um erro interno." -#: templates/nlayout.html:56 +#: templates/nlayout.html:62 msgid "Powered by Modoboa" msgstr "Powered by Modoboa" @@ -2393,11 +2481,11 @@ msgstr "Fechar" msgid "Welcome to Modoboa" msgstr "Benvindo ao Modoboa" -#: templates/registration/login.html:33 +#: templates/registration/login.html:34 msgid "Remember me" msgstr "Lembrar-me" -#: templates/registration/login.html:35 +#: templates/registration/login.html:36 msgid "Log in" msgstr "Entrar" @@ -2413,7 +2501,7 @@ msgstr "Configurações por usuário" msgid "Prefered language" msgstr "Idioma preferido" -#: userprefs/app_settings.py:26 +#: userprefs/app_settings.py:27 msgid "Prefered language to display pages" msgstr "Idioma preferido para exibir páginas" @@ -2447,13 +2535,16 @@ msgstr "Conservar cópias locais" #: userprefs/forms.py:67 msgid "Forward messages and store copies into your local mailbox" -msgstr "Reencaminhar mensagens e armazenar cópias na sua caixa de correio local" +msgstr "" +"Reencaminhar mensagens e armazenar cópias na sua caixa de correio local" #: userprefs/forms.py:84 msgid "" "You can't define a forward to a local destination. Please ask your " "administrator to create an alias instead." -msgstr "Não é possível definir um reencaminhamento para um destino local. Por favor informe-se junto de um administrador para criar um alias." +msgstr "" +"Não é possível definir um reencaminhamento para um destino local. Por favor " +"informe-se junto de um administrador para criar um alias." #: userprefs/views.py:32 msgid "You need a mailbox in order to define a forward" @@ -2501,3 +2592,27 @@ msgstr "Atualizar o sua informação pessoal" #: userprefs/templatetags/uprefs_extras.py:57 msgid "Logout" msgstr "Sair" + +#~ msgid "Failed to rename mailbox: %s" +#~ msgstr "Falha ao renomear a caixa de correio: %s" + +#~ msgid "Failed to remove mailbox: %s" +#~ msgstr "Falha ao remover a caixa de correio:%s" + +#~ msgid "Mailbox %s does not exist" +#~ msgstr "Caixa de correio %s não existe" + +#~ msgid "Delete the domain" +#~ msgstr "Apagar o domínio" + +#~ msgid "Delete this account" +#~ msgstr "Apagar esta conta" + +#~ msgid "Delete this distribution list" +#~ msgstr "Apagar esta lista de distribuição" + +#~ msgid "Delete this forward" +#~ msgstr "Apagar este reencaminhamento" + +#~ msgid "Delete this alias" +#~ msgstr "Apagar este 'alias'" diff --git a/modoboa/locale/sv/LC_MESSAGES/django.po b/modoboa/locale/sv/LC_MESSAGES/django.po index f8a7c0833..7d8e66cac 100644 --- a/modoboa/locale/sv/LC_MESSAGES/django.po +++ b/modoboa/locale/sv/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Modoboa\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-06-01 16:40+0200\n" +"POT-Creation-Date: 2013-09-20 22:30+0200\n" "PO-Revision-Date: 2013-06-01 14:36+0000\n" "Last-Translator: Antoine Nguyen \n" "Language-Team: Swedish (http://www.transifex.com/projects/p/modoboa/language/" @@ -27,8 +27,8 @@ msgstr "Administrerings konsoll" msgid "Web based console to manage domains, accounts and aliases" msgstr "Webbaserad konsoll för att hantera domäner, konton och alias" -#: admin/__init__.py:16 admin/forms.py:179 admin/forms.py:614 -#: admin/views.py:93 admin/views.py:441 +#: admin/__init__.py:16 admin/forms.py:211 admin/forms.py:652 +#: admin/views.py:94 admin/views.py:447 #: extensions/postfix_autoreply/app_settings.py:11 #: extensions/sievefilters/app_settings.py:50 #: extensions/stats/app_settings.py:11 extensions/webmail/app_settings.py:11 @@ -247,15 +247,24 @@ msgstr "Standard topp omdirigering" msgid "The default redirection used when no application is specified" msgstr "Standard omdirigering när ingen applikation angetts" -#: admin/app_settings.py:230 +#: admin/app_settings.py:213 +msgid "Key must be either 16, 24, or 32 bytes long" +msgstr "" + +#: admin/app_settings.py:222 +#, fuzzy +msgid "Invalid syntax" +msgstr "Ogiltig rad" + +#: admin/app_settings.py:245 msgid "This field is required" msgstr "Detta fält är obligatoriskt" -#: admin/forms.py:16 admin/forms.py:459 admin/tables.py:18 +#: admin/forms.py:20 admin/forms.py:497 admin/tables.py:18 msgid "Alias(es)" msgstr "Alias" -#: admin/forms.py:18 +#: admin/forms.py:22 msgid "" "Alias(es) of this domain. Indicate only one name per input, press ENTER to " "add a new input." @@ -263,23 +272,23 @@ msgstr "" "Alias för denna domän. Ange endast ett namn per rad, tryck ENTER för att " "lägga till en rad." -#: admin/forms.py:55 +#: admin/forms.py:59 msgid "An alias with this name already exists" msgstr "Ett alias med detta namn finns redan" -#: admin/forms.py:69 +#: admin/forms.py:73 msgid "A domain with this name already exists" msgstr "En domän med detta namn existerar redan" -#: admin/forms.py:114 +#: admin/forms.py:146 msgid "Create a domain administrator" msgstr "Skapa en domän administratör" -#: admin/forms.py:116 +#: admin/forms.py:148 msgid "Automatically create an administrator for this domain" msgstr "Skapa en domän administratör automatiskt för denna domän" -#: admin/forms.py:120 admin/tables.py:12 admin/tables.py:47 +#: admin/forms.py:152 admin/tables.py:12 admin/tables.py:47 #: admin/templates/admin/editdomainform.html:13 #: admin/templates/admin/identities_table.html:5 #: admin/templates/admin/information.html:8 @@ -288,7 +297,7 @@ msgstr "Skapa en domän administratör automatiskt för denna domän" msgid "Name" msgstr "Namn" -#: admin/forms.py:122 +#: admin/forms.py:154 msgid "" "The administrator's name. Don't include the domain's name here, it will be " "automatically appended." @@ -296,28 +305,28 @@ msgstr "" "Administratörens namn. Inkludera inte domänens namn här, den kommer att " "läggas till automatiskt." -#: admin/forms.py:128 +#: admin/forms.py:160 msgid "Create aliases" msgstr "Skapa alias." -#: admin/forms.py:130 +#: admin/forms.py:162 msgid "Automatically create standard aliases for this domain" msgstr "Skapa automatiskt standard alias för den här domänen" -#: admin/forms.py:143 +#: admin/forms.py:175 msgid "Invalid format" msgstr "Ogiltigt format" -#: admin/forms.py:155 +#: admin/forms.py:187 #, python-format msgid "User '%s' already exists" msgstr "Användare '%s' finns redan" -#: admin/forms.py:203 +#: admin/forms.py:235 msgid "Email address" msgstr "E-post adress" -#: admin/forms.py:204 +#: admin/forms.py:236 msgid "" "The distribution list address. Use the '*' character to create a 'catchall' " "address (ex: *@domain.tld)." @@ -325,11 +334,11 @@ msgstr "" "Distributionslistans adress. Använd '*' för att skapa en 'catchall' adress " "(ex: *@domain.tld)." -#: admin/forms.py:207 +#: admin/forms.py:239 msgid "Recipients" msgstr "Mottagare" -#: admin/forms.py:208 +#: admin/forms.py:240 msgid "" "Mailbox(es) this alias will point to. Indicate only one address per input, " "press ENTER to add a new input." @@ -337,111 +346,110 @@ msgstr "" "Brevlåda/or detta alias kommer att peka på. Ange endast en adress per " "inlägg, tryck ENTER för att lägga till en ny inlägg." -#: admin/forms.py:246 admin/forms.py:504 admin/forms.py:530 -#: admin/models.py:1147 +#: admin/forms.py:278 admin/forms.py:542 admin/forms.py:568 msgid "Domain does not exist" msgstr "Domän existerar inte" -#: admin/forms.py:248 +#: admin/forms.py:280 msgid "You don't have access to this domain" msgstr "Du har inte åtkomst till denna domän" -#: admin/forms.py:268 +#: admin/forms.py:300 msgid "Invalid mailbox" msgstr "Ogiltig brevlåda" -#: admin/forms.py:284 +#: admin/forms.py:316 admin/models.py:1202 #, python-format msgid "Local recipient %s not found" msgstr "Lokal mottagare %s kunde inte hittas" -#: admin/forms.py:286 admin/forms.py:292 +#: admin/forms.py:318 admin/forms.py:324 #, python-format msgid "Recipient %s already present" msgstr "Mottagare %s finns redan" -#: admin/forms.py:297 +#: admin/forms.py:329 msgid "No recipient defined" msgstr "Ingen mottagare definierad" -#: admin/forms.py:311 extensions/webmail/forms.py:19 +#: admin/forms.py:343 extensions/webmail/forms.py:19 msgid "Select a file" msgstr "Välj en fil" -#: admin/forms.py:313 admin/forms.py:341 +#: admin/forms.py:345 admin/forms.py:373 msgid "Separator" msgstr "Separator" -#: admin/forms.py:316 +#: admin/forms.py:348 msgid "Continue on error" msgstr "Fortsätt vid fel" -#: admin/forms.py:317 +#: admin/forms.py:349 msgid "Don't treat duplicated objects as error" msgstr "Behandla inte duplicerade objekt som fel" -#: admin/forms.py:332 +#: admin/forms.py:364 msgid "Crypt passwords" msgstr "Krypterade lösenord" -#: admin/forms.py:333 +#: admin/forms.py:365 msgid "Check this option if passwords contained in your file are not crypted" msgstr "Markera det här alternativet om lösenord i filen inte är krypterad" -#: admin/forms.py:339 +#: admin/forms.py:371 msgid "File name" msgstr "Filnamn" -#: admin/forms.py:371 admin/templates/admin/editdomainform.html:13 +#: admin/forms.py:403 admin/templates/admin/editdomainform.html:13 #: auth/forms.py:7 msgid "Username" msgstr "Användarnamn" -#: admin/forms.py:373 +#: admin/forms.py:405 msgid "Role" msgstr "Roll" -#: admin/forms.py:374 admin/forms.py:401 +#: admin/forms.py:406 admin/forms.py:433 msgid "Choose" msgstr "Välj" -#: admin/forms.py:375 +#: admin/forms.py:407 msgid "What level of permission this user will have" msgstr "Vilken nivå av behörighet den här användaren har" -#: admin/forms.py:377 auth/forms.py:11 +#: admin/forms.py:409 auth/forms.py:11 msgid "Password" msgstr "Lösenord" -#: admin/forms.py:379 userprefs/forms.py:18 +#: admin/forms.py:411 userprefs/forms.py:18 msgid "Confirmation" msgstr "Bekräftelse" -#: admin/forms.py:381 +#: admin/forms.py:413 msgid "Enter the same password as above, for verification." msgstr "Ange samma lösenord som ovan för verifiering." -#: admin/forms.py:392 +#: admin/forms.py:424 msgid "Enabled" msgstr "Aktiverad" -#: admin/forms.py:434 +#: admin/forms.py:471 msgid "The two password fields didn't match." msgstr "Dessa två lösnordsfält matchar inte." -#: admin/forms.py:440 +#: admin/forms.py:477 msgid "You can't disable your own account" msgstr "Du kan inte inaktivera ditt eget konto" -#: admin/forms.py:450 +#: admin/forms.py:488 msgid "E-mail" msgstr "E-post" -#: admin/forms.py:452 +#: admin/forms.py:490 msgid "Quota" msgstr "Kvota" -#: admin/forms.py:454 +#: admin/forms.py:492 msgid "" "Quota in MB for this mailbox. Define a custom value or use domain's default " "one. Leave empty to define an unlimited value (not allowed for domain " @@ -451,7 +459,7 @@ msgstr "" "domänens förvalda. Lämna tomt för att definiera ett obegränsat värde (ej " "tillåtet för domänadministratörer)." -#: admin/forms.py:461 +#: admin/forms.py:499 msgid "" "Alias(es) of this mailbox. Indicate only one address per input, press ENTER " "to add a new input. Use the '*' character to create a 'catchall' alias (ex: " @@ -461,132 +469,132 @@ msgstr "" "lägga till ny rad. Använd '*' för att skapa ett 'catchall' alias (ex: " "*@domain.tld)." -#: admin/forms.py:512 +#: admin/forms.py:550 #, python-format msgid "Mailbox %s already exists" msgstr "Brevlåda %s finns redan" -#: admin/forms.py:572 +#: admin/forms.py:610 msgid "Domain(s)" msgstr "Domän(er)" -#: admin/forms.py:574 +#: admin/forms.py:612 msgid "Domain(s) that user administrates" msgstr "Domän(er) användaren administrerar" -#: admin/forms.py:616 admin/views.py:444 +#: admin/forms.py:654 admin/views.py:450 msgid "Mail" msgstr "Post" -#: admin/forms.py:618 +#: admin/forms.py:656 msgid "Permissions" msgstr "Rättigheter" -#: admin/models.py:78 +#: admin/models.py:80 msgid "You can't delete your own account" msgstr "Du kan inte radera ditt eget konto" -#: admin/models.py:159 +#: admin/models.py:161 msgid "Failed to update password: LDAP module not installed" msgstr "Misslyckades med att uppdatera lösenord: LDAP modul ej installerad" -#: admin/models.py:165 +#: admin/models.py:167 #, python-format msgid "Failed to update password: %s" msgstr "Misslyckades med att uppdatera lösenord: %s" -#: admin/models.py:192 +#: admin/models.py:194 msgid "account" msgstr "konto" -#: admin/models.py:494 admin/models.py:720 admin/models.py:782 +#: admin/models.py:496 admin/models.py:733 admin/models.py:795 msgid "Invalid line" msgstr "Ogiltig rad" -#: admin/models.py:498 +#: admin/models.py:500 msgid "You can't import an account with a role greater than yours" msgstr "Du kan inte importera konto med en roll större än din" -#: admin/models.py:518 +#: admin/models.py:506 +#, python-format +msgid "The simple user '%s' must have a valid email address" +msgstr "" + +#: admin/models.py:510 +#, python-format +msgid "username and email fields must not differ for '%s'" +msgstr "" + +#: admin/models.py:534 #, python-format msgid "Account import failed (%s): domain does not exist" msgstr "Konto import misslyckades (%s): domänen existerar inte" -#: admin/models.py:607 admin/models.py:733 +#: admin/models.py:624 admin/models.py:746 msgid "name" msgstr "namn" -#: admin/models.py:608 +#: admin/models.py:625 msgid "The domain name" msgstr "Domännamnet" -#: admin/models.py:610 +#: admin/models.py:627 msgid "Default quota in MB applied to mailboxes" msgstr "Standard kvota i MB applicerad för brevlådor" -#: admin/models.py:613 admin/models.py:740 admin/models.py:1020 -#: admin/models.py:1181 extensions/postfix_autoreply/models.py:19 +#: admin/models.py:630 admin/models.py:753 admin/models.py:1045 +#: admin/models.py:1217 extensions/postfix_autoreply/models.py:27 msgid "enabled" msgstr "aktiverad" -#: admin/models.py:614 +#: admin/models.py:631 msgid "Check to activate this domain" msgstr "Markera för att aktivera denna domän" -#: admin/models.py:734 +#: admin/models.py:747 msgid "The alias name" msgstr "Alias namn" -#: admin/models.py:736 +#: admin/models.py:749 msgid "target" msgstr "mål" -#: admin/models.py:737 +#: admin/models.py:750 msgid "The domain this alias points to" msgstr "Domän dit detta alias pekar mot" -#: admin/models.py:741 admin/models.py:1021 +#: admin/models.py:754 admin/models.py:1046 msgid "Check to activate this alias" msgstr "Markera för aktivera detta alias" -#: admin/models.py:788 +#: admin/models.py:801 #, python-format msgid "Unknown domain %s" msgstr "Okänt kommando %s" -#: admin/models.py:805 admin/models.py:1006 +#: admin/models.py:818 admin/models.py:1031 msgid "address" msgstr "adress" -#: admin/models.py:806 +#: admin/models.py:819 msgid "Mailbox address (without the @domain.tld part)" msgstr "Brevlåde adress (utan @domain.tld)" -#: admin/models.py:852 +#: admin/models.py:877 #, python-format msgid "Failed to retrieve mailbox location (%s)" msgstr "Kunde inte hitta brevlådans sökväg (%s)" -#: admin/models.py:868 -#, python-format -msgid "Failed to rename mailbox: %s" -msgstr "Kunde byta namn på brevlåda: %s" - -#: admin/models.py:894 -#, python-format -msgid "Failed to remove mailbox: %s" -msgstr "Kunde inte radera brevlåda: %s" - -#: admin/models.py:909 +#: admin/models.py:921 #, python-format msgid "Quota is greater than the allowed domain's limit (%dM)" msgstr "Kvotan är större än domänens gräns (%dM)" -#: admin/models.py:914 +#: admin/models.py:926 msgid "A quota is required" msgstr "En kvota krävs" -#: admin/models.py:1007 +#: admin/models.py:1032 msgid "" "The alias address (without the domain part). For a 'catch-all' address, just " "enter an * character." @@ -594,57 +602,57 @@ msgstr "" "Alias adress (utan domän delen). För en \"catch-all\"-adress, ange bara " "asterisk *." -#: admin/models.py:1011 +#: admin/models.py:1036 msgid "mailboxes" msgstr "brevlådor" -#: admin/models.py:1012 +#: admin/models.py:1037 msgid "The mailboxes this alias points to" msgstr "Brevlådorna detta alias pekar till" -#: admin/models.py:1016 +#: admin/models.py:1041 msgid "The aliases this alias points to" msgstr "Det alias detta alias pekar till" -#: admin/models.py:1064 +#: admin/models.py:1089 msgid "distribution list" msgstr "distributionslista" -#: admin/models.py:1065 +#: admin/models.py:1090 msgid "forward" msgstr "vidarebefordra" -#: admin/models.py:1066 +#: admin/models.py:1091 msgid "alias" msgstr "alias" -#: admin/models.py:1142 +#: admin/models.py:1170 #, python-format msgid "Invalid line: %s" msgstr "Ogiltig rad: %s" -#: admin/models.py:1167 -#, python-format -msgid "Mailbox %s does not exist" -msgstr "Brevlådan %s finns inte" +#: admin/models.py:1175 +#, fuzzy, python-format +msgid "Domain '%s' does not exist" +msgstr "Domän existerar inte" -#: admin/models.py:1182 +#: admin/models.py:1218 msgid "Check to enable this extension" msgstr "Markera för att aktivera detta tillägg" -#: admin/models.py:1282 +#: admin/models.py:1318 msgid "added" msgstr "tillagd" -#: admin/models.py:1285 +#: admin/models.py:1321 msgid "modified" msgstr "ändrad" -#: admin/models.py:1288 +#: admin/models.py:1324 msgid "deleted" msgstr "raderad" -#: admin/models.py:1290 +#: admin/models.py:1326 #, python-format msgid "%(object)s '%(name)s' %(action)s by user %(user)s" msgstr "%(object)s '%(name)s' %(action)s av användare %(user)s" @@ -654,7 +662,7 @@ msgid "Edit domain" msgstr "Redigera domän" #: admin/tables.py:21 admin/templates/admin/identities_table.html:8 -#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:79 +#: admin/templates/admin/listing.html:17 extensions/sievefilters/views.py:83 #: extensions/sievefilters/templates/sievefilters/filter.html:17 #: extensions/sievefilters/templates/sievefilters/guieditor.html:5 #: extensions/webmail/templatetags/webextras.py:97 @@ -669,143 +677,143 @@ msgstr "Version" msgid "Description" msgstr "Beskrivning" -#: admin/views.py:87 +#: admin/views.py:88 msgid "New domain" msgstr "Ny domän" -#: admin/views.py:88 admin/views.py:97 admin/views.py:225 admin/views.py:438 -#: admin/views.py:445 extensions/sievefilters/views.py:120 -#: extensions/sievefilters/views.py:187 extensions/webmail/views.py:131 +#: admin/views.py:89 admin/views.py:98 admin/views.py:228 admin/views.py:444 +#: admin/views.py:451 extensions/sievefilters/views.py:129 +#: extensions/sievefilters/views.py:198 extensions/webmail/views.py:136 msgid "Create" msgstr "Skapa" -#: admin/views.py:94 admin/views.py:442 +#: admin/views.py:95 admin/views.py:448 msgid "Next" msgstr "Nästa" -#: admin/views.py:96 +#: admin/views.py:97 msgid "Options" msgstr "Inställningar" -#: admin/views.py:98 admin/views.py:446 +#: admin/views.py:99 admin/views.py:452 msgid "Previous" msgstr "Föregående" -#: admin/views.py:111 +#: admin/views.py:112 msgid "Domain created" msgstr "Domän skapad" -#: admin/views.py:144 admin/views.py:282 admin/views.py:492 +#: admin/views.py:146 admin/views.py:285 admin/views.py:498 #: extensions/postfix_autoreply/templates/postfix_autoreply/autoreply.html:9 -#: extensions/sievefilters/views.py:139 extensions/webmail/views.py:162 +#: extensions/sievefilters/views.py:148 extensions/webmail/views.py:168 #: userprefs/templates/userprefs/forward.html:8 #: userprefs/templates/userprefs/profile.html:8 msgid "Update" msgstr "Uppdatera" -#: admin/views.py:160 +#: admin/views.py:162 msgid "Domain modified" msgstr "Domän ändrad" -#: admin/views.py:186 +#: admin/views.py:189 msgid "You can't delete your own domain" msgstr "Du kan inte radera din egen domän" -#: admin/views.py:189 +#: admin/views.py:192 msgid "Domain deleted" msgid_plural "Domains deleted" msgstr[0] "Domän raderad" msgstr[1] "Domäner raderade" -#: admin/views.py:204 +#: admin/views.py:207 msgid "Alias with this name already exists" msgstr "Alias med detta namn existerar redan" -#: admin/views.py:247 +#: admin/views.py:250 msgid "New distribution list" msgstr "Ny distributionslista" -#: admin/views.py:248 +#: admin/views.py:251 msgid "Distribution list created" msgstr "Distributionslista skapad" -#: admin/views.py:257 +#: admin/views.py:260 msgid "New alias" msgstr "Nytt alias" -#: admin/views.py:258 +#: admin/views.py:261 msgid "Alias created" msgstr "Alias skapat" -#: admin/views.py:267 +#: admin/views.py:270 msgid "New forward" msgstr "Ny vidarebefodring" -#: admin/views.py:268 +#: admin/views.py:271 msgid "Forward created" msgstr "Vidarebefodring skapad" -#: admin/views.py:286 +#: admin/views.py:289 msgid "Distribution list modified" msgstr "Distributionslista ändrad" -#: admin/views.py:288 +#: admin/views.py:291 msgid "Forward modified" msgstr "Vidarebefodring ändrad" -#: admin/views.py:290 +#: admin/views.py:293 msgid "Alias modified" msgstr "Alias ändrat" -#: admin/views.py:403 admin/views.py:541 admin/views.py:546 -#: extensions/amavis/views.py:195 extensions/amavis/views.py:201 -#: extensions/amavis/views.py:234 extensions/amavis/views.py:238 -#: extensions/amavis/views.py:240 extensions/webmail/views.py:36 -#: extensions/webmail/views.py:64 extensions/webmail/views.py:77 -#: extensions/webmail/views.py:93 extensions/webmail/views.py:109 -#: extensions/webmail/views.py:193 extensions/webmail/views.py:419 -#: extensions/webmail/views.py:430 extensions/webmail/views.py:457 +#: admin/views.py:402 admin/views.py:545 admin/views.py:550 +#: extensions/amavis/views.py:204 extensions/amavis/views.py:210 +#: extensions/amavis/views.py:243 extensions/amavis/views.py:247 +#: extensions/amavis/views.py:249 extensions/webmail/views.py:41 +#: extensions/webmail/views.py:68 extensions/webmail/views.py:81 +#: extensions/webmail/views.py:98 extensions/webmail/views.py:114 +#: extensions/webmail/views.py:200 extensions/webmail/views.py:427 +#: extensions/webmail/views.py:438 extensions/webmail/views.py:465 #: lib/formutils.py:32 lib/formutils.py:37 msgid "Invalid request" msgstr "Ogiltig förfrågan" -#: admin/views.py:435 +#: admin/views.py:441 msgid "New account" msgstr "Nytt konto" -#: admin/views.py:459 +#: admin/views.py:465 msgid "Account created" msgstr "Konto skapat" -#: admin/views.py:507 +#: admin/views.py:513 msgid "Account updated" msgstr "Konto uppdaterat" -#: admin/views.py:531 +#: admin/views.py:535 msgid "Account deleted" msgid_plural "Accounts deleted" msgstr[0] "Konto raderat" msgstr[1] "Konton raderade" -#: admin/views.py:586 +#: admin/views.py:590 msgid "Parameters saved" msgstr "Parametrar sparade" -#: admin/views.py:632 +#: admin/views.py:636 msgid "Modifications applied." msgstr "Modifieringar tillämpade." -#: admin/views.py:740 +#: admin/views.py:743 #, python-format msgid "Object already exists: %s" msgstr "Objektet existerar redan: %s" -#: admin/views.py:742 +#: admin/views.py:745 #, python-format msgid "%d objects imported successfully" msgstr "%d objekt importerade" -#: admin/views.py:760 +#: admin/views.py:763 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
                        \n" @@ -833,25 +841,25 @@ msgstr "" "⏎\n" "

                        Du kan använda ett annat tecken separator.

                        ⏎\n" -#: admin/views.py:772 +#: admin/views.py:775 msgid "Import identities" msgstr "Importera konton" -#: admin/views.py:773 admin/views.py:843 admin/templatetags/admin_extras.py:87 +#: admin/views.py:776 admin/views.py:846 admin/templatetags/admin_extras.py:87 #: admin/templatetags/admin_extras.py:144 msgid "Import" msgstr "Importera" -#: admin/views.py:803 +#: admin/views.py:806 msgid "Export identities" msgstr "Exportera konton" -#: admin/views.py:804 admin/views.py:860 admin/templatetags/admin_extras.py:93 +#: admin/views.py:807 admin/views.py:863 admin/templatetags/admin_extras.py:93 #: admin/templatetags/admin_extras.py:150 msgid "Export" msgstr "Exportera" -#: admin/views.py:832 +#: admin/views.py:835 msgid "" "Provide a CSV file where lines respect one of the following formats:\n" "
                          \n" @@ -871,11 +879,11 @@ msgstr "" "en av de tidigare värdena.\n" "

                          Du kan använda ett annat tecken som separator.\n" -#: admin/views.py:842 +#: admin/views.py:845 msgid "Import domains" msgstr "Importera domäner" -#: admin/views.py:859 +#: admin/views.py:862 msgid "Export domains" msgstr "Exportera domäner" @@ -948,7 +956,7 @@ msgid "Tags" msgstr "Tagg" #: admin/templates/admin/importform.html:5 -#: admin/templatetags/admin_extras.py:305 +#: admin/templatetags/admin_extras.py:290 msgid "Help" msgstr "Hjälp" @@ -995,7 +1003,7 @@ msgid "Previously on Modoboa..." msgstr "Tidigare på Modoboa..." #: admin/templates/admin/logs.html:6 extensions/amavis/sql_listing.py:25 -#: extensions/webmail/lib.py:37 extensions/webmail/lib.py:406 +#: extensions/webmail/lib.py:38 extensions/webmail/lib.py:411 msgid "Date" msgstr "Datum" @@ -1098,34 +1106,21 @@ msgid "View the domain's identities" msgstr "Visa domänens konton" #: admin/templatetags/admin_extras.py:178 -msgid "Delete the domain" -msgstr "Radera domänen" - #: admin/templatetags/admin_extras.py:194 -msgid "Delete this account" -msgstr "Radera detta konto" +#: admin/templatetags/admin_extras.py:201 +#, fuzzy, python-format +msgid "Delete %s?" +msgstr "Radera" -#: admin/templatetags/admin_extras.py:202 -msgid "Delete this distribution list" -msgstr "Radera denna distributionslista" - -#: admin/templatetags/admin_extras.py:209 -msgid "Delete this forward" -msgstr "Radera denna vidarebefodring" - -#: admin/templatetags/admin_extras.py:216 -msgid "Delete this alias" -msgstr "Radera detta alia" - -#: admin/templatetags/admin_extras.py:238 +#: admin/templatetags/admin_extras.py:223 msgid "Remove this permission" msgstr "Radera detta tillstånd" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "Yes" msgstr "Ja" -#: admin/templatetags/admin_extras.py:279 lib/formutils.py:206 +#: admin/templatetags/admin_extras.py:264 lib/formutils.py:206 msgid "No" msgstr "Nej" @@ -1134,11 +1129,11 @@ msgstr "Nej" msgid "User '%s' successfully logged in" msgstr "Användare '%s' har loggat in" -#: auth/views.py:41 +#: auth/views.py:44 msgid "Your username and password didn't match. Please try again." msgstr "Ditt användarnamn och lösenord matchar inte. Var vänlig försök igen." -#: auth/views.py:64 +#: auth/views.py:67 #, python-format msgid "User '%s' logged out" msgstr "Användare '%s' har loggat ut" @@ -1197,16 +1192,16 @@ msgstr "Enkel amavis hantering frontend" msgid "Quarantine" msgstr "Karantän" -#: extensions/amavis/__init__.py:127 +#: extensions/amavis/__init__.py:129 msgid "pending requests" msgstr "väntande förfrågningar" -#: extensions/amavis/__init__.py:144 +#: extensions/amavis/__init__.py:149 #, python-format msgid "%d pending requests" msgstr "%d väntande förfrågningar" -#: extensions/amavis/__init__.py:156 +#: extensions/amavis/__init__.py:161 msgid "Content filter" msgstr "Innehålls filter" @@ -1321,12 +1316,12 @@ msgid "Virus filter" msgstr "Virus filter" #: extensions/amavis/models.py:94 extensions/amavis/models.py:102 -#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:268 +#: extensions/amavis/models.py:110 extensions/sievefilters/views.py:281 msgid "yes" msgstr "ja" #: extensions/amavis/models.py:95 extensions/amavis/models.py:103 -#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:272 +#: extensions/amavis/models.py:111 extensions/sievefilters/views.py:285 msgid "no" msgstr "nej" @@ -1374,13 +1369,13 @@ msgstr "" "Ändra skräppost ämnesrad med vald text. Välj 'standard' för att använd " "globala inställningar." -#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:36 +#: extensions/amavis/sql_listing.py:23 extensions/webmail/lib.py:37 msgid "From" msgstr "Från" #: extensions/amavis/sql_listing.py:24 extensions/sievefilters/forms.py:68 -#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:35 -#: extensions/webmail/lib.py:404 templates/common/email_searchbar.html:6 +#: extensions/webmail/forms.py:10 extensions/webmail/lib.py:36 +#: extensions/webmail/lib.py:409 templates/common/email_searchbar.html:6 msgid "Subject" msgstr "Ämne" @@ -1390,37 +1385,37 @@ msgstr "Ämne" msgid "To" msgstr "Till" -#: extensions/amavis/views.py:34 +#: extensions/amavis/views.py:43 msgid "Empty quarantine" msgstr "Karantän tom" -#: extensions/amavis/views.py:202 +#: extensions/amavis/views.py:211 msgid "Message deleted" msgstr "Meddelande raderat" -#: extensions/amavis/views.py:223 +#: extensions/amavis/views.py:232 #, python-format msgid "%(count)d message deleted successfully" msgid_plural "%(count)d messages deleted successfully" msgstr[0] "%(count)d meddelande raderadat" msgstr[1] "%(count)d meddelanden raderade" -#: extensions/amavis/views.py:243 +#: extensions/amavis/views.py:252 msgid "Request sent" msgstr "Begäran skickad" -#: extensions/amavis/views.py:249 +#: extensions/amavis/views.py:258 msgid "Message released" msgstr "Meddelande släppt" -#: extensions/amavis/views.py:271 +#: extensions/amavis/views.py:280 #, python-format msgid "%(count)d request sent" msgid_plural "%(count)d requests sent" msgstr[0] "%(count)d förfrågning skickad" msgstr[1] "%(count)d förfrågningar skickadade" -#: extensions/amavis/views.py:295 +#: extensions/amavis/views.py:304 #, python-format msgid "%(count)d message released successfully" msgid_plural "%(count)d messages released successfully" @@ -1546,7 +1541,7 @@ msgstr "Gräns" msgid "Reseller" msgstr "Återförsäljare" -#: extensions/limits/__init__.py:96 +#: extensions/limits/__init__.py:94 msgid "Resources" msgstr "Resurser" @@ -1665,23 +1660,23 @@ msgstr "Aktivera auto-svar fram till detta datum" msgid "This date is over" msgstr "Detta datum har varit" -#: extensions/postfix_autoreply/models.py:15 +#: extensions/postfix_autoreply/models.py:19 msgid "subject" msgstr "ämne" -#: extensions/postfix_autoreply/models.py:16 +#: extensions/postfix_autoreply/models.py:20 msgid "The subject that will appear in sent emails" msgstr "Ämnesraden i skickade e-post meddelanden" -#: extensions/postfix_autoreply/models.py:17 +#: extensions/postfix_autoreply/models.py:23 msgid "content" msgstr "innehåll" -#: extensions/postfix_autoreply/models.py:18 +#: extensions/postfix_autoreply/models.py:24 msgid "The content that will appear in sent emails" msgstr "Innehållet i skickade e-post meddelanden" -#: extensions/postfix_autoreply/models.py:20 +#: extensions/postfix_autoreply/models.py:28 msgid "Activate/Deactivate your auto reply" msgstr "Aktivera / inaktivera din autosvar" @@ -1817,53 +1812,53 @@ msgstr "" msgid "Not enough space on server" msgstr "Inte tillräckligt med utrymme på servern" -#: extensions/sievefilters/views.py:64 +#: extensions/sievefilters/views.py:68 msgid "Failed to retrieve filters set" msgstr "Det gick inte att hämta filteruppsättning" -#: extensions/sievefilters/views.py:117 +#: extensions/sievefilters/views.py:126 #: extensions/sievefilters/templatetags/sfilters_tags.py:33 msgid "New filter" msgstr "Nytt filter" -#: extensions/sievefilters/views.py:124 +#: extensions/sievefilters/views.py:133 msgid "Filter created" msgstr "Filter krashade" -#: extensions/sievefilters/views.py:136 +#: extensions/sievefilters/views.py:145 #: extensions/sievefilters/templatetags/sfilters_tags.py:77 msgid "Edit filter" msgstr "Redigera filter" -#: extensions/sievefilters/views.py:145 +#: extensions/sievefilters/views.py:154 msgid "Filter modified" msgstr "Filter modifierat" -#: extensions/sievefilters/views.py:165 +#: extensions/sievefilters/views.py:176 msgid "Filter removed" msgstr "Filter raderat" -#: extensions/sievefilters/views.py:166 +#: extensions/sievefilters/views.py:177 msgid "Failed to remove filter" msgstr "Det gick inte att radera filtret" -#: extensions/sievefilters/views.py:180 +#: extensions/sievefilters/views.py:191 msgid "Filters set saved" msgstr "Filter uppsättning sparat" -#: extensions/sievefilters/views.py:185 +#: extensions/sievefilters/views.py:196 msgid "Create a new filters set" msgstr "Skapa ny filteruppsättning" -#: extensions/sievefilters/views.py:208 +#: extensions/sievefilters/views.py:219 msgid "Filters set created" msgstr "Filter uppsättning skapat" -#: extensions/sievefilters/views.py:229 +#: extensions/sievefilters/views.py:240 msgid "Filters set deleted" msgstr "Filter uppsättning raderad" -#: extensions/sievefilters/views.py:241 +#: extensions/sievefilters/views.py:252 msgid "Filters set activated" msgstr "Filter uppsättning aktiverad" @@ -1879,15 +1874,15 @@ msgstr "Aktivera" msgid "No filter defined yet" msgstr "Inga filter definierade än" -#: extensions/sievefilters/templates/sievefilters/index.html:55 +#: extensions/sievefilters/templates/sievefilters/index.html:56 msgid "Filter sets" msgstr "Filter uppsättning" -#: extensions/sievefilters/templates/sievefilters/index.html:59 +#: extensions/sievefilters/templates/sievefilters/index.html:60 msgid "active" msgstr "aktivera" -#: extensions/sievefilters/templates/sievefilters/index.html:73 +#: extensions/sievefilters/templates/sievefilters/index.html:74 msgid "" "No filters set defined yet. You must create one in order to define filters." msgstr "" @@ -2204,84 +2199,89 @@ msgstr "Server svar" msgid "Cci" msgstr "BCC" -#: extensions/webmail/imaputils.py:259 +#: extensions/webmail/imaputils.py:237 +#, fuzzy +msgid "Failed to retrieve hierarchy delimiter" +msgstr "Det gick inte att hämta filteruppsättning" + +#: extensions/webmail/imaputils.py:278 #, python-format msgid "Connection to IMAP server failed: %s" msgstr "Anslutning till IMAP servern misslyckades: %s" -#: extensions/webmail/lib.py:353 +#: extensions/webmail/lib.py:358 msgid "wrote:" msgstr "skrev:" -#: extensions/webmail/lib.py:418 extensions/webmail/lib.py:422 +#: extensions/webmail/lib.py:423 extensions/webmail/lib.py:427 msgid "Original message" msgstr "Orginalmeddelande" -#: extensions/webmail/views.py:81 +#: extensions/webmail/views.py:86 #, python-format msgid "%(count)d message deleted" msgid_plural "%(count)d messages deleted" msgstr[0] "" msgstr[1] "" -#: extensions/webmail/views.py:98 +#: extensions/webmail/views.py:103 msgid "Unknown action" msgstr "Okänd åtgärd" -#: extensions/webmail/views.py:111 lib/email_listing.py:137 +#: extensions/webmail/views.py:116 lib/email_listing.py:137 msgid "Empty mailbox" msgstr "Tom brevlåda" -#: extensions/webmail/views.py:128 -#: extensions/webmail/templatetags/webextras.py:169 +#: extensions/webmail/views.py:133 +#: extensions/webmail/templatetags/webextras.py:170 msgid "Create a new mailbox" msgstr "Skapa en ny brevlåda" -#: extensions/webmail/views.py:143 +#: extensions/webmail/views.py:149 msgid "Mailbox created" msgstr "Brevlåda skapad" -#: extensions/webmail/views.py:159 +#: extensions/webmail/views.py:165 msgid "Edit mailbox" msgstr "Redigera brevlåda" -#: extensions/webmail/views.py:173 +#: extensions/webmail/views.py:180 msgid "Mailbox updated" msgstr "Brevlåda uppdaterad" -#: extensions/webmail/views.py:207 extensions/webmail/views.py:388 -#: extensions/webmail/views.py:497 +#: extensions/webmail/views.py:214 extensions/webmail/views.py:396 +#: extensions/webmail/views.py:505 msgid "Bad request" msgstr "Ogiltig fråga" -#: extensions/webmail/views.py:238 +#: extensions/webmail/views.py:246 msgid "Failed to save attachment: " msgstr "Det gick inte att spara bilaga:" -#: extensions/webmail/views.py:241 +#: extensions/webmail/views.py:249 #, python-format msgid "Attachment is too big (limit: %s)" msgstr "Bilagan är för stor (max:% s)" -#: extensions/webmail/views.py:247 +#: extensions/webmail/views.py:255 #: extensions/webmail/templates/webmail/compose.html:15 #: extensions/webmail/templates/webmail/headers.html:4 msgid "Attachments" msgstr "Bilagor" -#: extensions/webmail/views.py:263 +#: extensions/webmail/views.py:271 msgid "Bad query" msgstr "Dålig fråga" -#: extensions/webmail/views.py:273 +#: extensions/webmail/views.py:281 msgid "Failed to remove attachment: " msgstr "Misslyckades med att radera bilaga:" -#: extensions/webmail/views.py:278 +#: extensions/webmail/views.py:286 msgid "Unknown attachment" msgstr "Okänd bilaa" -#: extensions/webmail/views.py:493 +#: extensions/webmail/views.py:501 msgid "Undefined action" msgstr "Odefinierad åtgärd" @@ -2312,7 +2312,7 @@ msgstr[1] " %(counter)s filer" msgid "Parent mailbox" msgstr "Brevlådas förälder" -#: extensions/webmail/templates/webmail/index.html:36 +#: extensions/webmail/templates/webmail/index.html:38 msgid "Mailbox quota" msgstr "Brevlåde kvota" @@ -2374,15 +2374,15 @@ msgstr "Som oläst" msgid "Compress folder" msgstr "Komprimera katalog" -#: extensions/webmail/templatetags/webextras.py:109 +#: extensions/webmail/templatetags/webextras.py:110 msgid "Empty folder" msgstr "Töm katalog" -#: extensions/webmail/templatetags/webextras.py:177 +#: extensions/webmail/templatetags/webextras.py:178 msgid "Edit the selected mailbox" msgstr "Redigera vald brevlåda" -#: extensions/webmail/templatetags/webextras.py:182 +#: extensions/webmail/templatetags/webextras.py:183 msgid "Remove the selected mailbox" msgstr "Radera vald brevlåda" @@ -2436,7 +2436,7 @@ msgstr "Den begärda sidan finns inte." msgid "An internal error occured." msgstr "Ett internt fel uppstod." -#: templates/nlayout.html:56 +#: templates/nlayout.html:62 msgid "Powered by Modoboa" msgstr "Powered by Modoboa" @@ -2470,11 +2470,11 @@ msgstr "Stäng" msgid "Welcome to Modoboa" msgstr "Välkommen till Modoboa" -#: templates/registration/login.html:33 +#: templates/registration/login.html:34 msgid "Remember me" msgstr "Kom ihåg mig" -#: templates/registration/login.html:35 +#: templates/registration/login.html:36 msgid "Log in" msgstr "Logga in" @@ -2490,7 +2490,7 @@ msgstr "Per användare inställningar" msgid "Prefered language" msgstr "Önskat språk" -#: userprefs/app_settings.py:26 +#: userprefs/app_settings.py:27 msgid "Prefered language to display pages" msgstr "Önskat språk för att visa sidor" @@ -2580,3 +2580,27 @@ msgstr "Uppdatera personlig information" #: userprefs/templatetags/uprefs_extras.py:57 msgid "Logout" msgstr "Logga ut" + +#~ msgid "Failed to rename mailbox: %s" +#~ msgstr "Kunde byta namn på brevlåda: %s" + +#~ msgid "Failed to remove mailbox: %s" +#~ msgstr "Kunde inte radera brevlåda: %s" + +#~ msgid "Mailbox %s does not exist" +#~ msgstr "Brevlådan %s finns inte" + +#~ msgid "Delete the domain" +#~ msgstr "Radera domänen" + +#~ msgid "Delete this account" +#~ msgstr "Radera detta konto" + +#~ msgid "Delete this distribution list" +#~ msgstr "Radera denna distributionslista" + +#~ msgid "Delete this forward" +#~ msgstr "Radera denna vidarebefodring" + +#~ msgid "Delete this alias" +#~ msgstr "Radera detta alia" diff --git a/modoboa/static/js/confirmation.js b/modoboa/static/js/confirmation.js index e360eba04..59bd9314d 100644 --- a/modoboa/static/js/confirmation.js +++ b/modoboa/static/js/confirmation.js @@ -36,9 +36,11 @@ id: "confirmbox", 'class': "modal" }); + var question = (typeof this.options.question == 'function') + ? this.options.question.apply(this) : this.options.question; box.append($('