Projects
Kolab:3.4
pykolab
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 148
View file
pykolab.spec
Changed
@@ -28,19 +28,13 @@ Summary: Kolab Groupware Solution Name: pykolab -Version: 0.7.8 -Release: 3%{?dist} +Version: 0.7.9 +Release: 1%{?dist} License: GPLv3+ Group: Applications/System URL: http://kolab.org/ Source0: http://files.kolab.org/releases/%{name}-%{version}.tar.gz -Patch4: remove-plugin-threading_as_default.patch -Patch5: deliver-to-shared-folders-with-spaces.patch -Patch6: fix_kolabsaslauthd_centos7.patch -Patch7: fix_run_kolabd_centos7.patch -Patch8: fix_clamd_sock_centos7.patch -Patch9: fix_wallace_pid_location_centos7.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildArch: noarch @@ -206,15 +200,8 @@ %prep %setup -q -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 - %build -autoreconf -v +autoreconf -v || automake --add-missing && autoreconf -v %configure %install @@ -535,8 +522,10 @@ %attr(0700,%{kolab_user},%{kolab_group}) %dir %{_var}/spool/pykolab/wallace %changelog -* Mon Feb 23 2015 Timotheus Pokorra (TBits.net) <tp@tbits.net> -- fix location of wallace pid file on CentOS7, #4673 +* Mon Feb 23 2015 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 0.7.9-1 +- Release of version 0.7.9, see; + + https://issues.kolab.org/buglist.cgi?target_milestone=0.7.9&product=pykolab * Fri Feb 20 2015 Timotheus Pokorra (TBits.net) <tp@tbits.net> - more fixes for CentOS7, fix path for /run/kolabd, fixing #2626
View file
deliver-to-shared-folders-with-spaces.patch
Deleted
@@ -1,25 +0,0 @@ -From 1ae974030e1e71565872f7265ba33f1cd82986bd Mon Sep 17 00:00:00 2001 -From: Daniel Hoffend <dh@dotlan.net> -Date: Wed, 18 Feb 2015 00:55:40 +0100 -Subject: [PATCH] deliver to shared folders with spaces #4613 - ---- - pykolab/setup/setup_mta.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/pykolab/setup/setup_mta.py b/pykolab/setup/setup_mta.py -index 88c6f6c..0cd9c33 100644 ---- a/pykolab/setup/setup_mta.py -+++ b/pykolab/setup/setup_mta.py -@@ -226,7 +226,7 @@ bind_pw = %(service_bind_pw)s - - query_filter = (&(|(mail=%%s)(alias=%%s))(objectclass=kolabsharedfolder)(kolabFolderType=mail)) - result_attribute = kolabtargetfolder --result_format = shared+%%s -+result_format = "shared+%%s" - """ % { - "base_dn": conf.get('ldap', 'base_dn'), - "server_host": server_host, --- -1.9.1 -
View file
fix_clamd_sock_centos7.patch
Deleted
@@ -1,54 +0,0 @@ -From e43e509c773c7f69ab4c479c708d20aae0cf063d Mon Sep 17 00:00:00 2001 -From: Timotheus Pokorra <tp@tbits.net> -Date: Thu, 19 Feb 2015 13:38:54 +0100 -Subject: [PATCH 2/2] CentOS7: make sure we are using the correct path for the - clamd.sock (#3565) reading from - /etc/clamd.d/amavisd.conf, otherwise defaulting to - /var/spool/amavisd/clamd.sock which was previously used - ---- - pykolab/setup/setup_mta.py | 7 +++++++ - share/templates/amavisd.conf.tpl | 2 +- - 2 files changed, 8 insertions(+), 1 deletion(-) - -diff --git a/pykolab/setup/setup_mta.py b/pykolab/setup/setup_mta.py -index 0cd9c33..56109fe 100644 ---- a/pykolab/setup/setup_mta.py -+++ b/pykolab/setup/setup_mta.py -@@ -363,6 +363,7 @@ result_format = "shared+%%s" - 'primary_domain': conf.get('kolab', 'primary_domain'), - 'ldap_filter': "(|(mail=%m)(alias=%m))", - 'ldap_base_dn': conf.get('ldap', 'base_dn'), -+ 'clamdsock': '/var/spool/amavisd/clamd.sock', - } - - template_file = None -@@ -381,6 +382,12 @@ result_format = "shared+%%s" - template_definition = fp.read() - fp.close() - -+ if os.path.isfile('/etc/clamd.d/amavisd.conf'): -+ amavisdconf_content = file('/etc/clamd.d/amavisd.conf') -+ for line in amavisdconf_content: -+ if line.startswith('LocalSocket'): -+ amavisd_settings['clamdsock'] = line[len('LocalSocket '):].strip() -+ - t = Template(template_definition, searchList=[amavisd_settings]) - - fp = None -diff --git a/share/templates/amavisd.conf.tpl b/share/templates/amavisd.conf.tpl -index 12fb4ed..1fa43fb 100644 ---- a/share/templates/amavisd.conf.tpl -+++ b/share/templates/amavisd.conf.tpl -@@ -373,7 +373,7 @@ use strict; - - # \#\## http://www.clamav.net/ - ['ClamAV-clamd', -- \&ask_daemon, ["CONTSCAN {}\n", "/var/spool/amavisd/clamd.sock"], -+ \&ask_daemon, ["CONTSCAN {}\n", "$clamdsock"], - qr/\bOK\$/m, qr/\bFOUND\$/m, - qr/^.*?: (?!Infected Archive)(.*) FOUND\$/m ], - # # NOTE: run clamd under the same user as amavisd, or run it under its own --- -1.7.9.5 -
View file
fix_kolabsaslauthd_centos7.patch
Deleted
@@ -1,26 +0,0 @@ -From 8ffb806fd0a0ff53dbb38daa00aee542785b323b Mon Sep 17 00:00:00 2001 -From: Timotheus Pokorra <tp@tbits.net> -Date: Thu, 19 Feb 2015 10:54:24 +0100 -Subject: [PATCH] CentOS7 systemd: fix location of kolab-saslauthd socket - (#4628) from the default of /var/run/saslauthd/mux to /run/saslauthd/mux - ---- - saslauthd/kolab-saslauthd.systemd | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/saslauthd/kolab-saslauthd.systemd b/saslauthd/kolab-saslauthd.systemd -index a39073c..f54b9d0 100644 ---- a/saslauthd/kolab-saslauthd.systemd -+++ b/saslauthd/kolab-saslauthd.systemd -@@ -6,7 +6,7 @@ After=syslog.target network.target - Type=forking - PIDFile=/var/run/kolab-saslauthd/kolab-saslauthd.pid - EnvironmentFile=/etc/sysconfig/kolab-saslauthd --ExecStart=/usr/sbin/kolab-saslauthd $FLAGS -+ExecStart=/usr/sbin/kolab-saslauthd $FLAGS --socket /run/saslauthd/mux - ExecReload=/bin/kill -HUP $MAINPID - ExecStop=/bin/kill -TERM $MAINPID - --- -1.8.3.1 -
View file
fix_run_kolabd_centos7.patch
Deleted
@@ -1,23 +0,0 @@ -From ae9894cee0f8b85978d6b96d57d0a006d2c975ae Mon Sep 17 00:00:00 2001 -From: Timotheus Pokorra <tp@tbits.net> -Date: Fri, 20 Feb 2015 07:15:23 +0100 -Subject: [PATCH 1/2] CentOS7 systemd: need to adjust the - kolabd.tmpfiles.d.conf as well (#2626) that was - pointing still to /var/run/kolabd instead of - /run/kolabd as in the spec file - ---- - kolabd/kolabd.tmpfiles.d.conf | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/kolabd/kolabd.tmpfiles.d.conf b/kolabd/kolabd.tmpfiles.d.conf -index ce98b6e..abea15c 100644 ---- a/kolabd/kolabd.tmpfiles.d.conf -+++ b/kolabd/kolabd.tmpfiles.d.conf -@@ -1,2 +1,2 @@ --d /var/run/kolabd 750 kolab kolab -+d /run/kolabd 750 kolab kolab - --- -1.7.9.5 -
View file
fix_wallace_pid_location_centos7.patch
Deleted
@@ -1,40 +0,0 @@ -From 2560d642b84828e6feba4d934b3b7f8e589d141a Mon Sep 17 00:00:00 2001 -From: Timotheus Pokorra <tp@tbits.net> -Date: Mon, 23 Feb 2015 07:31:21 +0100 -Subject: [PATCH] CentOS7 systemd: use /run/wallaced as location for the pid file (#4673) - instead of a mix of /var/run/wallaced and /run/wallaced - ---- - wallace/wallace.systemd | 4 ++-- - wallace/wallace.tmpfiles.d.conf | 2 +- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/wallace/wallace.systemd b/wallace/wallace.systemd -index 38a6604..c033269 100644 ---- a/wallace/wallace.systemd -+++ b/wallace/wallace.systemd -@@ -4,11 +4,11 @@ After=syslog.target network.target - - [Service] - Type=forking --PIDFile=/var/run/wallaced/wallaced.pid -+PIDFile=/run/wallaced/wallaced.pid - User=kolab - Group=kolab - EnvironmentFile=/etc/sysconfig/wallace --ExecStart=/usr/sbin/wallaced $FLAGS -+ExecStart=/usr/sbin/wallaced $FLAGS --pid-file /run/wallaced/wallaced.pid - ExecReload=/bin/kill -HUP $MAINPID - ExecStop=/bin/kill -TERM $MAINPID - -diff --git a/wallace/wallace.tmpfiles.d.conf b/wallace/wallace.tmpfiles.d.conf -index 7dd659a..b072311 100644 ---- a/wallace/wallace.tmpfiles.d.conf -+++ b/wallace/wallace.tmpfiles.d.conf -@@ -1,2 +1,2 @@ --d /var/run/wallaced 750 kolab kolab -+d /run/wallaced 750 kolab kolab - --- -1.7.1 -
View file
remove-plugin-threading_as_default.patch
Deleted
@@ -1,24 +0,0 @@ -From dc75af98a0caf858d5e35100f9b6a51bc4b21309 Mon Sep 17 00:00:00 2001 -From: Daniel Hoffend <dh@dotlan.net> -Date: Sun, 15 Feb 2015 01:07:59 +0100 -Subject: [PATCH] plugin threading_as_default no longer exists #4570 - ---- - share/templates/roundcubemail/config.inc.php.tpl | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/share/templates/roundcubemail/config.inc.php.tpl b/share/templates/roundcubemail/config.inc.php.tpl -index 77cadab..7206a09 100644 ---- a/share/templates/roundcubemail/config.inc.php.tpl -+++ b/share/templates/roundcubemail/config.inc.php.tpl -@@ -68,7 +68,6 @@ - 'password', - 'redundant_attachments', - 'tasklist', -- 'threading_as_default', - // contextmenu must be after kolab_addressbook (#444) - 'contextmenu', - ); --- -1.9.1 -
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +pykolab (0.7.9-0~kolab1) unstable; urgency=low + + * https://issues.kolab.org/buglist.cgi?target_milestone=0.7.9&product=pykolab + + -- Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Mon, 23 Feb 2015 01:49:00 +0100 + pykolab (0.7.8-0~kolab3) unstable; urgency=low * deliver to shared folders with spaces #4613
View file
pykolab-0.7.8.tar.gz/configure.ac -> pykolab-0.7.9.tar.gz/configure.ac
Changed
@@ -1,4 +1,4 @@ -AC_INIT([pykolab], 0.7.8) +AC_INIT([pykolab], 0.7.9) AC_SUBST([RELEASE], 1) AC_CONFIG_SRCDIR(pykolab/constants.py.in)
View file
pykolab-0.7.8.tar.gz/kolabd/kolabd.tmpfiles.d.conf -> pykolab-0.7.9.tar.gz/kolabd/kolabd.tmpfiles.d.conf
Changed
@@ -1,2 +1,2 @@ -d /var/run/kolabd 750 kolab kolab +d /run/kolabd 750 kolab kolab
View file
pykolab-0.7.8.tar.gz/po/de.po -> pykolab-0.7.9.tar.gz/po/de.po
Changed
@@ -5,7 +5,8 @@ # Translators: # Christoph Wickert <christoph.wickert@gmail.com>, 2015 # Christoph Wickert <christoph.wickert@gmail.com>, 2011 -# Ettore Atalan <atalanttore@googlemail.com>, 2014 +# Dirk Marschner <info@marschner.cx>, 2015 +# Ettore Atalan <atalanttore@googlemail.com>, 2014-2015 # Torsten Grote <grote@kolabsys.com>, 2012 # Jeroen van Meeuwen <vanmeeuwen@kolabsys.com>, 2015 # balin <johannes_graumann@web.de>, 2012 @@ -18,8 +19,8 @@ "Project-Id-Version: Kolab Groupware Solution\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-01-14 01:36+0100\n" -"PO-Revision-Date: 2015-01-23 15:10+0000\n" -"Last-Translator: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com>\n" +"PO-Revision-Date: 2015-02-01 15:31+0000\n" +"Last-Translator: Dirk Marschner <info@marschner.cx>\n" "Language-Team: German (http://www.transifex.com/projects/p/kolab/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -44,12 +45,12 @@ #: ../bin/kolab_smtp_access_policy.py:528 #, python-format msgid "Could not find envelope sender user %s (511)" -msgstr "" +msgstr "Konnte Absender-Umschlag für Benutzer %s nicht finden (511)" #: ../bin/kolab_smtp_access_policy.py:571 #, python-format msgid "Obtained authenticated user details for %r: %r" -msgstr "" +msgstr "Erhaltene Details des authentifizieren Benutzers %r: %r" #: ../bin/kolab_smtp_access_policy.py:628 #, python-format @@ -78,18 +79,18 @@ msgid "" "Verifying authenticated sender '%(sender)s' with sasl_username " "'%(sasl_username)s' for recipient '%(recipient)s'" -msgstr "" +msgstr "Überprüfe authentisierten Absender '%(sender)s' mit SASL-Benutzernamen '%(sasl_username)s' für Empfänger '%(recipient)s'" #: ../bin/kolab_smtp_access_policy.py:752 #, python-format msgid "" "Verifying unauthenticated sender '%(sender)s' for recipient '%(recipient)s'" -msgstr "" +msgstr "Überprüfe unauthentisierten Absender '%(sender)s' für Empfänger '%(recipient)s'" #: ../bin/kolab_smtp_access_policy.py:768 #, python-format msgid "Reproducing verify_recipient(%s, %s) from cache" -msgstr "" +msgstr "Reproduziere verify_recipient(%s, %s) aus Cache" #: ../bin/kolab_smtp_access_policy.py:805 #, python-format @@ -106,20 +107,20 @@ msgid "" "Checking the recipient for domain %s that is not ours. This is probably a " "configuration error." -msgstr "" +msgstr "Überprüfe Empfänger für fremde Domäne %s. Dies ist wahrscheinlich ein Konfigurationsfehler." #: ../bin/kolab_smtp_access_policy.py:838 msgid "" "This recipient address is related to multiple object entries and the SMTP " "Access Policy can therefore not restrict message flow" -msgstr "" +msgstr "Diese Empfänger-Adresse bezieht sich auf mehrere Objekt-Einträge. Die SMTP Access Policy kann deshalb den Nachrichtenfluss nicht einschränken." #: ../bin/kolab_smtp_access_policy.py:855 #, python-format msgid "" "Recipient address %r not found. Allowing since the MTA was configured to " "accept the recipient." -msgstr "" +msgstr "Emfänger-Adresse %r nicht gefunden. Erlauben, da MTA konfiguriert wurde, diesen Empfänger zu akzeptieren." #: ../bin/kolab_smtp_access_policy.py:891 msgid "Invalid recipient" @@ -133,24 +134,24 @@ #: ../bin/kolab_smtp_access_policy.py:1051 #, python-format msgid "Sender %s is not allowed to send to recipient %s" -msgstr "" +msgstr "Absender %s darf nicht an Empfänger %s senden" #: ../bin/kolab_smtp_access_policy.py:1039 #, python-format msgid "Reproducing verify_sender(%r) from cache" -msgstr "" +msgstr "Reproduziere verify_sender(%r) aus Cache" #: ../bin/kolab_smtp_access_policy.py:1056 msgid "Unverifiable sender." -msgstr "" +msgstr "Nicht überprüfbarer Absender." #: ../bin/kolab_smtp_access_policy.py:1061 msgid "Sender is not using an alias" -msgstr "" +msgstr "Absender nutzt keinen Alias" #: ../bin/kolab_smtp_access_policy.py:1069 msgid "Sender uses unauthorized envelope sender address" -msgstr "" +msgstr "Absender nutzt unerlaubte Absender-Umschlag Adresse" #: ../bin/kolab_smtp_access_policy.py:1086 msgid "Could not verify sender" @@ -159,7 +160,7 @@ #: ../bin/kolab_smtp_access_policy.py:1093 msgid "" "Verifying whether sender is allowed to send to recipient using sender policy" -msgstr "" +msgstr "Überprüfe ob Absender an Empfänger gemäß Absender-Richtlinie senden darf" #: ../bin/kolab_smtp_access_policy.py:1106 #, python-format @@ -177,7 +178,7 @@ #: ../bin/kolab_smtp_access_policy.py:1135 #, python-format msgid "Sender %s not allowed to send to recipient %s" -msgstr "" +msgstr "Absender %s darf nicht an Empfänger %s senden" #: ../bin/kolab_smtp_access_policy.py:1156 msgid "Cleaning up the cache" @@ -187,42 +188,42 @@ msgid "" "The 'uri' setting in the kolab_smtp_access_policy section is soon going to " "be deprecated in favor of 'cache_uri'" -msgstr "" +msgstr "Die 'uri' Einstellung im Abschnitt kolab_smtp_access_policy wird bald überholt sein. Nutzen Sie 'cache_uri' stattdessen " #: ../bin/kolab_smtp_access_policy.py:1195 #, python-format msgid "Operational Error in caching: %s" -msgstr "" +msgstr "Betriebsbedingter Fehler beim Cachen: %s" #: ../bin/kolab_smtp_access_policy.py:1247 #, python-format msgid "Caching the policy result with timestamp %d" -msgstr "" +msgstr "Cachen des Richtlinienergebnisses mit Zeitstempel %d" #: ../bin/kolab_smtp_access_policy.py:1321 #, python-format msgid "Returning action DEFER_IF_PERMIT: %s" -msgstr "" +msgstr "Antwort Aktion DEFER_IF_PERMIT: %s" #: ../bin/kolab_smtp_access_policy.py:1326 #, python-format msgid "Returning action DUNNO: %s" -msgstr "" +msgstr "Antwort Aktion DUNNO: %s" #: ../bin/kolab_smtp_access_policy.py:1331 #, python-format msgid "Returning action HOLD: %s" -msgstr "" +msgstr "Antwort Aktion HOLD: %s" #: ../bin/kolab_smtp_access_policy.py:1336 #, python-format msgid "Returning action PERMIT: %s" -msgstr "" +msgstr "Antwort Aktion PERMIT: %s" #: ../bin/kolab_smtp_access_policy.py:1461 #, python-format msgid "Returning action REJECT: %s" -msgstr "" +msgstr "Antwort Aktion REJECT: %s" #: ../bin/kolab_smtp_access_policy.py:1507 msgid "Starting to loop for new request" @@ -230,7 +231,7 @@ #: ../bin/kolab_smtp_access_policy.py:1514 msgid "Timeout for policy request reading exceeded" -msgstr "" +msgstr "Zeitüberschreitung beim Lesen der Richtlinienanfrage" #: ../bin/kolab_smtp_access_policy.py:1520 msgid "End of current request" @@ -239,11 +240,11 @@ #: ../bin/kolab_smtp_access_policy.py:1524 #, python-format msgid "Getting line: %s" -msgstr "" +msgstr "Lese Zeile: %s" #: ../bin/kolab_smtp_access_policy.py:1528 msgid "Returning request" -msgstr "" +msgstr "Rückgabe Richtlinenanfordung" #: ../bin/kolab_smtp_access_policy.py:1557 msgid "Access Policy Options" @@ -268,27 +269,27 @@ #: ../bin/kolab_smtp_access_policy.py:1596 #, python-format msgid "Got request instance %s" -msgstr "" +msgstr "Anfrage bekommen für Instanz %s" #: ../bin/kolab_smtp_access_policy.py:1605 #, python-format msgid "Request instance %s is in state %s" -msgstr "" +msgstr "Anfrage-Instanz %s ist im Status %s" #: ../bin/kolab_smtp_access_policy.py:1613 #, python-format msgid "Request instance %s is not yet in DATA state" -msgstr "" +msgstr "Anfrage-Instanz %s ist noch nicht im DATA Status" #: ../bin/kolab_smtp_access_policy.py:1625 #, python-format msgid "Request instance %s reached DATA state" -msgstr "" +msgstr "Anfrage-Instanz %s hat DATA Status erreicht" #: ../bin/kolab_smtp_access_policy.py:1645 #, python-format msgid "Unhandled exception caught: %r" -msgstr "" +msgstr "Unbehandelte Ausnahme abgefangen: %r" #: ../bin/kolab_smtp_access_policy.py:1649 msgid "Sender access denied" @@ -341,7 +342,7 @@ #: ../wallace/__init__.py:374 #, python-format msgid "Switching real and effective group id to %d" -msgstr "" +msgstr "Wechsle reale und effektive Gruppen-ID zu %d" #: ../kolabd/__init__.py:153 ../pykolab/utils.py:258 #: ../saslauthd/__init__.py:332 ../wallace/__init__.py:396 @@ -353,12 +354,12 @@ #: ../wallace/__init__.py:406 #, python-format msgid "Switching real and effective user id to %d" -msgstr "" +msgstr "Wechsle reale und effektive Benutzer-ID zu %d" #: ../kolabd/__init__.py:172 ../saslauthd/__init__.py:351 #: ../wallace/__init__.py:415 msgid "Could not change real and effective uid and/or gid" -msgstr "" +msgstr "Konnte reale und effektive UID und/oder GID nicht ändern" #: ../kolabd/__init__.py:192 ../saslauthd/__init__.py:142 #: ../wallace/__init__.py:435 @@ -367,7 +368,7 @@ #: ../kolabd/__init__.py:197 ../kolabd/__init__.py:208 msgid "Traceback occurred, please report a " -msgstr "" +msgstr "Traceback passiert, bitte melden Sie einen" #: ../kolabd/__init__.py:203 ../saslauthd/__init__.py:150 #: ../wallace/__init__.py:444 @@ -377,7 +378,7 @@ #: ../kolabd/__init__.py:230 msgid "Could not connect to LDAP, is it running?" -msgstr "" +msgstr "Konnte nicht zu LDAP verbinden, läuft es?" #: ../kolabd/__init__.py:233 ../pykolab/auth/ldap/__init__.py:2242 #: ../pykolab/cli/cmd_sync.py:67 @@ -386,29 +387,29 @@ #: ../kolabd/__init__.py:244 msgid "No domains. Not syncing" -msgstr "" +msgstr "Keine Domänen. Keine Synchronisation" #: ../kolabd/__init__.py:279 #, python-format msgid "added domains: %r, removed domains: %r" -msgstr "" +msgstr "Domänen hinzugefügt: %r, Domänen entfernt: %r" #: ../kolabd/process.py:33 #, python-format msgid "Process created for domain %s" -msgstr "" +msgstr "Prozess gestartet für Domäne %s" #: ../kolabd/process.py:42 #, python-format msgid "Synchronizing for domain %s" -msgstr "" +msgstr "Synchronisiere für Domäne %s" #: ../kolabd/process.py:59 #, python-format msgid "" "Error in process %r, terminating:\n" "\t%r" -msgstr "" +msgstr "Fehler im Prozess %r, beende:\n\t%r" #: ../kolabd.py:31 ../setup-kolab.py:36 ../wallace.py:31 msgid "Cannot load pykolab/constants.py:" @@ -417,27 +418,27 @@ #: ../pykolab/auth/__init__.py:89 #, python-format msgid "Called for domain %r" -msgstr "" +msgstr "Aufgerufen für Domäne %r" #: ../pykolab/auth/__init__.py:106 ../pykolab/auth/__init__.py:115 #, python-format msgid "Using section %s and domain %s" -msgstr "" +msgstr "Benutze Abschnitt %s und Domäne %s" #: ../pykolab/auth/__init__.py:120 #, python-format msgid "Connecting to Authentication backend for domain %s" -msgstr "" +msgstr "Verbinde zu Authentifizierungsbackend für Domäne %s" #: ../pykolab/auth/__init__.py:131 #, python-format msgid "Section %s has no option 'auth_mechanism'" -msgstr "" +msgstr "Abschnitt %s hat keinen Wert 'auth_mechanism'" #: ../pykolab/auth/__init__.py:138 #, python-format msgid "Section %s has auth_mechanism: %r" -msgstr "" +msgstr "Abschnitt %s hat auth_mechanism: %r" #: ../pykolab/auth/__init__.py:147 ../pykolab/auth/__init__.py:156 msgid "Starting LDAP..." @@ -446,17 +447,17 @@ #: ../pykolab/auth/ldap/cache.py:126 #, python-format msgid "Inserting cache entry %r" -msgstr "" +msgstr "Hinzufügen Cacheeintrag %r" #: ../pykolab/auth/ldap/cache.py:147 #, python-format msgid "Updating timestamp for cache entry %r" -msgstr "" +msgstr "Aktualisiere Zeitstempel für Cacheeintrag %r" #: ../pykolab/auth/ldap/cache.py:155 #, python-format msgid "Updating result_attribute for cache entry %r" -msgstr "" +msgstr "Aktualisiere result_attribute für Cacheeintrag %r" #: ../pykolab/auth/ldap/__init__.py:52 msgid "Python LDAP library does not support persistent search" @@ -470,7 +471,7 @@ #: ../pykolab/auth/ldap/__init__.py:175 ../pykolab/auth/ldap/__init__.py:226 #, python-format msgid "Authentication cache failed: %r" -msgstr "" +msgstr "Authentifizierungscache fehlgeschlagen: %r" #: ../pykolab/auth/ldap/__init__.py:216 ../pykolab/auth/ldap/__init__.py:240 #, python-format @@ -485,16 +486,16 @@ #: ../pykolab/auth/ldap/__init__.py:249 #, python-format msgid "Error occured, there is no such object: %r" -msgstr "" +msgstr "Ausnahme aufgetreten, es gibt kein solches Objekt: %r" #: ../pykolab/auth/ldap/__init__.py:254 msgid "Authentication cache failed to clear entry" -msgstr "" +msgstr "Authentifizierungscache konnte Eintrag nicht entfernen" #: ../pykolab/auth/ldap/__init__.py:260 #, python-format msgid "Exception occured: %r" -msgstr "" +msgstr "Ausnahme aufgetreten: %r" #: ../pykolab/auth/ldap/__init__.py:280 msgid "Connecting to LDAP..." @@ -513,23 +514,23 @@ #: ../pykolab/auth/ldap/__init__.py:373 #, python-format msgid "Entry DN: %r" -msgstr "" +msgstr "Eintrag DN: %r" #: ../pykolab/auth/ldap/__init__.py:376 #, python-format msgid "" "ldap search: (%r, %r, filterstr='(objectclass=*)', attrlist=[ 'dn' ] + %r" -msgstr "" +msgstr "LDAP Suche: (%r, %r, filterstr='(objectclass=*)', attrlist=[ 'dn' ] + %r" #: ../pykolab/auth/ldap/__init__.py:481 #, python-format msgid "Finding recipient with filter %r" -msgstr "" +msgstr "Finde Empfänger mit Filter %r" #: ../pykolab/auth/ldap/__init__.py:557 #, python-format msgid "Finding resource with filter %r" -msgstr "" +msgstr "Finde Ressource mit Filter %r" #: ../pykolab/auth/ldap/__init__.py:588 #, python-format @@ -539,50 +540,50 @@ #: ../pykolab/auth/ldap/__init__.py:625 #, python-format msgid "Not applying recipient policy for %s " -msgstr "" +msgstr "Keine Anwendung der Empfängerrichtlinie für %s" #: ../pykolab/auth/ldap/__init__.py:635 #, python-format msgid "Applying recipient policy to %r" -msgstr "" +msgstr "Anwendung Empfängerrichtlinie zu %r" #: ../pykolab/auth/ldap/__init__.py:652 #, python-format msgid "Using mail attributes: %r, with primary %r and " -msgstr "" +msgstr "Benutze Mailattribute: %r, mit primary %r und " #: ../pykolab/auth/ldap/__init__.py:663 #, python-format msgid "key %r not in entry" -msgstr "" +msgstr "Key %r nicht im Eintrag" #: ../pykolab/auth/ldap/__init__.py:665 #, python-format msgid "key %r is the prim. mail attr." -msgstr "" +msgstr "Key %r ist das primäre Mailattr." #: ../pykolab/auth/ldap/__init__.py:667 msgid "prim. mail pol. is not empty" -msgstr "" +msgstr "Primäre Mailrichtlinie ist nicht leer" #: ../pykolab/auth/ldap/__init__.py:670 #, python-format msgid "key %r is the sec. mail attr." -msgstr "" +msgstr "Key %r ist das sekundäre Mailattr." #: ../pykolab/auth/ldap/__init__.py:672 msgid "sec. mail pol. is not empty" -msgstr "" +msgstr "Sekundäre Mailrichtlinie ist nicht leer" #: ../pykolab/auth/ldap/__init__.py:676 ../pykolab/auth/ldap/__init__.py:690 #, python-format msgid "Attributes %r are not yet available for entry %r" -msgstr "" +msgstr "Attribute %r sind für Eintrag %r noch nicht verfügbar" #: ../pykolab/auth/ldap/__init__.py:729 #, python-format msgid "No results for mail address %s found" -msgstr "" +msgstr "Keine Ergebnisse für E-Mail-Adresse %s gefunden" #: ../pykolab/auth/ldap/__init__.py:740 #, python-format @@ -592,25 +593,25 @@ #: ../pykolab/auth/ldap/__init__.py:750 #, python-format msgid "Too bad, primary email address %s " -msgstr "" +msgstr "Schlecht, primäre E-Mail-Adresse %s" #: ../pykolab/auth/ldap/__init__.py:761 ../pykolab/auth/ldap/__init__.py:850 msgid "Address assigned to us" -msgstr "" +msgstr "Uns zugewiesene Adresse" #: ../pykolab/auth/ldap/__init__.py:816 #, python-format msgid "No results for address %s found" -msgstr "" +msgstr "Keine Ergebnisse für Adresse %s gefunden" #: ../pykolab/auth/ldap/__init__.py:827 #, python-format msgid "1 result for address %s found, " -msgstr "" +msgstr "1 Ergebnis für Adresse %s gefunden, " #: ../pykolab/auth/ldap/__init__.py:838 msgid "Too bad, secondary email " -msgstr "" +msgstr "Schlecht, sekundäre E-Mail-Adresse" #: ../pykolab/auth/ldap/__init__.py:865 msgid "Recipient policy composed the following set of secondary " @@ -619,11 +620,11 @@ #: ../pykolab/auth/ldap/__init__.py:876 #, python-format msgid "Secondary mail addresses that we want is not None: %r" -msgstr "" +msgstr "Gewünschte sekundäre E-Mail-Adresse ist nicht leer: %r" #: ../pykolab/auth/ldap/__init__.py:887 msgid "Avoiding the duplication of the primary mail " -msgstr "" +msgstr "Verhindere die Dopplung der primären E-Mail" #: ../pykolab/auth/ldap/__init__.py:898 #, python-format @@ -736,7 +737,7 @@ #: ../pykolab/auth/ldap/__init__.py:2511 #, python-format msgid "Change Type: %r (%r)" -msgstr "" +msgstr "Typ ändern: %r (%r)" #: ../pykolab/auth/ldap/__init__.py:2519 #, python-format @@ -766,7 +767,7 @@ #: ../pykolab/auth/ldap/__init__.py:2758 #, python-format msgid "Found support for %s" -msgstr "" +msgstr "Unterstützung für %s gefunden" #: ../pykolab/auth/ldap/__init__.py:2803 #, python-format @@ -821,7 +822,7 @@ #: ../pykolab/cli/cmd_add_alias.py:105 #, python-format msgid "Recipient %r is not the primary recipient for address %r" -msgstr "" +msgstr "Empfänger %r ist nicht der primäre Empfänger für Adresse %r" #: ../pykolab/cli/cmd_add_domain.py:36 #: ../pykolab/cli/cmd_count_domain_mailboxes.py:38 @@ -843,11 +844,11 @@ #: ../pykolab/cli/cmd_add_domain.py:42 msgid "Add alias domain." -msgstr "" +msgstr "Hinzufügen Alias-Domäne." #: ../pykolab/cli/cmd_add_domain.py:47 msgid "Add a new domain." -msgstr "" +msgstr "Hinzufügen einer neuen Domäne." #: ../pykolab/cli/cmd_add_domain.py:55 ../pykolab/cli/cmd_delete_domain.py:44 #: ../pykolab/cli/cmd_find_domain.py:44 @@ -904,7 +905,7 @@ #: ../pykolab/cli/cmd_create_mailbox.py:50 msgid "Create folder on PARTITION." -msgstr "" +msgstr "Verzeichnis anlegen auf PARTITION." #: ../pykolab/cli/cmd_create_mailbox.py:60 msgid "Invalid argument" @@ -916,7 +917,7 @@ #: ../pykolab/cli/cmd_delete_domain.py:36 msgid "Delete a domain." -msgstr "" +msgstr "Domäne löschen." #: ../pykolab/cli/cmd_delete_mailbox_acl.py:45 #: ../pykolab/cli/cmd_delete_mailbox_acl.py:49 @@ -954,20 +955,20 @@ #: ../pykolab/cli/cmd_delete_mailbox.py:57 #, python-format msgid "No such folder(s): %s" -msgstr "" +msgstr "Kein solch Verzeichnis: %s" #: ../pykolab/cli/cmd_delete_mailbox.py:62 msgid "No folders to delete." -msgstr "" +msgstr "Keine zu löschenden Ordner." #: ../pykolab/cli/cmd_delete_mailbox.py:69 #, python-format msgid "Could not delete mailbox '%s'" -msgstr "" +msgstr "Konnte Postfach '%s' nicht löschen" #: ../pykolab/cli/cmd_delete_message.py:36 msgid "Delete a message from a folder" -msgstr "" +msgstr "Lösche eine Nachricht aus Verzeichnis" #: ../pykolab/cli/cmd_delete_message.py:49 msgid "Specify a UID" @@ -1089,7 +1090,7 @@ #: ../pykolab/cli/cmd_mailbox_cleanup.py:140 #, python-format msgid "Deleting folder '%s'" -msgstr "" +msgstr "Ordner '%s' wird gelöscht" #: ../pykolab/cli/cmd_mailbox_cleanup.py:134 #: ../pykolab/cli/cmd_mailbox_cleanup.py:144 @@ -1114,26 +1115,26 @@ #: ../pykolab/cli/cmd_remove_mailaddress.py:49 msgid "Invalid or unqualified email address." -msgstr "" +msgstr "Ungültige oder unqualifizierte E-Mail-Adresse." #: ../pykolab/cli/cmd_remove_mailaddress.py:57 #, python-format msgid "No recipient found for email address %r" -msgstr "" +msgstr "Kein Empfänger gefunden für E-Mail-Adresse %r" #: ../pykolab/cli/cmd_remove_mailaddress.py:60 #, python-format msgid "Found the following recipient(s): %r" -msgstr "" +msgstr "Folgende Empfänger gefunden: %r" #: ../pykolab/cli/cmd_remove_mailaddress.py:66 #, python-format msgid "Using the following mail attributes: %r" -msgstr "" +msgstr "Nutze folgende Mail-Attribute: %r" #: ../pykolab/cli/cmd_remove_mailaddress.py:90 msgid "Found the following recipients:" -msgstr "" +msgstr "Folgende Empfänger gefunden:" #: ../pykolab/cli/cmd_remove_user_subscription.py:37 msgid "Unsubscribe a user from a folder." @@ -1151,11 +1152,11 @@ #: ../pykolab/cli/cmd_rename_mailbox.py:52 msgid "No target mailbox name specified" -msgstr "" +msgstr "Keine Name für Ziel-Postfach angegeben" #: ../pykolab/cli/cmd_rename_mailbox.py:54 msgid "No source mailbox name specified" -msgstr "" +msgstr "Keine Name für Quell-Postfach angegeben" #: ../pykolab/cli/cmd_rename_mailbox.py:66 #, python-format @@ -1190,7 +1191,7 @@ #: ../pykolab/cli/cmd_set_quota.py:43 ../pykolab/cli/cmd_set_quota.py:47 msgid "New quota" -msgstr "" +msgstr "Neues Kontingent" #: ../pykolab/cli/cmd_sync_mailhost_attrs.py:44 msgid "Delete mailboxes for recipients that do not appear to exist in LDAP." @@ -1401,7 +1402,7 @@ #: ../pykolab/cli/telemetry/cmd_examine_command_issue.py:60 #: ../pykolab/cli/telemetry/cmd_examine_session.py:65 msgid "Invalid session identifier" -msgstr "" +msgstr "Ungültiger Sitzungsbezeichner" #: ../pykolab/cli/telemetry/cmd_examine_command_issue.py:75 #: ../pykolab/cli/telemetry/cmd_examine_session.py:100 @@ -1445,7 +1446,7 @@ #: ../pykolab/conf/entitlement.py:141 #, python-format msgid "License file %s not readable!" -msgstr "" +msgstr "Lizenzdatei %s nicht lesbar!" #: ../pykolab/conf/entitlement.py:147 msgid "No entitlement directory found" @@ -1646,11 +1647,11 @@ #: ../pykolab/imap/cyrus.py:143 msgid "Detected we are running in a Murder topology" -msgstr "" +msgstr "Dieses System läuft in einer Murder-Topologie" #: ../pykolab/imap/cyrus.py:147 msgid "This system is not part of a murder topology" -msgstr "" +msgstr "Dieses System ist nicht Teil einer Murder-Topologie" #: ../pykolab/imap/cyrus.py:168 #, python-format @@ -1669,7 +1670,7 @@ #: ../pykolab/imap/cyrus.py:200 #, python-format msgid "No annotations for %s: %r" -msgstr "" +msgstr "Keine Annotationen für %s: %r" #: ../pykolab/imap/cyrus.py:207 #, python-format @@ -1679,17 +1680,17 @@ #: ../pykolab/imap/cyrus.py:227 #, python-format msgid "Setting quota for folder %s to %s" -msgstr "" +msgstr "Setze Quota für Verzeichnis %s auf %s" #: ../pykolab/imap/cyrus.py:231 #, python-format msgid "Could not set quota for mailfolder %s" -msgstr "" +msgstr "Konnte Quota für Verzeichnis %s nicht setzen" #: ../pykolab/imap/cyrus.py:241 #, python-format msgid "Moving INBOX folder %s to %s on partition %s" -msgstr "" +msgstr "Verschiebe INBOX Verzeichnis %s nach %s auf Partition %s" #: ../pykolab/imap/cyrus.py:243 #, python-format @@ -1699,27 +1700,27 @@ #: ../pykolab/imap/cyrus.py:259 #, python-format msgid "Setting annotation %s on folder %s" -msgstr "" +msgstr "Setze Annotation %s auf Verzeichnis %s" #: ../pykolab/imap/cyrus.py:264 #, python-format msgid "Could not set annotation %r on mail folder %r: %r" -msgstr "" +msgstr "Konnte Annotation %r auf Verzeichnis %r nicht setzen: %r" #: ../pykolab/imap/cyrus.py:268 #, python-format msgid "Transferring folder %s from %s to %s" -msgstr "" +msgstr "Übertrage Verzeichnis %s von %s nach %s" #: ../pykolab/imap/cyrus.py:328 #, python-format msgid "Undeleting %s to %s" -msgstr "" +msgstr "Wiederherstellen %s nach %s" #: ../pykolab/imap/cyrus.py:339 #, python-format msgid "Would have transfered %s from %s to %s" -msgstr "" +msgstr "Haben %s von %s nach %s übertragen" #: ../pykolab/imap/cyrus.py:341 #, python-format @@ -1739,7 +1740,7 @@ #: ../pykolab/imap/__init__.py:70 #, python-format msgid "Iterating over %d folders" -msgstr "" +msgstr "Iteriere über %d Verzeichnisse" #. Set the ACL to '' (effectively deleting the ACL entry) #: ../pykolab/imap/__init__.py:83 @@ -1896,7 +1897,7 @@ #: ../pykolab/imap/__init__.py:769 #, python-format msgid "Server for mailbox %r is %r" -msgstr "" +msgstr "Server für Postfach %r ist %r" #: ../pykolab/imap/__init__.py:777 #, python-format @@ -1989,30 +1990,30 @@ #: ../pykolab/itip/__init__.py:61 msgid "Could not read iTip from message." -msgstr "" +msgstr "Konnte iTip nicht aus Nachricht lesen." #: ../pykolab/itip/__init__.py:69 #, python-format msgid "Duplicate iTip object: %s" -msgstr "" +msgstr "Verdopple iTip Objekt: %s" #: ../pykolab/itip/__init__.py:93 msgid "iTip event without a start" -msgstr "" +msgstr "iTip Termin ohne einen Beginn" #: ../pykolab/itip/__init__.py:138 msgid "Message is not an iTip message (non-multipart message)" -msgstr "" +msgstr "Nachricht ist keine iTip Nachricht (keine Multipart Nachricht)" #: ../pykolab/itip/__init__.py:221 #, python-format msgid "Send iTip reply %s for %s %r" -msgstr "" +msgstr "Sende iTip Antwort %s für %s %r" #: ../pykolab/itip/__init__.py:237 #, python-format msgid "Failed to compose iTip reply message: %r: %s" -msgstr "" +msgstr "Erstellung iTip Antwortnachricht fehlgeschlagen: %r: %s" #: ../pykolab/itip/__init__.py:248 ../pykolab/itip/__init__.py:292 #: ../wallace/module_invitationpolicy.py:1082 @@ -2025,12 +2026,12 @@ #: ../pykolab/itip/__init__.py:280 #, python-format msgid "Failed to compose iTip request message: %r" -msgstr "" +msgstr "Erstellung iTip Anforderungsnachricht fehlgeschlagen: %r" #: ../pykolab/logger.py:168 ../pykolab/logger.py:175 #, python-format msgid "Could not change permissions on %s: %r" -msgstr "" +msgstr "Konnte Berechtigungen auf %s nicht ändern: %r" #: ../pykolab/logger.py:192 #, python-format @@ -2879,37 +2880,37 @@ #: ../pykolab/xml/recurrence_rule.py:38 #, python-format msgid "Every %d year(s)" -msgstr "" +msgstr "Alle %d Jahr(e)" #: ../pykolab/xml/recurrence_rule.py:39 #, python-format msgid "Every %d month(s)" -msgstr "" +msgstr "Alle %d Monat(e)" #: ../pykolab/xml/recurrence_rule.py:40 #, python-format msgid "Every %d week(s)" -msgstr "" +msgstr "Alle %d Woche(n)" #: ../pykolab/xml/recurrence_rule.py:41 #, python-format msgid "Every %d day(s)" -msgstr "" +msgstr "Alle %d Tag(e)" #: ../pykolab/xml/recurrence_rule.py:42 #, python-format msgid "Every %d hours" -msgstr "" +msgstr "Alle %d Stunden" #: ../pykolab/xml/recurrence_rule.py:43 #, python-format msgid "Every %d minutes" -msgstr "" +msgstr "Alle %d Minuten" #: ../pykolab/xml/recurrence_rule.py:44 #, python-format msgid "Every %d seconds" -msgstr "" +msgstr "Alle %d Sekunden" #: ../pykolab/xml/todo.py:110 msgid "Todo due needs datetime.date or datetime.datetime instance" @@ -2945,7 +2946,7 @@ #: ../pykolab/xml/utils.py:133 msgid "Attendee" -msgstr "" +msgstr "Teilnehmer" #: ../pykolab/xml/utils.py:134 msgid "Start" @@ -2973,15 +2974,15 @@ #: ../pykolab/xml/utils.py:140 msgid "Attachment" -msgstr "" +msgstr "Anhang" #: ../pykolab/xml/utils.py:141 msgid "Alarm" -msgstr "" +msgstr "Alarm" #: ../pykolab/xml/utils.py:142 msgid "Classification" -msgstr "" +msgstr "Einstufung" #: ../pykolab/xml/utils.py:143 msgid "Progress" @@ -3087,7 +3088,7 @@ #: ../wallace/module_resources.py:1333 #, python-format msgid "Booking request for %s requires confirmation" -msgstr "" +msgstr "Buchungsanfrage für %s benötigt eine Bestätigung" #: ../tests/functional/test_wallace/test_007_invitationpolicy.py:240 #: ../wallace/module_invitationpolicy.py:448 @@ -3770,88 +3771,88 @@ #: ../wallace/module_resources.py:704 #, python-format msgid "Failed to access resource calendar:: %r" -msgstr "" +msgstr "Zugriff auf Ressourcenkalender fehlgeschlagen: %r" #: ../wallace/module_resources.py:733 #, python-format msgid "Apply invitation policies %r" -msgstr "" +msgstr "Anwenden der Einladungsrichtlinie %r" #: ../wallace/module_resources.py:752 #, python-format msgid "Adding event to %r: %r" -msgstr "" +msgstr "Hinzufügen Termin zu %r: %r" #: ../wallace/module_resources.py:806 #, python-format msgid "Failed to save event to resource calendar at %r: %r" -msgstr "" +msgstr "Speichern des Termins im Ressourcenkalender fehlgeschlagen in %r: %r" #: ../wallace/module_resources.py:823 #, python-format msgid "Delete resource calendar object %r in %r: %r" -msgstr "" +msgstr "Lösche Kalenderobjekt der Ressource %r in %r: %r" #: ../wallace/module_resources.py:866 #, python-format msgid "Checking if email address %r belongs to a resource (collection)" -msgstr "" +msgstr "Prüfe ob E-Mail-Adresse %r zu einer Ressource (Sammlung) gehört" #: ../wallace/module_resources.py:874 ../wallace/module_resources.py:946 #: ../wallace/module_resources.py:980 #, python-format msgid "Resource record(s): %r" -msgstr "" +msgstr "Ressourcen-Eintrag/Einträge: %r" #: ../wallace/module_resources.py:876 ../wallace/module_resources.py:948 #: ../wallace/module_resources.py:983 #, python-format msgid "No resource (collection) records found for %r" -msgstr "" +msgstr "Kein Ressourcen (Sammlung) - Eintrag für %r gefunden" #: ../wallace/module_resources.py:880 ../wallace/module_resources.py:952 #: ../wallace/module_resources.py:987 #, python-format msgid "Resource record: %r" -msgstr "" +msgstr "Ressourceneinträge: %r" #: ../wallace/module_resources.py:898 #, python-format msgid "Raw itip_events: %r" -msgstr "" +msgstr "Originale itip_events: %r" #: ../wallace/module_resources.py:906 #, python-format msgid "Raw set of attendees: %r" -msgstr "" +msgstr "Originalset der Teilnehmer: %r" #: ../wallace/module_resources.py:914 #, python-format msgid "Raw set of resources: %r" -msgstr "" +msgstr "Originalset der Ressourcen: %r" #: ../wallace/module_resources.py:919 #, python-format msgid "Raw set of organizers: %r" -msgstr "" +msgstr "Originalset der Organisatoren: %r" #: ../wallace/module_resources.py:939 #, python-format msgid "Checking if attendee %r is a resource (collection)" -msgstr "" +msgstr "Prüfe ob Teilnehmer %r eine Ressource (Sammlung) ist" #: ../wallace/module_resources.py:955 ../wallace/module_resources.py:989 msgid "Resource reservation made but no resource records found" -msgstr "" +msgstr "Ressourcenbuchung erfolgt, jedoch keine Ressourceneinträge gefunden" #: ../wallace/module_resources.py:974 #, python-format msgid "Checking if resource %r is a resource (collection)" -msgstr "" +msgstr "Prüfe ob Resource %r eine Resource (Sammlung)" #: ../wallace/module_resources.py:992 msgid "The following resources are being referred to in the " -msgstr "" +msgstr "Auf die folgenden Ressourcen wurde Bezug genommen in" #: ../wallace/module_resources.py:1157 #, python-format @@ -3861,7 +3862,7 @@ "\n" " Your reservation was delegated to \"%s\" which is available for the requested time.\n" " " -msgstr "" +msgstr "\n*** Dies ist eine automatisch erstellte E-Mail. Bitte antworten Sie nicht direkt darauf. ***\n\nIhre Reservierung wurde an \"%s\" delegiert, welche(r) zum angeforderten Termin verfügbar ist.\n " #: ../wallace/module_resources.py:1176 #, python-format @@ -3871,7 +3872,7 @@ " \n" " We hereby inform you that your reservation was %s.\n" " " -msgstr "" +msgstr "\n*** Dies ist eine automatisch erstellte E-Mail. Bitte antworten Sie nicht direkt darauf. ***\n\nHiermit informieren wir Sie, dass die Buchung %s wurde.\n " #: ../wallace/module_resources.py:1183 #, python-format @@ -3885,11 +3886,11 @@ #: ../wallace/module_resources.py:1218 #, python-format msgid "Sending booking notification for event %r to %r from %r" -msgstr "" +msgstr "Sende Buchungsbenachrichtigung für Termin %r zu %r von %r" #: ../wallace/module_resources.py:1236 msgid "failed" -msgstr "" +msgstr "fehlgeschlagen" #: ../wallace/module_resources.py:1256 #, python-format @@ -3899,7 +3900,7 @@ "\n" " *** This is an automated message, sent to you as the resource owner. ***\n" " " -msgstr "" +msgstr "\nDie Buchungsanfrage für %(resource)s durch %(orgname)s <%(orgemail)s> ist %(status)s für %(date)s.\n\n*** Dies ist eine automatisch erstellte E-Mail. Bitte antworten Sie nicht direkt darauf. ***\n " #: ../wallace/module_resources.py:1262 #, python-format @@ -3910,12 +3911,12 @@ "\n" " *** This is an automated message, sent to you as the resource owner. ***\n" " " -msgstr "" +msgstr "\nEine Buchungsanfrage für %(resource)s konnte nicht automatisch verarbeitet werden.\nBitte kontaktieren Sie %(orgname)s <%(orgemail)s>, welcher die Resource für den %(date)s angefragt hat.\nSubject: %(summary)s.\n\n*** Dies ist eine automatisch erstellte E-Mail. Bitte antworten Sie nicht direkt darauf. ***" #: ../wallace/module_resources.py:1306 #, python-format msgid "Clone invitation for owner confirmation: %r from %r" -msgstr "" +msgstr "Kopiere Einladung für Eigentümer Bestätigung: %r von %r" #: ../wallace/module_resources.py:1312 #, python-format @@ -3932,7 +3933,7 @@ "\n" " *** This is an automated message, please don't reply by email. ***\n" " " -msgstr "" +msgstr "\nEine Buchungsanfrage für %(resource)s benötigt Ihre Zustimmung!\nBitte akzeptieren Sie die Anfrage oder lehnen Sie diese ab ohne die Anfrage in Ihrem Kalender zu speichern.\n\nDie Buchungsanfrage wurde gesendet von %(orgname)s <%(orgemail)s>.\n\nBetreff: %(summary)s.\nTermin: %(date)s\nTeilnehmer: %(attendees)s\n\n*** Dies ist eine automatisch erstellte E-Mail. Bitte antworten Sie nicht direkt darauf. ***" #. This is a nested module #: ../wallace/modules.py:97 @@ -3943,12 +3944,12 @@ #: ../wallace/modules.py:108 ../wallace/modules.py:120 #, python-format msgid "No such module %r in modules %r (1)." -msgstr "" +msgstr "Kein solches Modul %r in Modulen %r (1)." #: ../wallace/modules.py:113 #, python-format msgid "No such module %r in modules %r (2)." -msgstr "" +msgstr "Kein solches Modul %r in Modulen %r (2)." #: ../wallace/modules.py:126 #, python-format @@ -3958,7 +3959,7 @@ #: ../wallace/modules.py:129 #, python-format msgid "Deferring message in %s (by module %s)" -msgstr "" +msgstr "Zurückgestellte Nachricht in %s (durch Modul %s)" #: ../wallace/modules.py:141 #, python-format @@ -3979,12 +3980,12 @@ #: ../wallace/modules.py:147 #, python-format msgid "Message in file %s older then 5 days, deleting" -msgstr "" +msgstr "Nachricht in Datei %s älter als 5 Tage, lösche" #: ../wallace/modules.py:172 #, python-format msgid "Rejecting message in %s (by module %s)" -msgstr "" +msgstr "Weise Nachricht in %s (durch Modul %s) zurück" #: ../wallace/modules.py:193 #, python-format @@ -4006,22 +4007,22 @@ msgid "" "X-Wallace-Module: %s\n" "X-Wallace-Result: REJECT\n" -msgstr "" +msgstr "X-Wallace-Modul: %s\nX-Wallace-Ergebnis: REJECT\n" #: ../wallace/modules.py:267 #, python-format msgid "Accepting message in %s (by module %s)" -msgstr "" +msgstr "Akzeptiere Nachricht in %s (durch Modul %s)" #: ../wallace/modules.py:269 #, python-format msgid "Accepting message in: %r" -msgstr "" +msgstr "Akzeptiere Nachricht in: %r" #: ../wallace/modules.py:276 #, python-format msgid "recipients: %r" -msgstr "" +msgstr "Empfänger: %r" #: ../wallace/modules.py:354 #, python-format
View file
pykolab-0.7.8.tar.gz/po/de_DE.po -> pykolab-0.7.9.tar.gz/po/de_DE.po
Changed
@@ -3,21 +3,29 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: -# Christoph Wickert <christoph.wickert@gmail.com>, 2012 +# Christoph Wickert <christoph.wickert@gmail.com>, 2015 +# Christoph Wickert <christoph.wickert@gmail.com>, 2011 +# Dirk Marschner <info@marschner.cx>, 2015 +# Ettore Atalan <atalanttore@googlemail.com>, 2014-2015 # Torsten Grote <grote@kolabsys.com>, 2012 +# Jeroen van Meeuwen <vanmeeuwen@kolabsys.com>, 2015 +# balin <johannes_graumann@web.de>, 2012 +# Jo <jo@caj-augsburg.de>, 2012 +# bitnukl, 2014 # Thomas Brüderli <roundcube@gmail.com>, 2014 +# Till Savekoul <till@koul.de>, 2012 msgid "" msgstr "" "Project-Id-Version: Kolab Groupware Solution\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-01-14 01:36+0100\n" -"PO-Revision-Date: 2015-01-21 16:28+0000\n" -"Last-Translator: Thomas Brüderli <roundcube@gmail.com>\n" -"Language-Team: German (Germany) (http://www.transifex.com/projects/p/kolab/language/de_DE/)\n" +"PO-Revision-Date: 2015-02-01 15:31+0000\n" +"Last-Translator: Dirk Marschner <info@marschner.cx>\n" +"Language-Team: German (http://www.transifex.com/projects/p/kolab/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: de_DE\n" +"Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../bin/kolab_smtp_access_policy.py:210 @@ -37,12 +45,12 @@ #: ../bin/kolab_smtp_access_policy.py:528 #, python-format msgid "Could not find envelope sender user %s (511)" -msgstr "" +msgstr "Konnte Absender-Umschlag für Benutzer %s nicht finden (511)" #: ../bin/kolab_smtp_access_policy.py:571 #, python-format msgid "Obtained authenticated user details for %r: %r" -msgstr "" +msgstr "Erhaltene Details des authentifizieren Benutzers %r: %r" #: ../bin/kolab_smtp_access_policy.py:628 #, python-format @@ -58,7 +66,7 @@ #, python-format msgid "" "User %s attempted to use envelope sender address %s without authorization" -msgstr "" +msgstr "Benutzer %s versuchte die Absendeadresse %s ohne Berechtigung zu verwenden" #: ../bin/kolab_smtp_access_policy.py:714 #: ../bin/kolab_smtp_access_policy.py:725 @@ -71,23 +79,23 @@ msgid "" "Verifying authenticated sender '%(sender)s' with sasl_username " "'%(sasl_username)s' for recipient '%(recipient)s'" -msgstr "" +msgstr "Überprüfe authentisierten Absender '%(sender)s' mit SASL-Benutzernamen '%(sasl_username)s' für Empfänger '%(recipient)s'" #: ../bin/kolab_smtp_access_policy.py:752 #, python-format msgid "" "Verifying unauthenticated sender '%(sender)s' for recipient '%(recipient)s'" -msgstr "" +msgstr "Überprüfe unauthentisierten Absender '%(sender)s' für Empfänger '%(recipient)s'" #: ../bin/kolab_smtp_access_policy.py:768 #, python-format msgid "Reproducing verify_recipient(%s, %s) from cache" -msgstr "" +msgstr "Reproduziere verify_recipient(%s, %s) aus Cache" #: ../bin/kolab_smtp_access_policy.py:805 #, python-format msgid "Using authentication domain %s instead of %s" -msgstr "Benutze Authentisierungsdomain %s anstelle von %s" +msgstr "Authentisierungsdomain %s anstelle von %s wird verwendet" #: ../bin/kolab_smtp_access_policy.py:815 #, python-format @@ -99,20 +107,20 @@ msgid "" "Checking the recipient for domain %s that is not ours. This is probably a " "configuration error." -msgstr "" +msgstr "Überprüfe Empfänger für fremde Domäne %s. Dies ist wahrscheinlich ein Konfigurationsfehler." #: ../bin/kolab_smtp_access_policy.py:838 msgid "" "This recipient address is related to multiple object entries and the SMTP " "Access Policy can therefore not restrict message flow" -msgstr "" +msgstr "Diese Empfänger-Adresse bezieht sich auf mehrere Objekt-Einträge. Die SMTP Access Policy kann deshalb den Nachrichtenfluss nicht einschränken." #: ../bin/kolab_smtp_access_policy.py:855 #, python-format msgid "" "Recipient address %r not found. Allowing since the MTA was configured to " "accept the recipient." -msgstr "" +msgstr "Emfänger-Adresse %r nicht gefunden. Erlauben, da MTA konfiguriert wurde, diesen Empfänger zu akzeptieren." #: ../bin/kolab_smtp_access_policy.py:891 msgid "Invalid recipient" @@ -120,30 +128,30 @@ #: ../bin/kolab_smtp_access_policy.py:902 msgid "Could not find this user, accepting" -msgstr "" +msgstr "Konnte keine Einschränkung für diesen Benutzer finden, akzeptiere Nachricht" #: ../bin/kolab_smtp_access_policy.py:975 #: ../bin/kolab_smtp_access_policy.py:1051 #, python-format msgid "Sender %s is not allowed to send to recipient %s" -msgstr "" +msgstr "Absender %s darf nicht an Empfänger %s senden" #: ../bin/kolab_smtp_access_policy.py:1039 #, python-format msgid "Reproducing verify_sender(%r) from cache" -msgstr "" +msgstr "Reproduziere verify_sender(%r) aus Cache" #: ../bin/kolab_smtp_access_policy.py:1056 msgid "Unverifiable sender." -msgstr "" +msgstr "Nicht überprüfbarer Absender." #: ../bin/kolab_smtp_access_policy.py:1061 msgid "Sender is not using an alias" -msgstr "" +msgstr "Absender nutzt keinen Alias" #: ../bin/kolab_smtp_access_policy.py:1069 msgid "Sender uses unauthorized envelope sender address" -msgstr "" +msgstr "Absender nutzt unerlaubte Absender-Umschlag Adresse" #: ../bin/kolab_smtp_access_policy.py:1086 msgid "Could not verify sender" @@ -152,7 +160,7 @@ #: ../bin/kolab_smtp_access_policy.py:1093 msgid "" "Verifying whether sender is allowed to send to recipient using sender policy" -msgstr "" +msgstr "Überprüfe ob Absender an Empfänger gemäß Absender-Richtlinie senden darf" #: ../bin/kolab_smtp_access_policy.py:1106 #, python-format @@ -170,7 +178,7 @@ #: ../bin/kolab_smtp_access_policy.py:1135 #, python-format msgid "Sender %s not allowed to send to recipient %s" -msgstr "" +msgstr "Absender %s darf nicht an Empfänger %s senden" #: ../bin/kolab_smtp_access_policy.py:1156 msgid "Cleaning up the cache" @@ -180,42 +188,42 @@ msgid "" "The 'uri' setting in the kolab_smtp_access_policy section is soon going to " "be deprecated in favor of 'cache_uri'" -msgstr "" +msgstr "Die 'uri' Einstellung im Abschnitt kolab_smtp_access_policy wird bald überholt sein. Nutzen Sie 'cache_uri' stattdessen " #: ../bin/kolab_smtp_access_policy.py:1195 #, python-format msgid "Operational Error in caching: %s" -msgstr "" +msgstr "Betriebsbedingter Fehler beim Cachen: %s" #: ../bin/kolab_smtp_access_policy.py:1247 #, python-format msgid "Caching the policy result with timestamp %d" -msgstr "" +msgstr "Cachen des Richtlinienergebnisses mit Zeitstempel %d" #: ../bin/kolab_smtp_access_policy.py:1321 #, python-format msgid "Returning action DEFER_IF_PERMIT: %s" -msgstr "" +msgstr "Antwort Aktion DEFER_IF_PERMIT: %s" #: ../bin/kolab_smtp_access_policy.py:1326 #, python-format msgid "Returning action DUNNO: %s" -msgstr "" +msgstr "Antwort Aktion DUNNO: %s" #: ../bin/kolab_smtp_access_policy.py:1331 #, python-format msgid "Returning action HOLD: %s" -msgstr "" +msgstr "Antwort Aktion HOLD: %s" #: ../bin/kolab_smtp_access_policy.py:1336 #, python-format msgid "Returning action PERMIT: %s" -msgstr "" +msgstr "Antwort Aktion PERMIT: %s" #: ../bin/kolab_smtp_access_policy.py:1461 #, python-format msgid "Returning action REJECT: %s" -msgstr "" +msgstr "Antwort Aktion REJECT: %s" #: ../bin/kolab_smtp_access_policy.py:1507 msgid "Starting to loop for new request" @@ -223,7 +231,7 @@ #: ../bin/kolab_smtp_access_policy.py:1514 msgid "Timeout for policy request reading exceeded" -msgstr "" +msgstr "Zeitüberschreitung beim Lesen der Richtlinienanfrage" #: ../bin/kolab_smtp_access_policy.py:1520 msgid "End of current request" @@ -232,11 +240,11 @@ #: ../bin/kolab_smtp_access_policy.py:1524 #, python-format msgid "Getting line: %s" -msgstr "" +msgstr "Lese Zeile: %s" #: ../bin/kolab_smtp_access_policy.py:1528 msgid "Returning request" -msgstr "" +msgstr "Rückgabe Richtlinenanfordung" #: ../bin/kolab_smtp_access_policy.py:1557 msgid "Access Policy Options" @@ -248,334 +256,334 @@ #: ../bin/kolab_smtp_access_policy.py:1570 msgid "Verify the recipient access policy." -msgstr "" +msgstr "Verifiziere die Empfänger-Zugriffs-Richtlinie." #: ../bin/kolab_smtp_access_policy.py:1576 msgid "Verify the sender access policy." -msgstr "" +msgstr "Verifiziere die Sender-Zugriffs-Richtlinie." #: ../bin/kolab_smtp_access_policy.py:1582 msgid "Allow unauthenticated senders." -msgstr "" +msgstr "Erlaube nicht authentisierte Sender." #: ../bin/kolab_smtp_access_policy.py:1596 #, python-format msgid "Got request instance %s" -msgstr "" +msgstr "Anfrage bekommen für Instanz %s" #: ../bin/kolab_smtp_access_policy.py:1605 #, python-format msgid "Request instance %s is in state %s" -msgstr "" +msgstr "Anfrage-Instanz %s ist im Status %s" #: ../bin/kolab_smtp_access_policy.py:1613 #, python-format msgid "Request instance %s is not yet in DATA state" -msgstr "" +msgstr "Anfrage-Instanz %s ist noch nicht im DATA Status" #: ../bin/kolab_smtp_access_policy.py:1625 #, python-format msgid "Request instance %s reached DATA state" -msgstr "" +msgstr "Anfrage-Instanz %s hat DATA Status erreicht" #: ../bin/kolab_smtp_access_policy.py:1645 #, python-format msgid "Unhandled exception caught: %r" -msgstr "" +msgstr "Unbehandelte Ausnahme abgefangen: %r" #: ../bin/kolab_smtp_access_policy.py:1649 msgid "Sender access denied" -msgstr "" +msgstr "Sender Zugriff verweigert" #: ../bin/kolab_smtp_access_policy.py:1651 msgid "Recipient access denied" -msgstr "" +msgstr "Empfänger Zugriff verweigert" #: ../bin/kolab_smtp_access_policy.py:1653 msgid "No objections" -msgstr "" +msgstr "Keine Einwände" #: ../conf.py:37 ../kolab-cli.py:34 ../saslauthd.py:33 msgid "Cannot load pykolab/logger.py:" -msgstr "" +msgstr "Laden von pykolab/logger.py nicht möglich:" #: ../kolabd/__init__.py:49 ../saslauthd/__init__.py:51 #: ../wallace/__init__.py:107 msgid "Daemon Options" -msgstr "" +msgstr "Daemon Optionen" #: ../kolabd/__init__.py:56 ../saslauthd/__init__.py:58 #: ../wallace/__init__.py:114 msgid "Fork to the background." -msgstr "" +msgstr "In den Hintergrund abtauchen" #: ../kolabd/__init__.py:65 ../saslauthd/__init__.py:67 #: ../wallace/__init__.py:148 msgid "Path to the PID file to use." -msgstr "" +msgstr "Pfad zur PID-Datei" #: ../kolabd/__init__.py:74 ../saslauthd/__init__.py:85 #: ../wallace/__init__.py:165 msgid "Run as user USERNAME" -msgstr "" +msgstr "Als Benutzer USERNAME ausführen" #: ../kolabd/__init__.py:84 ../saslauthd/__init__.py:95 #: ../wallace/__init__.py:131 msgid "Run as group GROUPNAME" -msgstr "" +msgstr "Als Gruppe GROUPNAME ausführen" #: ../kolabd/__init__.py:122 ../pykolab/utils.py:234 #: ../saslauthd/__init__.py:301 ../wallace/__init__.py:365 #, python-format msgid "Group %s does not exist" -msgstr "" +msgstr "Gruppe %s exisitert nicht" #: ../kolabd/__init__.py:131 ../saslauthd/__init__.py:310 #: ../wallace/__init__.py:374 #, python-format msgid "Switching real and effective group id to %d" -msgstr "" +msgstr "Wechsle reale und effektive Gruppen-ID zu %d" #: ../kolabd/__init__.py:153 ../pykolab/utils.py:258 #: ../saslauthd/__init__.py:332 ../wallace/__init__.py:396 #, python-format msgid "User %s does not exist" -msgstr "" +msgstr "Benutzer %s existiert nicht" #: ../kolabd/__init__.py:163 ../saslauthd/__init__.py:342 #: ../wallace/__init__.py:406 #, python-format msgid "Switching real and effective user id to %d" -msgstr "" +msgstr "Wechsle reale und effektive Benutzer-ID zu %d" #: ../kolabd/__init__.py:172 ../saslauthd/__init__.py:351 #: ../wallace/__init__.py:415 msgid "Could not change real and effective uid and/or gid" -msgstr "" +msgstr "Konnte reale und effektive UID und/oder GID nicht ändern" #: ../kolabd/__init__.py:192 ../saslauthd/__init__.py:142 #: ../wallace/__init__.py:435 msgid "Interrupted by user" -msgstr "" +msgstr "Vom Benutzer unterbrochen" #: ../kolabd/__init__.py:197 ../kolabd/__init__.py:208 msgid "Traceback occurred, please report a " -msgstr "" +msgstr "Traceback passiert, bitte melden Sie einen" #: ../kolabd/__init__.py:203 ../saslauthd/__init__.py:150 #: ../wallace/__init__.py:444 #, python-format msgid "Type Error: %s" -msgstr "" +msgstr "Typ-Fehler: %s" #: ../kolabd/__init__.py:230 msgid "Could not connect to LDAP, is it running?" -msgstr "" +msgstr "Konnte nicht zu LDAP verbinden, läuft es?" #: ../kolabd/__init__.py:233 ../pykolab/auth/ldap/__init__.py:2242 #: ../pykolab/cli/cmd_sync.py:67 msgid "Listing domains..." -msgstr "Domänen werden geladen…" +msgstr "Liste Domains auf..." #: ../kolabd/__init__.py:244 msgid "No domains. Not syncing" -msgstr "" +msgstr "Keine Domänen. Keine Synchronisation" #: ../kolabd/__init__.py:279 #, python-format msgid "added domains: %r, removed domains: %r" -msgstr "" +msgstr "Domänen hinzugefügt: %r, Domänen entfernt: %r" #: ../kolabd/process.py:33 #, python-format msgid "Process created for domain %s" -msgstr "" +msgstr "Prozess gestartet für Domäne %s" #: ../kolabd/process.py:42 #, python-format msgid "Synchronizing for domain %s" -msgstr "" +msgstr "Synchronisiere für Domäne %s" #: ../kolabd/process.py:59 #, python-format msgid "" "Error in process %r, terminating:\n" "\t%r" -msgstr "" +msgstr "Fehler im Prozess %r, beende:\n\t%r" #: ../kolabd.py:31 ../setup-kolab.py:36 ../wallace.py:31 msgid "Cannot load pykolab/constants.py:" -msgstr "" +msgstr "Konnte nicht pykolab/constants.py laden:" #: ../pykolab/auth/__init__.py:89 #, python-format msgid "Called for domain %r" -msgstr "" +msgstr "Aufgerufen für Domäne %r" #: ../pykolab/auth/__init__.py:106 ../pykolab/auth/__init__.py:115 #, python-format msgid "Using section %s and domain %s" -msgstr "" +msgstr "Benutze Abschnitt %s und Domäne %s" #: ../pykolab/auth/__init__.py:120 #, python-format msgid "Connecting to Authentication backend for domain %s" -msgstr "" +msgstr "Verbinde zu Authentifizierungsbackend für Domäne %s" #: ../pykolab/auth/__init__.py:131 #, python-format msgid "Section %s has no option 'auth_mechanism'" -msgstr "" +msgstr "Abschnitt %s hat keinen Wert 'auth_mechanism'" #: ../pykolab/auth/__init__.py:138 #, python-format msgid "Section %s has auth_mechanism: %r" -msgstr "" +msgstr "Abschnitt %s hat auth_mechanism: %r" #: ../pykolab/auth/__init__.py:147 ../pykolab/auth/__init__.py:156 msgid "Starting LDAP..." -msgstr "" +msgstr "Starte LDAP..." #: ../pykolab/auth/ldap/cache.py:126 #, python-format msgid "Inserting cache entry %r" -msgstr "" +msgstr "Hinzufügen Cacheeintrag %r" #: ../pykolab/auth/ldap/cache.py:147 #, python-format msgid "Updating timestamp for cache entry %r" -msgstr "" +msgstr "Aktualisiere Zeitstempel für Cacheeintrag %r" #: ../pykolab/auth/ldap/cache.py:155 #, python-format msgid "Updating result_attribute for cache entry %r" -msgstr "" +msgstr "Aktualisiere result_attribute für Cacheeintrag %r" #: ../pykolab/auth/ldap/__init__.py:52 msgid "Python LDAP library does not support persistent search" -msgstr "" +msgstr "Die Python LDAP Bibliothek unterstützt keine persistente Suche" #: ../pykolab/auth/ldap/__init__.py:143 #, python-format msgid "Attempting to authenticate user %s in realm %s" -msgstr "" +msgstr "Versuche Benutzer %s in Bereich %s zu authentisieren" #: ../pykolab/auth/ldap/__init__.py:175 ../pykolab/auth/ldap/__init__.py:226 #, python-format msgid "Authentication cache failed: %r" -msgstr "" +msgstr "Authentifizierungscache fehlgeschlagen: %r" #: ../pykolab/auth/ldap/__init__.py:216 ../pykolab/auth/ldap/__init__.py:240 #, python-format msgid "Binding with user_dn %s and password %s" -msgstr "" +msgstr "Binde mit user_dn %s und Passwort %s" #: ../pykolab/auth/ldap/__init__.py:231 ../pykolab/auth/ldap/__init__.py:263 #, python-format msgid "Failed to authenticate as user %s" -msgstr "" +msgstr "Autorisation als Benutzer %s gescheitert" #: ../pykolab/auth/ldap/__init__.py:249 #, python-format msgid "Error occured, there is no such object: %r" -msgstr "" +msgstr "Ausnahme aufgetreten, es gibt kein solches Objekt: %r" #: ../pykolab/auth/ldap/__init__.py:254 msgid "Authentication cache failed to clear entry" -msgstr "" +msgstr "Authentifizierungscache konnte Eintrag nicht entfernen" #: ../pykolab/auth/ldap/__init__.py:260 #, python-format msgid "Exception occured: %r" -msgstr "" +msgstr "Ausnahme aufgetreten: %r" #: ../pykolab/auth/ldap/__init__.py:280 msgid "Connecting to LDAP..." -msgstr "Zum LDAP verbinden…" +msgstr "Verbinde zum LDAP..." #: ../pykolab/auth/ldap/__init__.py:284 #, python-format msgid "Attempting to use LDAP URI %s" -msgstr "" +msgstr "Versuche LDAP URI %s zu benutzen" #: ../pykolab/auth/ldap/__init__.py:371 #, python-format msgid "Entry ID: %r" -msgstr "" +msgstr "Eintragkennung: %r" #: ../pykolab/auth/ldap/__init__.py:373 #, python-format msgid "Entry DN: %r" -msgstr "" +msgstr "Eintrag DN: %r" #: ../pykolab/auth/ldap/__init__.py:376 #, python-format msgid "" "ldap search: (%r, %r, filterstr='(objectclass=*)', attrlist=[ 'dn' ] + %r" -msgstr "" +msgstr "LDAP Suche: (%r, %r, filterstr='(objectclass=*)', attrlist=[ 'dn' ] + %r" #: ../pykolab/auth/ldap/__init__.py:481 #, python-format msgid "Finding recipient with filter %r" -msgstr "" +msgstr "Finde Empfänger mit Filter %r" #: ../pykolab/auth/ldap/__init__.py:557 #, python-format msgid "Finding resource with filter %r" -msgstr "" +msgstr "Finde Ressource mit Filter %r" #: ../pykolab/auth/ldap/__init__.py:588 #, python-format msgid "Using timestamp %r" -msgstr "" +msgstr "Zeitstempel %r wird verwendet" #: ../pykolab/auth/ldap/__init__.py:625 #, python-format msgid "Not applying recipient policy for %s " -msgstr "" +msgstr "Keine Anwendung der Empfängerrichtlinie für %s" #: ../pykolab/auth/ldap/__init__.py:635 #, python-format msgid "Applying recipient policy to %r" -msgstr "" +msgstr "Anwendung Empfängerrichtlinie zu %r" #: ../pykolab/auth/ldap/__init__.py:652 #, python-format msgid "Using mail attributes: %r, with primary %r and " -msgstr "" +msgstr "Benutze Mailattribute: %r, mit primary %r und " #: ../pykolab/auth/ldap/__init__.py:663 #, python-format msgid "key %r not in entry" -msgstr "" +msgstr "Key %r nicht im Eintrag" #: ../pykolab/auth/ldap/__init__.py:665 #, python-format msgid "key %r is the prim. mail attr." -msgstr "" +msgstr "Key %r ist das primäre Mailattr." #: ../pykolab/auth/ldap/__init__.py:667 msgid "prim. mail pol. is not empty" -msgstr "" +msgstr "Primäre Mailrichtlinie ist nicht leer" #: ../pykolab/auth/ldap/__init__.py:670 #, python-format msgid "key %r is the sec. mail attr." -msgstr "" +msgstr "Key %r ist das sekundäre Mailattr." #: ../pykolab/auth/ldap/__init__.py:672 msgid "sec. mail pol. is not empty" -msgstr "" +msgstr "Sekundäre Mailrichtlinie ist nicht leer" #: ../pykolab/auth/ldap/__init__.py:676 ../pykolab/auth/ldap/__init__.py:690 #, python-format msgid "Attributes %r are not yet available for entry %r" -msgstr "" +msgstr "Attribute %r sind für Eintrag %r noch nicht verfügbar" #: ../pykolab/auth/ldap/__init__.py:729 #, python-format msgid "No results for mail address %s found" -msgstr "" +msgstr "Keine Ergebnisse für E-Mail-Adresse %s gefunden" #: ../pykolab/auth/ldap/__init__.py:740 #, python-format @@ -585,25 +593,25 @@ #: ../pykolab/auth/ldap/__init__.py:750 #, python-format msgid "Too bad, primary email address %s " -msgstr "" +msgstr "Schlecht, primäre E-Mail-Adresse %s" #: ../pykolab/auth/ldap/__init__.py:761 ../pykolab/auth/ldap/__init__.py:850 msgid "Address assigned to us" -msgstr "" +msgstr "Uns zugewiesene Adresse" #: ../pykolab/auth/ldap/__init__.py:816 #, python-format msgid "No results for address %s found" -msgstr "" +msgstr "Keine Ergebnisse für Adresse %s gefunden" #: ../pykolab/auth/ldap/__init__.py:827 #, python-format msgid "1 result for address %s found, " -msgstr "" +msgstr "1 Ergebnis für Adresse %s gefunden, " #: ../pykolab/auth/ldap/__init__.py:838 msgid "Too bad, secondary email " -msgstr "" +msgstr "Schlecht, sekundäre E-Mail-Adresse" #: ../pykolab/auth/ldap/__init__.py:865 msgid "Recipient policy composed the following set of secondary " @@ -612,11 +620,11 @@ #: ../pykolab/auth/ldap/__init__.py:876 #, python-format msgid "Secondary mail addresses that we want is not None: %r" -msgstr "" +msgstr "Gewünschte sekundäre E-Mail-Adresse ist nicht leer: %r" #: ../pykolab/auth/ldap/__init__.py:887 msgid "Avoiding the duplication of the primary mail " -msgstr "" +msgstr "Verhindere die Dopplung der primären E-Mail" #: ../pykolab/auth/ldap/__init__.py:898 #, python-format @@ -635,7 +643,7 @@ #: ../pykolab/auth/ldap/__init__.py:924 ../pykolab/auth/ldap/__init__.py:930 #, python-format msgid "entry[%s]: %r" -msgstr "" +msgstr "Eintrag[%s]: %r" #: ../pykolab/auth/ldap/__init__.py:941 #, python-format @@ -657,7 +665,7 @@ #: ../pykolab/auth/ldap/__init__.py:1031 #, python-format msgid "Using filter %r" -msgstr "" +msgstr "Filter %r wird verwendet" #: ../pykolab/auth/ldap/__init__.py:1046 #, python-format @@ -692,7 +700,7 @@ #: ../pykolab/auth/ldap/__init__.py:1481 ../pykolab/auth/ldap/__init__.py:2809 #, python-format msgid "%s" -msgstr "" +msgstr "%s" #: ../pykolab/auth/ldap/__init__.py:1748 ../pykolab/auth/ldap/__init__.py:1948 #, python-format @@ -707,16 +715,16 @@ #: ../pykolab/auth/ldap/__init__.py:2162 #, python-format msgid "Finding domain root dn for domain %s" -msgstr "" +msgstr "Suche root dn für die Domain %s" #: ../pykolab/auth/ldap/__init__.py:2269 msgid "Authentication database DOWN" -msgstr "" +msgstr "Authentisierungsdatenbank UNTEN" #: ../pykolab/auth/ldap/__init__.py:2353 ../pykolab/auth/ldap/__init__.py:2401 #, python-format msgid "Entry type: %s" -msgstr "" +msgstr "Eintragtyp: %s" #: ../pykolab/auth/ldap/__init__.py:2490 msgid "LDAP Search Result Data Entry:" @@ -729,7 +737,7 @@ #: ../pykolab/auth/ldap/__init__.py:2511 #, python-format msgid "Change Type: %r (%r)" -msgstr "" +msgstr "Typ ändern: %r (%r)" #: ../pykolab/auth/ldap/__init__.py:2519 #, python-format @@ -744,7 +752,7 @@ #: ../pykolab/auth/ldap/__init__.py:2584 #, python-format msgid "%d results..." -msgstr "%d Ergebnisse…" +msgstr "%d Ergebnisse..." #: ../pykolab/auth/ldap/__init__.py:2687 #, python-format @@ -759,7 +767,7 @@ #: ../pykolab/auth/ldap/__init__.py:2758 #, python-format msgid "Found support for %s" -msgstr "" +msgstr "Unterstützung für %s gefunden" #: ../pykolab/auth/ldap/__init__.py:2803 #, python-format @@ -814,7 +822,7 @@ #: ../pykolab/cli/cmd_add_alias.py:105 #, python-format msgid "Recipient %r is not the primary recipient for address %r" -msgstr "" +msgstr "Empfänger %r ist nicht der primäre Empfänger für Adresse %r" #: ../pykolab/cli/cmd_add_domain.py:36 #: ../pykolab/cli/cmd_count_domain_mailboxes.py:38 @@ -832,15 +840,15 @@ #: ../pykolab/cli/cmd_sync_mailhost_attrs.py:39 ../pykolab/cli/cmd_sync.py:45 #: ../pykolab/cli/cmd_undelete_mailbox.py:34 msgid "CLI Options" -msgstr "Kommandozeilenoptionen" +msgstr "Kommandozeilen-Parameter" #: ../pykolab/cli/cmd_add_domain.py:42 msgid "Add alias domain." -msgstr "" +msgstr "Hinzufügen Alias-Domäne." #: ../pykolab/cli/cmd_add_domain.py:47 msgid "Add a new domain." -msgstr "" +msgstr "Hinzufügen einer neuen Domäne." #: ../pykolab/cli/cmd_add_domain.py:55 ../pykolab/cli/cmd_delete_domain.py:44 #: ../pykolab/cli/cmd_find_domain.py:44 @@ -850,24 +858,24 @@ #: ../pykolab/cli/cmd_add_domain.py:67 ../pykolab/cli/cmd_delete_domain.py:56 #: ../pykolab/cli/cmd_find_domain.py:56 msgid "Domain name" -msgstr "" +msgstr "Name der Domain" #: ../pykolab/cli/cmd_add_user_subscription.py:37 msgid "Subscribe a user to a folder." -msgstr "" +msgstr "Aboniere einen Ordner für einen Benutzer." #: ../pykolab/cli/cmd_add_user_subscription.py:47 #: ../pykolab/cli/cmd_add_user_subscription.py:51 #: ../pykolab/cli/cmd_remove_user_subscription.py:47 #: ../pykolab/cli/cmd_remove_user_subscription.py:51 msgid "Folder pattern" -msgstr "" +msgstr "Ordnermuster" #: ../pykolab/cli/cmd_add_user_subscription.py:50 #: ../pykolab/cli/cmd_list_user_subscriptions.py:63 #: ../pykolab/cli/cmd_remove_user_subscription.py:50 msgid "User ID" -msgstr "" +msgstr "Benutzer ID" #: ../pykolab/cli/cmd_add_user_subscription.py:72 #: ../pykolab/cli/cmd_remove_user_subscription.py:72 @@ -880,7 +888,7 @@ #: ../pykolab/cli/cmd_list_messages.py:67 #: ../pykolab/cli/cmd_remove_user_subscription.py:73 msgid "No such folder" -msgstr "" +msgstr "Dieser Ordner ist nicht vorhanden" #: ../pykolab/cli/cmd_count_domain_mailboxes.py:44 #: ../pykolab/cli/cmd_list_deleted_mailboxes.py:50 @@ -897,19 +905,19 @@ #: ../pykolab/cli/cmd_create_mailbox.py:50 msgid "Create folder on PARTITION." -msgstr "" +msgstr "Verzeichnis anlegen auf PARTITION." #: ../pykolab/cli/cmd_create_mailbox.py:60 msgid "Invalid argument" -msgstr "" +msgstr "Ungültiges Argument" #: ../pykolab/cli/cmd_create_mailbox.py:68 msgid "Invalid argument for metadata" -msgstr "" +msgstr "Ungültiges Argument für die Metadaten" #: ../pykolab/cli/cmd_delete_domain.py:36 msgid "Delete a domain." -msgstr "" +msgstr "Domäne löschen." #: ../pykolab/cli/cmd_delete_mailbox_acl.py:45 #: ../pykolab/cli/cmd_delete_mailbox_acl.py:49 @@ -928,7 +936,7 @@ #: ../tests/unit/test-015-translate.py:18 #: ../tests/unit/test-015-translate.py:20 msgid "Folder name" -msgstr "" +msgstr "Ordnername" #: ../pykolab/cli/cmd_delete_mailbox_acl.py:60 #: ../pykolab/cli/cmd_list_mailbox_acls.py:54 @@ -938,29 +946,29 @@ #: ../pykolab/cli/cmd_set_quota.py:58 #, python-format msgid "No such folder %r" -msgstr "" +msgstr "Kein Ordner %r verfügbar" #: ../pykolab/cli/cmd_delete_mailbox.py:44 msgid "No mailbox specified" -msgstr "" +msgstr "Keine Mailbox angegeben" #: ../pykolab/cli/cmd_delete_mailbox.py:57 #, python-format msgid "No such folder(s): %s" -msgstr "" +msgstr "Kein solch Verzeichnis: %s" #: ../pykolab/cli/cmd_delete_mailbox.py:62 msgid "No folders to delete." -msgstr "" +msgstr "Keine zu löschenden Ordner." #: ../pykolab/cli/cmd_delete_mailbox.py:69 #, python-format msgid "Could not delete mailbox '%s'" -msgstr "" +msgstr "Konnte Postfach '%s' nicht löschen" #: ../pykolab/cli/cmd_delete_message.py:36 msgid "Delete a message from a folder" -msgstr "" +msgstr "Lösche eine Nachricht aus Verzeichnis" #: ../pykolab/cli/cmd_delete_message.py:49 msgid "Specify a UID" @@ -978,12 +986,12 @@ #: ../pykolab/cli/cmd_export_mailbox.py:108 #, python-format msgid "%s is not a directory" -msgstr "" +msgstr "%s ist kein Verzeichnis" #: ../pykolab/cli/cmd_export_mailbox.py:118 #, python-format msgid "ZIP file at %s.zip" -msgstr "" +msgstr "ZIP-Datei unter %s.zip" #: ../pykolab/cli/cmd_export_mailbox.py:120 #, python-format @@ -1029,11 +1037,11 @@ #: ../pykolab/cli/cmd_list_user_subscriptions.py:47 msgid "List unsubscribed folders" -msgstr "" +msgstr "Liste nicht abonnierte Ordner" #: ../pykolab/cli/cmd_list_user_subscriptions.py:50 msgid "List the folders a user is subscribed to." -msgstr "" +msgstr "Liste die Ordner, die ein Benutzer abonniert hat." #: ../pykolab/cli/cmd_list_user_subscriptions.py:98 #, python-format @@ -1082,7 +1090,7 @@ #: ../pykolab/cli/cmd_mailbox_cleanup.py:140 #, python-format msgid "Deleting folder '%s'" -msgstr "" +msgstr "Ordner '%s' wird gelöscht" #: ../pykolab/cli/cmd_mailbox_cleanup.py:134 #: ../pykolab/cli/cmd_mailbox_cleanup.py:144 @@ -1107,30 +1115,30 @@ #: ../pykolab/cli/cmd_remove_mailaddress.py:49 msgid "Invalid or unqualified email address." -msgstr "" +msgstr "Ungültige oder unqualifizierte E-Mail-Adresse." #: ../pykolab/cli/cmd_remove_mailaddress.py:57 #, python-format msgid "No recipient found for email address %r" -msgstr "" +msgstr "Kein Empfänger gefunden für E-Mail-Adresse %r" #: ../pykolab/cli/cmd_remove_mailaddress.py:60 #, python-format msgid "Found the following recipient(s): %r" -msgstr "" +msgstr "Folgende Empfänger gefunden: %r" #: ../pykolab/cli/cmd_remove_mailaddress.py:66 #, python-format msgid "Using the following mail attributes: %r" -msgstr "" +msgstr "Nutze folgende Mail-Attribute: %r" #: ../pykolab/cli/cmd_remove_mailaddress.py:90 msgid "Found the following recipients:" -msgstr "" +msgstr "Folgende Empfänger gefunden:" #: ../pykolab/cli/cmd_remove_user_subscription.py:37 msgid "Unsubscribe a user from a folder." -msgstr "" +msgstr "Entferne einen Benutzer-Abonement von einem Ordner." #: ../pykolab/cli/cmd_remove_user_subscription.py:86 #, python-format @@ -1144,11 +1152,11 @@ #: ../pykolab/cli/cmd_rename_mailbox.py:52 msgid "No target mailbox name specified" -msgstr "" +msgstr "Keine Name für Ziel-Postfach angegeben" #: ../pykolab/cli/cmd_rename_mailbox.py:54 msgid "No source mailbox name specified" -msgstr "" +msgstr "Keine Name für Quell-Postfach angegeben" #: ../pykolab/cli/cmd_rename_mailbox.py:66 #, python-format @@ -1164,7 +1172,7 @@ #: ../pykolab/cli/cmd_set_mailbox_acl.py:51 #: ../pykolab/cli/cmd_set_mailbox_acl.py:56 msgid "ACI Permissions" -msgstr "" +msgstr "ACI-Berechtigungen" #: ../pykolab/cli/cmd_set_mailbox_metadata.py:45 msgid "Set annotation as user USER" @@ -1174,16 +1182,16 @@ #: ../pykolab/cli/cmd_set_mailbox_metadata.py:63 #: ../pykolab/cli/cmd_set_mailbox_metadata.py:68 msgid "Metadata value" -msgstr "" +msgstr "Metadatenwert" #: ../pykolab/cli/cmd_set_mailbox_metadata.py:62 #: ../pykolab/cli/cmd_set_mailbox_metadata.py:67 msgid "Metadata path" -msgstr "" +msgstr "Metadatenpfad" #: ../pykolab/cli/cmd_set_quota.py:43 ../pykolab/cli/cmd_set_quota.py:47 msgid "New quota" -msgstr "" +msgstr "Neues Kontingent" #: ../pykolab/cli/cmd_sync_mailhost_attrs.py:44 msgid "Delete mailboxes for recipients that do not appear to exist in LDAP." @@ -1246,17 +1254,17 @@ #: ../pykolab/cli/cmd_sync.py:72 #, python-format msgid "Found %d domains in %d seconds" -msgstr "" +msgstr "%d Domains in %d Sekunden gefunden" #: ../pykolab/cli/cmd_sync.py:85 #, python-format msgid "Running for domain %s" -msgstr "" +msgstr "Starte für Domain %s" #: ../pykolab/cli/cmd_sync.py:92 #, python-format msgid "Synchronizing users for %s took %d seconds" -msgstr "" +msgstr "Benutzer für %s zu synchronisieren dauerte %d Sekunden" #: ../pykolab/cli/cmd_sync.py:109 #, python-format @@ -1285,11 +1293,11 @@ #: ../pykolab/cli/commands.py:97 ../pykolab/setup/components.py:90 #, python-format msgid "Command Group: %s" -msgstr "" +msgstr "Befehlsgruppe: %s" #: ../pykolab/cli/commands.py:112 ../pykolab/cli/commands.py:117 msgid "No such command." -msgstr "" +msgstr "Dieses Kommando existiert nicht." #: ../pykolab/cli/commands.py:167 ../pykolab/setup/components.py:231 #, python-format @@ -1300,16 +1308,16 @@ #: ../wallace/modules.py:376 #, python-format msgid "Alias for %s" -msgstr "" +msgstr "Alias für %s" #: ../pykolab/cli/commands.py:200 ../pykolab/setup/components.py:265 msgid "Not yet implemented" -msgstr "" +msgstr "Diese Funktion ist noch nicht implementiert" #: ../pykolab/cli/sieve/cmd_list.py:43 ../pykolab/cli/sieve/cmd_put.py:42 #: ../pykolab/cli/sieve/cmd_refresh.py:44 ../pykolab/cli/sieve/cmd_test.py:43 msgid "Email Address" -msgstr "E-Mail-Adresse" +msgstr "E-mail-Adresse" #: ../pykolab/cli/sieve/cmd_refresh.py:99 #: ../pykolab/plugins/sievemgmt/__init__.py:111 @@ -1394,7 +1402,7 @@ #: ../pykolab/cli/telemetry/cmd_examine_command_issue.py:60 #: ../pykolab/cli/telemetry/cmd_examine_session.py:65 msgid "Invalid session identifier" -msgstr "" +msgstr "Ungültiger Sitzungsbezeichner" #: ../pykolab/cli/telemetry/cmd_examine_command_issue.py:75 #: ../pykolab/cli/telemetry/cmd_examine_session.py:100 @@ -1408,11 +1416,11 @@ #: ../pykolab/cli/telemetry/cmd_list_sessions.py:35 msgid "List Options" -msgstr "" +msgstr "Liste Optionen" #: ../pykolab/cli/telemetry/cmd_list_sessions.py:40 msgid "Display sessions since ..." -msgstr "" +msgstr "Zeige Sitzungen seit..." #: ../pykolab/cli/telemetry/cmd_list_sessions.py:58 #, python-format @@ -1438,7 +1446,7 @@ #: ../pykolab/conf/entitlement.py:141 #, python-format msgid "License file %s not readable!" -msgstr "" +msgstr "Lizenzdatei %s nicht lesbar!" #: ../pykolab/conf/entitlement.py:147 msgid "No entitlement directory found" @@ -1447,46 +1455,46 @@ #: ../pykolab/conf/__init__.py:87 #, python-format msgid "Setting %s to %r (from defaults)" -msgstr "" +msgstr "Setze %s auf %r (aus den Standardeinstellungen)" #: ../pykolab/conf/__init__.py:106 #, python-format msgid "Setting %s to %r (from CLI, verified)" -msgstr "" +msgstr "Setze %s auf %r (von der Kommandozeile, überprüft)" #: ../pykolab/conf/__init__.py:109 #, python-format msgid "Setting %s to %r (from CLI, not checked)" -msgstr "" +msgstr "Setze %s auf %r (von der Kommandozeile, nicht überprüft)" #: ../pykolab/conf/__init__.py:150 ../pykolab/conf/__init__.py:207 #, python-format msgid "Setting %s_%s to '****' (from configuration file)" -msgstr "" +msgstr "Setze %s_%s auf '****' (aus Konfigurationsdatei)" #: ../pykolab/conf/__init__.py:152 ../pykolab/conf/__init__.py:209 #, python-format msgid "Setting %s_%s to %r (from configuration file)" -msgstr "" +msgstr "Setze %s_%s auf %r (aus Konfigurationsdatei)" #: ../pykolab/conf/__init__.py:162 msgid "Setting options from configuration file" -msgstr "" +msgstr "Hole Optionen aus Konfigurationsdatei" #: ../pykolab/conf/__init__.py:223 #, python-format msgid "Configuration file %s not readable" -msgstr "" +msgstr "Konfigurationsdatei %s ist nicht lesbar" #: ../pykolab/conf/__init__.py:226 #, python-format msgid "Reading configuration file %s" -msgstr "" +msgstr "Lese Konfigurationsdatei %s" #: ../pykolab/conf/__init__.py:230 #, python-format msgid "Invalid configuration file %s" -msgstr "" +msgstr "Ungültige Konfigurationsdatei %s" #: ../pykolab/conf/__init__.py:233 #, python-format @@ -1498,100 +1506,100 @@ #. # #: ../pykolab/conf/__init__.py:267 msgid "Runtime Options" -msgstr "" +msgstr "Laufzeit-Einstellungen" #: ../pykolab/conf/__init__.py:272 msgid "Configuration file to use" -msgstr "" +msgstr "Konfigurationsdatei, die benutzt werden soll" #: ../pykolab/conf/__init__.py:278 msgid "Set the debugging " -msgstr "" +msgstr "Stelle Fehlerbehebung ein" #: ../pykolab/conf/__init__.py:286 msgid "Set the logging level. " -msgstr "" +msgstr "Setze das Protokollniveau" #: ../pykolab/conf/__init__.py:294 msgid "Log file to use" -msgstr "" +msgstr "Protokolldatei" #: ../pykolab/conf/__init__.py:300 msgid "Be quiet." -msgstr "" +msgstr "Sei still." #: ../pykolab/conf/__init__.py:306 msgid "Answer yes to all questions." -msgstr "" +msgstr "Ja auf alle Fragen." #: ../pykolab/conf/__init__.py:328 msgid "No command supplied" -msgstr "" +msgstr "Kein Befehl angegeben" #: ../pykolab/conf/__init__.py:416 msgid "Insufficient options. Need section, key and value -in that order." -msgstr "" +msgstr "Unzureichende Optionen. Brauche Sektion, Schlüssel und Wert in dieser Reihenfolge." #: ../pykolab/conf/__init__.py:419 #, python-format msgid "No section '%s' exists." -msgstr "" +msgstr "Es existiert keine Sektion '%s'." #: ../pykolab/conf/__init__.py:461 #, python-format msgid "Setting %s to %r (from the default values for CLI options)" -msgstr "" +msgstr "Setze %s auf %r (aus den Standardwerten für Kommandozeilenoptionen)" #: ../pykolab/conf/__init__.py:534 #, python-format msgid "Could not execute configuration function: %s" -msgstr "" +msgstr "Konnte die Konfigurationsfunktion nicht ausführen: %s" #: ../pykolab/conf/__init__.py:542 #, python-format msgid "Option %s/%s does not exist in config file %s, pulling from defaults" -msgstr "" +msgstr "Die Option %s/%s existiert in der Konfigurationsdatei %s nicht, sie wird aus den Standardeinstellungen geholt" #: ../pykolab/conf/__init__.py:550 ../pykolab/conf/__init__.py:553 msgid "Option does not exist in defaults." -msgstr "" +msgstr "Diese Option hat keinen Standardwert." #: ../pykolab/conf/__init__.py:563 #, python-format msgid "Configuration file %s not readable." -msgstr "" +msgstr "Konfigurationsdatei %s ist nicht lesbar." #: ../pykolab/conf/__init__.py:566 #, python-format msgid "Configuration file %s does not exist." -msgstr "" +msgstr "Konfigurationsdatei %s existiert nicht." #: ../pykolab/conf/__init__.py:571 msgid "" "WARNING: A negative debug level value does not make this program be any more" " silent." -msgstr "" +msgstr "Warnung: Eine negative Fehlerprotokollierungszahl macht dieses Programm nicht noch stiller." #: ../pykolab/conf/__init__.py:577 msgid "This program has 9 levels of verbosity. Using the maximum of 9." -msgstr "" +msgstr "Dieses Programm hat 9 Ebenen der Detailliertheit. Benutze das Maximum 9." #: ../pykolab/conf/__init__.py:585 ../pykolab/conf/__init__.py:591 #: ../pykolab/conf/__init__.py:595 ../pykolab/conf/__init__.py:601 msgid "Cannot start SASL authentication daemon" -msgstr "" +msgstr "Konnte SASL Authentisierungsdaemon nicht starten" #: ../pykolab/conf/__init__.py:612 msgid "No imaplib library found." -msgstr "" +msgstr "Keine imaplib-Bibliothek gefunden." #: ../pykolab/conf/__init__.py:622 msgid "No LMTP class found in the smtplib library." -msgstr "" +msgstr "Keine Klasse namens LMTP in der smtplib-Bibliothek gefunden." #: ../pykolab/conf/__init__.py:632 msgid "No SMTP class found in the smtplib library." -msgstr "" +msgstr "Keine Klasse namens SMTP in der smtplib-Bibliothek gefunden." #: ../pykolab/conf/__init__.py:646 #, python-format @@ -1611,7 +1619,7 @@ #: ../pykolab/constants.py.in:53 msgid "WARNING" -msgstr "" +msgstr "WARNUNG" #: ../pykolab/constants.py.in:53 msgid "" @@ -1621,16 +1629,16 @@ #: ../pykolab/constants.py.in:72 msgid "389 Directory Server or Red Hat Directory Server" -msgstr "" +msgstr "389 Verzeichnisserver oder Red Hat Verzeichnisserver" #: ../pykolab/constants.py.in:76 ../pykolab/constants.py.in:80 msgid "OpenLDAP or compatible" -msgstr "" +msgstr "OpenLDAP oder kompatibel" #: ../pykolab/imap/cyrus.py:80 #, python-format msgid "Could not connect to Cyrus IMAP server %r" -msgstr "" +msgstr "Verbindung zum Cyrus IMAP-Server %r nicht möglich" #: ../pykolab/imap/cyrus.py:138 #, python-format @@ -1639,11 +1647,11 @@ #: ../pykolab/imap/cyrus.py:143 msgid "Detected we are running in a Murder topology" -msgstr "" +msgstr "Dieses System läuft in einer Murder-Topologie" #: ../pykolab/imap/cyrus.py:147 msgid "This system is not part of a murder topology" -msgstr "" +msgstr "Dieses System ist nicht Teil einer Murder-Topologie" #: ../pykolab/imap/cyrus.py:168 #, python-format @@ -1662,7 +1670,7 @@ #: ../pykolab/imap/cyrus.py:200 #, python-format msgid "No annotations for %s: %r" -msgstr "" +msgstr "Keine Annotationen für %s: %r" #: ../pykolab/imap/cyrus.py:207 #, python-format @@ -1672,47 +1680,47 @@ #: ../pykolab/imap/cyrus.py:227 #, python-format msgid "Setting quota for folder %s to %s" -msgstr "" +msgstr "Setze Quota für Verzeichnis %s auf %s" #: ../pykolab/imap/cyrus.py:231 #, python-format msgid "Could not set quota for mailfolder %s" -msgstr "" +msgstr "Konnte Quota für Verzeichnis %s nicht setzen" #: ../pykolab/imap/cyrus.py:241 #, python-format msgid "Moving INBOX folder %s to %s on partition %s" -msgstr "" +msgstr "Verschiebe INBOX Verzeichnis %s nach %s auf Partition %s" #: ../pykolab/imap/cyrus.py:243 #, python-format msgid "Moving INBOX folder %s to %s" -msgstr "" +msgstr "Verschiebe Eingangsordner %s nach %s" #: ../pykolab/imap/cyrus.py:259 #, python-format msgid "Setting annotation %s on folder %s" -msgstr "" +msgstr "Setze Annotation %s auf Verzeichnis %s" #: ../pykolab/imap/cyrus.py:264 #, python-format msgid "Could not set annotation %r on mail folder %r: %r" -msgstr "" +msgstr "Konnte Annotation %r auf Verzeichnis %r nicht setzen: %r" #: ../pykolab/imap/cyrus.py:268 #, python-format msgid "Transferring folder %s from %s to %s" -msgstr "" +msgstr "Übertrage Verzeichnis %s von %s nach %s" #: ../pykolab/imap/cyrus.py:328 #, python-format msgid "Undeleting %s to %s" -msgstr "" +msgstr "Wiederherstellen %s nach %s" #: ../pykolab/imap/cyrus.py:339 #, python-format msgid "Would have transfered %s from %s to %s" -msgstr "" +msgstr "Haben %s von %s nach %s übertragen" #: ../pykolab/imap/cyrus.py:341 #, python-format @@ -1732,7 +1740,7 @@ #: ../pykolab/imap/__init__.py:70 #, python-format msgid "Iterating over %d folders" -msgstr "" +msgstr "Iteriere über %d Verzeichnisse" #. Set the ACL to '' (effectively deleting the ACL entry) #: ../pykolab/imap/__init__.py:83 @@ -1747,27 +1755,27 @@ #: ../pykolab/imap/__init__.py:168 #, python-format msgid "Logging on to Cyrus IMAP server %s" -msgstr "" +msgstr "Anmeldung am Cyrus IMAP Server %s" #: ../pykolab/imap/__init__.py:177 #, python-format msgid "Logging on to Dovecot IMAP server %s" -msgstr "" +msgstr "Anmeldung am Dovecot IMAP Server %s" #: ../pykolab/imap/__init__.py:186 #, python-format msgid "Logging on to generic IMAP server %s" -msgstr "" +msgstr "Anmeldung am generischen IMAP Server %s" #: ../pykolab/imap/__init__.py:204 #, python-format msgid "Reusing existing IMAP server connection to %s" -msgstr "" +msgstr "Verbindung zum IMAP-Server %s wird wieder verwendet" #: ../pykolab/imap/__init__.py:206 #, python-format msgid "Reconnecting to IMAP server %s" -msgstr "" +msgstr "Verbinde nochmal zum IMAP Server %s" #: ../pykolab/imap/__init__.py:223 msgid "Called imap.disconnect() on a server that we had no connection to." @@ -1781,12 +1789,12 @@ #: ../pykolab/imap/__init__.py:247 #, python-format msgid "Could not create folder %r" -msgstr "" +msgstr "Ordner %r konnte nicht erstellt werden" #: ../pykolab/imap/__init__.py:257 ../pykolab/imap/__init__.py:259 #, python-format msgid "%r has no attribute %s" -msgstr "" +msgstr "%r hat kein Attribut %s" #: ../pykolab/imap/__init__.py:393 #, python-format @@ -1796,7 +1804,7 @@ #: ../pykolab/imap/__init__.py:427 ../pykolab/imap/__init__.py:462 #, python-format msgid "Creating new shared folder %s" -msgstr "" +msgstr "Erzeuge einen neuen geteilten Ordner %s" #: ../pykolab/imap/__init__.py:487 ../pykolab/imap/__init__.py:740 #, python-format @@ -1806,7 +1814,7 @@ #: ../pykolab/imap/__init__.py:491 #, python-format msgid "Creating new mailbox for user %s" -msgstr "" +msgstr "Erzeuge eine neue Mailbox für Benutzer %s" #: ../pykolab/imap/__init__.py:506 ../pykolab/imap/__init__.py:613 msgid "Waiting for the Cyrus IMAP Murder to settle..." @@ -1815,7 +1823,7 @@ #: ../pykolab/imap/__init__.py:559 #, python-format msgid "Creating additional folders for user %s" -msgstr "" +msgstr "Erzeuge weitere Order für Benutzer %s" #: ../pykolab/imap/__init__.py:587 #, python-format @@ -1830,11 +1838,11 @@ #: ../pykolab/imap/__init__.py:618 #, python-format msgid "Mailbox already exists: %s" -msgstr "" +msgstr "Mailbox existiert bereits: %s" #: ../pykolab/imap/__init__.py:658 msgid "Subscribing user to the additional folders" -msgstr "" +msgstr "Abonniere weitere Ordner für den Benutzer" #: ../pykolab/imap/__init__.py:672 msgid "Using the following tests for folder subscriptions:" @@ -1843,12 +1851,12 @@ #: ../pykolab/imap/__init__.py:674 #, python-format msgid " %r" -msgstr "" +msgstr " %r" #: ../pykolab/imap/__init__.py:677 #, python-format msgid "Folder %s" -msgstr "" +msgstr "Ordner %s" #: ../pykolab/imap/__init__.py:689 #, python-format @@ -1873,33 +1881,33 @@ #: ../pykolab/imap/__init__.py:759 ../pykolab/imap/__init__.py:835 #, python-format msgid "Renaming INBOX from %s to %s" -msgstr "" +msgstr "Benenne INBOX Ordner von %s in %s um" #: ../pykolab/imap/__init__.py:763 #, python-format msgid "Could not rename INBOX folder %s to %s" -msgstr "" +msgstr "Konnte INBOX Ordner nicht von %s in %s umbenennen" #: ../pykolab/imap/__init__.py:765 ../pykolab/imap/__init__.py:839 #, python-format msgid "" "Moving INBOX folder %s won't succeed as target folder %s already exists" -msgstr "" +msgstr "Der INBOX-Ordner %s kann nicht verschoben werden, weil der Zielordner %s bereits existiert" #: ../pykolab/imap/__init__.py:769 #, python-format msgid "Server for mailbox %r is %r" -msgstr "" +msgstr "Server für Postfach %r ist %r" #: ../pykolab/imap/__init__.py:777 #, python-format msgid "Looking for folder '%s', we found folders: %r" -msgstr "" +msgstr "Auf der Suche nach dem Ordner '%s' haben wir diese Ordner gefunden: %r" #: ../pykolab/imap/__init__.py:800 #, python-format msgid "Setting ACL rights %s for subject %s on folder " -msgstr "" +msgstr "Richte ACL Rechte %s für Subjekt %s des Ordners ein" #: ../pykolab/imap/__init__.py:811 #, python-format @@ -1909,27 +1917,27 @@ #: ../pykolab/imap/__init__.py:832 #, python-format msgid "Found old INBOX folder %s" -msgstr "" +msgstr "Alter INBOX-Ordner %s gefunden" #: ../pykolab/imap/__init__.py:841 #, python-format msgid "Did not find old folder user/%s to rename" -msgstr "" +msgstr "Konnte alten Ordner user/%s nicht zum umbenennen finden." #: ../pykolab/imap/__init__.py:843 msgid "Value for user is not a dictionary" -msgstr "" +msgstr "Der Wert für user ist kein dictionary" #. TODO: Go in fact correct the quota. #: ../pykolab/imap/__init__.py:911 #, python-format msgid "Cannot get current IMAP quota for folder %s" -msgstr "" +msgstr "Kann aktuelles IMAP Kontingent für den Ordner %s nicht bekommen" #: ../pykolab/imap/__init__.py:924 #, python-format msgid "Quota for %s currently is %s" -msgstr "" +msgstr "Kontingent für %s ist aktuell %s" #: ../pykolab/imap/__init__.py:930 #, python-format @@ -1944,7 +1952,7 @@ #: ../pykolab/imap/__init__.py:1012 #, python-format msgid "Checking folder: %s" -msgstr "" +msgstr "Überprüfe Ordner: %s" #: ../pykolab/imap/__init__.py:1017 #, python-format @@ -1964,7 +1972,7 @@ #: ../pykolab/imap/__init__.py:1038 #, python-format msgid "Deleting folder %s" -msgstr "" +msgstr "Lösche Verzeichnis %s" #: ../pykolab/__init__.py:50 msgid "Returning thread local configuration" @@ -1982,30 +1990,30 @@ #: ../pykolab/itip/__init__.py:61 msgid "Could not read iTip from message." -msgstr "" +msgstr "Konnte iTip nicht aus Nachricht lesen." #: ../pykolab/itip/__init__.py:69 #, python-format msgid "Duplicate iTip object: %s" -msgstr "" +msgstr "Verdopple iTip Objekt: %s" #: ../pykolab/itip/__init__.py:93 msgid "iTip event without a start" -msgstr "" +msgstr "iTip Termin ohne einen Beginn" #: ../pykolab/itip/__init__.py:138 msgid "Message is not an iTip message (non-multipart message)" -msgstr "" +msgstr "Nachricht ist keine iTip Nachricht (keine Multipart Nachricht)" #: ../pykolab/itip/__init__.py:221 #, python-format msgid "Send iTip reply %s for %s %r" -msgstr "" +msgstr "Sende iTip Antwort %s für %s %r" #: ../pykolab/itip/__init__.py:237 #, python-format msgid "Failed to compose iTip reply message: %r: %s" -msgstr "" +msgstr "Erstellung iTip Antwortnachricht fehlgeschlagen: %r: %s" #: ../pykolab/itip/__init__.py:248 ../pykolab/itip/__init__.py:292 #: ../wallace/module_invitationpolicy.py:1082 @@ -2013,17 +2021,17 @@ #: ../wallace/module_resources.py:1247 #, python-format msgid "SMTP sendmail error: %r" -msgstr "" +msgstr "SMTP sendmail-Fehler: %r" #: ../pykolab/itip/__init__.py:280 #, python-format msgid "Failed to compose iTip request message: %r" -msgstr "" +msgstr "Erstellung iTip Anforderungsnachricht fehlgeschlagen: %r" #: ../pykolab/logger.py:168 ../pykolab/logger.py:175 #, python-format msgid "Could not change permissions on %s: %r" -msgstr "" +msgstr "Konnte Berechtigungen auf %s nicht ändern: %r" #: ../pykolab/logger.py:192 #, python-format @@ -2057,12 +2065,12 @@ #: ../pykolab/plugins/__init__.py:74 #, python-format msgid "RuntimeError for plugin %s: %s" -msgstr "" +msgstr "Laufzeitfehler von Plugin %s: %s" #: ../pykolab/plugins/__init__.py:78 #, python-format msgid "Plugin %s failed to load (%s: %s)" -msgstr "" +msgstr "Plugin %s konnte nicht geladen werden (%s: %s)" #: ../pykolab/plugins/__init__.py:116 ../pykolab/plugins/__init__.py:118 #, python-format @@ -2102,7 +2110,7 @@ #: ../pykolab/plugins/__init__.py:187 #, python-format msgid "Cannot check options for plugin %s: %s" -msgstr "" +msgstr "Kein Zugriff auf Einstellungen des Plugins %s: %s" #: ../pykolab/plugins/__init__.py:189 #, python-format @@ -2170,7 +2178,7 @@ #: ../pykolab/setup/components.py:58 msgid "Display this help." -msgstr "" +msgstr "Zeige diese Hilfe." #: ../pykolab/setup/components.py:149 msgid "No component selected, continuing for all components" @@ -2178,7 +2186,7 @@ #: ../pykolab/setup/components.py:187 ../pykolab/setup/components.py:192 msgid "No such component." -msgstr "" +msgstr "Keine solche Komponente." #: ../pykolab/setup/setup_freebusy.py:46 msgid "Setup Free/Busy." @@ -2190,7 +2198,7 @@ #: ../pykolab/setup/setup_imap.py:45 msgid "Setup IMAP." -msgstr "" +msgstr "Richte IMAP ein." #: ../pykolab/setup/setup_imap.py:89 msgid "Could not write out Cyrus IMAP configuration file /etc/imapd.conf" @@ -2213,7 +2221,7 @@ #: ../pykolab/setup/setup_kolabd.py:44 msgid "Setup the Kolab daemon." -msgstr "" +msgstr "Richte den Kolab Daemon ein." #: ../pykolab/setup/setup_kolabd.py:52 #, python-format @@ -2230,7 +2238,7 @@ #: ../pykolab/setup/setup_ldap.py:45 msgid "LDAP Options" -msgstr "" +msgstr "LDAP Optionen" #: ../pykolab/setup/setup_ldap.py:52 msgid "Specify FQDN (overriding defaults)." @@ -2254,7 +2262,7 @@ #: ../pykolab/setup/setup_ldap.py:88 msgid "Setup LDAP." -msgstr "" +msgstr "LDAP Einrichten" #: ../pykolab/setup/setup_ldap.py:97 msgid "Skipping setup of LDAP, as specified" @@ -2290,7 +2298,7 @@ #: ../pykolab/setup/setup_ldap.py:162 msgid "Administrator password" -msgstr "" +msgstr "Administrator Passwort" #: ../pykolab/setup/setup_ldap.py:169 msgid "" @@ -2304,7 +2312,7 @@ #: ../pykolab/setup/setup_ldap.py:178 msgid "Directory Manager password" -msgstr "" +msgstr "Verzeichnismanager Passwort" #: ../pykolab/setup/setup_ldap.py:185 msgid "" @@ -2317,11 +2325,11 @@ #: ../pykolab/setup/setup_ldap.py:195 ../pykolab/setup/setup_ldap.py:198 msgid "User" -msgstr "" +msgstr "Benutzer" #: ../pykolab/setup/setup_ldap.py:196 ../pykolab/setup/setup_ldap.py:199 msgid "Group" -msgstr "" +msgstr "Gruppe" #: ../pykolab/setup/setup_ldap.py:234 msgid "" @@ -2343,7 +2351,7 @@ "\n" " Invalid input. Please try again.\n" " " -msgstr "" +msgstr "\n Ungültige Eingabe. Bitte nochmals versuchen.\n " #: ../pykolab/setup/setup_ldap.py:262 msgid "" @@ -2372,7 +2380,7 @@ #: ../pykolab/setup/setup_ldap.py:344 msgid "Setting up 389 Directory Server" -msgstr "" +msgstr "Richte 389 Verzeichnisserver ein" #: ../pykolab/setup/setup_ldap.py:356 msgid "" @@ -2418,7 +2426,7 @@ #: ../pykolab/setup/setup_ldap.py:441 msgid "Cyrus Administrator password" -msgstr "" +msgstr "Cyrus Administrator Passwort" #: ../pykolab/setup/setup_ldap.py:448 msgid "" @@ -2432,30 +2440,30 @@ #: ../pykolab/setup/setup_ldap.py:457 msgid "Kolab Service password" -msgstr "" +msgstr "Kolab-Dienst-Passwort" #: ../pykolab/setup/setup_ldap.py:467 msgid "Writing out configuration to kolab.conf" -msgstr "" +msgstr "Schreibe Einstellungen in kolab.conf" #: ../pykolab/setup/setup_ldap.py:481 msgid "Inserting service users into LDAP." -msgstr "" +msgstr "Füge Service-Benutzer ins LDAP ein." #: ../pykolab/setup/setup_ldap.py:555 msgid "Writing out cn=kolab,cn=config" -msgstr "" +msgstr "Schreibe cn=kolab,cn=config" #. TODO: Add kolab-admin role #. TODO: Assign kolab-admin admin ACLs #: ../pykolab/setup/setup_ldap.py:579 #, python-format msgid "Adding domain %s to list of domains for this deployment" -msgstr "" +msgstr "Füge Domain %s zu dieser Installation hinzu" #: ../pykolab/setup/setup_ldap.py:607 msgid "Disabling anonymous binds" -msgstr "" +msgstr "Stelle anonymes Binden ab" #. TODO: Ensure the uid attribute is unique #. TODO^2: Consider renaming the general "attribute uniqueness to "uid @@ -2475,7 +2483,7 @@ #. TODO: Add kolab-admin role #: ../pykolab/setup/setup_ldap.py:642 msgid "Adding the kolab-admin role" -msgstr "" +msgstr "Füge Kolab-Admin Rolle hinzu" #. TODO: User writeable attributes on root_dn #: ../pykolab/setup/setup_ldap.py:653 @@ -2489,12 +2497,12 @@ #: ../pykolab/setup/setup_mta.py:41 msgid "Setup MTA." -msgstr "" +msgstr "Richte MTA ein." #: ../pykolab/setup/setup_mta.py:317 ../pykolab/setup/setup_php.py:106 #, python-format msgid "Setting key %r to %r" -msgstr "" +msgstr "Schlüssel %r wird auf %r festgelegt" #: ../pykolab/setup/setup_mta.py:350 msgid "Could not write out Postfix configuration file /etc/postfix/master.cf" @@ -2514,7 +2522,7 @@ #: ../pykolab/setup/setup_mysql.py:39 msgid "Setup MySQL." -msgstr "" +msgstr "Richte MySQL ein." #: ../pykolab/setup/setup_mysql.py:49 msgid "Could not start the MySQL database service." @@ -2536,7 +2544,7 @@ #: ../pykolab/setup/setup_roundcube.py:190 #: ../pykolab/setup/setup_syncroton.py:66 msgid "MySQL root password" -msgstr "" +msgstr "MySQL root Password" #: ../pykolab/setup/setup_mysql.py:88 msgid "" @@ -2561,7 +2569,7 @@ #: ../pykolab/setup/setup_mysql.py:151 msgid "MySQL kolab password" -msgstr "" +msgstr "MySQL-kolab Password" #: ../pykolab/setup/setup_mysql.py:170 msgid "Could not find the MySQL Kolab schema file" @@ -2569,11 +2577,11 @@ #: ../pykolab/setup/setup_php.py:42 msgid "PHP Options" -msgstr "" +msgstr "PHP Optionen" #: ../pykolab/setup/setup_php.py:49 msgid "Specify the timezone for PHP." -msgstr "" +msgstr "Zeitzone für PHP definieren." #: ../pykolab/setup/setup_php.py:57 msgid "Specify the path to the php.ini file used with the webserver." @@ -2581,7 +2589,7 @@ #: ../pykolab/setup/setup_php.py:61 msgid "Setup PHP." -msgstr "" +msgstr "Richte PHP ein." #: ../pykolab/setup/setup_php.py:66 msgid "" @@ -2594,7 +2602,7 @@ #: ../pykolab/setup/setup_php.py:74 msgid "Timezone ID" -msgstr "" +msgstr "Zeitzonen ID" #: ../pykolab/setup/setup_php.py:80 #, python-format @@ -2607,7 +2615,7 @@ #: ../pykolab/setup/setup_roundcube.py:44 msgid "Setup Roundcube." -msgstr "" +msgstr "Stelle Roundcube ein." #: ../pykolab/setup/setup_roundcube.py:48 msgid "" @@ -2620,12 +2628,12 @@ #: ../pykolab/setup/setup_roundcube.py:56 msgid "MySQL roundcube password" -msgstr "" +msgstr "MySQL roundcube Passwort" #: ../pykolab/setup/setup_roundcube.py:126 #, python-format msgid "Using template file %r" -msgstr "" +msgstr "Vorlagendatei %r wird verwendet" #: ../pykolab/setup/setup_roundcube.py:133 #, python-format @@ -2639,7 +2647,7 @@ #: ../pykolab/setup/setup_syncroton.py:40 msgid "Setup Syncroton." -msgstr "" +msgstr "Richte Syncroton ein." #. start_max = (int)(time.time()) #: ../pykolab/telemetry.py:588 @@ -2664,30 +2672,30 @@ #: ../pykolab/telemetry.py:652 msgid "No database available" -msgstr "" +msgstr "Keine Datenbank verfügbar" #: ../pykolab/utils.py:62 ../pykolab/utils.py:64 #, python-format msgid "Confirm %s: " -msgstr "" +msgstr "Bestätige %s:" #: ../pykolab/utils.py:67 msgid "Incorrect confirmation. " -msgstr "" +msgstr "Ungültige Bestätigung." #: ../pykolab/utils.py:72 ../pykolab/utils.py:77 #, python-format msgid "%s: " -msgstr "" +msgstr "%s:" #: ../pykolab/utils.py:74 ../pykolab/utils.py:79 #, python-format msgid "%s [%s]: " -msgstr "" +msgstr "%s [%s]: " #: ../pykolab/utils.py:124 msgid "Please answer 'yes' or 'no'." -msgstr "" +msgstr "Bitte antworten Sie mit 'yes' (ja) oder 'no' (nein)." #: ../pykolab/utils.py:164 msgid "Choice" @@ -2767,7 +2775,7 @@ #: ../pykolab/xml/attendee.py:14 ../pykolab/xml/attendee.py:22 msgid "Completed" -msgstr "" +msgstr "Erledigt" #: ../pykolab/xml/attendee.py:15 ../pykolab/xml/attendee.py:23 msgid "Started" @@ -2872,37 +2880,37 @@ #: ../pykolab/xml/recurrence_rule.py:38 #, python-format msgid "Every %d year(s)" -msgstr "" +msgstr "Alle %d Jahr(e)" #: ../pykolab/xml/recurrence_rule.py:39 #, python-format msgid "Every %d month(s)" -msgstr "" +msgstr "Alle %d Monat(e)" #: ../pykolab/xml/recurrence_rule.py:40 #, python-format msgid "Every %d week(s)" -msgstr "" +msgstr "Alle %d Woche(n)" #: ../pykolab/xml/recurrence_rule.py:41 #, python-format msgid "Every %d day(s)" -msgstr "" +msgstr "Alle %d Tag(e)" #: ../pykolab/xml/recurrence_rule.py:42 #, python-format msgid "Every %d hours" -msgstr "" +msgstr "Alle %d Stunden" #: ../pykolab/xml/recurrence_rule.py:43 #, python-format msgid "Every %d minutes" -msgstr "" +msgstr "Alle %d Minuten" #: ../pykolab/xml/recurrence_rule.py:44 #, python-format msgid "Every %d seconds" -msgstr "" +msgstr "Alle %d Sekunden" #: ../pykolab/xml/todo.py:110 msgid "Todo due needs datetime.date or datetime.datetime instance" @@ -2918,7 +2926,7 @@ #: ../pykolab/xml/utils.py:128 msgid "Location" -msgstr "" +msgstr "Ort" #: ../pykolab/xml/utils.py:129 msgid "Description" @@ -2926,7 +2934,7 @@ #: ../pykolab/xml/utils.py:130 msgid "URL" -msgstr "" +msgstr "URL" #: ../pykolab/xml/utils.py:131 msgid "Status" @@ -2934,27 +2942,27 @@ #: ../pykolab/xml/utils.py:132 msgid "Priority" -msgstr "" +msgstr "Priorität" #: ../pykolab/xml/utils.py:133 msgid "Attendee" -msgstr "" +msgstr "Teilnehmer" #: ../pykolab/xml/utils.py:134 msgid "Start" -msgstr "" +msgstr "Beginn" #: ../pykolab/xml/utils.py:135 msgid "End" -msgstr "" +msgstr "Ende" #: ../pykolab/xml/utils.py:136 msgid "Due" -msgstr "" +msgstr "Fällig" #: ../pykolab/xml/utils.py:137 msgid "Repeat" -msgstr "" +msgstr "Wiederholung" #: ../pykolab/xml/utils.py:138 msgid "Repeat Exception" @@ -2962,23 +2970,23 @@ #: ../pykolab/xml/utils.py:139 msgid "Organizer" -msgstr "" +msgstr "Organisator" #: ../pykolab/xml/utils.py:140 msgid "Attachment" -msgstr "" +msgstr "Anhang" #: ../pykolab/xml/utils.py:141 msgid "Alarm" -msgstr "" +msgstr "Alarm" #: ../pykolab/xml/utils.py:142 msgid "Classification" -msgstr "" +msgstr "Einstufung" #: ../pykolab/xml/utils.py:143 msgid "Progress" -msgstr "" +msgstr "Fortschritt" #: ../pykolab/xml/utils.py:188 #, python-format @@ -3000,7 +3008,7 @@ #: ../pykolab/xml/utils.py:197 msgid "Play sound" -msgstr "" +msgstr "Audio abspielen" #: ../pykolab/xml/utils.py:203 #, python-format @@ -3040,7 +3048,7 @@ #: ../wallace/__init__.py:439 ../wallace/__init__.py:448 msgid "" "Traceback occurred, please report a bug at http://bugzilla.kolabsys.com" -msgstr "" +msgstr "Ein Fehler mit Traceback trat auf, bitte legen Sie einen Bericht auf http://bugzilla.kolabsys.com an" #: ../saslauthd/__init__.py:194 msgid "kolab-saslauthd could not accept " @@ -3066,7 +3074,7 @@ #: ../wallace/module_resources.py:1235 #, python-format msgid "Booking for %s has been %s" -msgstr "" +msgstr "Buchung für %s wurde %s" #. check confirmation message sent to resource owner (jane) #. check first confirmation message sent to resource owner (jane) @@ -3080,13 +3088,13 @@ #: ../wallace/module_resources.py:1333 #, python-format msgid "Booking request for %s requires confirmation" -msgstr "" +msgstr "Buchungsanfrage für %s benötigt eine Bestätigung" #: ../tests/functional/test_wallace/test_007_invitationpolicy.py:240 #: ../wallace/module_invitationpolicy.py:448 #, python-format msgid "\"%(summary)s\" has been %(status)s" -msgstr "" +msgstr "\"%(summary)s\" wurde %(status)s" #. check for notification message #. this notification should be suppressed until mark has replied, too @@ -3103,7 +3111,7 @@ #: ../wallace/module_invitationpolicy.py:1071 #, python-format msgid "\"%s\" has been updated" -msgstr "" +msgstr "\"%s\" wurde aktualisiert" #: ../tests/functional/test_wallace/test_007_invitationpolicy.py:813 #: ../tests/functional/test_wallace/test_007_invitationpolicy.py:825 @@ -3115,7 +3123,7 @@ #: ../wallace/module_invitationpolicy.py:1133 #, python-format msgid "\"%s\" has been cancelled" -msgstr "" +msgstr "\"%s\" wurde abgesagt" #: ../tests/unit/test-011-itip.py:465 #, python-format @@ -3144,7 +3152,7 @@ #: ../wallace/__init__.py:122 msgid "Bind address for Wallace." -msgstr "" +msgstr "Bind-Adresse für Wallace." #: ../wallace/__init__.py:140 msgid "Number of threads to use." @@ -3152,7 +3160,7 @@ #: ../wallace/__init__.py:156 msgid "Port that Wallace is supposed to use." -msgstr "" +msgstr "Port, den Wallace benutzen soll." #: ../wallace/__init__.py:205 #, python-format @@ -3161,11 +3169,11 @@ #: ../wallace/__init__.py:217 msgid "Could not shut down socket" -msgstr "" +msgstr "Konnte Socket nicht schließen" #: ../wallace/__init__.py:286 msgid "Accepted connection" -msgstr "" +msgstr "Verbindung akzeptiert" #: ../wallace/__init__.py:464 #, python-format @@ -3415,7 +3423,7 @@ #: ../wallace/module_invitationpolicy.py:694 #, python-format msgid "IMAP proxy authentication failed: %r" -msgstr "" +msgstr "IMAP-Proxy Authentifizierung fehlgeschlagen: %r" #: ../wallace/module_invitationpolicy.py:716 #, python-format @@ -3503,7 +3511,7 @@ #: ../wallace/module_invitationpolicy.py:1041 msgid "(removed)" -msgstr "" +msgstr "(entfernt)" #: ../wallace/module_invitationpolicy.py:1047 #, python-format @@ -3512,7 +3520,7 @@ " The assignment for '%(summary)s' has been updated in your tasklist.\n" " %(roundup)s\n" " " -msgstr "" +msgstr "\nDie Zuweisung für '%(summary)s' wurde in ihrer Aufgabenliste aktualisiert.\n%(roundup)s\n " #: ../wallace/module_invitationpolicy.py:1055 #, python-format @@ -3521,18 +3529,18 @@ " The event '%(summary)s' at %(start)s has been updated in your calendar.\n" " %(roundup)s\n" " " -msgstr "" +msgstr "\nDas Ereignis '%(summary)s' um %(start)s wurde in ihrem Kalender aktualisiert.\n%(roundup)s\n " #: ../wallace/module_invitationpolicy.py:1064 #: ../wallace/module_invitationpolicy.py:1126 #: ../wallace/module_invitationpolicy.py:1216 msgid "*** This is an automated message. Please do not reply. ***" -msgstr "" +msgstr "*** Dies ist eine automatisierte Nachricht. Bitte antworten Sie nicht. ***" #: ../wallace/module_invitationpolicy.py:1099 #, python-format msgid "Send cancellation notification for %s %r to user %r" -msgstr "" +msgstr "Benachrichtigung über die Absage von %s %r an Nutzer %r senden" #: ../wallace/module_invitationpolicy.py:1109 #, python-format @@ -3541,7 +3549,7 @@ " The assignment for '%(summary)s' has been cancelled by %(organizer)s.\n" " The copy in your tasklist as been marked as cancelled accordingly.\n" " " -msgstr "" +msgstr "\nDie Zuweisung für Aufgabe '%(summary)s' wurde von %(organizer)s abgesagt.\nDie Kopie in Ihrer Taskliste wurde entsprechend aktualisiert." #: ../wallace/module_invitationpolicy.py:1117 #, python-format @@ -3550,22 +3558,22 @@ " The event '%(summary)s' at %(start)s has been cancelled by %(organizer)s.\n" " The copy in your calendar as been marked as cancelled accordingly.\n" " " -msgstr "" +msgstr "\nDas Ereignis '%(summary)s' um %(start)s wurde von %(organizer)s abgesagt.\nDie Kopie in ihrem Kalender wurde entsprechend aktualisiert." #: ../wallace/module_invitationpolicy.py:1206 #, python-format msgid "Updated %s's copy of %r: %r" -msgstr "" +msgstr "%s's Kopie von %r wurde aktualisiert: %r" #: ../wallace/module_invitationpolicy.py:1209 #, python-format msgid "Attendee %s's copy of %r not found" -msgstr "" +msgstr "Die Kopie des Teilnehmers %s von %r wurde nicht gefunden" #: ../wallace/module_invitationpolicy.py:1212 #, python-format msgid "Attendee %r not found in LDAP" -msgstr "" +msgstr "Teilnehmer %r wurde nicht in LDAP gefunden" #: ../wallace/module_invitationpolicy.py:1219 #, python-format @@ -3763,88 +3771,88 @@ #: ../wallace/module_resources.py:704 #, python-format msgid "Failed to access resource calendar:: %r" -msgstr "" +msgstr "Zugriff auf Ressourcenkalender fehlgeschlagen: %r" #: ../wallace/module_resources.py:733 #, python-format msgid "Apply invitation policies %r" -msgstr "" +msgstr "Anwenden der Einladungsrichtlinie %r" #: ../wallace/module_resources.py:752 #, python-format msgid "Adding event to %r: %r" -msgstr "" +msgstr "Hinzufügen Termin zu %r: %r" #: ../wallace/module_resources.py:806 #, python-format msgid "Failed to save event to resource calendar at %r: %r" -msgstr "" +msgstr "Speichern des Termins im Ressourcenkalender fehlgeschlagen in %r: %r" #: ../wallace/module_resources.py:823 #, python-format msgid "Delete resource calendar object %r in %r: %r" -msgstr "" +msgstr "Lösche Kalenderobjekt der Ressource %r in %r: %r" #: ../wallace/module_resources.py:866 #, python-format msgid "Checking if email address %r belongs to a resource (collection)" -msgstr "" +msgstr "Prüfe ob E-Mail-Adresse %r zu einer Ressource (Sammlung) gehört" #: ../wallace/module_resources.py:874 ../wallace/module_resources.py:946 #: ../wallace/module_resources.py:980 #, python-format msgid "Resource record(s): %r" -msgstr "" +msgstr "Ressourcen-Eintrag/Einträge: %r" #: ../wallace/module_resources.py:876 ../wallace/module_resources.py:948 #: ../wallace/module_resources.py:983 #, python-format msgid "No resource (collection) records found for %r" -msgstr "" +msgstr "Kein Ressourcen (Sammlung) - Eintrag für %r gefunden" #: ../wallace/module_resources.py:880 ../wallace/module_resources.py:952 #: ../wallace/module_resources.py:987 #, python-format msgid "Resource record: %r" -msgstr "" +msgstr "Ressourceneinträge: %r" #: ../wallace/module_resources.py:898 #, python-format msgid "Raw itip_events: %r" -msgstr "" +msgstr "Originale itip_events: %r" #: ../wallace/module_resources.py:906 #, python-format msgid "Raw set of attendees: %r" -msgstr "" +msgstr "Originalset der Teilnehmer: %r" #: ../wallace/module_resources.py:914 #, python-format msgid "Raw set of resources: %r" -msgstr "" +msgstr "Originalset der Ressourcen: %r" #: ../wallace/module_resources.py:919 #, python-format msgid "Raw set of organizers: %r" -msgstr "" +msgstr "Originalset der Organisatoren: %r" #: ../wallace/module_resources.py:939 #, python-format msgid "Checking if attendee %r is a resource (collection)" -msgstr "" +msgstr "Prüfe ob Teilnehmer %r eine Ressource (Sammlung) ist" #: ../wallace/module_resources.py:955 ../wallace/module_resources.py:989 msgid "Resource reservation made but no resource records found" -msgstr "" +msgstr "Ressourcenbuchung erfolgt, jedoch keine Ressourceneinträge gefunden" #: ../wallace/module_resources.py:974 #, python-format msgid "Checking if resource %r is a resource (collection)" -msgstr "" +msgstr "Prüfe ob Resource %r eine Resource (Sammlung)" #: ../wallace/module_resources.py:992 msgid "The following resources are being referred to in the " -msgstr "" +msgstr "Auf die folgenden Ressourcen wurde Bezug genommen in" #: ../wallace/module_resources.py:1157 #, python-format @@ -3854,7 +3862,7 @@ "\n" " Your reservation was delegated to \"%s\" which is available for the requested time.\n" " " -msgstr "" +msgstr "\n*** Dies ist eine automatisch erstellte E-Mail. Bitte antworten Sie nicht direkt darauf. ***\n\nIhre Reservierung wurde an \"%s\" delegiert, welche(r) zum angeforderten Termin verfügbar ist.\n " #: ../wallace/module_resources.py:1176 #, python-format @@ -3864,7 +3872,7 @@ " \n" " We hereby inform you that your reservation was %s.\n" " " -msgstr "" +msgstr "\n*** Dies ist eine automatisch erstellte E-Mail. Bitte antworten Sie nicht direkt darauf. ***\n\nHiermit informieren wir Sie, dass die Buchung %s wurde.\n " #: ../wallace/module_resources.py:1183 #, python-format @@ -3878,11 +3886,11 @@ #: ../wallace/module_resources.py:1218 #, python-format msgid "Sending booking notification for event %r to %r from %r" -msgstr "" +msgstr "Sende Buchungsbenachrichtigung für Termin %r zu %r von %r" #: ../wallace/module_resources.py:1236 msgid "failed" -msgstr "" +msgstr "fehlgeschlagen" #: ../wallace/module_resources.py:1256 #, python-format @@ -3892,7 +3900,7 @@ "\n" " *** This is an automated message, sent to you as the resource owner. ***\n" " " -msgstr "" +msgstr "\nDie Buchungsanfrage für %(resource)s durch %(orgname)s <%(orgemail)s> ist %(status)s für %(date)s.\n\n*** Dies ist eine automatisch erstellte E-Mail. Bitte antworten Sie nicht direkt darauf. ***\n " #: ../wallace/module_resources.py:1262 #, python-format @@ -3903,12 +3911,12 @@ "\n" " *** This is an automated message, sent to you as the resource owner. ***\n" " " -msgstr "" +msgstr "\nEine Buchungsanfrage für %(resource)s konnte nicht automatisch verarbeitet werden.\nBitte kontaktieren Sie %(orgname)s <%(orgemail)s>, welcher die Resource für den %(date)s angefragt hat.\nSubject: %(summary)s.\n\n*** Dies ist eine automatisch erstellte E-Mail. Bitte antworten Sie nicht direkt darauf. ***" #: ../wallace/module_resources.py:1306 #, python-format msgid "Clone invitation for owner confirmation: %r from %r" -msgstr "" +msgstr "Kopiere Einladung für Eigentümer Bestätigung: %r von %r" #: ../wallace/module_resources.py:1312 #, python-format @@ -3925,59 +3933,59 @@ "\n" " *** This is an automated message, please don't reply by email. ***\n" " " -msgstr "" +msgstr "\nEine Buchungsanfrage für %(resource)s benötigt Ihre Zustimmung!\nBitte akzeptieren Sie die Anfrage oder lehnen Sie diese ab ohne die Anfrage in Ihrem Kalender zu speichern.\n\nDie Buchungsanfrage wurde gesendet von %(orgname)s <%(orgemail)s>.\n\nBetreff: %(summary)s.\nTermin: %(date)s\nTeilnehmer: %(attendees)s\n\n*** Dies ist eine automatisch erstellte E-Mail. Bitte antworten Sie nicht direkt darauf. ***" #. This is a nested module #: ../wallace/modules.py:97 #, python-format msgid "Module Group: %s" -msgstr "" +msgstr "Modulgruppe: %s" #: ../wallace/modules.py:108 ../wallace/modules.py:120 #, python-format msgid "No such module %r in modules %r (1)." -msgstr "" +msgstr "Kein solches Modul %r in Modulen %r (1)." #: ../wallace/modules.py:113 #, python-format msgid "No such module %r in modules %r (2)." -msgstr "" +msgstr "Kein solches Modul %r in Modulen %r (2)." #: ../wallace/modules.py:126 #, python-format msgid "Holding message in queue for manual review (%s by %s)" -msgstr "" +msgstr "Behalte Nachricht zur manuellen Prüfung in der Warteliste (%s von %s)" #: ../wallace/modules.py:129 #, python-format msgid "Deferring message in %s (by module %s)" -msgstr "" +msgstr "Zurückgestellte Nachricht in %s (durch Modul %s)" #: ../wallace/modules.py:141 #, python-format msgid "The time when the message was sent: %r" -msgstr "" +msgstr "Zeitpunkt des Versandts: %r" #: ../wallace/modules.py:142 #, python-format msgid "The time now: %r" -msgstr "" +msgstr "Die Zeit ist jetzt: %r" #: ../wallace/modules.py:143 #, python-format msgid "The time delta: %r" -msgstr "" +msgstr "Die Zeitdifferenz: %r" #. TODO: Send NDR back to user #: ../wallace/modules.py:147 #, python-format msgid "Message in file %s older then 5 days, deleting" -msgstr "" +msgstr "Nachricht in Datei %s älter als 5 Tage, lösche" #: ../wallace/modules.py:172 #, python-format msgid "Rejecting message in %s (by module %s)" -msgstr "" +msgstr "Weise Nachricht in %s (durch Modul %s) zurück" #: ../wallace/modules.py:193 #, python-format @@ -3992,31 +4000,31 @@ "Your message is being delivered to any other recipients you may have\n" "sent your message to. There is no need to resend the message to those\n" "recipients.\n" -msgstr "" +msgstr "Ich bin das E-Mail-System Wallace auf %s.\n\nMit Bedauern muß ich Sie informieren, daß die angehängte Nachricht\nnicht an die folgenden Empfänger zugestellt werden konnte:\n\n- %s\n\nFalls Sie noch andere Empfänger angegeben haben wurde die Nachricht\nan diese zugestellt. An diese Empfänger müssen sie die Nachricht\nnicht erneut senden.\n" #: ../wallace/modules.py:208 #, python-format msgid "" "X-Wallace-Module: %s\n" "X-Wallace-Result: REJECT\n" -msgstr "" +msgstr "X-Wallace-Modul: %s\nX-Wallace-Ergebnis: REJECT\n" #: ../wallace/modules.py:267 #, python-format msgid "Accepting message in %s (by module %s)" -msgstr "" +msgstr "Akzeptiere Nachricht in %s (durch Modul %s)" #: ../wallace/modules.py:269 #, python-format msgid "Accepting message in: %r" -msgstr "" +msgstr "Akzeptiere Nachricht in: %r" #: ../wallace/modules.py:276 #, python-format msgid "recipients: %r" -msgstr "" +msgstr "Empfänger: %r" #: ../wallace/modules.py:354 #, python-format msgid "Module '%s' already registered" -msgstr "" +msgstr "Modul '%s' ist bereits registriert"
View file
pykolab-0.7.8.tar.gz/pykolab/itip/__init__.py -> pykolab-0.7.9.tar.gz/pykolab/itip/__init__.py
Changed
@@ -1,6 +1,7 @@ import icalendar import pykolab import traceback +import kolabformat from pykolab.xml import to_dt from pykolab.xml import event_from_ical @@ -86,6 +87,7 @@ itip['uid'] = str(c['uid']) itip['method'] = str(cal['method']).upper() itip['sequence'] = int(c['sequence']) if c.has_key('sequence') else 0 + itip['recurrence-id'] = c['recurrence-id'].dt if c.has_key('recurrence-id') and hasattr(c['recurrence-id'], 'dt') else None if c.has_key('dtstart'): itip['start'] = c['dtstart'].dt @@ -151,30 +153,52 @@ return conflict # don't consider conflict if event has TRANSP:TRANSPARENT - if kolab_event.get_transparency(): + if _is_transparent(kolab_event): return conflict _es = to_dt(kolab_event.get_start()) _ee = to_dt(kolab_event.get_ical_dtend()) # use iCal style end date: next day for all-day events + _ev = kolab_event # naive loops to check for collisions in (recurring) events # TODO: compare recurrence rules directly (e.g. matching time slot or weekday or monthday) while not conflict and _es is not None: _is = to_dt(itip_event['start']) _ie = to_dt(itip_event['end']) + _iv = itip_event['xml'] while not conflict and _is is not None: # log.debug("* Comparing event dates at %s/%s with %s/%s" % (_es, _ee, _is, _ie), level=9) - conflict = check_date_conflict(_es, _ee, _is, _ie) - _is = to_dt(itip_event['xml'].get_next_occurence(_is)) if kolab_event.is_recurring() else None + conflict = not _is_transparent(_ev) and not _is_transparent(_iv) and check_date_conflict(_es, _ee, _is, _ie) + _is = to_dt(itip_event['xml'].get_next_occurence(_is)) if itip_event['xml'].is_recurring() else None _ie = to_dt(itip_event['xml'].get_occurence_end_date(_is)) + # get full occurrence to compare the dates from a possible exception + if _is is not None and len(itip_event['xml'].get_exceptions()): + _ix = itip_event['xml'].get_instance(_is) + if _ix is not None: + _is = to_dt(_ix.get_start()) + _ie = to_dt(_ix.get_end()) + _iv = _ix + _es = to_dt(kolab_event.get_next_occurence(_es)) if kolab_event.is_recurring() else None _ee = to_dt(kolab_event.get_occurence_end_date(_es)) + # get full instance to compare the dates from a possible exception + if _es is not None and len(kolab_event.get_exceptions()): + _ex = kolab_event.get_instance(_es) + if _ex is not None: + _es = to_dt(_ex.get_start()) + _ee = to_dt(_ex.get_end()) + _ev = _ex + return conflict +def _is_transparent(event): + return event.get_transparency() or event.get_status() == kolabformat.StatusCancelled + + def check_date_conflict(_es, _ee, _is, _ie): """ Check the given event start/end dates for conflicts
View file
pykolab-0.7.8.tar.gz/pykolab/setup/setup_mta.py -> pykolab-0.7.9.tar.gz/pykolab/setup/setup_mta.py
Changed
@@ -226,7 +226,7 @@ query_filter = (&(|(mail=%%s)(alias=%%s))(objectclass=kolabsharedfolder)(kolabFolderType=mail)) result_attribute = kolabtargetfolder -result_format = shared+%%s +result_format = "shared+%%s" """ % { "base_dn": conf.get('ldap', 'base_dn'), "server_host": server_host, @@ -363,6 +363,7 @@ 'primary_domain': conf.get('kolab', 'primary_domain'), 'ldap_filter': "(|(mail=%m)(alias=%m))", 'ldap_base_dn': conf.get('ldap', 'base_dn'), + 'clamdsock': '/var/spool/amavisd/clamd.sock', } template_file = None @@ -381,6 +382,12 @@ template_definition = fp.read() fp.close() + if os.path.isfile('/etc/clamd.d/amavisd.conf'): + amavisdconf_content = file('/etc/clamd.d/amavisd.conf') + for line in amavisdconf_content: + if line.startswith('LocalSocket'): + amavisd_settings['clamdsock'] = line[len('LocalSocket '):].strip() + t = Template(template_definition, searchList=[amavisd_settings]) fp = None
View file
pykolab-0.7.8.tar.gz/pykolab/xml/event.py -> pykolab-0.7.9.tar.gz/pykolab/xml/event.py
Changed
@@ -58,13 +58,14 @@ class Event(object): type = 'event' + thisandfuture = False status_map = { None: kolabformat.StatusUndefined, "TENTATIVE": kolabformat.StatusTentative, "CONFIRMED": kolabformat.StatusConfirmed, "CANCELLED": kolabformat.StatusCancelled, - "COMPLETD": kolabformat.StatusCompleted, + "COMPLETED": kolabformat.StatusCompleted, "IN-PROCESS": kolabformat.StatusInProcess, "NEEDS-ACTION": kolabformat.StatusNeedsAction, } @@ -120,6 +121,7 @@ def __init__(self, from_ical="", from_string=""): self._attendees = [] self._categories = [] + self._exceptions = [] self._attachment_parts = [] if isinstance(from_ical, str) and from_ical == "": @@ -128,6 +130,7 @@ else: self.event = kolabformat.readEvent(from_string, False) self._load_attendees() + self._load_exceptions() else: self.from_ical(from_ical, from_string) @@ -139,10 +142,22 @@ att.copy_from(a) self._attendees.append(att) - def add_attendee(self, email, name=None, rsvp=False, role=None, participant_status=None, cutype="INDIVIDUAL", params=None): - attendee = Attendee(email, name, rsvp, role, participant_status, cutype, params) - self._attendees.append(attendee) - self.event.setAttendees(self._attendees) + def _load_exceptions(self): + for ex in self.event.exceptions(): + exception = Event() + exception.uid = ex.uid() + exception.event = ex + exception._load_attendees() + self._exceptions.append(exception) + + def add_attendee(self, email_or_attendee, name=None, rsvp=False, role=None, participant_status=None, cutype="INDIVIDUAL", params=None): + if isinstance(email_or_attendee, Attendee): + attendee = email_or_attendee + else: + attendee = Attendee(email_or_attendee, name, rsvp, role, participant_status, cutype, params) + + # apply update to self and all exceptions + self.update_attendees([attendee], True) def add_category(self, category): self._categories.append(ustr(category)) @@ -161,10 +176,35 @@ valid_datetime = True if not valid_datetime: - raise InvalidEventDateError, _("Event start needs datetime.date or datetime.datetime instance") + raise InvalidEventDateError, _("Exdate needs datetime.date or datetime.datetime instance, got %r") % (type(_datetime)) self.event.addExceptionDate(xmlutils.to_cdatetime(_datetime, True)) + def add_exception(self, exception): + # sanity checks + if not self.is_recurring(): + raise EventIntegrityError, "Cannot add exceptions to a non-recurring event" + + recurrence_id = exception.get_recurrence_id() + if recurrence_id is None: + raise EventIntegrityError, "Recurrence exceptions require a Recurrence-ID property" + + # check if an exception with the given recurrence-id already exists + append = True + vexceptions = self.event.exceptions() + for i, ex in enumerate(self._exceptions): + if ex.get_recurrence_id() == recurrence_id and ex.thisandfuture == exception.thisandfuture: + # update the existing exception + vexceptions[i] = exception.event + self._exceptions[i] = exception + append = False + + if append: + vexceptions.append(exception.event) + self._exceptions.append(exception) + + self.event.setExceptions(vexceptions) + def as_string_itip(self, method="REQUEST"): cal = icalendar.Calendar() cal.add( @@ -184,6 +224,19 @@ # TODO: Add timezone information using icalendar.?() # Not sure if there is a class for it. + cal.add_component(self.to_ical()) + + # add recurrence exceptions + if len(self._exceptions) > 0 and not method == 'REPLY': + for exception in self._exceptions: + cal.add_component(exception.to_ical()) + + if hasattr(cal, 'to_ical'): + return cal.to_ical() + elif hasattr(cal, 'as_string'): + return cal.as_string() + + def to_ical(self): event = icalendar.Event() # Required @@ -191,8 +244,9 @@ # NOTE: Make sure to list(set()) or duplicates may arise for attr in list(set(event.singletons)): - ical_getter = 'get_ical_%s' % (attr.lower()) - default_getter = 'get_%s' % (attr.lower()) + _attr = attr.lower().replace('-', '') + ical_getter = 'get_ical_%s' % (_attr) + default_getter = 'get_%s' % (_attr) retval = None if hasattr(self, ical_getter): retval = getattr(self, ical_getter)() @@ -205,8 +259,9 @@ # NOTE: Make sure to list(set()) or duplicates may arise for attr in list(set(event.multiple)): - ical_getter = 'get_ical_%s' % (attr.lower()) - default_getter = 'get_%s' % (attr.lower()) + _attr = attr.lower().replace('-', '') + ical_getter = 'get_ical_%s' % (_attr) + default_getter = 'get_%s' % (_attr) retval = None if hasattr(self, ical_getter): retval = getattr(self, ical_getter)() @@ -221,12 +276,7 @@ for cs in self.event.customProperties(): event.add(cs.identifier, cs.value) - cal.add_component(event) - - if hasattr(cal, 'to_ical'): - return cal.to_ical() - elif hasattr(cal, 'as_string'): - return cal.as_string() + return event def delegate(self, delegators, delegatees, names=None): if not isinstance(delegators, list): @@ -261,7 +311,7 @@ self.event.setAttendees(self._attendees) def from_ical(self, ical, raw=None): - if isinstance(ical, icalendar.Event) or isinstance(ical_event, icalendar.Calendar): + if isinstance(ical, icalendar.Event) or isinstance(ical, icalendar.Calendar): ical_event = ical elif hasattr(icalendar.Event, 'from_ical'): ical_event = icalendar.Event.from_ical(ical) @@ -305,7 +355,10 @@ ical = "BEGIN:VCALENDAR\nVERSION:2.0\n" + ical + "\nEND:VCALENDAR" from kolab.calendaring import EventCal self.event = EventCal() - self.event.fromICal(ical) + success = self.event.fromICal(ical) + if success: + self._load_exceptions() + return success def get_attendee_participant_status(self, attendee): return attendee.get_participant_status() @@ -420,6 +473,9 @@ def get_exception_dates(self): return map(lambda _: xmlutils.from_cdatetime(_, True), self.event.exceptionDates()) + def get_exceptions(self): + return self._exceptions + def get_attachments(self): return self.event.attachments() @@ -541,6 +597,9 @@ except: return datetime.datetime.now() + def get_ical_lastmodified(self): + return self.get_ical_dtstamp() + def get_ical_dtstart(self): return self.get_start() @@ -575,6 +634,23 @@ return [ comment ] return None + def get_ical_recurrenceid(self): + rid = self.get_recurrence_id() + if isinstance(rid, datetime.datetime) or isinstance(rid, datetime.date): + prop = icalendar.vDatetime(rid) + if self.thisandfuture: + prop.params.update({'RANGE':'THISANDFUTURE'}) + return prop + + return None + + def get_ical_rrule(self): + result = [] + rrule = self.get_recurrence() + if rrule.isValid(): + result.append(rrule.to_ical()) + return result + def get_location(self): return self.event.location() @@ -616,6 +692,14 @@ self.set_uid(uuid.uuid4()) return self.get_uid() + def get_recurrence_id(self): + self.thisandfuture = self.event.thisAndFuture(); + return xmlutils.from_cdatetime(self.event.recurrenceID(), True) + + def get_thisandfuture(self): + self.thisandfuture = self.event.thisAndFuture(); + return self.thisandfuture + def get_sequence(self): return self.event.sequence() @@ -625,6 +709,17 @@ def get_transparency(self): return self.event.transparency() + def get_recurrence(self): + return RecurrenceRule(self.event.recurrenceRule()) + + def set_attendees(self, _attendees, recursive=False): + if recursive: + self._attendees = [] + self.update_attendees(_attendees, True) + else: + self._attendees = _attendees + self.event.setAttendees(self._attendees) + def set_attendee_participant_status(self, attendee, status, rsvp=None): """ Set the participant status of an attendee to status. @@ -639,6 +734,32 @@ if rsvp is not None: attendee.set_rsvp(rsvp) + # apply update to self and all exceptions + self.update_attendees([attendee], False) + + def update_attendees(self, _attendees, append=True): + self.merge_attendee_data(_attendees, append) + + if len(self._exceptions): + vexceptions = self.event.exceptions() + for i, exception in enumerate(self._exceptions): + exception.merge_attendee_data(_attendees, append) + vexceptions[i] = exception.event + self.event.setExceptions(vexceptions) + + def merge_attendee_data(self, _attendees, append=True): + for attendee in _attendees: + found = False + + for candidate in self._attendees: + if candidate.get_email() == attendee.get_email(): + candidate.copy_from(attendee) + found = True + break + + if not found and append: + self._attendees.append(attendee) + self.event.setAttendees(self._attendees) def set_classification(self, classification): @@ -678,7 +799,7 @@ valid_datetime = True if not valid_datetime: - raise InvalidEventDateError, _("Event end needs datetime.date or datetime.datetime instance") + raise InvalidEventDateError, _("Event end needs datetime.date or datetime.datetime instance, got %r") % (type(_datetime)) self.event.setEnd(xmlutils.to_cdatetime(_datetime, True)) @@ -698,6 +819,7 @@ attr = attr.replace('-', '') ical_setter = 'set_ical_' + attr default_setter = 'set_' + attr + params = value.params if hasattr(value, 'params') else {} if isinstance(value, icalendar.vDDDTypes) and hasattr(value, 'dt'): value = value.dt @@ -706,6 +828,8 @@ self.add_category(value) elif attr == "class": self.set_classification(value) + elif attr == "recurrenceid": + self.set_ical_recurrenceid(value, params) elif hasattr(self, ical_setter): getattr(self, ical_setter)(value) elif hasattr(self, default_setter): @@ -800,6 +924,13 @@ def set_ical_uid(self, uid): self.set_uid(str(uid)) + def set_ical_recurrenceid(self, value, params): + try: + self.thisandfuture = params.get('RANGE', '') == 'THISANDFUTURE' + self.set_recurrence_id(value, self.thisandfuture) + except InvalidEventDateError, e: + pass + def set_lastmodified(self, _datetime=None): valid_datetime = False if isinstance(_datetime, datetime.date): @@ -813,7 +944,7 @@ _datetime = datetime.datetime.utcnow() if not valid_datetime: - raise InvalidEventDateError, _("Event start needs datetime.date or datetime.datetime instance") + raise InvalidEventDateError, _("Event last-modified needs datetime.date or datetime.datetime instance, got %r") % (type(_datetime)) self.event.setLastModified(xmlutils.to_cdatetime(_datetime, False, True)) @@ -856,7 +987,7 @@ valid_datetime = True if not valid_datetime: - raise InvalidEventDateError, _("Event start needs datetime.date or datetime.datetime instance") + raise InvalidEventDateError, _("Event start needs datetime.date or datetime.datetime instance, got %r") % (type(_datetime)) self.event.setStart(xmlutils.to_cdatetime(_datetime, True)) @@ -875,6 +1006,27 @@ self.uid = uid self.event.setUid(str(uid)) + def set_recurrence_id(self, _datetime, _thisandfuture=None): + valid_datetime = False + if isinstance(_datetime, datetime.date): + valid_datetime = True + + if isinstance(_datetime, datetime.datetime): + # If no timezone information is passed on, use the one from event start + if _datetime.tzinfo == None: + _start = self.get_start() + _datetime = _datetime.replace(tzinfo=_start.tzinfo) + + valid_datetime = True + + if not valid_datetime: + raise InvalidEventDateError, _("Event recurrence-id needs datetime.datetime instance") + + if _thisandfuture is None: + _thisandfuture = self.thisandfuture + + self.event.setRecurrenceID(xmlutils.to_cdatetime(_datetime), _thisandfuture) + def set_transparency(self, transp): return self.event.setTransparency(transp) @@ -1160,7 +1312,7 @@ next_datetime = None # next_datetime is always a cdatetime, convert to date if necessary - if not isinstance(self.get_start(), datetime.datetime): + if next_datetime and not isinstance(self.get_start(), datetime.datetime): next_datetime = datetime.date(next_datetime.year, next_datetime.month, next_datetime.day) return next_datetime @@ -1193,16 +1345,56 @@ if next_start: instance = Event(from_string=str(self)) instance.set_start(next_start) - instance.set_recurrence(kolabformat.RecurrenceRule()) # remove recurrence rules - instance.event.setRecurrenceID(instance.event.start(), False) + instance.event.setRecurrenceID(xmlutils.to_cdatetime(next_start), False) next_end = self.get_occurence_end_date(next_start) if next_end: instance.set_end(next_end) + # unset recurrence rule and exceptions + instance.set_recurrence(kolabformat.RecurrenceRule()) + instance.event.setExceptions(kolabformat.vectorevent()) + instance.event.setExceptionDates(kolabformat.vectordatetime()) + instance._exceptions = [] + instance._isexception = False + + # unset attachments list (only stored in main event) + instance.event.setAttachments(kolabformat.vectorattachment()) + + # copy data from matching exception + # (give precedence to single occurrence exceptions over thisandfuture) + for exception in self._exceptions: + recurrence_id = exception.get_recurrence_id() + if recurrence_id == next_start and (not exception.thisandfuture or not instance._isexception): + instance = exception + instance._isexception = True + if not exception.thisandfuture: + break + elif exception.thisandfuture and next_start > recurrence_id: + # TODO: merge exception properties over this instance + adjust start/end with the according offset + pass + return instance return None + def get_instance(self, _datetime): + # If no timezone information is given, use the one from event start + if _datetime.tzinfo == None: + _start = self.get_start() + _datetime = _datetime.replace(tzinfo=_start.tzinfo) + + instance = self.get_next_instance(_datetime - datetime.timedelta(days=1)) + while instance: + recurrence_id = instance.get_recurrence_id() + if type(recurrence_id) == type(_datetime) and recurrence_id <= _datetime: + if xmlutils.dates_equal(recurrence_id, _datetime): + return instance + instance = self.get_next_instance(instance.get_start()) + else: + break + + return None + def _recurrence_end(self): """ Determine a reasonable end date for infinitely recurring events
View file
pykolab-0.7.8.tar.gz/pykolab/xml/recurrence_rule.py -> pykolab-0.7.9.tar.gz/pykolab/xml/recurrence_rule.py
Changed
@@ -142,6 +142,9 @@ def set_byday(self, bdays): daypos = kolabformat.vectordaypos() for wday in bdays: + if isinstance(wday, str): + wday = icalendar.vWeekday(wday) + weekday = str(wday)[-2:] occurrence = int(wday.relative) if str(wday)[0] == '-': @@ -177,7 +180,11 @@ name_map = dict([(v, k) for (k, v) in map.iteritems()]) return name_map[val] if name_map.has_key(val) else 'UNKNOWN' - def to_dict(self): + def to_ical(self): + rrule = icalendar.vRecur(dict((k,v) for k,v in self.to_dict(True).items() if not (type(v) == str and v == '' or type(v) == list and len(v) == 0))) + return rrule + + def to_dict(self, raw=False): if not self.isValid() or self.frequency() == kolabformat.RecurrenceRule.FreqNone: return None @@ -194,9 +201,12 @@ if isinstance(val, kolabformat.cDateTime): val = xmlutils.from_cdatetime(val, True) elif isinstance(val, kolabformat.vectori): - val = ",".join([int(v) for x in val]) + val = [int(x) for x in val] elif isinstance(val, kolabformat.vectordaypos): - val = ",".join(["%s%s" % (str(x.occurence()) if x.occurence() != 0 else '', self._translate_value(x.weekday(), self.weekday_map)) for x in val]) + val = ["%s%s" % (str(x.occurence()) if x.occurence() != 0 else '', self._translate_value(x.weekday(), self.weekday_map)) for x in val] + + if not raw and isinstance(val, list): + val = ",".join(val) if val is not None: data[p] = val
View file
pykolab-0.7.8.tar.gz/pykolab/xml/todo.py -> pykolab-0.7.9.tar.gz/pykolab/xml/todo.py
Changed
@@ -41,6 +41,7 @@ def __init__(self, from_ical="", from_string=""): self._attendees = [] self._categories = [] + self._exceptions = [] self._attachment_parts = [] self.properties_map.update({
View file
pykolab-0.7.8.tar.gz/pykolab/xml/utils.py -> pykolab-0.7.9.tar.gz/pykolab/xml/utils.py
Changed
@@ -122,6 +122,11 @@ return _cdatetime +def dates_equal(a, b): + date_format = '%Y%m%d' if isinstance(a, datetime.date) and isinstance(b, datetime.date) else '%Y%m%dT%H%M%S' + return type(a) == type(b) and a.strftime(date_format) == b.strftime(date_format) + + property_labels = { "name": N_("Name"), "summary": N_("Summary"), @@ -183,7 +188,7 @@ elif propname == 'rrule': from . import recurrence_rule - rrule = recurrence_rule.frequency_label(value['frequency']) % (value['interval']) + rrule = recurrence_rule.frequency_label(value['freq']) % (value['interval']) if value.has_key('count') and value['count'] > 0: rrule += " " + _("for %d times") % (value['count']) elif value.has_key('until') and (isinstance(value['until'], datetime.datetime) or isinstance(value['until'], datetime.date)):
View file
pykolab-0.7.8.tar.gz/saslauthd/kolab-saslauthd.systemd -> pykolab-0.7.9.tar.gz/saslauthd/kolab-saslauthd.systemd
Changed
@@ -6,7 +6,7 @@ Type=forking PIDFile=/var/run/kolab-saslauthd/kolab-saslauthd.pid EnvironmentFile=/etc/sysconfig/kolab-saslauthd -ExecStart=/usr/sbin/kolab-saslauthd $FLAGS +ExecStart=/usr/sbin/kolab-saslauthd $FLAGS --socket /run/saslauthd/mux ExecReload=/bin/kill -HUP $MAINPID ExecStop=/bin/kill -TERM $MAINPID
View file
pykolab-0.7.8.tar.gz/share/templates/amavisd.conf.tpl -> pykolab-0.7.9.tar.gz/share/templates/amavisd.conf.tpl
Changed
@@ -373,7 +373,7 @@ # \#\## http://www.clamav.net/ ['ClamAV-clamd', - \&ask_daemon, ["CONTSCAN {}\n", "/var/spool/amavisd/clamd.sock"], + \&ask_daemon, ["CONTSCAN {}\n", "$clamdsock"], qr/\bOK\$/m, qr/\bFOUND\$/m, qr/^.*?: (?!Infected Archive)(.*) FOUND\$/m ], # # NOTE: run clamd under the same user as amavisd, or run it under its own
View file
pykolab-0.7.8.tar.gz/share/templates/roundcubemail/config.inc.php.tpl -> pykolab-0.7.9.tar.gz/share/templates/roundcubemail/config.inc.php.tpl
Changed
@@ -68,7 +68,6 @@ 'password', 'redundant_attachments', 'tasklist', - 'threading_as_default', // contextmenu must be after kolab_addressbook (#444) 'contextmenu', );
View file
pykolab-0.7.8.tar.gz/tests/functional/test_wallace/test_005_resource_invitation.py -> pykolab-0.7.9.tar.gz/tests/functional/test_wallace/test_005_resource_invitation.py
Changed
@@ -4,11 +4,13 @@ import email import datetime import uuid +import re from pykolab.imap import IMAP from wallace import module_resources from pykolab.translate import _ +from pykolab.xml import utils as xmlutils from pykolab.xml import event_from_message from pykolab.xml import participant_status_label from pykolab.itip import events_from_message @@ -26,7 +28,7 @@ CALSCALE:GREGORIAN METHOD:REQUEST BEGIN:VEVENT -UID:%s +UID:%s%s DTSTAMP:20140213T125414Z DTSTART;TZID=Europe/London:%s DTEND;TZID=Europe/London:%s @@ -47,7 +49,7 @@ CALSCALE:GREGORIAN METHOD:REQUEST BEGIN:VEVENT -UID:%s +UID:%s%s DTSTAMP:20140215T125414Z DTSTART;TZID=Europe/London:%s DTEND;TZID=Europe/London:%s @@ -69,7 +71,7 @@ CALSCALE:GREGORIAN METHOD:REQUEST BEGIN:VEVENT -UID:%s +UID:%s%s DTSTAMP;VALUE=DATE-TIME:20140227T141939Z DTSTART;VALUE=DATE-TIME;TZID=Europe/London:%s DTEND;VALUE=DATE-TIME;TZID=Europe/London:%s @@ -94,7 +96,7 @@ CALSCALE:GREGORIAN METHOD:CANCEL BEGIN:VEVENT -UID:%s +UID:%s%s DTSTAMP:20140218T125414Z DTSTART;TZID=Europe/London:20120713T100000 DTEND;TZID=Europe/London:20120713T110000 @@ -116,7 +118,7 @@ CALSCALE:GREGORIAN METHOD:REQUEST BEGIN:VEVENT -UID:%s +UID:%s%s DTSTAMP:20140213T125414Z DTSTART;VALUE=DATE:%s DTEND;VALUE=DATE:%s @@ -137,10 +139,10 @@ CALSCALE:GREGORIAN METHOD:REQUEST BEGIN:VEVENT -UID:%s +UID:%s%s DTSTAMP:20140213T125414Z -DTSTART;TZID=Europe/Zurich:%s -DTEND;TZID=Europe/Zurich:%s +DTSTART;TZID=Europe/London:%s +DTEND;TZID=Europe/London:%s RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=10 SUMMARY:test DESCRIPTION:test @@ -214,8 +216,8 @@ } from tests.functional.user_add import user_add - user_add("John", "Doe") - user_add("Jane", "Manager") + user_add("John", "Doe", kolabinvitationpolicy='ALL_MANUAL') + user_add("Jane", "Manager", kolabinvitationpolicy='ALL_MANUAL') funcs.purge_resources() self.audi = funcs.resource_add("car", "Audi A4") @@ -242,7 +244,7 @@ smtp.sendmail(from_addr, to_addr, mime_message % (to_addr, itip_payload)) smtp.quit() - def send_itip_invitation(self, resource_email, start=None, allday=False, template=None, uid=None): + def send_itip_invitation(self, resource_email, start=None, allday=False, template=None, uid=None, instance=None): if start is None: start = datetime.datetime.now() @@ -258,8 +260,13 @@ default_template = itip_invitation date_format = '%Y%m%dT%H%M%S' + recurrence_id = '' + if instance is not None: + recurrence_id = "\nRECURRENCE-ID;TZID=Europe/London:" + instance.strftime(date_format) + self.send_message((template if template is not None else default_template) % ( uid, + recurrence_id, start.strftime(date_format), end.strftime(date_format), resource_email @@ -268,13 +275,24 @@ return uid - def send_itip_update(self, resource_email, uid, start=None, template=None): + def send_itip_update(self, resource_email, uid, start=None, template=None, sequence=None, instance=None): if start is None: start = datetime.datetime.now() end = start + datetime.timedelta(hours=4) + + recurrence_id = '' + if instance is not None: + recurrence_id = "\nRECURRENCE-ID;TZID=Europe/London:" + instance.strftime('%Y%m%dT%H%M%S') + + if sequence is not None: + if not template: + template = itip_update + template = re.sub(r'SEQUENCE:\d+', 'SEQUENCE:' + str(sequence), template) + self.send_message((template if template is not None else itip_update) % ( uid, + recurrence_id, start.strftime('%Y%m%dT%H%M%S'), end.strftime('%Y%m%dT%H%M%S'), resource_email @@ -283,9 +301,14 @@ return uid - def send_itip_cancel(self, resource_email, uid): + def send_itip_cancel(self, resource_email, uid, instance=None): + recurrence_id = '' + if instance is not None: + recurrence_id = "\nRECURRENCE-ID;TZID=Europe/London:" + instance.strftime('%Y%m%dT%H%M%S') + self.send_message(itip_cancellation % ( uid, + recurrence_id, resource_email ), resource_email) @@ -293,6 +316,21 @@ return uid + def send_owner_response(self, event, partstat, from_addr=None): + if from_addr is None: + from_addr = self.jane['mail'] + + itip_reply = event.to_message_itip(from_addr, + method="REPLY", + participant_status=partstat, + message_text="Request " + partstat, + subject="Booking has been %s" % (partstat) + ) + + smtp = smtplib.SMTP('localhost', 10026) + smtp.sendmail(from_addr, str(event.get_organizer().email()), str(itip_reply)) + smtp.quit() + def check_message_received(self, subject, from_addr=None, mailbox=None): if mailbox is None: mailbox = self.john['mailbox'] @@ -303,7 +341,7 @@ imap.imap.m.select(mailbox) found = None - retries = 10 + retries = 15 while not found and retries > 0: retries -= 1 @@ -322,7 +360,7 @@ return found - def check_resource_calendar_event(self, mailbox, uid=None): + def check_resource_calendar_event(self, mailbox, uid=None, instance=None): imap = IMAP() imap.connect() @@ -345,7 +383,7 @@ continue found = event_from_message(event_message) - if found: + if found and (instance is None or found.is_recurring() or xmlutils.dates_equal(instance, found.get_recurrence_id())): break time.sleep(1) @@ -656,19 +694,9 @@ notify = self.check_message_received(_('Booking request for %s requires confirmation') % (self.room3['cn']), mailbox=self.jane['mailbox']) self.assertIsInstance(notify, email.message.Message) - itip_event = events_from_message(notify)[0] - # resource owner confirms reservation request - itip_reply = itip_event['xml'].to_message_itip(self.jane['mail'], - method="REPLY", - participant_status='ACCEPTED', - message_text="Request accepted", - subject=_('Booking for %s has been %s') % (self.room3['cn'], participant_status_label('ACCEPTED')) - ) - - smtp = smtplib.SMTP('localhost', 10026) - smtp.sendmail(self.jane['mail'], str(itip_event['organizer']), str(itip_reply)) - smtp.quit() + itip_event = events_from_message(notify)[0] + self.send_owner_response(itip_event['xml'], 'ACCEPTED', from_addr=self.jane['mail']) # requester (john) now gets the ACCEPTED response response = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('ACCEPTED') }, self.room3['mail']) @@ -802,3 +830,156 @@ # check confirmation message sent to resource owner (jane) notify = self.check_message_received(_('Booking request for %s requires confirmation') % (self.room3['cn']), mailbox=self.jane['mailbox']) self.assertIsInstance(notify, email.message.Message) + + + def test_017_reschedule_single_occurrence(self): + self.purge_mailbox(self.john['mailbox']) + + # register a recurring resource invitation + start = datetime.datetime(2015,2,10, 12,0,0) + uid = self.send_itip_invitation(self.audi['mail'], start, template=itip_recurring) + + accept = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('ACCEPTED') }) + self.assertIsInstance(accept, email.message.Message) + + self.purge_mailbox(self.john['mailbox']) + + # send rescheduling request to a single instance + exdate = start + datetime.timedelta(days=14) + exstart = exdate + datetime.timedelta(hours=5) + self.send_itip_update(self.audi['mail'], uid, exstart, instance=exdate) + + accept = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('ACCEPTED') }) + self.assertIsInstance(accept, email.message.Message) + self.assertIn("RECURRENCE-ID;TZID=Europe/London:" + exdate.strftime('%Y%m%dT%H%M%S'), str(accept)) + + event = self.check_resource_calendar_event(self.audi['kolabtargetfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + self.assertEqual(len(event.get_exceptions()), 1) + + # send new invitation for now free slot + uid = self.send_itip_invitation(self.audi['mail'], exdate, template=itip_invitation.replace('SUMMARY:test', 'SUMMARY:new')) + + accept = self.check_message_received(self.itip_reply_subject % { 'summary':'new', 'status':participant_status_label('ACCEPTED') }) + self.assertIsInstance(accept, email.message.Message) + + # send rescheduling request to that single instance again: now conflicting + exdate = start + datetime.timedelta(days=14) + exstart = exdate + datetime.timedelta(hours=2) + self.send_itip_update(self.audi['mail'], uid, exstart, instance=exdate, sequence=3) + + response = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('DECLINED') }) + self.assertIsInstance(response, email.message.Message) + self.assertIn("RECURRENCE-ID;TZID=Europe/London:", str(response)) + + + def test_018_invite_single_occurrence(self): + self.purge_mailbox(self.john['mailbox']) + self.purge_mailbox(self.boxter['kolabtargetfolder']) + + start = datetime.datetime(2015,3,2, 18,30,0) + uid = self.send_itip_invitation(self.boxter['mail'], start, instance=start) + + accept = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('ACCEPTED') }) + self.assertIsInstance(accept, email.message.Message) + self.assertIn("RECURRENCE-ID;TZID=Europe/London:" + start.strftime('%Y%m%dT%H%M%S'), str(accept)) + + self.purge_mailbox(self.john['mailbox']) + + # send a second invitation for another instance with the same UID + nextstart = datetime.datetime(2015,3,9, 18,30,0) + self.send_itip_invitation(self.boxter['mail'], nextstart, uid=uid, instance=nextstart) + + accept = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('ACCEPTED') }) + self.assertIsInstance(accept, email.message.Message) + self.assertIn("RECURRENCE-ID;TZID=Europe/London:" + nextstart.strftime('%Y%m%dT%H%M%S'), str(accept)) + + self.purge_mailbox(self.john['mailbox']) + + # send rescheduling request to the first instance + exstart = start + datetime.timedelta(hours=2) + self.send_itip_update(self.boxter['mail'], uid, exstart, instance=start) + + accept = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('ACCEPTED') }) + self.assertIsInstance(accept, email.message.Message) + self.assertIn("RECURRENCE-ID;TZID=Europe/London:" + start.strftime('%Y%m%dT%H%M%S'), str(accept)) + + # the resource calendar now has two reservations stored + one = self.check_resource_calendar_event(self.boxter['kolabtargetfolder'], uid, start) + self.assertIsInstance(one, pykolab.xml.Event) + self.assertIsInstance(one.get_recurrence_id(), datetime.datetime) + self.assertEqual(one.get_start().hour, exstart.hour) + + two = self.check_resource_calendar_event(self.boxter['kolabtargetfolder'], uid, nextstart) + self.assertIsInstance(two, pykolab.xml.Event) + self.assertIsInstance(two.get_recurrence_id(), datetime.datetime) + + + def test_019_cancel_single_occurrence(self): + self.purge_mailbox(self.john['mailbox']) + + # register a recurring resource invitation + start = datetime.datetime(2015,2,12, 14,0,0) + uid = self.send_itip_invitation(self.passat['mail'], start, template=itip_recurring) + + accept = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('ACCEPTED') }) + self.assertIsInstance(accept, email.message.Message) + + exdate = start + datetime.timedelta(days=7) + self.send_itip_cancel(self.passat['mail'], uid, instance=exdate) + + time.sleep(5) # wait for IMAP to update + event = self.check_resource_calendar_event(self.passat['kolabtargetfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + self.assertEqual(len(event.get_exceptions()), 1) + + exception = event.get_instance(exdate) + self.assertEqual(exception.get_status(True), 'CANCELLED') + self.assertTrue(exception.get_transparency()) + + + def test_020_owner_confirmation_single_occurrence(self): + self.purge_mailbox(self.john['mailbox']) + self.purge_mailbox(self.jane['mailbox']) + + start = datetime.datetime(2015,4,18, 14,0,0) + uid = self.send_itip_invitation(self.room3['mail'], start, template=itip_recurring) + + notify = self.check_message_received(_('Booking request for %s requires confirmation') % (self.room3['cn']), mailbox=self.jane['mailbox']) + self.assertIsInstance(notify, email.message.Message) + + # resource owner confirms reservation request (entire series) + itip_event = events_from_message(notify)[0] + self.send_owner_response(itip_event['xml'], 'ACCEPTED', from_addr=self.jane['mail']) + + self.purge_mailbox(self.john['mailbox']) + self.purge_mailbox(self.jane['mailbox']) + + # send rescheduling request to a single instance + exdate = start + datetime.timedelta(days=14) + exstart = exdate + datetime.timedelta(hours=4) + self.send_itip_update(self.room3['mail'], uid, exstart, instance=exdate) + + # check confirmation message sent to resource owner (jane) + notify = self.check_message_received(_('Booking request for %s requires confirmation') % (self.room3['cn']), mailbox=self.jane['mailbox']) + self.assertIsInstance(notify, email.message.Message) + self.assertIn("RECURRENCE-ID;TZID=Europe/London:" + exdate.strftime('%Y%m%dT%H%M%S'), str(notify)) + + itip_event = events_from_message(notify)[0] + self.assertIsInstance(itip_event['xml'].get_recurrence_id(), datetime.datetime) + + # resource owner declines reservation request + self.send_owner_response(itip_event['xml'], 'DECLINED', from_addr=self.jane['mail']) + + # requester (john) now gets the DECLINED response + response = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('DECLINED') }, self.room3['mail']) + self.assertIsInstance(response, email.message.Message) + self.assertIn("RECURRENCE-ID;TZID=Europe/London:" + exdate.strftime('%Y%m%dT%H%M%S'), str(response)) + + event = self.check_resource_calendar_event(self.room3['kolabtargetfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + self.assertEqual(len(event.get_exceptions()), 1) + + exception = event.get_instance(exdate) + self.assertEqual(exception.get_attendee_by_email(self.room3['mail']).get_participant_status(True), 'DECLINED') +
View file
pykolab-0.7.8.tar.gz/tests/functional/test_wallace/test_007_invitationpolicy.py -> pykolab-0.7.9.tar.gz/tests/functional/test_wallace/test_007_invitationpolicy.py
Changed
@@ -29,7 +29,7 @@ CALSCALE:GREGORIAN METHOD:REQUEST BEGIN:VEVENT -UID:%(uid)s +UID:%(uid)s%(recurrenceid)s DTSTAMP:20140213T125414Z DTSTART;TZID=Europe/Berlin:%(start)s DTEND;TZID=Europe/Berlin:%(end)s @@ -51,7 +51,7 @@ CALSCALE:GREGORIAN METHOD:CANCEL BEGIN:VEVENT -UID:%(uid)s +UID:%(uid)s%(recurrenceid)s DTSTAMP:20140218T125414Z DTSTART;TZID=Europe/Berlin:20120713T100000 DTEND;TZID=Europe/Berlin:20120713T110000 @@ -74,8 +74,8 @@ BEGIN:VEVENT UID:%(uid)s DTSTAMP:20140213T125414Z -DTSTART;TZID=Europe/Zurich:%(start)s -DTEND;TZID=Europe/Zurich:%(end)s +DTSTART;TZID=Europe/Berlin:%(start)s +DTEND;TZID=Europe/Berlin:%(end)s RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=10 SUMMARY:%(summary)s DESCRIPTION:test @@ -95,7 +95,7 @@ METHOD:REPLY BEGIN:VEVENT SUMMARY:%(summary)s -UID:%(uid)s +UID:%(uid)s%(recurrenceid)s DTSTART;TZID=Europe/Berlin;VALUE=DATE-TIME:%(start)s DTEND;TZID=Europe/Berlin;VALUE=DATE-TIME:%(end)s DTSTAMP;VALUE=DATE-TIME:20140706T171038Z @@ -115,7 +115,7 @@ METHOD:REPLY BEGIN:VEVENT SUMMARY:%(summary)s -UID:%(uid)s +UID:%(uid)s%(recurrenceid)s DTSTART;TZID=Europe/Berlin;VALUE=DATE-TIME:%(start)s DTEND;TZID=Europe/Berlin;VALUE=DATE-TIME:%(end)s DTSTAMP;VALUE=DATE-TIME:20140706T171038Z @@ -351,11 +351,12 @@ smtp = smtplib.SMTP('localhost', 10026) smtp.sendmail(from_addr, to_addr, mime_message % (to_addr, method, itip_payload)) - def send_itip_invitation(self, attendee_email, start=None, allday=False, template=None, summary="test", sequence=0, partstat='NEEDS-ACTION', from_addr=None): + def send_itip_invitation(self, attendee_email, start=None, allday=False, template=None, summary="test", sequence=0, partstat='NEEDS-ACTION', from_addr=None, instance=None): if start is None: start = datetime.datetime.now() uid = str(uuid.uuid4()) + recurrence_id = '' if allday: default_template = itip_allday @@ -372,8 +373,12 @@ else: default_template = default_template.replace("john.doe@example.org", from_addr) + if instance is not None: + recurrence_id = "\nRECURRENCE-ID;TZID=Europe/Berlin:" + instance.strftime(date_format) + self.send_message((template if template is not None else default_template) % { 'uid': uid, + 'recurrenceid': recurrence_id, 'start': start.strftime(date_format), 'end': end.strftime(date_format), 'mailto': attendee_email, @@ -385,15 +390,23 @@ return uid - def send_itip_update(self, attendee_email, uid, start=None, template=None, summary="test", sequence=1, partstat='ACCEPTED'): + def send_itip_update(self, attendee_email, uid, start=None, template=None, summary="test", sequence=1, partstat='ACCEPTED', instance=None): if start is None: start = datetime.datetime.now() end = start + datetime.timedelta(hours=4) + + date_format = '%Y%m%dT%H%M%S' + recurrence_id = '' + + if instance is not None: + recurrence_id = "\nRECURRENCE-ID;TZID=Europe/Berlin:" + instance.strftime(date_format) + self.send_message((template if template is not None else itip_invitation) % { 'uid': uid, - 'start': start.strftime('%Y%m%dT%H%M%S'), - 'end': end.strftime('%Y%m%dT%H%M%S'), + 'recurrenceid': recurrence_id, + 'start': start.strftime(date_format), + 'end': end.strftime(date_format), 'mailto': attendee_email, 'summary': summary, 'sequence': sequence, @@ -403,15 +416,23 @@ return uid - def send_itip_reply(self, uid, attendee_email, mailto, start=None, template=None, summary="test", sequence=0, partstat='ACCEPTED'): + def send_itip_reply(self, uid, attendee_email, mailto, start=None, template=None, summary="test", sequence=0, partstat='ACCEPTED', instance=None): if start is None: start = datetime.datetime.now() end = start + datetime.timedelta(hours=4) + + date_format = '%Y%m%dT%H%M%S' + recurrence_id = '' + + if instance is not None: + recurrence_id = "\nRECURRENCE-ID;TZID=Europe/Berlin:" + instance.strftime(date_format) + self.send_message((template if template is not None else itip_reply) % { 'uid': uid, - 'start': start.strftime('%Y%m%dT%H%M%S'), - 'end': end.strftime('%Y%m%dT%H%M%S'), + 'recurrenceid': recurrence_id, + 'start': start.strftime(date_format), + 'end': end.strftime(date_format), 'mailto': attendee_email, 'organizer': mailto, 'summary': summary, @@ -424,9 +445,18 @@ return uid - def send_itip_cancel(self, attendee_email, uid, template=None, summary="test", sequence=1): + def send_itip_cancel(self, attendee_email, uid, template=None, summary="test", sequence=1, instance=None, thisandfuture=False): + recurrence_id = '' + + if instance is not None: + recurrence_id = "\nRECURRENCE-ID;TZID=Europe/Berlin%s:%s" % ( + ';RANGE=THISANDFUTURE' if thisandfuture else '', + instance.strftime('%Y%m%dT%H%M%S') + ) + self.send_message((template if template is not None else itip_cancellation) % { 'uid': uid, + 'recurrenceid': recurrence_id, 'mailto': attendee_email, 'summary': summary, 'sequence': sequence, @@ -436,7 +466,7 @@ return uid - def create_calendar_event(self, start=None, summary="test", sequence=0, user=None, attendees=None, folder=None): + def create_calendar_event(self, start=None, summary="test", sequence=0, user=None, attendees=None, folder=None, recurring=False, uid=None): if start is None: start = datetime.datetime.now(pytz.timezone("Europe/Berlin")) if user is None: @@ -453,12 +483,23 @@ event.set_end(end) event.set_organizer(user['mail'], user['displayname']) + if uid: + event.set_uid(uid) + for attendee in attendees: event.add_attendee(attendee['mail'], attendee['displayname'], role="REQ-PARTICIPANT", participant_status="NEEDS-ACTION", rsvp=True) event.set_summary(summary) event.set_sequence(sequence) + if recurring and isinstance(recurring, kolabformat.RecurrenceRule): + event.set_recurrence(rrule) + else: + rrule = kolabformat.RecurrenceRule() + rrule.setFrequency(kolabformat.RecurrenceRule.Daily) + rrule.setCount(10) + event.set_recurrence(rrule) + # create event with attachment vattach = event.get_attachments() attachment = kolabformat.Attachment() @@ -1046,6 +1087,187 @@ self.assertIsInstance(event, pykolab.xml.Event) + def test_015_update_single_occurrence(self): + self.purge_mailbox(self.john['mailbox']) + + start = datetime.datetime(2015,4,2, 14,0,0) + uid = self.send_itip_invitation(self.jane['mail'], start, template=itip_recurring) + + response = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('ACCEPTED') }, self.jane['mail']) + self.assertIsInstance(response, email.message.Message) + + event = self.check_user_calendar_event(self.jane['kolabcalendarfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + self.assertTrue(event.is_recurring()) + + # send update to a single instance with the same sequence: no re-scheduling + exdate = start + datetime.timedelta(days=14) + self.send_itip_update(self.jane['mail'], uid, exdate, summary="test exception", sequence=0, partstat='ACCEPTED', instance=exdate) + + time.sleep(10) + event = self.check_user_calendar_event(self.jane['kolabcalendarfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + self.assertEqual(len(event.get_exceptions()), 1) + + exception = event.get_instance(exdate) + self.assertEqual(exception.get_summary(), "test exception") + self.assertEqual(exception.get_attendee(self.jane['mail']).get_participant_status(), kolabformat.PartAccepted) + + + def test_015_reschedule_single_occurrence(self): + self.purge_mailbox(self.john['mailbox']) + + start = datetime.datetime(2015,4,10, 9,0,0) + uid = self.send_itip_invitation(self.jane['mail'], start, template=itip_recurring) + + response = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('ACCEPTED') }, self.jane['mail']) + self.assertIsInstance(response, email.message.Message) + + # send update to a single instance with the same sequence: no re-scheduling + exdate = start + datetime.timedelta(days=14) + exstart = exdate + datetime.timedelta(hours=5) + self.send_itip_update(self.jane['mail'], uid, exstart, summary="test resceduled", sequence=1, partstat='NEEDS-ACTION', instance=exdate) + + response = self.check_message_received(self.itip_reply_subject % { 'summary':'test resceduled', 'status':participant_status_label('ACCEPTED') }, self.jane['mail']) + self.assertIsInstance(response, email.message.Message) + + time.sleep(10) + event = self.check_user_calendar_event(self.jane['kolabcalendarfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + self.assertEqual(len(event.get_exceptions()), 1) + + # re-schedule again, conflicts with itself + exstart = exdate + datetime.timedelta(hours=6) + self.send_itip_update(self.jane['mail'], uid, exstart, summary="test new", sequence=2, partstat='NEEDS-ACTION', instance=exdate) + + response = self.check_message_received(self.itip_reply_subject % { 'summary':'test new', 'status':participant_status_label('ACCEPTED') }, self.jane['mail']) + self.assertIsInstance(response, email.message.Message) + + # check for updated excaption + time.sleep(10) + event = self.check_user_calendar_event(self.jane['kolabcalendarfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + self.assertEqual(len(event.get_exceptions()), 1) + + exception = event.get_instance(exdate) + self.assertIsInstance(exception, pykolab.xml.Event) + self.assertEqual(exception.get_start().strftime('%Y%m%dT%H%M%S'), exstart.strftime('%Y%m%dT%H%M%S')) + + + def test_016_reply_single_occurrence(self): + self.purge_mailbox(self.john['mailbox']) + + start = datetime.datetime(2015,3,7, 10,0,0, tzinfo=pytz.timezone("Europe/Zurich")) + uid = self.create_calendar_event(start, attendees=[self.jane, self.mark], recurring=True) + + event = self.check_user_calendar_event(self.john['kolabcalendarfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + + # store a copy in mark's calendar, too + self.create_calendar_event(start, attendees=[self.jane, self.mark], recurring=True, folder=self.mark['kolabcalendarfolder'], uid=uid) + + # send a reply for a single occurrence from jane + exdate = start + datetime.timedelta(days=7) + self.send_itip_reply(uid, self.jane['mail'], self.john['mail'], start=exdate, instance=exdate) + + # check for the updated event in john's calendar + time.sleep(10) + event = self.check_user_calendar_event(self.john['kolabcalendarfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + self.assertEqual(len(event.get_exceptions()), 1) + + exception = event.get_instance(exdate) + self.assertEqual(exception.get_attendee(self.jane['mail']).get_participant_status(), kolabformat.PartAccepted) + + # check mark's copy for partstat update being stored in an exception, too + marks = self.check_user_calendar_event(self.mark['kolabcalendarfolder'], uid) + self.assertIsInstance(marks, pykolab.xml.Event) + self.assertEqual(len(marks.get_exceptions()), 1) + + exception = marks.get_instance(exdate) + self.assertEqual(exception.get_attendee(self.jane['mail']).get_participant_status(), kolabformat.PartAccepted) + + # send a reply for a the entire series from mark + self.send_itip_reply(uid, self.mark['mail'], self.john['mail'], start=start) + + # check for the updated event in john's calendar + time.sleep(10) + event = self.check_user_calendar_event(self.john['kolabcalendarfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + self.assertEqual(len(event.get_exceptions()), 1) + + exception = event.get_instance(exdate) + self.assertEqual(exception.get_attendee(self.mark['mail']).get_participant_status(), kolabformat.PartAccepted) + + def test_017_cancel_single_occurrence(self): + self.purge_mailbox(self.john['mailbox']) + + start = datetime.datetime(2015,3,20, 19,0,0, tzinfo=pytz.timezone("Europe/Zurich")) + uid = self.send_itip_invitation(self.jane['mail'], summary="recurring", start=start, template=itip_recurring) + + response = self.check_message_received(self.itip_reply_subject % { 'summary':'recurring', 'status':participant_status_label('ACCEPTED') }, self.jane['mail']) + self.assertIsInstance(response, email.message.Message) + + event = self.check_user_calendar_event(self.jane['kolabcalendarfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + + exdate = start + datetime.timedelta(days=14) + self.send_itip_cancel(self.jane['mail'], uid, summary="recurring cancelled", instance=exdate) + + time.sleep(10) + event = self.check_user_calendar_event(self.jane['kolabcalendarfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + self.assertEqual(len(event.get_exceptions()), 1) + + exception = event.get_instance(exdate) + self.assertEqual(exception.get_status(True), 'CANCELLED') + self.assertTrue(exception.get_transparency()) + + # send a new invitation for the cancelled slot + uid = self.send_itip_invitation(self.jane['mail'], summary="new booking", start=exdate) + + response = self.check_message_received(self.itip_reply_subject % { 'summary':'new booking', 'status':participant_status_label('ACCEPTED') }, self.jane['mail']) + self.assertIsInstance(response, email.message.Message) + + def test_017_cancel_thisandfuture(self): + self.purge_mailbox(self.john['mailbox']) + + start = datetime.datetime(2015,5,4, 6,30,0) + uid = self.send_itip_invitation(self.mark['mail'], summary="recurring", start=start, template=itip_recurring) + + response = self.check_message_received(self.itip_reply_subject % { 'summary':'recurring', 'status':participant_status_label('ACCEPTED') }, self.mark['mail']) + self.assertIsInstance(response, email.message.Message) + + event = self.check_user_calendar_event(self.mark['kolabcalendarfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + + exdate = start + datetime.timedelta(days=14) + self.send_itip_cancel(self.mark['mail'], uid, summary="recurring ended", instance=exdate, thisandfuture=True) + + time.sleep(10) + event = self.check_user_calendar_event(self.mark['kolabcalendarfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + + rrule = event.get_recurrence().to_dict() + self.assertIsInstance(rrule['until'], datetime.datetime) + self.assertEqual(rrule['until'].strftime('%Y%m%d'), (exdate - datetime.timedelta(days=1)).strftime('%Y%m%d')) + + + def test_018_invite_individual_occurrences(self): + self.purge_mailbox(self.john['mailbox']) + + start = datetime.datetime(2015,1,30, 17,0,0, tzinfo=pytz.timezone("Europe/Zurich")) + uid = self.send_itip_invitation(self.jane['mail'], summary="single", start=start, instance=start) + + response = self.check_message_received(self.itip_reply_subject % { 'summary':'single', 'status':participant_status_label('ACCEPTED') }, self.jane['mail']) + self.assertIsInstance(response, email.message.Message) + self.assertIn("RECURRENCE-ID", str(response)) + + event = self.check_user_calendar_event(self.jane['kolabcalendarfolder'], uid) + self.assertIsInstance(event, pykolab.xml.Event) + self.assertIsInstance(event.get_recurrence_id(), datetime.datetime) + + def test_020_task_assignment_accept(self): start = datetime.datetime(2014,9,10, 19,0,0) uid = self.send_itip_invitation(self.jane['mail'], start, summary='work', template=itip_todo)
View file
pykolab-0.7.8.tar.gz/tests/unit/test-003-event.py -> pykolab-0.7.9.tar.gz/tests/unit/test-003-event.py
Changed
@@ -9,6 +9,7 @@ from pykolab.xml import Attendee from pykolab.xml import Event +from pykolab.xml import RecurrenceRule from pykolab.xml import EventIntegrityError from pykolab.xml import InvalidAttendeeParticipantStatusError from pykolab.xml import InvalidEventDateError @@ -69,6 +70,25 @@ END:VEVENT """ +ical_exception = """ +BEGIN:VEVENT +UID:7a35527d-f783-4b58-b404-b1389bd2fc57 +DTSTAMP;VALUE=DATE-TIME:20140407T122311Z +CREATED;VALUE=DATE-TIME:20140407T122245Z +LAST-MODIFIED;VALUE=DATE-TIME:20140407T122311Z +RECURRENCE-ID;TZID=Europe/Zurich;RANGE=THISANDFUTURE:20140606T110000 +DTSTART;TZID=Europe/Zurich;VALUE=DATE-TIME:20140607T120000 +DTEND;TZID=Europe/Zurich;VALUE=DATE-TIME:20140607T143000 +SUMMARY:Exception +CATEGORIES:Personal +TRANSP:TRANSPARENT +PRIORITY:2 +SEQUENCE:3 +STATUS:CANCELLED +ORGANIZER;CN=Doe\, John:mailto:john.doe@example.org +END:VEVENT +""" + xml_event = """ <icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> <vcalendar> @@ -119,7 +139,7 @@ <recur> <freq>DAILY</freq> <until> - <date>2014-07-25</date> + <date>2015-07-25</date> </until> </recur> </rrule> @@ -241,6 +261,72 @@ </valarm> </components> </vevent> + <vevent> + <properties> + <uid> + <text>75c740bb-b3c6-442c-8021-ecbaeb0a025e</text> + </uid> + <created> + <date-time>2014-07-07T01:28:23Z</date-time> + </created> + <dtstamp> + <date-time>2014-07-07T01:28:23Z</date-time> + </dtstamp> + <sequence> + <integer>2</integer> + </sequence> + <class> + <text>PUBLIC</text> + </class> + <dtstart> + <parameters> + <tzid> + <text>/kolab.org/Europe/London</text> + </tzid> + </parameters> + <date-time>2014-08-16T13:00:00</date-time> + </dtstart> + <dtend> + <parameters> + <tzid><text>/kolab.org/Europe/London</text></tzid> + </parameters> + <date-time>2014-08-16T16:00:00</date-time> + </dtend> + <recurrence-id> + <parameters> + <tzid> + <text>/kolab.org/Europe/London</text> + </tzid> + <range> + <text>THISANDFUTURE</text> + </range> + </parameters> + <date-time>2014-08-16T10:00:00</date-time> + </recurrence-id> + <summary> + <text>exception</text> + </summary> + <description> + <text>exception</text> + </description> + <location> + <text>Room 101</text> + </location> + <organizer> + <parameters> + <cn><text>Doe, John</text></cn> + </parameters> + <cal-address>mailto:%3Cjohn%40example.org%3E</cal-address> + </organizer> + <attendee> + <parameters> + <partstat><text>DECLINED</text></partstat> + <role><text>REQ-PARTICIPANT</text></role> + </parameters> + <cal-address>mailto:%3Cjane%40example.org%3E</cal-address> + </attendee> + </properties> + </vevent> </components> </vcalendar> </icalendar> @@ -319,6 +405,13 @@ def test_009_invalid_participant_status(self): self.assertRaises(InvalidAttendeeParticipantStatusError, self.event.set_attendee_participant_status, "jane@doe.org", "INVALID") + def test_009_update_attendees(self): + jane = self.event.get_attendee("jane@doe.org") + jane.set_name("Jane (GI) Doe") + self.event.update_attendees([jane]) + self.assertEqual(len(self.event.get_attendees()), 2) + self.assertEqual(self.event.get_attendee("jane@doe.org").get_name(), "Jane (GI) Doe") + def test_010_datetime_from_string(self): self.assertRaises(InvalidEventDateError, self.event.set_start, "2012-05-23 11:58:00") @@ -366,7 +459,7 @@ 2.1.3//EN CALSCALE:GREGORIAN METHOD:REQUEST - """ + ical_event + "END:VCALENDAR" + """ + ical_event + ical_exception + "END:VCALENDAR" ical = icalendar.Calendar.from_ical(ical_str) event = event_from_ical(ical.walk('VEVENT')[0], ical_str) @@ -389,6 +482,12 @@ self.assertIsInstance(event.get_exception_dates()[0], datetime.datetime) self.assertEqual(len(event.get_alarms()), 1) self.assertEqual(len(event.get_attachments()), 2) + self.assertEqual(len(event.get_exceptions()), 1) + + exception = event.get_exceptions()[0] + self.assertIsInstance(exception.get_recurrence_id(), datetime.datetime) + # self.assertEqual(exception.thisandfuture, True) + self.assertEqual(str(exception.get_start()), "2014-06-07 12:00:00+02:00") def test_018_ical_to_message(self): event = event_from_ical(ical_event) @@ -436,6 +535,15 @@ self.event.set_sequence(3) self.event.set_classification('CONFIDENTIAL') self.event.add_custom_property('X-Custom', 'check') + self.event.set_recurrence_id(datetime.datetime(2014, 05, 23, 11, 0, 0), True) + + rrule = RecurrenceRule() + rrule.set_frequency(kolabformat.RecurrenceRule.Weekly) + rrule.set_byday(['2WE','-1SU']) + rrule.setBymonth([2]) + rrule.set_count(10) + rrule.set_until(datetime.datetime(2014,7,23, 11,0,0, tzinfo=pytz.utc)) + self.event.set_recurrence(rrule); ical = icalendar.Calendar.from_ical(self.event.as_string_itip()) event = ical.walk('VEVENT')[0] @@ -446,6 +554,16 @@ self.assertEqual(event['X-CUSTOM'], "check") self.assertIsInstance(event['dtstamp'].dt, datetime.datetime) self.assertEqual(event['class'], "CONFIDENTIAL") + self.assertIsInstance(event['recurrence-id'].dt, datetime.datetime) + self.assertEqual(event['recurrence-id'].params.get('RANGE'), 'THISANDFUTURE') + + self.assertTrue(event.has_key('rrule')) + self.assertEqual(event['rrule']['FREQ'][0], 'WEEKLY') + self.assertEqual(event['rrule']['INTERVAL'][0], 1) + self.assertEqual(event['rrule']['COUNT'][0], 10) + self.assertEqual(event['rrule']['BYMONTH'][0], 2) + self.assertEqual(event['rrule']['BYDAY'], ['2WE','-1SU']) + self.assertIsInstance(event['rrule']['UNTIL'][0], datetime.datetime) def test_019_to_message_itip(self): self.event = Event() @@ -529,6 +647,7 @@ # check get_next_instance() which returns a clone of the base event next_instance = self.event.get_next_instance(next_date) self.assertIsInstance(next_instance, Event) + self.assertIsInstance(next_instance.get_recurrence_id(), datetime.datetime) self.assertEqual(self.event.get_summary(), next_instance.get_summary()) self.assertEqual(next_instance.get_start().month, 7) self.assertFalse(next_instance.is_recurring()) @@ -554,6 +673,50 @@ self.assertEqual(self.event.get_next_occurence(_start), None) self.assertEqual(self.event.get_last_occurrence(), None) + def test_021_add_exceptions(self): + event = event_from_ical(ical_event) + exception = event_from_ical(ical_exception) + self.assertIsInstance(event, Event) + self.assertIsInstance(exception, Event) + + event.add_exception(exception) + self.assertEquals(len(event.get_exceptions()), 1) + + # second call shall replace the existing exception + event.add_exception(exception) + self.assertEquals(len(event.get_exceptions()), 1) + + # first real occurrence should be our exception + occurrence = event.get_next_instance(event.get_start()) + self.assertEqual(occurrence.get_summary(), "Exception") + + def test_021_ical_exceptions(self): + self.event.set_summary("test") + self.event.set_start(datetime.datetime(2014, 05, 23, 11, 00, 00, tzinfo=pytz.timezone("Europe/London"))) + self.event.set_end(datetime.datetime(2014, 05, 23, 12, 30, 00, tzinfo=pytz.timezone("Europe/London"))) + + rrule = kolabformat.RecurrenceRule() + rrule.setFrequency(kolabformat.RecurrenceRule.Weekly) + self.event.set_recurrence(rrule) + + xmlexception = Event(from_string=str(self.event)) + xmlexception.set_start(datetime.datetime(2014, 05, 30, 14, 00, 00, tzinfo=pytz.timezone("Europe/London"))) + xmlexception.set_end(datetime.datetime(2014, 05, 30, 16, 00, 00, tzinfo=pytz.timezone("Europe/London"))) + xmlexception.set_recurrence_id(datetime.datetime(2014, 05, 30, 11, 0, 0), False) + self.event.add_exception(xmlexception) + + ical = icalendar.Calendar.from_ical(self.event.as_string_itip()) + vevents = ical.walk('VEVENT') + event = vevents[0] + exception = vevents[1] + + self.assertEqual(event['uid'], self.event.get_uid()) + self.assertEqual(event['summary'], "test") + + self.assertEqual(exception['uid'], self.event.get_uid()) + self.assertIsInstance(exception['recurrence-id'].dt, datetime.datetime) + self.assertEqual(exception['recurrence-id'].params.get('RANGE'), None) + def test_022_load_from_xml(self): event = event_from_string(xml_event) self.assertEqual(event.uid, '75c740bb-b3c6-442c-8021-ecbaeb0a025e') @@ -562,7 +725,29 @@ self.assertEqual(len(event.get_attendee_by_email("somebody@else.com").get_delegated_to()), 1) self.assertEqual(event.get_sequence(), 1) self.assertIsInstance(event.get_start(), datetime.datetime) - self.assertEqual(str(event.get_start()), "2014-08-13 10:00:00+00:00") + self.assertEqual(str(event.get_start()), "2014-08-13 10:00:00+01:00") + self.assertTrue(event.is_recurring()) + + exceptions = event.get_exceptions() + self.assertEqual(len(exceptions), 1) + + exception = exceptions[0] + self.assertIsInstance(exception.get_recurrence_id(), datetime.datetime) + self.assertTrue(exception.thisandfuture) + self.assertEqual(str(exception.get_start()), "2014-08-16 13:00:00+01:00") + self.assertEqual(exception.get_attendee_by_email("jane@example.org").get_participant_status(), kolabformat.PartDeclined) + self.assertRaises(ValueError, exception.get_attendee, "somebody@else.com") + + # get instances with exception data + occurrence = event.get_next_instance(exception.get_start() - datetime.timedelta(days=1)) + self.assertEqual(occurrence.get_start(), exception.get_start()) + self.assertEqual(occurrence.get_summary(), "exception") + + # find instance directly by date + _recurrence_id = datetime.datetime(2014, 8, 15, 10, 0, 0) + occurrence = event.get_instance(_recurrence_id) + self.assertIsInstance(occurrence, Event) + self.assertEqual(str(occurrence.get_recurrence_id()), "2014-08-15 10:00:00+01:00") def test_023_load_from_message(self): event = event_from_message(event_from_ical(ical_event).to_message()) @@ -670,15 +855,38 @@ def test_026_property_to_string(self): data = event_from_string(xml_event).to_dict() self.assertEqual(property_to_string('sequence', data['sequence']), "1") - self.assertEqual(property_to_string('start', data['start']), "2014-08-13 10:00 (GMT)") + self.assertEqual(property_to_string('start', data['start']), "2014-08-13 10:00 (BST)") self.assertEqual(property_to_string('organizer', data['organizer']), "Doe, John") self.assertEqual(property_to_string('attendee', data['attendee'][0]), "jane@example.org, Accepted") - self.assertEqual(property_to_string('rrule', data['rrule']), "Every 1 day(s) until 2014-07-25") + self.assertEqual(property_to_string('rrule', data['rrule']), "Every 1 day(s) until 2015-07-25") self.assertEqual(property_to_string('exdate', data['exdate'][0]), "2014-07-19") self.assertEqual(property_to_string('alarm', data['alarm'][0]), "Display message 2 hour(s) before") self.assertEqual(property_to_string('attach', data['attach'][0]), "noname.1395223627.5555") + def test_027_merge_attendee_data(self): + event = event_from_string(xml_event) + + jane = event.get_attendee("jane@example.org") + jane.set_participant_status('TENTATIVE') + jack = Attendee("jack@example.org", name="Jack", role='OPT-PARTICIPANT') + some = event.set_attendee_participant_status("somebody@else.com", 'ACCEPTED') + + # update jane + add jack + event.update_attendees([jane,jack]) + self.assertEqual(len(event.get_attendees()), 3) + self.assertEqual(event.get_attendee("jane@example.org").get_participant_status(), kolabformat.PartTentative) + self.assertEqual(event.get_attendee("somebody@else.com").get_participant_status(), kolabformat.PartAccepted) + + # test write + read + event = event_from_string(str(event)) + exception = event.get_exceptions()[0] + self.assertEqual(len(exception.get_attendees()), 2) + self.assertEqual(event.get_attendee("jane@example.org").get_participant_status(), kolabformat.PartTentative) + self.assertEqual(event.get_attendee("jack@example.org").get_name(), "Jack") + self.assertRaises(ValueError, exception.get_attendee, "somebody@else.com") # not addded to exception + + def _find_prop_in_list(self, diff, name): for prop in diff: if prop['property'] == name:
View file
pykolab-0.7.8.tar.gz/tests/unit/test-011-itip.py -> pykolab-0.7.9.tar.gz/tests/unit/test-011-itip.py
Changed
@@ -451,6 +451,31 @@ event4.set_end(datetime.datetime(2012,7,1, 10,30,0, tzinfo=pytz.utc)) self.assertFalse(itip.check_event_conflict(event4, itip_event), "No conflict in two recurring events") + itip_event = itip.events_from_message(message_from_string(itip_non_multipart))[0] + + rrule.setFrequency(kolabformat.RecurrenceRule.Daily) + rrule.setCount(10) + + event5 = Event() + event5.set_recurrence(rrule); + event5.set_start(datetime.datetime(2012,7,9, 10,0,0, tzinfo=pytz.timezone("Europe/London"))) + event5.set_end(datetime.datetime(2012,7,9, 11,0,0, tzinfo=pytz.timezone("Europe/London"))) + + event_xml = str(event5) + exception = Event(from_string=event_xml) + exception.set_start(datetime.datetime(2012,7,13, 14,0,0, tzinfo=pytz.timezone("Europe/London"))) + exception.set_end(datetime.datetime(2012,7,13, 16,0,0, tzinfo=pytz.timezone("Europe/London"))) + exception.set_recurrence_id(datetime.datetime(2012,7,13, 10,0,0, tzinfo=pytz.timezone("Europe/London")), False) + event5.add_exception(exception) + self.assertFalse(itip.check_event_conflict(event5, itip_event), "No conflict with exception date") + + exception = Event(from_string=event_xml) + exception.set_start(datetime.datetime(2012,7,13, 10,0,0, tzinfo=pytz.timezone("Europe/London"))) + exception.set_end(datetime.datetime(2012,7,13, 11,0,0, tzinfo=pytz.timezone("Europe/London"))) + exception.set_status('CANCELLED') + exception.set_recurrence_id(datetime.datetime(2012,7,13, 10,0,0, tzinfo=pytz.timezone("Europe/London")), False) + event5.add_exception(exception) + self.assertFalse(itip.check_event_conflict(event5, itip_event), "No conflict with cancelled exception") def test_003_send_reply(self): itip_events = itip.events_from_message(message_from_string(itip_non_multipart))
View file
pykolab-0.7.8.tar.gz/wallace/module_invitationpolicy.py -> pykolab-0.7.9.tar.gz/wallace/module_invitationpolicy.py
Changed
@@ -18,6 +18,7 @@ # import datetime +import pytz import os import tempfile import time @@ -25,6 +26,7 @@ import urllib import hashlib import traceback +import re from email import message_from_string from email.parser import Parser @@ -398,7 +400,7 @@ condition_fulfilled = True # find existing event in user's calendar - existing = find_existing_object(itip_event['uid'], itip_event['type'], receiving_user, True) + (existing, master) = find_existing_object(itip_event['uid'], itip_event['type'], itip_event['recurrence-id'], receiving_user, True) # compare sequence number to determine a (re-)scheduling request if existing is not None: @@ -454,7 +456,7 @@ receiving_attendee.set_name(receiving_user['cn']) # send iTip reply - if respond_with is not None: + if respond_with is not None and not respond_with == 'NEEDS-ACTION': receiving_attendee.set_participant_status(respond_with) send_reply(recipient_email, itip_event, invitation_response_text(itip_event['type']), subject=_('"%(summary)s" has been %(status)s')) @@ -478,7 +480,7 @@ if not nonpart or existing: # save new copy from iTip - if store_object(itip_event['xml'], receiving_user, targetfolder): + if store_object(itip_event['xml'], receiving_user, targetfolder, master): if policy & COND_FORWARD: log.debug(_("Forward invitation for notification"), level=5) return MESSAGE_FORWARD @@ -509,7 +511,7 @@ # find existing event in user's calendar # sets/checks lock to avoid concurrent wallace processes trying to update the same event simultaneously - existing = find_existing_object(itip_event['uid'], itip_event['type'], receiving_user, True) + (existing, master) = find_existing_object(itip_event['uid'], itip_event['type'], itip_event['recurrence-id'], receiving_user, True) if existing: # compare sequence number to avoid outdated replies? @@ -521,16 +523,18 @@ return MESSAGE_FORWARD log.debug(_("Auto-updating %s %r on iTip REPLY") % (existing.type, existing.uid), level=8) + updated_attendees = [] try: - existing_attendee = existing.get_attendee(sender_email) existing.set_attendee_participant_status(sender_email, sender_attendee.get_participant_status(), rsvp=False) + existing_attendee = existing.get_attendee(sender_email) + updated_attendees.append(existing_attendee) except Exception, e: log.error("Could not find corresponding attende in organizer's copy: %r" % (e)) # append delegated-from attendee ? if len(sender_attendee.get_delegated_from()) > 0: - existing._attendees.append(sender_attendee) - existing.event.setAttendees(existing._attendees) + existing.add_attendee(sender_attendee) + updated_attendees.append(sender_attendee) else: # TODO: accept new participant if ACT_ACCEPT ? remove_write_lock(existing._lock_key) @@ -544,28 +548,30 @@ existing_delegatee = existing.find_attendee(delegatee_email) if not existing_delegatee: - existing._attendees.append(sender_delegatee) + existing.add_attendee(sender_delegatee) log.debug(_("Add delegatee: %r") % (sender_delegatee.to_dict()), level=9) else: existing_delegatee.copy_from(sender_delegatee) log.debug(_("Update existing delegatee: %r") % (existing_delegatee.to_dict()), level=9) + updated_attendees.append(sender_delegatee) + # copy all parameters from replying attendee (e.g. delegated-to, role, etc.) existing_attendee.copy_from(sender_attendee) - existing.event.setAttendees(existing._attendees) + existing.update_attendees([existing_attendee]) log.debug(_("Update delegator: %r") % (existing_attendee.to_dict()), level=9) except Exception, e: log.error("Could not find delegated-to attendee: %r" % (e)) # update the organizer's copy of the object - if update_object(existing, receiving_user): + if update_object(existing, receiving_user, master): if policy & COND_NOTIFY: send_update_notification(existing, receiving_user, existing, True) # update all other attendee's copies if conf.get('wallace','invitationpolicy_autoupdate_other_attendees_on_reply'): - propagate_changes_to_attendees_accounts(existing) + propagate_changes_to_attendees_accounts(existing, updated_attendees) return MESSAGE_PROCESSED @@ -589,12 +595,20 @@ # auto-update the local copy with STATUS=CANCELLED if policy & ACT_UPDATE: # find existing object in user's folders - existing = find_existing_object(itip_event['uid'], itip_event['type'], receiving_user, True) + (existing, master) = find_existing_object(itip_event['uid'], itip_event['type'], itip_event['recurrence-id'], receiving_user, True) if existing: + # on this-and-future cancel requests, set the recurrence until date on the master event + if itip_event['recurrence-id'] and master and itip_event['xml'].get_thisandfuture(): + rrule = master.get_recurrence() + rrule.set_count(0) + rrule.set_until(existing.get_start().astimezone(pytz.utc) + datetime.timedelta(days=-1)) + master.set_recurrence(rrule) + existing.set_recurrence_id(existing.get_recurrence_id(), True) + existing.set_status('CANCELLED') existing.set_transparency(True) - if update_object(existing, receiving_user): + if update_object(existing, receiving_user, master): # send cancellation notification if policy & ACT_UPDATE_AND_NOTIFY: send_cancel_notification(existing, receiving_user) @@ -602,7 +616,7 @@ return MESSAGE_PROCESSED else: - log.error(_("The object referred by this reply was not found in the user's folders. Forwarding to Inbox.")) + log.error(_("The object referred by this cancel request was not found in the user's folders. Forwarding to Inbox.")) return MESSAGE_FORWARD return None @@ -735,7 +749,7 @@ for folder in folders: # exclude shared and other user's namespace - if not ns_other is None and folder.startswith(ns_other): + if not ns_other is None and folder.startswith(ns_other) and user_rec.has_key('_delegated_mailboxes'): # allow shared folders from delegators if len([_mailbox for _mailbox in user_rec['_delegated_mailboxes'] if folder.startswith(ns_other + _mailbox + '/')]) == 0: continue; @@ -765,7 +779,7 @@ return result -def find_existing_object(uid, type, user_rec, lock=False): +def find_existing_object(uid, type, recurrence_id, user_rec, lock=False): """ Search user's private folders for the given object (by UID+type) """ @@ -778,13 +792,20 @@ set_write_lock(lock_key) event = None + master = None for folder in list_user_folders(user_rec, type): log.debug(_("Searching folder %r for %s %r") % (folder, type, uid), level=8) imap.imap.m.select(imap.folder_utf7(folder)) - typ, data = imap.imap.m.search(None, '(UNDELETED HEADER SUBJECT "%s")' % (uid)) + res, data = imap.imap.m.search(None, '(UNDELETED HEADER SUBJECT "%s")' % (uid)) for num in reversed(data[0].split()): - typ, data = imap.imap.m.fetch(num, '(RFC822)') + res, data = imap.imap.m.fetch(num, '(UID RFC822)') + + try: + msguid = re.search(r"\WUID (\d+)", data[0][0]).group(1) + except Exception, e: + log.error(_("No UID found in IMAP response: %r") % (data[0][0])) + continue try: if type == 'task': @@ -792,19 +813,35 @@ else: event = event_from_message(message_from_string(data[0][1])) + # find instance in a recurring series + if recurrence_id and event.is_recurring(): + master = event + event = master.get_instance(recurrence_id) + setattr(master, '_imap_folder', folder) + setattr(master, '_msguid', msguid) + + # compare recurrence-id and skip to next message if not matching + elif recurrence_id and not event.is_recurring() and not xmlutils.dates_equal(recurrence_id, event.get_recurrence_id()): + log.debug(_("Recurrence-ID not matching on message %s, skipping: %r != %r") % ( + msguid, recurrence_id, event.get_recurrence_id() + ), level=8) + continue + setattr(event, '_imap_folder', folder) setattr(event, '_lock_key', lock_key) + setattr(event, '_msguid', msguid) + except Exception, e: log.error(_("Failed to parse %s from message %s/%s: %s") % (type, folder, num, traceback.format_exc())) continue if event and event.uid == uid: - return event + return (event, master) if lock_key is not None: remove_write_lock(lock_key) - return event + return (event, master) def check_availability(itip_event, receiving_user): @@ -824,12 +861,12 @@ log.debug(_("Listing events from folder %r") % (folder), level=8) imap.imap.m.select(imap.folder_utf7(folder)) - typ, data = imap.imap.m.search(None, '(UNDELETED HEADER X-Kolab-Type "application/x-vnd.kolab.event")') + res, data = imap.imap.m.search(None, '(UNDELETED HEADER X-Kolab-Type "application/x-vnd.kolab.event")') num_messages += len(data[0].split()) for num in reversed(data[0].split()): event = None - typ, data = imap.imap.m.fetch(num, '(RFC822)') + res, data = imap.imap.m.fetch(num, '(RFC822)') try: event = event_from_message(message_from_string(data[0][1])) @@ -907,25 +944,30 @@ return hashlib.md5("%s/%s" % (user['mail'], uid)).hexdigest() -def update_object(object, user_rec): +def update_object(object, user_rec, master=None): """ Update the given object in IMAP (i.e. delete + append) """ success = False + saveobj = object - if hasattr(object, '_imap_folder'): - delete_object(object) - object.set_lastmodified() # update last-modified timestamp - success = store_object(object, user_rec, object._imap_folder) + # updating a single instance only: use master event + if object.get_recurrence_id() and master: + saveobj = master + + if hasattr(saveobj, '_imap_folder'): + if delete_object(saveobj): + saveobj.set_lastmodified() # update last-modified timestamp + success = store_object(object, user_rec, saveobj._imap_folder, master) # remove write lock for this event - if hasattr(object, '_lock_key') and object._lock_key is not None: - remove_write_lock(object._lock_key) + if hasattr(saveobj, '_lock_key') and saveobj._lock_key is not None: + remove_write_lock(saveobj._lock_key) return success -def store_object(object, user_rec, targetfolder=None): +def store_object(object, user_rec, targetfolder=None, master=None): """ Append the given object to the user's default calendar/tasklist """ @@ -943,7 +985,15 @@ log.error(_("Failed to save %s: no target folder found for user %r") % (object.type, user_rec['mail'])) return Fasle - log.debug(_("Save %s %r to user folder %r") % (object.type, object.uid, targetfolder), level=8) + saveobj = object + + # updating a single instance only: add exception to master event + if object.get_recurrence_id() and master: + object.set_lastmodified() # update last-modified timestamp + master.add_exception(object) + saveobj = master + + log.debug(_("Save %s %r to user folder %r") % (saveobj.type, saveobj.uid, targetfolder), level=8) try: imap.imap.m.select(imap.folder_utf7(targetfolder)) @@ -951,13 +1001,13 @@ imap.folder_utf7(targetfolder), None, None, - object.to_message(creator="Kolab Server <wallace@localhost>").as_string() + saveobj.to_message(creator="Kolab Server <wallace@localhost>").as_string() ) return result except Exception, e: log.error(_("Failed to save %s to user folder at %r: %r") % ( - object.type, targetfolder, e + saveobj.type, targetfolder, e )) return False @@ -968,18 +1018,37 @@ Removes the IMAP object with the given UID from a user's folder """ targetfolder = existing._imap_folder - imap.imap.m.select(imap.folder_utf7(targetfolder)) + msguid = existing._msguid if hasattr(existing, '_msguid') else None - typ, data = imap.imap.m.search(None, '(HEADER SUBJECT "%s")' % existing.uid) + try: + imap.imap.m.select(imap.folder_utf7(targetfolder)) - log.debug(_("Delete %s %r in %r: %r") % ( - existing.type, existing.uid, targetfolder, data - ), level=8) + # delete by IMAP UID + if msguid is not None: + log.debug(_("Delete %s %r in %r by UID: %r") % ( + existing.type, existing.uid, targetfolder, msguid + ), level=8) - for num in data[0].split(): - imap.imap.m.store(num, '+FLAGS', '\\Deleted') + imap.imap.m.uid('store', msguid, '+FLAGS', '(\\Deleted)') + else: + res, data = imap.imap.m.search(None, '(HEADER SUBJECT "%s")' % existing.uid) - imap.imap.m.expunge() + log.debug(_("Delete %s %r in %r: %r") % ( + existing.type, existing.uid, targetfolder, data + ), level=8) + + for num in data[0].split(): + imap.imap.m.store(num, '+FLAGS', '(\\Deleted)') + + imap.imap.m.expunge() + return True + + except Exception, e: + log.error(_("Failed to delete %s from folder %r: %r") % ( + existing.type, targetfolder, e + )) + + return False def send_update_notification(object, receiving_user, old=None, reply=True): @@ -1076,6 +1145,9 @@ 'roundup': roundup } + if object.get_recurrence_id(): + message_text += "\n" + _("NOTE: This update only refers to this single occurrence!") + message_text += "\n" + _("*** This is an automated message. Please do not reply. ***") # compose mime message @@ -1092,7 +1164,8 @@ smtp.set_debuglevel(True) try: - smtp.sendmail(orgemail, receiving_user['mail'], msg.as_string()) + success = smtp.sendmail(orgemail, receiving_user['mail'], msg.as_string()) + log.debug(_("Sent update notification to %r: %r") % (receiving_user['mail'], success), level=8) except Exception, e: log.error(_("SMTP sendmail error: %r") % (e)) @@ -1191,23 +1264,30 @@ return condition_fulfilled -def propagate_changes_to_attendees_accounts(object): +def propagate_changes_to_attendees_accounts(object, updated_attendees=None): """ Find and update copies of this object in all attendee's personal folders """ + recurrence_id = object.get_recurrence_id() + for attendee in object.get_attendees(): attendee_user_dn = user_dn_from_email_address(attendee.get_email()) if attendee_user_dn: attendee_user = auth.get_entry_attributes(None, attendee_user_dn, ['*']) - attendee_object = find_existing_object(object.uid, object.type, attendee_user, True) # does IMAP authenticate + (attendee_object, master_object) = find_existing_object(object.uid, object.type, recurrence_id, attendee_user, True) # does IMAP authenticate if attendee_object: - try: - attendee_entry = attendee_object.get_attendee_by_email(attendee_user['mail']) - except: - attendee_entry = None + # find attendee's entry by one of its email addresses + attendee_emails = auth.extract_recipient_addresses(attendee_user) + for attendee_email in attendee_emails: + try: + attendee_entry = attendee_object.get_attendee_by_email(attendee_email) + except: + attendee_entry = None + if attendee_entry: + break # copy all attendees from master object (covers additions and removals) - new_attendees = kolabformat.vectorattendee(); + new_attendees = []; for a in object.get_attendees(): # keep my own entry intact if attendee_entry is not None and attendee_entry.get_email() == a.get_email(): @@ -1215,9 +1295,13 @@ else: new_attendees.append(a) - attendee_object.event.setAttendees(new_attendees) + attendee_object.set_attendees(new_attendees) + + if updated_attendees and not recurrence_id: + log.debug("Update Attendees %r for %s" % ([a.get_email()+':'+a.get_participant_status(True) for a in updated_attendees], attendee_user['mail']), level=8) + attendee_object.update_attendees(updated_attendees, False) - success = update_object(attendee_object, attendee_user) + success = update_object(attendee_object, attendee_user, master_object) log.debug(_("Updated %s's copy of %r: %r") % (attendee_user['mail'], object.uid, success), level=8) else:
View file
pykolab-0.7.8.tar.gz/wallace/module_resources.py -> pykolab-0.7.9.tar.gz/wallace/module_resources.py
Changed
@@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2010-2013 Kolab Systems AG (http://www.kolabsys.com) +# Copyright 2010-2015 Kolab Systems AG (http://www.kolabsys.com) # # Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> # @@ -44,6 +44,7 @@ from pykolab.conf import Conf from pykolab.imap import IMAP from pykolab.xml import to_dt +from pykolab.xml import utils as xmlutils from pykolab.xml import event_from_message from pykolab.xml import participant_status_label from pykolab.itip import events_from_message @@ -265,14 +266,16 @@ # find initial reservation referenced by the reply if reference_uid: - event = find_existing_event(reference_uid, receiving_resource) + (event, master) = find_existing_event(reference_uid, itip_event['recurrence-id'], receiving_resource) + log.debug(_("iTip REPLY to %r, %r; matches %r") % (reference_uid, itip_event['recurrence-id'], type(event)), level=8) + if event: try: sender_attendee = itip_event['xml'].get_attendee_by_email(sender_email) owner_reply = sender_attendee.get_participant_status() log.debug(_("Sender Attendee: %r => %r") % (sender_attendee, owner_reply), level=9) except Exception, e: - log.error("Could not find envelope sender attendee: %r" % (e)) + log.error(_("Could not find envelope sender attendee: %r") % (e)) continue # compare sequence number to avoid outdated replies @@ -287,18 +290,16 @@ if comment: event.set_comment(str(comment)) - itip_event_ = dict(xml=event, uid=event.get_uid()) + _itip_event = dict(xml=event, uid=event.get_uid(), _master=master) + _itip_event['recurrence-id'] = event.get_recurrence_id() if owner_reply == kolabformat.PartAccepted: event.set_status(kolabformat.StatusConfirmed) - accept_reservation_request(itip_event_, receiving_resource, confirmed=True) + accept_reservation_request(_itip_event, receiving_resource, confirmed=True) elif owner_reply == kolabformat.PartDeclined: - decline_reservation_request(itip_event_, receiving_resource) - # TODO: set status=CANCELLED instead of deleting? - # event.set_status(kolabformat.StatusCancelled) - delete_resource_event(reference_uid, receiving_resource) + decline_reservation_request(_itip_event, receiving_resource) else: - log.info("Invalid response (%r) recieved from resource owner for event %r" % ( + log.info(_("Invalid response (%r) recieved from resource owner for event %r") % ( sender_attendee.get_participant_status(True), reference_uid )) else: @@ -316,7 +317,7 @@ receiving_attendee = itip_event['xml'].get_attendee_by_email(receiving_resource['mail']) log.debug(_("Receiving Resource: %r; %r") % (receiving_resource, receiving_attendee), level=9) except Exception, e: - log.error("Could not find envelope attendee: %r" % (e)) + log.error(_("Could not find envelope attendee: %r") % (e)) continue # ignore updates and cancellations to resource collections who already delegated the event @@ -329,7 +330,19 @@ for resource in resource_dns: if resources[resource]['mail'] in [a.get_email() for a in itip_event['xml'].get_attendees()] \ and resources[resource].has_key('kolabtargetfolder'): - delete_resource_event(itip_event['uid'], resources[resource]) + (event, master) = find_existing_event(itip_event['uid'], itip_event['recurrence-id'], resources[resource]) + # remove entire event + if event and master is None: + log.debug(_("Cancellation for entire event %r: deleting") % (itip_event['uid']), level=8) + delete_resource_event(itip_event['uid'], resources[resource], event._msguid) + # just cancel one single occurrence: add exception with status=cancelled + elif master and master.is_recurring(): + log.debug(_("Cancellation for a single occurrence %r of %r: updating...") % (itip_event['recurrence-id'], itip_event['uid']), level=8) + event.set_status('CANCELLED') + event.set_transparency(True) + _itip_event = dict(xml=event, uid=event.get_uid(), _master=master) + _itip_event['recurrence-id'] = event.get_recurrence_id() + save_resource_event(_itip_event, resources[resource]) done = True @@ -345,11 +358,6 @@ # accept reservation if available_resource is not None: if available_resource['mail'] in [a.get_email() for a in itip_event['xml'].get_attendees()]: - # replace existing copy of this event - if len(available_resource['existing_events']) > 0: - for uid in available_resource['existing_events']: - delete_resource_event(uid, available_resource) - log.debug(_("Accept invitation for individual resource %r / %r") % (available_resource['dn'], available_resource['mail']), level=8) # check if reservation was delegated @@ -557,6 +565,10 @@ # This is the event being conflicted with! for itip_event in itip_events: + # do not re-assign single occurrences to another resource + if itip_event['recurrence-id'] is not None: + continue + # Now we have the event that was conflicting if resources[resource]['mail'] in [a.get_email() for a in itip_event['xml'].get_attendees()]: # this resource initially was delegated from a collection ? @@ -583,8 +595,8 @@ # remove existing_events as we now delegated back to the collection if len(resources[resource]['existing_events']) > 0: - for uid in resources[resource]['existing_events']: - delete_resource_event(uid, resources[resource]) + for existing in resources[resource]['existing_events']: + delete_resource_event(existing.uid, resources[resource], existing._msguid) done = True @@ -655,7 +667,13 @@ level=9 ) - typ, data = imap.imap.m.fetch(num, '(RFC822)') + typ, data = imap.imap.m.fetch(num, '(UID RFC822)') + + try: + msguid = re.search(r"\WUID (\d+)", data[0][0]).group(1) + except Exception, e: + log.error(_("No UID found in IMAP response: %r") % (data[0][0])) + continue event_message = message_from_string(data[0][1]) @@ -669,8 +687,12 @@ for itip in itip_events: conflict = check_event_conflict(event, itip) - if event.get_uid() == itip['uid']: - resource_rec['existing_events'].append(itip['uid']) + if event.get_uid() == itip['uid'] and (event.is_recurring() or itip['recurrence-id'] == event.get_recurrence_id()): + setattr(event, '_msguid', msguid) + if event.is_recurring(): + resource_rec['existing_master'] = event + else: + resource_rec['existing_events'].append(event) if conflict: log.info( @@ -686,13 +708,14 @@ return num_messages -def find_existing_event(uid, resource_rec): +def find_existing_event(uid, recurrence_id, resource_rec): """ Search the resources's calendar folder for the given event (by UID) """ global imap event = None + master = None mailbox = resource_rec['kolabtargetfolder'] log.debug(_("Searching %r for event %r") % (mailbox, uid), level=9) @@ -705,18 +728,39 @@ return event for num in reversed(data[0].split()): - typ, data = imap.imap.m.fetch(num, '(RFC822)') + typ, data = imap.imap.m.fetch(num, '(UID RFC822)') + + try: + msguid = re.search(r"\WUID (\d+)", data[0][0]).group(1) + except Exception, e: + log.error(_("No UID found in IMAP response: %r") % (data[0][0])) + continue try: event = event_from_message(message_from_string(data[0][1])) + + # find instance in a recurring series + if recurrence_id and event.is_recurring(): + master = event + event = master.get_instance(recurrence_id) + setattr(master, '_msguid', msguid) + + # compare recurrence-id and skip to next message if not matching + elif recurrence_id and not event.is_recurring() and not xmlutils.dates_equal(recurrence_id, event.get_recurrence_id()): + log.debug(_("Recurrence-ID not matching on message %s, skipping: %r != %r") % ( + msguid, recurrence_id, event.get_recurrence_id() + ), level=8) + continue + setattr(event, '_msguid', msguid) + except Exception, e: log.error(_("Failed to parse event from message %s/%s: %r") % (mailbox, num, e)) continue if event and event.uid == uid: - return event + return (event, master) - return event + return (event, master) def accept_reservation_request(itip_event, resource, delegator=None, confirmed=False): @@ -746,7 +790,7 @@ partstat ) - saved = save_resource_event(itip_event, resource, replace=confirmed) + saved = save_resource_event(itip_event, resource) log.debug( _("Adding event to %r: %r") % (resource['kolabtargetfolder'], saved), @@ -773,6 +817,20 @@ "DECLINED" ) + # update master event + if resource.get('existing_master') is not None or itip_event.get('_master') is not None: + save_resource_event(itip_event, resource) + + # remove old copy of the reservation + elif resource.get('existing_events', []) and len(resource['existing_events']) > 0: + for existing in resource['existing_events']: + delete_resource_event(existing.uid, resource, existing._msguid) + + # delete old event referenced by itip_event (from owner confirmation) + elif hasattr(itip_event['xml'], '_msguid'): + delete_resource_event(itip_event['xml'].uid, resource, itip_event['xml']._msguid) + + # send response and notification owner = get_resource_owner(resource) send_response(resource['mail'], itip_event, get_resource_owner(resource)) @@ -780,25 +838,41 @@ send_owner_notification(resource, owner, itip_event, True) -def save_resource_event(itip_event, resource, replace=False): +def save_resource_event(itip_event, resource): """ Append the given event object to the resource's calendar """ try: - # Administrator login name comes from configuration. + save_event = itip_event['xml'] targetfolder = imap.folder_quote(resource['kolabtargetfolder']) + # add exception to existing recurring main event + if resource.get('existing_master') is not None: + save_event = resource['existing_master'] + save_event.add_exception(itip_event['xml']) + + elif itip_event.get('_master') is not None: + save_event = itip_event['_master'] + save_event.add_exception(itip_event['xml']) + # remove old copy of the reservation (also sets ACLs) - if replace: - delete_resource_event(itip_event['uid'], resource) + if resource.has_key('existing_events') and len(resource['existing_events']) > 0: + for existing in resource['existing_events']: + delete_resource_event(existing.uid, resource, existing._msguid) + + # delete old version referenced save_event + elif hasattr(save_event, '_msguid'): + delete_resource_event(save_event.uid, resource, save_event._msguid) + else: imap.set_acl(targetfolder, conf.get(conf.get('kolab', 'imap_backend'), 'admin_login'), "lrswipkxtecda") + # append new version result = imap.imap.m.append( targetfolder, None, None, - itip_event['xml'].to_message(creator="Kolab Server <wallace@localhost>").as_string() + save_event.to_message(creator="Kolab Server <wallace@localhost>").as_string() ) return result @@ -810,24 +884,42 @@ return False -def delete_resource_event(uid, resource): +def delete_resource_event(uid, resource, msguid=None): """ Removes the IMAP object with the given UID from a resource's calendar folder """ targetfolder = imap.folder_quote(resource['kolabtargetfolder']) - imap.set_acl(targetfolder, conf.get(conf.get('kolab', 'imap_backend'), 'admin_login'), "lrswipkxtecda") - imap.imap.m.select(targetfolder) - typ, data = imap.imap.m.search(None, '(HEADER SUBJECT "%s")' % uid) + try: + imap.set_acl(targetfolder, conf.get(conf.get('kolab', 'imap_backend'), 'admin_login'), "lrswipkxtecda") + imap.imap.m.select(targetfolder) - log.debug(_("Delete resource calendar object %r in %r: %r") % ( - uid, resource['kolabtargetfolder'], data - ), level=9) + # delete by IMAP UID + if msguid is not None: + log.debug(_("Delete resource calendar object from %r by UID %r") % ( + targetfolder, msguid + ), level=8) - for num in data[0].split(): - imap.imap.m.store(num, '+FLAGS', '\\Deleted') + imap.imap.m.uid('store', msguid, '+FLAGS', '(\\Deleted)') + else: + typ, data = imap.imap.m.search(None, '(HEADER SUBJECT "%s")' % uid) - imap.imap.m.expunge() + log.debug(_("Delete resource calendar object %r in %r: %r") % ( + uid, resource['kolabtargetfolder'], data + ), level=9) + + for num in data[0].split(): + imap.imap.m.store(num, '+FLAGS', '\\Deleted') + + imap.imap.m.expunge() + return True + + except Exception, e: + log.error(_("Failed to delete calendar object %r from folder %r: %r") % ( + uid, targetfolder, e + )) + + return False def reject(filepath): @@ -1116,7 +1208,7 @@ if not isinstance(collections, list): collections = [ (collections['dn'],collections) ] - log.debug("Check collections %r for kolabinvitationpolicy attributes" % (collections), level=9) + log.debug(_("Check collections %r for kolabinvitationpolicy attributes") % (collections), level=9) for dn,collection in collections: # ldap.search_entry_by_attribute() doesn't return the attributes lower-cased @@ -1289,6 +1381,13 @@ organizer = event.get_organizer() event_attendees = [a.get_displayname() for a in event.get_attendees() if not a.get_cutype() == kolabformat.CutypeResource] + log.debug( + _("Clone invitation for owner confirmation: %r from %r") % ( + itip_event['uid'], event.get_organizer().email() + ), + level=8 + ) + # generate new UID and set the resource as organizer (mail, domain) = resource['mail'].split('@') event.set_uid(str(uuid.uuid4())) @@ -1302,13 +1401,6 @@ # flag this iTip message as confirmation type event.add_custom_property('X-Kolab-InvitationType', 'CONFIRMATION') - log.debug( - _("Clone invitation for owner confirmation: %r from %r") % ( - itip_event['uid'], event.get_organizer().email() - ), - level=8 - ) - message_text = _(""" A reservation request for %(resource)s requires your approval! Please either accept or decline this invitation without saving it to your calendar.
View file
pykolab.dsc
Changed
@@ -2,7 +2,7 @@ Source: pykolab Binary: pykolab, kolab-cli, kolab-conf, kolab-saslauthd, kolab-server, kolab-telemetry, kolab-xml, wallace Architecture: all -Version: 0.7.8-0~kolab3 +Version: 0.7.9-0~kolab1 Maintainer: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Uploaders: Paul Klos <kolab@klos2day.nl> Homepage: http://www.kolab.org @@ -40,5 +40,5 @@ pykolab deb python optional wallace deb python optional Files: - 00000000000000000000000000000000 0 pykolab-0.7.8.tar.gz + 00000000000000000000000000000000 0 pykolab-0.7.9.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.