Projects
Kolab:16
pykolab
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 47
View file
pykolab.spec
Changed
@@ -33,7 +33,7 @@ Summary: Kolab Groupware Solution Name: pykolab -Version: 0.8.13 +Version: 0.8.14 Release: 1%{?dist} License: GPLv3+ Group: Applications/System @@ -565,6 +565,9 @@ %attr(0700,%{kolab_user},%{kolab_group}) %dir %{_var}/spool/pykolab/wallace %changelog +* Fri Aug 16 2019 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 0.8.14-1 +* Release of version 0.8.14 + * Tue Jun 4 2019 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 0.8.12-1 - Release of version 0.8.12
View file
0001-Fix-settting-up-new-MySQL-servers-with-root-password.patch
Deleted
@@ -1,300 +0,0 @@ -From 0515774829661080010492539335f2f84967ddea Mon Sep 17 00:00:00 2001 -From: "Jeroen van Meeuwen (Kolab Systems)" <vanmeeuwen@kolabsys.com> -Date: Mon, 29 Jul 2019 13:35:10 +0200 -Subject: [PATCH 1/2] Fix settting up new MySQL servers with root passwords - rather than auth sockets. - ---- - pykolab/setup/setup_mysql.py | 197 ++++++++++++++++++++++++----------- - 1 file changed, 137 insertions(+), 60 deletions(-) - -diff --git a/pykolab/setup/setup_mysql.py b/pykolab/setup/setup_mysql.py -index 2b3e17c..ec9e6d4 100644 ---- a/pykolab/setup/setup_mysql.py -+++ b/pykolab/setup/setup_mysql.py -@@ -33,30 +33,34 @@ from pykolab.translate import _ - log = pykolab.getLogger('pykolab.setup') - conf = pykolab.getConf() - -+ - def __init__(): - components.register('mysql', execute, description=description()) - -+ - def cli_options(): - ldap_group = conf.add_cli_parser_option_group(_("MySQL Options")) - - ldap_group.add_option( -- "--mysqlserver", -- dest = "mysqlserver", -- action = "store", -- help = _("Specify whether to use an (existing) or (new) MySQL server.") -- ) -+ "--mysqlserver", -+ dest="mysqlserver", -+ action="store", -+ help=_("Specify whether to use an (existing) or (new) MySQL server.") -+ ) -+ - - def description(): - return _("Setup MySQL.") - --def execute(*args, **kw): -+ -+def execute(*args, **kw): # noqa: C901 - - socket_paths = [ -- "/var/lib/mysql/mysql.sock", -- "/var/run/mysqld/mysqld.sock", -- "/var/run/mysql/mysql.sock", -- "/var/run/mysqld/mysqld.pid" -- ] -+ "/var/lib/mysql/mysql.sock", -+ "/var/run/mysqld/mysqld.sock", -+ "/var/run/mysql/mysql.sock", -+ "/var/run/mysqld/mysqld.pid" -+ ] - - # on CentOS7, there is MariaDB instead of MySQL - mysqlservice = 'mysqld.service' -@@ -73,7 +77,7 @@ def execute(*args, **kw): - elif os.path.isfile('/sbin/service'): - subprocess.call(['/sbin/service', 'mysqld', 'restart']) - elif os.path.isfile('/usr/sbin/service'): -- subprocess.call(['/usr/sbin/service','mysql','restart']) -+ subprocess.call(['/usr/sbin/service', 'mysql', 'restart']) - else: - log.error(_("Could not start the MySQL database service.")) - -@@ -84,8 +88,9 @@ def execute(*args, **kw): - elif os.path.isfile('/usr/sbin/update-rc.d'): - subprocess.call(['/usr/sbin/update-rc.d', 'mysql', 'defaults']) - else: -- log.error(_("Could not configure to start on boot, the " + \ -- "MySQL database service.")) -+ log.error( -+ _("Could not configure to start on boot, the MySQL database service.") -+ ) - - log.info(_("Waiting for at most 30 seconds for MySQL/MariaDB to settle...")) - max_wait = 30 -@@ -99,9 +104,9 @@ def execute(*args, **kw): - time.sleep(1) - - options = { -- 1: "Existing MySQL server (with root password already set).", -- 2: "New MySQL server (needs to be initialized)." -- } -+ 1: "Existing MySQL server (with root password already set).", -+ 2: "New MySQL server (needs to be initialized)." -+ } - - answer = 0 - if len([x for x in socket_paths if os.path.exists(x)]) > 0: -@@ -115,37 +120,76 @@ def execute(*args, **kw): - - if answer == "1" or answer == 1: - print >> sys.stderr, utils.multiline_message( -- _(""" -- Please supply the root password for MySQL, so we can set -- up user accounts for other components that use MySQL. -- """) -- ) -+ _(""" -+ Please supply the root password for MySQL, so we can set -+ up user accounts for other components that use MySQL. -+ """) -+ ) - - mysql_root_password = utils.ask_question( -- _("MySQL root password"), -- password=True -- ) -+ _("MySQL root password"), -+ password=True -+ ) - - else: - print >> sys.stderr, utils.multiline_message( -- _(""" -- Please supply a root password for MySQL. This password -- will be the administrative user for this MySQL server, -- and it should be kept a secret. After this setup process -- has completed, Kolab is going to discard and forget -- about this password, but you will need it for -- administrative tasks in MySQL. -- """) -- ) -+ _(""" -+ Please supply a root password for MySQL. This password -+ will be the administrative user for this MySQL server, -+ and it should be kept a secret. After this setup process -+ has completed, Kolab is going to discard and forget -+ about this password, but you will need it for -+ administrative tasks in MySQL. -+ """) -+ ) - - mysql_root_password = utils.ask_question( -- _("MySQL root password"), -- default=utils.generate_password(), -- password=True, -- confirm=True -- ) -+ _("MySQL root password"), -+ default=utils.generate_password(), -+ password=True, -+ confirm=True -+ ) -+ -+ p1 = subprocess.Popen( -+ [ -+ 'echo', -+ 'UPDATE mysql.user SET Password=PASSWORD(\'%s\') WHERE User=\'root\';' % ( -+ mysql_root_password -+ ) -+ ], -+ stdout=subprocess.PIPE -+ ) -+ -+ p2 = subprocess.Popen(['mysql'], stdin=p1.stdout) -+ p1.stdout.close() -+ p2.communicate() -+ -+ p1 = subprocess.Popen( -+ [ -+ 'echo', -+ "UPDATE mysql.user SET authentication_string=PASSWORD('%s') WHERE User='root';" % ( -+ mysql_root_password -+ ) -+ ], -+ stdout=subprocess.PIPE -+ ) -+ -+ p2 = subprocess.Popen(['mysql'], stdin=p1.stdout) -+ p1.stdout.close() -+ p2.communicate() -+ -+ p1 = subprocess.Popen( -+ [ -+ 'echo', -+ """ -+ UPDATE mysql.user -+ SET plugin='mysql_native_password' -+ WHERE User='root' AND plugin='auth_socket'; -+ """ -+ ], -+ stdout=subprocess.PIPE -+ ) - -- p1 = subprocess.Popen(['echo', 'UPDATE mysql.user SET Password=PASSWORD(\'%s\') WHERE User=\'root\';' % (mysql_root_password)], stdout=subprocess.PIPE) - p2 = subprocess.Popen(['mysql'], stdin=p1.stdout) - p1.stdout.close() - p2.communicate() -@@ -162,7 +206,7 @@ password='%s' - """ % (mysql_root_password) - - fp = open('/tmp/kolab-setup-my.cnf', 'w') -- os.chmod('/tmp/kolab-setup-my.cnf', 0600) -+ os.chmod('/tmp/kolab-setup-my.cnf', 600) - fp.write(data) - fp.close() - -@@ -174,41 +218,74 @@ password='%s' - if filename.endswith('oracle.sql'): - continue - -- schema_file = os.path.join(root,filename) -+ schema_file = os.path.join(root, filename) - -- if not schema_file == None: -+ if schema_file is not None: - p1 = subprocess.Popen(['echo', 'create database kolab;'], stdout=subprocess.PIPE) - p2 = subprocess.Popen(['mysql', '--defaults-file=/tmp/kolab-setup-my.cnf'], stdin=p1.stdout) - p1.stdout.close() - p2.communicate() - - print >> sys.stderr, utils.multiline_message( -- _(""" -- Please supply a password for the MySQL user 'kolab'. -- This password will be used by Kolab services, such as -- the Web Administration Panel. -- """) -- ) -+ _(""" -+ Please supply a password for the MySQL user 'kolab'. -+ This password will be used by Kolab services, such as -+ the Web Administration Panel. -+ """) -+ ) - - mysql_kolab_password = utils.ask_question( -- _("MySQL kolab password"), -- default=utils.generate_password(), -- password=True, -- confirm=True -- ) -+ _("MySQL kolab password"), -+ default=utils.generate_password(), -+ password=True, -+ confirm=True -+ ) -+ -+ p1 = subprocess.Popen( -+ [ -+ 'echo', -+ "GRANT ALL PRIVILEGES ON kolab.* TO 'kolab'@'localhost' IDENTIFIED BY '%s';" % ( -+ mysql_kolab_password -+ ) -+ ], -+ stdout=subprocess.PIPE -+ ) -+ -+ p2 = subprocess.Popen( -+ [ -+ 'mysql', -+ '--defaults-file=/tmp/kolab-setup-my.cnf' -+ ], -+ stdin=p1.stdout -+ ) - -- p1 = subprocess.Popen(['echo', 'GRANT ALL PRIVILEGES ON kolab.* TO \'kolab\'@\'localhost\' IDENTIFIED BY \'%s\';' % (mysql_kolab_password)], stdout=subprocess.PIPE) -- p2 = subprocess.Popen(['mysql', '--defaults-file=/tmp/kolab-setup-my.cnf'], stdin=p1.stdout) - p1.stdout.close() - p2.communicate() - - p1 = subprocess.Popen(['cat', schema_file], stdout=subprocess.PIPE) -- p2 = subprocess.Popen(['mysql', '--defaults-file=/tmp/kolab-setup-my.cnf', 'kolab'], stdin=p1.stdout) -+ p2 = subprocess.Popen( -+ [ -+ 'mysql', -+ '--defaults-file=/tmp/kolab-setup-my.cnf', -+ 'kolab' -+ ], -+ stdin=p1.stdout -+ ) -+ - p1.stdout.close() - p2.communicate() - -- conf.command_set('kolab_wap', 'sql_uri', 'mysql://kolab:%s@localhost/kolab' % (mysql_kolab_password)) -- conf.command_set('kolab_smtp_access_policy', 'cache_uri', 'mysql://kolab:%s@localhost/kolab' % (mysql_kolab_password)) -+ conf.command_set( -+ 'kolab_wap', -+ 'sql_uri', -+ 'mysql://kolab:%s@localhost/kolab' % (mysql_kolab_password) -+ ) -+ -+ conf.command_set( -+ 'kolab_smtp_access_policy', -+ 'cache_uri', -+ 'mysql://kolab:%s@localhost/kolab' % (mysql_kolab_password) -+ ) -+ - else: - log.warning(_("Could not find the MySQL Kolab schema file")) -- --- -2.20.1 -
View file
0002-Work-around-out-dated-augeas-on-Xenial.patch
Deleted
@@ -1,150 +0,0 @@ -From 5e23af6c1d6e11135bb977afd92acb9c8c1a9155 Mon Sep 17 00:00:00 2001 -From: "Jeroen van Meeuwen (Kolab Systems)" <vanmeeuwen@kolabsys.com> -Date: Mon, 29 Jul 2019 14:15:32 +0200 -Subject: [PATCH 2/2] Work around out-dated augeas on Xenial - ---- - pykolab/setup/setup_php.py | 103 ++++++++++++++++++++++--------------- - 1 file changed, 62 insertions(+), 41 deletions(-) - -diff --git a/pykolab/setup/setup_php.py b/pykolab/setup/setup_php.py -index 942d09f..f27dd3f 100644 ---- a/pykolab/setup/setup_php.py -+++ b/pykolab/setup/setup_php.py -@@ -35,50 +35,60 @@ from pykolab.translate import _ - log = pykolab.getLogger('pykolab.setup') - conf = pykolab.getConf() - -+ - def __init__(): - components.register('php', execute, description=description()) - -+ - def cli_options(): - php_group = conf.add_cli_parser_option_group(_("PHP Options")) - - php_group.add_option( -- "--timezone", -- dest = "timezone", -- action = "store", -- default = None, -- help = _("Specify the timezone for PHP.") -- ) -+ "--timezone", -+ dest="timezone", -+ action="store", -+ default=None, -+ help=_("Specify the timezone for PHP.") -+ ) - - php_group.add_option( -- "--with-php-ini", -- dest = "php_ini_path", -- action = "store", -- default = None, -- help = _("Specify the path to the php.ini file used with the webserver.") -- ) -+ "--with-php-ini", -+ dest="php_ini_path", -+ action="store", -+ default=None, -+ help=_("Specify the path to the php.ini file used with the webserver.") -+ ) -+ - - def description(): - return _("Setup PHP.") - -+ - def execute(*args, **kw): -- if conf.timezone == None: -+ if conf.timezone is None: - print >> sys.stderr, utils.multiline_message( -- _(""" -- Please supply the timezone PHP should be using. -- You have to use a Continent or Country / City locality name -- like 'Europe/Berlin', but not just 'CEST'. -- """) -- ) -+ _(""" -+ Please supply the timezone PHP should be using. -+ You have to use a Continent or Country / City locality name -+ like 'Europe/Berlin', but not just 'CEST'. -+ """) -+ ) - - conf.timezone = utils.ask_question( -- _("Timezone ID"), -- default="UTC" -- ) -+ _("Timezone ID"), -+ default="UTC" -+ ) - -- if not conf.php_ini_path == None: -+ if conf.php_ini_path is not None: - if not os.path.isfile(conf.php_ini_path): -- log.error(_("Cannot configure PHP through %r (No such file or directory)") % (conf.php_ini_path)) -+ log.error( -+ _("Cannot configure PHP through %r (No such file or directory)") % ( -+ conf.php_ini_path -+ ) -+ ) -+ - return -+ - php_ini = conf.php_ini_path - - else: -@@ -98,20 +108,31 @@ def execute(*args, **kw): - log.error(_("Could not find PHP configuration file php.ini")) - return - -- myaugeas = Augeas() -- -- setting_base = '/files%s/' % (php_ini) -- -- setting = os.path.join(setting_base, 'Date', 'date.timezone') -- current_value = myaugeas.get(setting) -- -- if current_value == None: -- insert_paths = myaugeas.match('/files%s/Date/*' % (php_ini)) -- insert_path = insert_paths[(len(insert_paths)-1)] -- myaugeas.insert(insert_path, 'date.timezone', False) -- -- log.debug(_("Setting key %r to %r") % ('Date/date.timezone', conf.timezone), level=8) -- myaugeas.set(setting, conf.timezone) -- -- myaugeas.save() -- -+ try: -+ myaugeas = Augeas() -+ -+ setting_base = '/files%s/' % (php_ini) -+ -+ setting = os.path.join(setting_base, 'Date', 'date.timezone') -+ current_value = myaugeas.get(setting) -+ -+ if current_value is None: -+ insert_paths = myaugeas.match('/files%s/Date/*' % (php_ini)) -+ insert_path = insert_paths[(len(insert_paths) - 1)] -+ myaugeas.insert(insert_path, 'date.timezone', False) -+ -+ log.debug(_("Setting key %r to %r") % ('Date/date.timezone', conf.timezone), level=8) -+ myaugeas.set(setting, conf.timezone) -+ -+ myaugeas.save() -+ except IndexError: -+ subprocess.Popen( -+ [ -+ 'sed', -+ '-i', -+ '-r', -+ '-e', -+ r's|^(;*)date\.timezone.*$|date.timezone = %s|g' % (conf.timezone), -+ php_ini -+ ] -+ ) --- -2.20.1 -
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +pykolab (0.8.14-0~kolab1) unstable; urgency=low + + * Release of version 0.8.14 + + -- Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Fri, 16 Aug 2019 01:49:00 +0100 + pykolab (0.8.13-0~kolab5) unstable; urgency=low * Require both python-pymysql and python-mysqldb
View file
debian.series
Changed
@@ -1,3 +1,1 @@ cyrus-imapd.conf-cert-paths.patch -p1 -0001-Fix-settting-up-new-MySQL-servers-with-root-password.patch -p1 -0002-Work-around-out-dated-augeas-on-Xenial.patch -p1
View file
pykolab-0.8.13.tar.gz/.arclint -> pykolab-0.8.14.tar.gz/.arclint
Changed
@@ -19,6 +19,7 @@ "E131": "disabled", "E201": "disabled", "E202": "disabled", + "E221": "disabled", "E225": "disabled", "E231": "disabled", "E251": "disabled",
View file
pykolab-0.8.13.tar.gz/configure.ac -> pykolab-0.8.14.tar.gz/configure.ac
Changed
@@ -1,4 +1,4 @@ -AC_INIT([pykolab], 0.8.13) +AC_INIT([pykolab], 0.8.14) AC_SUBST([RELEASE], 1) AC_CONFIG_SRCDIR(pykolab/constants.py.in)
View file
pykolab-0.8.13.tar.gz/pykolab/itip/__init__.py -> pykolab-0.8.14.tar.gz/pykolab/itip/__init__.py
Changed
@@ -1,26 +1,33 @@ -import icalendar -import pykolab +import re import traceback + +import icalendar import kolabformat -import re +import pykolab +from pykolab.translate import _ from pykolab.xml import to_dt from pykolab.xml import event_from_ical from pykolab.xml import todo_from_ical from pykolab.xml import participant_status_label -from pykolab.translate import _ + from tzlocal import windows_tz +# pylint: disable=invalid-name log = pykolab.getLogger('pykolab.wallace') def events_from_message(message, methods=None): return objects_from_message(message, ["VEVENT"], methods) + def todos_from_message(message, methods=None): return objects_from_message(message, ["VTODO"], methods) -def objects_from_message(message, objnames, methods=None): + +# pylint: disable=too-many-branches +# pylint: disable=too-many-statements +def objects_from_message(message, objnames, methods=None): # noqa: C901 """ Obtain the iTip payload from email.message <message> """ @@ -30,7 +37,7 @@ # iTip methods we are actually interested in. Other methods will be ignored. if methods is None: - methods = [ "REQUEST", "CANCEL" ] + methods = ["REQUEST", "CANCEL"] # Are all iTip messages multipart? No! RFC 6047, section 2.4 states "A # MIME body part containing content information that conforms to this @@ -38,19 +45,23 @@ # therefore also be multipart. # Check each part + # pylint: disable=too-many-nested-blocks for part in message.walk(): # The iTip part MUST be Content-Type: text/calendar (RFC 6047, section 2.4) # But in real word, other mime-types are used as well - if part.get_content_type() in [ "text/calendar", "text/x-vcalendar", "application/ics" ]: - if not str(part.get_param('method')).upper() in methods: - log.info(_("Method %r not really interesting for us.") % (part.get_param('method'))) + if part.get_content_type() in ["text/calendar", "text/x-vcalendar", "application/ics"]: + if str(part.get_param('method')).upper() not in methods: + log.info("Method %r not really interesting for us." % (part.get_param('method'))) continue # Get the itip_payload itip_payload = part.get_payload(decode=True) - log.debug(_("Raw iTip payload (%r): %r") % (part.get_param('charset'), itip_payload), level=8) + log.debug( + "Raw iTip payload (%r): %r" % (part.get_param('charset'), itip_payload), + level=8 + ) # Convert unsupported timezones, etc. itip_payload = _convert_itip_payload(itip_payload) @@ -90,33 +101,37 @@ itip['type'] = 'task' if c.name == 'VTODO' else 'event' 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 + itip['sequence'] = int(c['sequence']) if 'sequence' in c else 0 - if c.has_key('dtstart'): + itip['recurrence-id'] = None + if 'recurrence-id' in c: + if hasattr(c['recurrence-id'], 'dt'): + itip['recurrence-id'] = c['recurrence-id'].dt + + if 'dtstart' in c: itip['start'] = c['dtstart'].dt elif itip['type'] == 'event': log.error(_("iTip event without a start")) continue - if c.has_key('dtend'): + if 'dtend' in c: itip['end'] = c['dtend'].dt - if c.has_key('duration'): + if 'duration' in c: itip['duration'] = c['duration'].dt itip['end'] = itip['start'] + c['duration'].dt # Outlook can send itip replies with no organizer property - if c.has_key('organizer'): + if 'organizer' in c: itip['organizer'] = c['organizer'] - if c.has_key('attendee'): + if 'attendee' in c: itip['attendees'] = c['attendee'] - if itip.has_key('attendees') and not isinstance(itip['attendees'], list): + if 'attendees' in itip and not isinstance(itip['attendees'], list): itip['attendees'] = [c['attendee']] - if c.has_key('resources'): + if 'resources' in c: itip['resources'] = c['resources'] itip['raw'] = itip_payload @@ -127,8 +142,13 @@ itip['xml'] = todo_from_ical(c, itip_payload) else: itip['xml'] = event_from_ical(c, itip_payload) - except Exception, e: - log.error("event|todo_from_ical() exception: %r; iCal: %s" % (e, itip_payload)) + + # pylint: disable=broad-except + except Exception as e: + log.error( + "event|todo_from_ical() exception: %r; iCal: %s" % (e, itip_payload) + ) + continue itip_objects.append(itip) @@ -148,6 +168,7 @@ return itip_objects + def check_event_conflict(kolab_event, itip_event): """ Determine whether the given kolab event conflicts with the given itip event @@ -166,14 +187,11 @@ 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 - _ei = 0 + # use iCal style end date: next day for all-day events + _ee = to_dt(kolab_event.get_ical_dtend()) _is = to_dt(itip_event['start']) _ie = to_dt(itip_event['end']) - _iv = itip_event['xml'] - _ii = 0 # Escape looping through anything if neither of the events is recurring. if not itip_event['xml'].is_recurring() and not kolab_event.is_recurring(): @@ -193,10 +211,17 @@ # the older one. if _ee < _is: while _ee < _is and _es is not None and kolab_event.is_recurring(): - log.debug("Attempt to move forward kolab event recurrence from %s closer to %s" % (_ee, _is), level=8) + log.debug( + "Attempt to move forward kolab event recurrence from {} closer to {}".format( + _ee, + _is + ), + level=8 + ) + __es = to_dt(kolab_event.get_next_occurence(_es)) - if not __es is None: + if __es is not None and not __es == _es: _es = __es _ee = to_dt(kolab_event.get_occurence_end_date(_es)) else: @@ -207,10 +232,17 @@ # prime spot, this time with the iTip event. elif _ie < _es: while _ie < _es and _is is not None and itip_event['xml'].is_recurring(): - log.debug("Attempt to move forward itip event recurrence from %s closer to %s" % (_ie, _es), level=8) + log.debug( + "Attempt to move forward itip event recurrence from {} closer to {}".format( + _ie, + _es + ), + level=8 + ) + __is = to_dt(itip_event['xml'].get_next_occurence(_is)) - if not __is is None: + if __is is not None and not _is == __is: _is = __is _ie = to_dt(itip_event['xml'].get_occurence_end_date(_is)) else: @@ -219,7 +251,12 @@ # Now that we have some events somewhere in the same neighborhood... conflict = check_date_conflict(_es, _ee, _is, _ie) - log.debug("* Comparing itip at %s/%s with kolab at %s/%s: %r (%d)" % (_is, _ie, _es, _ee, conflict, loop), level=8) + log.debug( + "* Comparing itip at %s/%s with kolab at %s/%s: conflict - %r (occurence - %d)" % ( + _is, _ie, _es, _ee, conflict, loop + ), + level=8 + ) if not conflict: if kolab_event.is_recurring() and itip_event['xml'].is_recurring(): @@ -237,9 +274,11 @@ return conflict + def _is_transparent(event): return event.get_transparency() or event.get_status() == kolabformat.StatusCancelled + def _convert_itip_payload(itip): matchlist = re.findall("^((DTSTART|DTEND|DUE|EXDATE|COMPLETED)[:;][^\n]+)$", itip, re.MULTILINE) @@ -267,6 +306,7 @@ return itip + def check_date_conflict(_es, _ee, _is, _ie): """ Check the given event start/end dates for conflicts @@ -285,7 +325,7 @@ conflict = True elif _es == _is: conflict = True - else: # _es > _is + else: # _es > _is if _es < _ie: conflict = True else: @@ -304,29 +344,47 @@ smtp = None if isinstance(itip_events, dict): - itip_events = [ itip_events ] + itip_events = [itip_events] for itip_event in itip_events: attendee = itip_event['xml'].get_attendee_by_email(from_address) participant_status = itip_event['xml'].get_ical_attendee_participant_status(attendee) - log.debug(_("Send iTip reply %s for %s %r") % (participant_status, itip_event['xml'].type, itip_event['xml'].uid), level=8) + log.debug( + "Send iTip reply {} for {} {}".format( + participant_status, + itip_event['xml'].type, + itip_event['xml'].uid + ), + level=8 + ) event_summary = itip_event['xml'].get_summary() - message_text = response_text % { 'summary':event_summary, 'status':participant_status_label(participant_status), 'name':attendee.get_name() } + message_text = response_text % { + 'summary': event_summary, + 'status': participant_status_label(participant_status), + 'name': attendee.get_name() + } if subject is not None: - subject = subject % { 'summary':event_summary, 'status':participant_status_label(participant_status), 'name':attendee.get_name() } + subject = subject % { + 'summary': event_summary, + 'status': participant_status_label(participant_status), + 'name': attendee.get_name() + } try: - message = itip_event['xml'].to_message_itip(from_address, + message = itip_event['xml'].to_message_itip( + from_address, method="REPLY", participant_status=participant_status, message_text=message_text, subject=subject ) - except Exception, e: - log.error(_("Failed to compose iTip reply message: %r: %s") % (e, traceback.format_exc())) + + # pylint: disable=broad-except + except Exception as e: + log.error("Failed to compose iTip reply message: %r: %s" % (e, traceback.format_exc())) return smtp = smtplib.SMTP("localhost", 10026) # replies go through wallace again @@ -336,7 +394,9 @@ try: smtp.sendmail(message['From'], message['To'], message.as_string()) - except Exception, e: + + # pylint: disable=broad-except + except Exception as e: log.error(_("SMTP sendmail error: %r") % (e)) if smtp: @@ -353,22 +413,25 @@ smtp = None if isinstance(itip_events, dict): - itip_events = [ itip_events ] + itip_events = [itip_events] for itip_event in itip_events: event_summary = itip_event['xml'].get_summary() - message_text = request_text % { 'summary':event_summary } + message_text = request_text % {'summary': event_summary} if subject is not None: - subject = subject % { 'summary':event_summary } + subject = subject % {'summary': event_summary} try: - message = itip_event['xml'].to_message_itip(None, + message = itip_event['xml'].to_message_itip( + None, method="REQUEST", message_text=message_text, subject=subject ) - except Exception, e: + + # pylint: disable=broad-except + except Exception as e: log.error(_("Failed to compose iTip request message: %r") % (e)) return @@ -380,7 +443,9 @@ try: smtp.sendmail(message['From'], to_address, message.as_string()) - except Exception, e: + + # pylint: disable=broad-except + except Exception as e: log.error(_("SMTP sendmail error: %r") % (e)) if smtp:
View file
pykolab-0.8.13.tar.gz/pykolab/logger.py -> pykolab-0.8.14.tar.gz/pykolab/logger.py
Changed
@@ -35,16 +35,27 @@ self.logger = logger self.log_level = log_level self.linebuf = '' + self.skip_next = False def write(self, buf): - # ugly patch to make smtplib debug logging records appear on one line in log file + # ugly patch to make smtplib and smtpd debug logging records appear on one line in log file # smtplib uses "print>>stderr, var, var" statements for debug logging. These # statements are splited into separate lines on separating whitespace. + for line in buf.rstrip().splitlines(): + if self.skip_next: + self.skip_next = False + continue + if buf != '\n': - if line.startswith('send:') or line.startswith('reply:'): + linestarts = line.split(':')[0] + if linestarts in ['send', 'reply', 'Data', 'recips', 'Peer', 'sender']: self.linebuf = line - return + elif linestarts.startswith('===>'): + # Do not log lines starting with ====> + self.linebuf = '' + self.skip_next = True + continue else: self.logger.log(self.log_level, '%s %s', self.linebuf, line.rstrip()[:150]) self.linebuf = '' @@ -52,6 +63,14 @@ def flush(self): pass +class LoggerAdapter(logging.LoggerAdapter): + """ + Custom LoggingAdapter to log Wallace mail message Queue ID + """ + + def process(self, msg, kwargs): + return '%s %s' % (self.extra['qid'], msg), kwargs + class Logger(logging.Logger): """ The PyKolab version of a logger.
View file
pykolab-0.8.13.tar.gz/pykolab/setup/setup_mysql.py -> pykolab-0.8.14.tar.gz/pykolab/setup/setup_mysql.py
Changed
@@ -33,30 +33,34 @@ log = pykolab.getLogger('pykolab.setup') conf = pykolab.getConf() + def __init__(): components.register('mysql', execute, description=description()) + def cli_options(): ldap_group = conf.add_cli_parser_option_group(_("MySQL Options")) ldap_group.add_option( - "--mysqlserver", - dest = "mysqlserver", - action = "store", - help = _("Specify whether to use an (existing) or (new) MySQL server.") - ) + "--mysqlserver", + dest="mysqlserver", + action="store", + help=_("Specify whether to use an (existing) or (new) MySQL server.") + ) + def description(): return _("Setup MySQL.") -def execute(*args, **kw): + +def execute(*args, **kw): # noqa: C901 socket_paths = [ - "/var/lib/mysql/mysql.sock", - "/var/run/mysqld/mysqld.sock", - "/var/run/mysql/mysql.sock", - "/var/run/mysqld/mysqld.pid" - ] + "/var/lib/mysql/mysql.sock", + "/var/run/mysqld/mysqld.sock", + "/var/run/mysql/mysql.sock", + "/var/run/mysqld/mysqld.pid" + ] # on CentOS7, there is MariaDB instead of MySQL mysqlservice = 'mysqld.service' @@ -73,7 +77,7 @@ elif os.path.isfile('/sbin/service'): subprocess.call(['/sbin/service', 'mysqld', 'restart']) elif os.path.isfile('/usr/sbin/service'): - subprocess.call(['/usr/sbin/service','mysql','restart']) + subprocess.call(['/usr/sbin/service', 'mysql', 'restart']) else: log.error(_("Could not start the MySQL database service.")) @@ -84,8 +88,9 @@ elif os.path.isfile('/usr/sbin/update-rc.d'): subprocess.call(['/usr/sbin/update-rc.d', 'mysql', 'defaults']) else: - log.error(_("Could not configure to start on boot, the " + \ - "MySQL database service.")) + log.error( + _("Could not configure to start on boot, the MySQL database service.") + ) log.info(_("Waiting for at most 30 seconds for MySQL/MariaDB to settle...")) max_wait = 30 @@ -99,9 +104,9 @@ time.sleep(1) options = { - 1: "Existing MySQL server (with root password already set).", - 2: "New MySQL server (needs to be initialized)." - } + 1: "Existing MySQL server (with root password already set).", + 2: "New MySQL server (needs to be initialized)." + } answer = 0 if len([x for x in socket_paths if os.path.exists(x)]) > 0: @@ -115,37 +120,76 @@ if answer == "1" or answer == 1: print >> sys.stderr, utils.multiline_message( - _(""" - Please supply the root password for MySQL, so we can set - up user accounts for other components that use MySQL. - """) - ) + _(""" + Please supply the root password for MySQL, so we can set + up user accounts for other components that use MySQL. + """) + ) mysql_root_password = utils.ask_question( - _("MySQL root password"), - password=True - ) + _("MySQL root password"), + password=True + ) else: print >> sys.stderr, utils.multiline_message( - _(""" - Please supply a root password for MySQL. This password - will be the administrative user for this MySQL server, - and it should be kept a secret. After this setup process - has completed, Kolab is going to discard and forget - about this password, but you will need it for - administrative tasks in MySQL. - """) - ) + _(""" + Please supply a root password for MySQL. This password + will be the administrative user for this MySQL server, + and it should be kept a secret. After this setup process + has completed, Kolab is going to discard and forget + about this password, but you will need it for + administrative tasks in MySQL. + """) + ) mysql_root_password = utils.ask_question( - _("MySQL root password"), - default=utils.generate_password(), - password=True, - confirm=True - ) + _("MySQL root password"), + default=utils.generate_password(), + password=True, + confirm=True + ) + + p1 = subprocess.Popen( + [ + 'echo', + 'UPDATE mysql.user SET Password=PASSWORD(\'%s\') WHERE User=\'root\';' % ( + mysql_root_password + ) + ], + stdout=subprocess.PIPE + ) + + p2 = subprocess.Popen(['mysql'], stdin=p1.stdout) + p1.stdout.close() + p2.communicate() + + p1 = subprocess.Popen( + [ + 'echo', + "UPDATE mysql.user SET authentication_string=PASSWORD('%s') WHERE User='root';" % ( + mysql_root_password + ) + ], + stdout=subprocess.PIPE + ) + + p2 = subprocess.Popen(['mysql'], stdin=p1.stdout) + p1.stdout.close() + p2.communicate() + + p1 = subprocess.Popen( + [ + 'echo', + """ + UPDATE mysql.user + SET plugin='mysql_native_password' + WHERE User='root' AND plugin='auth_socket'; + """ + ], + stdout=subprocess.PIPE + ) - p1 = subprocess.Popen(['echo', 'UPDATE mysql.user SET Password=PASSWORD(\'%s\') WHERE User=\'root\';' % (mysql_root_password)], stdout=subprocess.PIPE) p2 = subprocess.Popen(['mysql'], stdin=p1.stdout) p1.stdout.close() p2.communicate() @@ -162,7 +206,7 @@ """ % (mysql_root_password) fp = open('/tmp/kolab-setup-my.cnf', 'w') - os.chmod('/tmp/kolab-setup-my.cnf', 0600) + os.chmod('/tmp/kolab-setup-my.cnf', 600) fp.write(data) fp.close() @@ -174,41 +218,74 @@ if filename.endswith('oracle.sql'): continue - schema_file = os.path.join(root,filename) + schema_file = os.path.join(root, filename) - if not schema_file == None: + if schema_file is not None: p1 = subprocess.Popen(['echo', 'create database kolab;'], stdout=subprocess.PIPE) p2 = subprocess.Popen(['mysql', '--defaults-file=/tmp/kolab-setup-my.cnf'], stdin=p1.stdout) p1.stdout.close() p2.communicate() print >> sys.stderr, utils.multiline_message( - _(""" - Please supply a password for the MySQL user 'kolab'. - This password will be used by Kolab services, such as - the Web Administration Panel. - """) - ) + _(""" + Please supply a password for the MySQL user 'kolab'. + This password will be used by Kolab services, such as + the Web Administration Panel. + """) + ) mysql_kolab_password = utils.ask_question( - _("MySQL kolab password"), - default=utils.generate_password(), - password=True, - confirm=True - ) + _("MySQL kolab password"), + default=utils.generate_password(), + password=True, + confirm=True + ) + + p1 = subprocess.Popen( + [ + 'echo', + "GRANT ALL PRIVILEGES ON kolab.* TO 'kolab'@'localhost' IDENTIFIED BY '%s';" % ( + mysql_kolab_password + ) + ], + stdout=subprocess.PIPE + ) + + p2 = subprocess.Popen( + [ + 'mysql', + '--defaults-file=/tmp/kolab-setup-my.cnf' + ], + stdin=p1.stdout + ) - p1 = subprocess.Popen(['echo', 'GRANT ALL PRIVILEGES ON kolab.* TO \'kolab\'@\'localhost\' IDENTIFIED BY \'%s\';' % (mysql_kolab_password)], stdout=subprocess.PIPE) - p2 = subprocess.Popen(['mysql', '--defaults-file=/tmp/kolab-setup-my.cnf'], stdin=p1.stdout) p1.stdout.close() p2.communicate() p1 = subprocess.Popen(['cat', schema_file], stdout=subprocess.PIPE) - p2 = subprocess.Popen(['mysql', '--defaults-file=/tmp/kolab-setup-my.cnf', 'kolab'], stdin=p1.stdout) + p2 = subprocess.Popen( + [ + 'mysql', + '--defaults-file=/tmp/kolab-setup-my.cnf', + 'kolab' + ], + stdin=p1.stdout + ) + p1.stdout.close() p2.communicate() - conf.command_set('kolab_wap', 'sql_uri', 'mysql://kolab:%s@localhost/kolab' % (mysql_kolab_password)) - conf.command_set('kolab_smtp_access_policy', 'cache_uri', 'mysql://kolab:%s@localhost/kolab' % (mysql_kolab_password)) + conf.command_set( + 'kolab_wap', + 'sql_uri', + 'mysql://kolab:%s@localhost/kolab' % (mysql_kolab_password) + ) + + conf.command_set( + 'kolab_smtp_access_policy', + 'cache_uri', + 'mysql://kolab:%s@localhost/kolab' % (mysql_kolab_password) + ) + else: log.warning(_("Could not find the MySQL Kolab schema file")) -
View file
pykolab-0.8.13.tar.gz/pykolab/setup/setup_php.py -> pykolab-0.8.14.tar.gz/pykolab/setup/setup_php.py
Changed
@@ -35,50 +35,60 @@ log = pykolab.getLogger('pykolab.setup') conf = pykolab.getConf() + def __init__(): components.register('php', execute, description=description()) + def cli_options(): php_group = conf.add_cli_parser_option_group(_("PHP Options")) php_group.add_option( - "--timezone", - dest = "timezone", - action = "store", - default = None, - help = _("Specify the timezone for PHP.") - ) + "--timezone", + dest="timezone", + action="store", + default=None, + help=_("Specify the timezone for PHP.") + ) php_group.add_option( - "--with-php-ini", - dest = "php_ini_path", - action = "store", - default = None, - help = _("Specify the path to the php.ini file used with the webserver.") - ) + "--with-php-ini", + dest="php_ini_path", + action="store", + default=None, + help=_("Specify the path to the php.ini file used with the webserver.") + ) + def description(): return _("Setup PHP.") + def execute(*args, **kw): - if conf.timezone == None: + if conf.timezone is None: print >> sys.stderr, utils.multiline_message( - _(""" - Please supply the timezone PHP should be using. - You have to use a Continent or Country / City locality name - like 'Europe/Berlin', but not just 'CEST'. - """) - ) + _(""" + Please supply the timezone PHP should be using. + You have to use a Continent or Country / City locality name + like 'Europe/Berlin', but not just 'CEST'. + """) + ) conf.timezone = utils.ask_question( - _("Timezone ID"), - default="UTC" - ) + _("Timezone ID"), + default="UTC" + ) - if not conf.php_ini_path == None: + if conf.php_ini_path is not None: if not os.path.isfile(conf.php_ini_path): - log.error(_("Cannot configure PHP through %r (No such file or directory)") % (conf.php_ini_path)) + log.error( + _("Cannot configure PHP through %r (No such file or directory)") % ( + conf.php_ini_path + ) + ) + return + php_ini = conf.php_ini_path else: @@ -98,20 +108,31 @@ log.error(_("Could not find PHP configuration file php.ini")) return - myaugeas = Augeas() - - setting_base = '/files%s/' % (php_ini) - - setting = os.path.join(setting_base, 'Date', 'date.timezone') - current_value = myaugeas.get(setting) - - if current_value == None: - insert_paths = myaugeas.match('/files%s/Date/*' % (php_ini)) - insert_path = insert_paths[(len(insert_paths)-1)] - myaugeas.insert(insert_path, 'date.timezone', False) - - log.debug(_("Setting key %r to %r") % ('Date/date.timezone', conf.timezone), level=8) - myaugeas.set(setting, conf.timezone) - - myaugeas.save() - + try: + myaugeas = Augeas() + + setting_base = '/files%s/' % (php_ini) + + setting = os.path.join(setting_base, 'Date', 'date.timezone') + current_value = myaugeas.get(setting) + + if current_value is None: + insert_paths = myaugeas.match('/files%s/Date/*' % (php_ini)) + insert_path = insert_paths[(len(insert_paths) - 1)] + myaugeas.insert(insert_path, 'date.timezone', False) + + log.debug(_("Setting key %r to %r") % ('Date/date.timezone', conf.timezone), level=8) + myaugeas.set(setting, conf.timezone) + + myaugeas.save() + except IndexError: + subprocess.Popen( + [ + 'sed', + '-i', + '-r', + '-e', + r's|^(;*)date\.timezone.*$|date.timezone = %s|g' % (conf.timezone), + php_ini + ] + )
View file
pykolab-0.8.13.tar.gz/wallace/__init__.py -> pykolab-0.8.14.tar.gz/wallace/__init__.py
Changed
@@ -26,7 +26,7 @@ import os import pwd import traceback -from smtpd import SMTPChannel +import smtpd import socket import struct import sys @@ -42,6 +42,7 @@ # pylint: disable=invalid-name log = pykolab.getLogger('pykolab.wallace') +sys.stderr = pykolab.logger.StderrToLogger(log) conf = pykolab.getConf() @@ -128,10 +129,15 @@ while True: while not self.finished.is_set(): self.finished.wait(self.interval) + log.debug(_("Timer looping function '%s' every %ss") % ( + self.function.__name__, + self.interval + ), level=8) self.function(*self.args, **self.kwargs) self.finished.set() - + log.debug(_("Timer loop %s") % ('still active','finished')[self.finished.is_set()], level=8) + break class WallaceDaemon: def __init__(self): @@ -177,6 +183,15 @@ ) daemon_group.add_option( + "--max-tasks", + dest = "max_tasks", + action = "store", + default = 10, + type = int, + help = _("Number of tasks per process.") + ) + + daemon_group.add_option( "-p", "--pid-file", dest="pidfile", action="store", @@ -226,7 +241,7 @@ self.parent_pid = os.getpid() if version.StrictVersion(sys.version[:3]) >= version.StrictVersion("2.7"): - self.pool = multiprocessing.Pool(conf.max_threads, worker_process, (), 1) + self.pool = multiprocessing.Pool(conf.max_threads, worker_process, (), conf.max_tasks) else: self.pool = multiprocessing.Pool(conf.max_threads, worker_process, ()) @@ -297,16 +312,25 @@ try: while 1: while self.current_connections >= self.max_connections: - log.debug("Out of connections.") + log.debug(_("Reached limit of max connections of: %s. Sleeping for 0.5s") % self.max_connections, level=6) time.sleep(0.5) pair = s.accept() - log.info(_("Accepted connection")) + log.debug(_("Accepted connection %r with address %r") % (pair if pair is not None else (None, None)), level=8) if pair is not None: self.current_connections += 1 connection, address = pair - SMTPChannel(self, connection, address) + + _smtpd = smtpd + # Set DEBUGSTREAM of smtpd to log to pykolab logger + if conf.debuglevel > 8: + _smtpd.DEBUGSTREAM = pykolab.logger.StderrToLogger(log) + + log.debug(_("Creating SMTPChannel for accepted message"), level=8) + channel = _smtpd.SMTPChannel(self, connection, address) asyncore.loop() + else: + log.error(_("Socket accepted, but (conn, address) tuple is None.")) # pylint: disable=broad-except except Exception: @@ -431,6 +455,7 @@ os.write(fp, data) os.close(fp) + log.debug(_("Started processing accepted message %s") % filename, level=8) self.pool.apply_async(pickup_message, (filename, (self.modules))) self.current_connections -= 1
View file
pykolab-0.8.13.tar.gz/wallace/module_footer.py -> pykolab-0.8.14.tar.gz/wallace/module_footer.py
Changed
@@ -29,7 +29,9 @@ from pykolab.translate import _ -log = pykolab.getLogger('pykolab.wallace') +log = pykolab.getLogger('pykolab.wallace/footer') +extra_log_params = {'qid': '-'} +log = pykolab.logger.LoggerAdapter(log, extra_log_params) conf = pykolab.getConf() mybasepath = '/var/spool/pykolab/wallace/footer/' @@ -49,6 +51,13 @@ return True def execute(*args, **kw): + global extra_log_params + + # TODO: Test for correct call. + filepath = args[0] + + extra_log_params['qid'] = os.path.basename(filepath) + if not os.path.isdir(mybasepath): os.makedirs(mybasepath) @@ -56,9 +65,6 @@ if not os.path.isdir(os.path.join(mybasepath, stage)): os.makedirs(os.path.join(mybasepath, stage)) - # TODO: Test for correct call. - filepath = args[0] - if 'stage' in kw: log.debug(_("Issuing callback after processing to stage %s") % (kw['stage']), level=8) log.debug(_("Testing cb_action_%s()") % (kw['stage']), level=8)
View file
pykolab-0.8.13.tar.gz/wallace/module_gpgencrypt.py -> pykolab-0.8.14.tar.gz/wallace/module_gpgencrypt.py
Changed
@@ -40,7 +40,9 @@ from pykolab.translate import _ -log = pykolab.getLogger('pykolab.wallace') +log = pykolab.getLogger('pykolab.wallace/gpgencrypt') +extra_log_params = {'qid': '-'} +log = pykolab.logger.LoggerAdapter(log, extra_log_params) conf = pykolab.getConf() mybasepath = '/var/spool/pykolab/wallace/gpgencrypt/' @@ -86,6 +88,13 @@ return msg def execute(*args, **kw): + global extra_log_params + + # TODO: Test for correct call. + filepath = args[0] + + extra_log_params['qid'] = os.path.basename(filepath) + if not os.path.isdir(mybasepath): os.makedirs(mybasepath) @@ -93,9 +102,6 @@ if not os.path.isdir(os.path.join(mybasepath, stage)): os.makedirs(os.path.join(mybasepath, stage)) - # TODO: Test for correct call. - filepath = args[0] - if kw.has_key('stage'): log.debug(_("Issuing callback after processing to stage %s") % (kw['stage']), level=8) log.debug(_("Testing cb_action_%s()") % (kw['stage']), level=8)
View file
pykolab-0.8.13.tar.gz/wallace/module_invitationpolicy.py -> pykolab-0.8.14.tar.gz/wallace/module_invitationpolicy.py
Changed
@@ -145,7 +145,10 @@ 'task': COND_TYPE_TASK } -log = pykolab.getLogger('pykolab.wallace') +log = pykolab.getLogger('pykolab.wallace/invitationpolicy') +extra_log_params = {'qid': '-'} +log = pykolab.logger.LoggerAdapter(log, extra_log_params) + conf = pykolab.getConf() mybasepath = '/var/spool/pykolab/wallace/invitationpolicy/' @@ -184,10 +187,12 @@ return """Invitation policy execution module.""" def cleanup(): - global auth, imap, write_locks + global auth, imap, write_locks, extra_log_params log.debug("cleanup(): %r, %r" % (auth, imap), level=8) + extra_log_params['qid'] = '-' + auth.disconnect() del auth @@ -200,7 +205,11 @@ remove_write_lock(key, False) def execute(*args, **kw): - global auth, imap + global auth, imap, extra_log_params + + filepath = args[0] + + extra_log_params['qid'] = os.path.basename(filepath) # (re)set language to default pykolab.translate.setUserLanguage(conf.get('kolab','default_locale')) @@ -217,8 +226,6 @@ auth = Auth() imap = IMAP() - filepath = args[0] - # ignore calls on lock files if '/locks/' in filepath or kw.has_key('stage') and kw['stage'] == 'locks': return False
View file
pykolab-0.8.13.tar.gz/wallace/module_optout.py -> pykolab-0.8.14.tar.gz/wallace/module_optout.py
Changed
@@ -35,7 +35,7 @@ from pykolab.translate import _ -log = pykolab.getLogger('pykolab.wallace') +log = pykolab.getLogger('pykolab.wallace/optout') conf = pykolab.getConf() mybasepath = '/var/spool/pykolab/wallace/optout/'
View file
pykolab-0.8.13.tar.gz/wallace/module_resources.py -> pykolab-0.8.14.tar.gz/wallace/module_resources.py
Changed
@@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +# pylint: disable=too-many-lines # Copyright 2010-2015 Kolab Systems AG (http://www.kolabsys.com) # # Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> @@ -17,40 +18,39 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # +import base64 import datetime -import icalendar + +from email import message_from_string +from email.parser import Parser +from email.utils import formataddr +from email.utils import getaddresses + import os -import pytz import random +import re import signal -import tempfile import time -from urlparse import urlparse -from dateutil.tz import tzlocal -import base64 import uuid -import re -from email import message_from_string -from email.parser import Parser -from email.utils import formataddr -from email.utils import getaddresses +from dateutil.tz import tzlocal import modules -import pykolab import kolabformat +import pykolab from pykolab.auth import Auth from pykolab.conf import Conf from pykolab.imap import IMAP +from pykolab.logger import LoggerAdapter +from pykolab.itip import events_from_message +from pykolab.itip import check_event_conflict +from pykolab.translate import _ 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 -from pykolab.itip import check_event_conflict -from pykolab.translate import _ # define some contstants used in the code below COND_NOTIFY = 256 @@ -59,14 +59,19 @@ ACT_REJECT = 8 ACT_ACCEPT_AND_NOTIFY = ACT_ACCEPT + COND_NOTIFY +# noqa: E241 policy_name_map = { - 'ACT_MANUAL': ACT_MANUAL, - 'ACT_ACCEPT': ACT_ACCEPT, - 'ACT_REJECT': ACT_REJECT, + 'ACT_MANUAL': ACT_MANUAL, # noqa: E241 + 'ACT_ACCEPT': ACT_ACCEPT, # noqa: E241 + 'ACT_REJECT': ACT_REJECT, # noqa: E241 'ACT_ACCEPT_AND_NOTIFY': ACT_ACCEPT_AND_NOTIFY } -log = pykolab.getLogger('pykolab.wallace') +# pylint: disable=invalid-name +log = pykolab.getLogger('pykolab.wallace/resources') +extra_log_params = {'qid': '-'} +log = LoggerAdapter(log, extra_log_params) + conf = pykolab.getConf() mybasepath = '/var/spool/pykolab/wallace/resources/' @@ -74,29 +79,35 @@ auth = None imap = None + def __init__(): modules.register('resources', execute, description=description(), heartbeat=heartbeat) + def accept(filepath): new_filepath = os.path.join( - mybasepath, - 'ACCEPT', - os.path.basename(filepath) - ) + mybasepath, + 'ACCEPT', + os.path.basename(filepath) + ) cleanup() os.rename(filepath, new_filepath) filepath = new_filepath - exec('modules.cb_action_ACCEPT(%r, %r)' % ('resources',filepath)) + exec('modules.cb_action_ACCEPT(%r, %r)' % ('resources', filepath)) + def description(): return """Resource management module.""" + def cleanup(): - global auth, imap + global auth, imap, extra_log_params log.debug("cleanup(): %r, %r" % (auth, imap), level=8) + extra_log_params['qid'] = '-' + auth.disconnect() del auth @@ -104,16 +115,27 @@ imap.disconnect() del imap -def execute(*args, **kw): - global auth, imap + +# pylint: disable=inconsistent-return-statements +# pylint: disable=too-many-branches +# pylint: disable=too-many-locals +# pylint: disable=too-many-return-statements +# pylint: disable=too-many-statements +def execute(*args, **kw): # noqa: C901 + global auth, imap, extra_log_params + + # TODO: Test for correct call. + filepath = args[0] + + extra_log_params['qid'] = os.path.basename(filepath) # (re)set language to default - pykolab.translate.setUserLanguage(conf.get('kolab','default_locale')) + pykolab.translate.setUserLanguage(conf.get('kolab', 'default_locale')) if not os.path.isdir(mybasepath): os.makedirs(mybasepath) - for stage in ['incoming', 'ACCEPT', 'REJECT', 'HOLD', 'DEFER' ]: + for stage in ['incoming', 'ACCEPT', 'REJECT', 'HOLD', 'DEFER']: if not os.path.isdir(os.path.join(mybasepath, stage)): os.makedirs(os.path.join(mybasepath, stage)) @@ -122,40 +144,37 @@ auth = Auth() imap = IMAP() - # TODO: Test for correct call. - filepath = args[0] - - if kw.has_key('stage'): + if 'stage' in kw: log.debug( - _("Issuing callback after processing to stage %s") % ( - kw['stage'] - ), - level=8 - ) + _("Issuing callback after processing to stage %s") % ( + kw['stage'] + ), + level=8 + ) log.debug(_("Testing cb_action_%s()") % (kw['stage']), level=8) if hasattr(modules, 'cb_action_%s' % (kw['stage'])): log.debug( - _("Attempting to execute cb_action_%s()") % (kw['stage']), - level=8 - ) + _("Attempting to execute cb_action_%s()") % (kw['stage']), + level=8 + ) exec( - 'modules.cb_action_%s(%r, %r)' % ( - kw['stage'], - 'resources', - filepath - ) + 'modules.cb_action_%s(%r, %r)' % ( + kw['stage'], + 'resources', + filepath ) + ) return filepath else: # Move to incoming new_filepath = os.path.join( - mybasepath, - 'incoming', - os.path.basename(filepath) - ) + mybasepath, + 'incoming', + os.path.basename(filepath) + ) if not filepath == new_filepath: log.debug("Renaming %r to %r" % (filepath, new_filepath)) @@ -169,8 +188,11 @@ if not message.get('X-Kolab-To'): return filepath - recipients = [address for displayname,address in getaddresses(message.get_all('X-Kolab-To'))] - sender_email = [address for displayname,address in getaddresses(message.get_all('X-Kolab-From'))][0] + recipients = [address for displayname, address in getaddresses(message.get_all('X-Kolab-To'))] + + sender_email = [ + address for displayname, address in getaddresses(message.get_all('X-Kolab-From')) + ][0] any_itips = False any_resources = False @@ -181,43 +203,46 @@ # is an iTip message by checking the length of this list. try: itip_events = events_from_message(message, ['REQUEST', 'REPLY', 'CANCEL']) - except Exception, e: - log.error(_("Failed to parse iTip events from message: %r" % (e))) + + # pylint: disable=broad-except + except Exception as errmsg: + log.error(_("Failed to parse iTip events from message: %r" % (errmsg))) itip_events = [] if not len(itip_events) > 0: - log.info( - _("Message is not an iTip message or does not contain any " + \ - "(valid) iTip.") - ) + log.info("Message is not an iTip message or does not contain any (valid) iTip.") else: any_itips = True log.debug( - _("iTip events attached to this message contain the " + \ - "following information: %r") % (itip_events), - level=8 - ) + "iTip events attached to this message contain the following information: %r" % ( + itip_events + ), + level=8 + ) if any_itips: # See if any iTip actually allocates a resource. - if len([x['resources'] for x in itip_events if x.has_key('resources')]) > 0 \ - or len([x['attendees'] for x in itip_events if x.has_key('attendees')]) > 0: - possibly_any_resources = True + if (len([x['resources'] for x in itip_events if 'resources' in x]) > 0 + or len([x['attendees'] for x in itip_events if 'attendees' in x]) > 0): + + possibly_any_resources = True if possibly_any_resources: auth.connect() for recipient in recipients: # extract reference UID from recipients like resource+UID@domain.org - if re.match('.+\+[A-Za-z0-9=/-]+@', recipient): + if re.match(r'.+\+[A-Za-z0-9=/-]+@', recipient): try: (prefix, host) = recipient.split('@') (local, uid) = prefix.split('+') reference_uid = base64.b64decode(uid, '-/') recipient = local + '@' + host - except: + + # pylint: disable=broad-except + except Exception: continue if not len(resource_record_from_email_address(recipient)) == 0: @@ -226,9 +251,14 @@ if any_resources: if not any_itips: - log.debug(_("Not an iTip message, but sent to resource nonetheless. Reject message"), level=5) + log.debug( + _("Not an iTip message, but sent to resource nonetheless. Reject message"), + level=5 + ) + reject(filepath) return False + else: # Continue. Resources and iTips. We like. pass @@ -246,11 +276,16 @@ # check if resource attendees match the envelope recipient if len(resource_dns) == 0: - log.info(_("No resource attendees matching envelope recipient %s, Reject message") % (resource_recipient)) + log.info( + _("No resource attendees matching envelope recipient %s, Reject message") % ( + resource_recipient + ) + ) + log.debug("%r" % (itip_events), level=8) reject(filepath) - return False + return False # Get the resource details, which includes details on the IMAP folder # This may append resource collection members to recource_dns @@ -269,23 +304,44 @@ # find initial reservation referenced by the reply if reference_uid: - (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) + (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=8) - except Exception, e: + log.debug( + _("Sender Attendee: %r => %r") % (sender_attendee, owner_reply), + level=8 + ) + + # pylint: disable=broad-except + except Exception as e: log.error(_("Could not find envelope sender attendee: %r") % (e)) continue # compare sequence number to avoid outdated replies if not itip_event['sequence'] == event.get_sequence(): - log.info(_("The iTip reply sequence (%r) doesn't match the referred event version (%r). Ignoring.") % ( - itip_event['sequence'], event.get_sequence() - )) + log.info( + _("The iTip reply sequence (%r) doesn't match the referred event version (%r). Ignoring.") % ( + itip_event['sequence'], + event.get_sequence() + ) + ) + continue # forward owner response comment @@ -306,7 +362,11 @@ sender_attendee.get_participant_status(True), reference_uid )) else: - log.info(_("Event referenced by this REPLY (%r) not found in resource calendar") % (reference_uid)) + log.info( + _("Event referenced by this REPLY (%r) not found in resource calendar") % ( + reference_uid + ) + ) else: log.info(_("No event reference found in this REPLY. Ignoring.")) @@ -317,9 +377,17 @@ # else: try: - receiving_attendee = itip_event['xml'].get_attendee_by_email(receiving_resource['mail']) - log.debug(_("Receiving Resource: %r; %r") % (receiving_resource, receiving_attendee), level=8) - except Exception, e: + receiving_attendee = itip_event['xml'].get_attendee_by_email( + receiving_resource['mail'] + ) + + log.debug( + _("Receiving Resource: %r; %r") % (receiving_resource, receiving_attendee), + level=8 + ) + + # pylint: disable=broad-except + except Exception as e: log.error(_("Could not find envelope attendee: %r") % (e)) continue @@ -330,23 +398,53 @@ if (att_delegated or att_nonpart) and not att_rsvp: done = True - log.debug(_("Recipient %r is non-participant, ignoring message") % (receiving_resource['mail']), level=8) + + log.debug( + _("Recipient %r is non-participant, ignoring message") % ( + receiving_resource['mail'] + ), + level=8 + ) # process CANCEL messages if not done and itip_event['method'] == "CANCEL": 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'): - (event, master) = find_existing_event(itip_event['uid'], itip_event['recurrence-id'], resources[resource]) - if event is None: - log.debug(_("Cancellation for an event %r: not found, skipping") % (itip_event['uid']), level=8) + r_emails = [a.get_email() for a in itip_event['xml'].get_attendees()] + _resource = resources[resource] + + if _resource['mail'] in r_emails and 'kolabtargetfolder' in _resource: + (event, master) = find_existing_event( + itip_event['uid'], + itip_event['recurrence-id'], + _resource + ) + + if not event: + continue + # remove entire event - elif 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) + if 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 else: - log.debug(_("Cancellation for a single occurrence %r of %r: updating...") % (itip_event['recurrence-id'], itip_event['uid']), level=8) + 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) @@ -360,9 +458,13 @@ cleanup() return - # do the magic for the receiving attendee - (available_resource, itip_event) = check_availability(itip_events, resource_dns, resources, receiving_attendee) + (available_resource, itip_event) = check_availability( + itip_events, + resource_dns, + resources, + receiving_attendee + ) _reject = False resource = None @@ -370,10 +472,12 @@ # accept reservation if available_resource is not None: - if available_resource['mail'] in [a.get_email() for a in itip_event['xml'].get_attendees()]: + atts = [a.get_email() for a in itip_event['xml'].get_attendees()] + if available_resource['mail'] in atts: # check if reservation was delegated - if available_resource['mail'] != receiving_resource['mail'] and receiving_attendee.get_participant_status() == kolabformat.PartDelegated: - original_resource = receiving_resource + if available_resource['mail'] != receiving_resource['mail']: + if receiving_attendee.get_participant_status() == kolabformat.PartDelegated: + original_resource = receiving_resource resource = available_resource else: @@ -383,20 +487,33 @@ if available_resource.has_key('memberof'): original_resource = resources[available_resource['memberof']] - if original_resource['mail'] in [a.get_email() for a in itip_event['xml'].get_attendees()]: + atts = [a.get_email() for a in itip_event['xml'].get_attendees()] + + if original_resource['mail'] in atts: # # Delegate: # - delegator: the original resource collection # - delegatee: the target resource # - itip_event['xml'].delegate(original_resource['mail'], available_resource['mail'], available_resource['cn']) + itip_event['xml'].delegate( + original_resource['mail'], + available_resource['mail'], + available_resource['cn'] + ) # set delegator to NON-PARTICIPANT and RSVP=FALSE delegator = itip_event['xml'].get_attendee_by_email(original_resource['mail']) delegator.set_role(kolabformat.NonParticipant) delegator.set_rsvp(False) - log.debug(_("Delegate invitation for resource collection %r to %r") % (original_resource['mail'], available_resource['mail']), level=8) + log.debug( + _("Delegate invitation for resource collection %r to %r") % ( + original_resource['mail'], + available_resource['mail'] + ), + level=8 + ) + resource = available_resource # Look for ACT_REJECT policy @@ -411,11 +528,32 @@ break if resource is not None and not _reject: - log.debug(_("Accept invitation for individual resource %r / %r") % (resource['dn'], resource['mail']), level=8) - accept_reservation_request(itip_event, resource, original_resource, False, invitationpolicy) + log.debug( + _("Accept invitation for individual resource %r / %r") % ( + resource['dn'], + resource['mail'] + ), + level=8 + ) + + accept_reservation_request( + itip_event, + resource, + original_resource, + False, + invitationpolicy + ) + else: resource = resources[resource_dns[0]] # this is the receiving resource record - log.debug(_("Decline invitation for individual resource %r / %r") % (resource['dn'], resource['mail']), level=8) + log.debug( + _("Decline invitation for individual resource %r / %r") % ( + resource['dn'], + resource['mail'] + ), + level=8 + ) + decline_reservation_request(itip_event, resource) cleanup() @@ -456,7 +594,8 @@ if resource_attrs.has_key('kolabtargetfolder'): try: expunge_resource_calendar(resource_attrs['kolabtargetfolder']) - except Exception, e: + # pylint: disable=broad-except + except Exception as e: log.error(_("Expunge resource calendar for %s (%s) failed: %r") % ( resource_dn, resource_attrs['kolabtargetfolder'], e )) @@ -500,11 +639,10 @@ typ, data = imap.imap.m.fetch(num, '(RFC822)') - event_message = message_from_string(data[0][1]) - try: event = event_from_message(message_from_string(data[0][1])) - except Exception, e: + # pylint: disable=broad-except + except Exception as e: log.error(_("Failed to parse event from message %s/%s: %r") % (mailbox, num, e)) continue @@ -544,7 +682,8 @@ # sets the 'conflicting' flag and adds a list of conflicting events found try: num_messages += read_resource_calendar(resources[resource], itip_events) - except Exception, e: + # pylint: disable=broad-except + except Exception as e: log.error(_("Failed to read resource calendar for %r: %r") % (resource, e)) end = time.time() @@ -697,15 +836,15 @@ try: msguid = re.search(r"\WUID (\d+)", data[0][0]).group(1) - except Exception, e: + # pylint: disable=broad-except + except Exception: log.error(_("No UID found in IMAP response: %r") % (data[0][0])) continue - event_message = message_from_string(data[0][1]) - try: event = event_from_message(message_from_string(data[0][1])) - except Exception, e: + # pylint: disable=broad-except + except Exception as e: log.error(_("Failed to parse event from message %s/%s: %r") % (mailbox, num, e)) continue @@ -749,7 +888,8 @@ try: imap.imap.m.select(imap.folder_quote(mailbox)) typ, data = imap.imap.m.search(None, '(UNDELETED HEADER SUBJECT "%s")' % (uid)) - except Exception, e: + # pylint: disable=broad-except + except Exception as e: log.error(_("Failed to access resource calendar:: %r") % (e)) return event @@ -758,7 +898,8 @@ try: msguid = re.search(r"\WUID (\d+)", data[0][0]).group(1) - except Exception, e: + # pylint: disable=broad-except + except Exception as e: log.error(_("No UID found in IMAP response: %r") % (data[0][0])) continue @@ -785,7 +926,8 @@ if event is not None: setattr(event, '_msguid', msguid) - except Exception, e: + # pylint: disable=broad-except + except Exception as e: log.error(_("Failed to parse event from message %s/%s: %r") % (mailbox, num, e)) event = None master = None @@ -911,7 +1053,8 @@ ) return result - except Exception, e: + # pylint: disable=broad-except + except Exception as e: log.error(_("Failed to save event to resource calendar at %r: %r") % ( resource['kolabtargetfolder'], e )) @@ -949,7 +1092,8 @@ imap.imap.m.expunge() return True - except Exception, e: + # pylint: disable=broad-except + except Exception as e: log.error(_("Failed to delete calendar object %r from folder %r: %r") % ( uid, targetfolder, e ))
View file
pykolab-0.8.13.tar.gz/wallace/module_signature.py -> pykolab-0.8.14.tar.gz/wallace/module_signature.py
Changed
@@ -33,7 +33,9 @@ from pykolab.translate import _ # pylint: disable=invalid-name -log = pykolab.getLogger('pykolab.wallace') +log = pykolab.getLogger('pykolab.wallace/signature') +extra_log_params = {'qid': '-'} +log = pykolab.logger.LoggerAdapter(log, extra_log_params) conf = pykolab.getConf() mybasepath = '/var/spool/pykolab/wallace/signature/' @@ -78,6 +80,13 @@ # pylint: disable=too-many-branches,too-many-locals,too-many-statements def execute(*args, **kw): # noqa: C901 + global extra_log_params + + # TODO: Test for correct call. + filepath = args[0] + + extra_log_params['qid'] = os.path.basename(filepath) + if not os.path.isdir(mybasepath): os.makedirs(mybasepath) @@ -85,9 +94,6 @@ if not os.path.isdir(os.path.join(mybasepath, stage)): os.makedirs(os.path.join(mybasepath, stage)) - # TODO: Test for correct call. - filepath = args[0] - if 'stage' in kw: log.debug(_("Issuing callback after processing to stage %s") % (kw['stage']), level=8) log.debug(_("Testing cb_action_%s()") % (kw['stage']), level=8)
View file
pykolab-0.8.13.tar.gz/wallace/modules.py -> pykolab-0.8.14.tar.gz/wallace/modules.py
Changed
@@ -42,7 +42,10 @@ from pykolab import constants from pykolab.translate import _ -log = pykolab.getLogger('pykolab.wallace') +log = pykolab.getLogger('pykolab.wallace/modules') +extra_log_params = {'qid': '-'} +log = pykolab.logger.LoggerAdapter(log, extra_log_params) + conf = pykolab.getConf() modules = {} @@ -204,9 +207,17 @@ return success def cb_action_HOLD(module, filepath): + global extra_log_params + + extra_log_params['qid'] = os.path.basename(filepath) + log.info(_("Holding message in queue for manual review (%s by %s)") % (filepath, module)) def cb_action_DEFER(module, filepath): + global extra_log_params + + extra_log_params['qid'] = os.path.basename(filepath) + log.info(_("Deferring message in %s (by module %s)") % (filepath, module)) # parse message headers @@ -250,6 +261,10 @@ #os.unlink(filepath) def cb_action_REJECT(module, filepath): + global extra_log_params + + extra_log_params['qid'] = os.path.basename(filepath) + log.info(_("Rejecting message in %s (by module %s)") % (filepath, module)) log.debug(_("Rejecting message in: %r") %(filepath), level=8) @@ -336,6 +351,10 @@ def cb_action_ACCEPT(module, filepath): + global extra_log_params + + extra_log_params['qid'] = os.path.basename(filepath) + log.info(_("Accepting message in %s (by module %s)") % (filepath, module)) log.debug(_("Accepting message in: %r") %(filepath), level=8)
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.8.13-0~kolab5 +Version: 0.8.14-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.8.13.tar.gz + 00000000000000000000000000000000 0 pykolab-0.8.14.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
.