summaryrefslogtreecommitdiffstats
path: root/wallace
diff options
context:
space:
mode:
Diffstat (limited to 'wallace')
-rw-r--r--wallace/module_footer.py4
-rw-r--r--wallace/module_gpgencrypt.py4
-rw-r--r--wallace/module_invitationpolicy.py62
-rw-r--r--wallace/module_optout.py12
-rw-r--r--wallace/module_resources.py84
-rw-r--r--wallace/module_signature.py2
-rw-r--r--wallace/modules.py8
7 files changed, 104 insertions, 72 deletions
diff --git a/wallace/module_footer.py b/wallace/module_footer.py
index 73916fb..2833a59 100644
--- a/wallace/module_footer.py
+++ b/wallace/module_footer.py
@@ -165,12 +165,12 @@ def execute(*args, **kw):
if content_type == "text/plain":
content = part.get_payload(decode=True)
- content = append_footer(content, footer['plain'], footer_position, false)
+ content = append_footer(content, footer['plain'], footer_position, False)
footer_added = set_part_content(part, content)
elif content_type == "text/html":
content = part.get_payload(decode=True)
- content = append_footer(content, footer['html'], footer_position, true)
+ content = append_footer(content, footer['html'], footer_position, True)
footer_added = set_part_content(part, content)
if footer_added:
diff --git a/wallace/module_gpgencrypt.py b/wallace/module_gpgencrypt.py
index e623fe1..9083055 100644
--- a/wallace/module_gpgencrypt.py
+++ b/wallace/module_gpgencrypt.py
@@ -102,7 +102,7 @@ def execute(*args, **kw):
if not os.path.isdir(os.path.join(mybasepath, stage)):
os.makedirs(os.path.join(mybasepath, stage))
- if kw.has_key('stage'):
+ 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)
if hasattr(modules, 'cb_action_%s' % (kw['stage'])):
@@ -286,7 +286,7 @@ def execute(*args, **kw):
os.unlink(filepath)
exec('modules.cb_action_%s(%r, %r)' % ('ACCEPT','gpgencrypt', new_filepath))
- except Exception, errmsg:
+ except Exception as errmsg:
log.error(_("An error occurred: %r") % (errmsg))
if conf.debuglevel > 8:
import traceback
diff --git a/wallace/module_invitationpolicy.py b/wallace/module_invitationpolicy.py
index 46e506d..63d8879 100644
--- a/wallace/module_invitationpolicy.py
+++ b/wallace/module_invitationpolicy.py
@@ -138,7 +138,7 @@ policy_name_map = {
'ACT_SAVE_AND_FORWARD': ACT_SAVE_AND_FORWARD + COND_TYPE_EVENT,
}
-policy_value_map = dict([(v &~ COND_TYPE_ALL, k) for (k, v) in policy_name_map.iteritems()])
+policy_value_map = dict([(v &~ COND_TYPE_ALL, k) for (k, v) in policy_name_map.items()])
object_type_conditons = {
'event': COND_TYPE_EVENT,
@@ -227,12 +227,12 @@ def execute(*args, **kw):
imap = IMAP()
# ignore calls on lock files
- if '/locks/' in filepath or kw.has_key('stage') and kw['stage'] == 'locks':
+ if '/locks/' in filepath or 'stage' in kw and kw['stage'] == 'locks':
return False
log.debug("Invitation policy executing for %r, %r" % (filepath, '/locks/' in filepath), level=8)
- if kw.has_key('stage'):
+ 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)
@@ -280,7 +280,7 @@ def execute(*args, **kw):
# is an iTip message by checking the length of this list.
try:
itip_events = objects_from_message(message, ['VEVENT','VTODO'], ['REQUEST', 'REPLY', 'CANCEL'])
- except Exception, errmsg:
+ except Exception as errmsg:
log.error(_("Failed to parse iTip objects from message: %r" % (errmsg)))
itip_events = []
@@ -292,7 +292,7 @@ def execute(*args, **kw):
log.debug(_("iTip objects attached to this message contain the following information: %r") % (itip_events), level=8)
# See if any iTip actually allocates a user.
- if any_itips and len([x['uid'] for x in itip_events if x.has_key('attendees') or x.has_key('organizer')]) > 0:
+ if any_itips and len([x['uid'] for x in itip_events if 'attendees' in x or 'organizer' in x]) > 0:
auth.connect()
# we're looking at the first itip object
@@ -329,7 +329,7 @@ def execute(*args, **kw):
# for replies, the organizer is the recipient
if itip_event['method'] == 'REPLY':
# Outlook can send iTip replies without an organizer property
- if itip_event.has_key('organizer'):
+ if 'organizer' in itip_event:
organizer_mailto = str(itip_event['organizer']).split(':')[-1]
user_attendees = [organizer_mailto] if organizer_mailto in recipient_emails else []
else:
@@ -337,10 +337,10 @@ def execute(*args, **kw):
else:
# Limit the attendees to the one that is actually invited with the current message.
- attendees = [str(a).split(':')[-1] for a in (itip_event['attendees'] if itip_event.has_key('attendees') else [])]
+ attendees = [str(a).split(':')[-1] for a in (itip_event['attendees'] if 'attendees' in itip_event else [])]
user_attendees = [a for a in attendees if a in recipient_emails]
- if itip_event.has_key('organizer'):
+ if 'organizer' in itip_event:
sender_email = itip_event['xml'].get_organizer().email()
# abort if no attendee matches the envelope recipient
@@ -354,7 +354,7 @@ def execute(*args, **kw):
recipient_email = user_attendees[0]
# change gettext language to the preferredlanguage setting of the receiving user
- if receiving_user.has_key('preferredlanguage'):
+ if 'preferredlanguage' in receiving_user:
pykolab.translate.setUserLanguage(receiving_user['preferredlanguage'])
# find user's kolabInvitationPolicy settings and the matching policy values
@@ -369,7 +369,7 @@ def execute(*args, **kw):
}
done = None
- if method_processing_map.has_key(itip_event['method']):
+ if itip_event['method'] in method_processing_map:
processor_func = method_processing_map[itip_event['method']]
# connect as cyrus-admin
@@ -413,7 +413,7 @@ def process_itip_request(itip_event, policy, recipient_email, sender_email, rece
try:
receiving_attendee = itip_event['xml'].get_attendee_by_email(recipient_email)
log.debug(_("Receiving attendee: %r") % (receiving_attendee.to_dict()), level=8)
- except Exception, errmsg:
+ except Exception as errmsg:
log.error("Could not find envelope attendee: %r" % (errmsg))
return MESSAGE_FORWARD
@@ -486,7 +486,7 @@ def process_itip_request(itip_event, policy, recipient_email, sender_email, rece
# if RSVP, send an iTip REPLY
if rsvp or scheduling_required:
# set attendee's CN from LDAP record if yet missing
- if not receiving_attendee.get_name() and receiving_user.has_key('cn'):
+ if not receiving_attendee.get_name() and 'cn' in receiving_user:
receiving_attendee.set_name(receiving_user['cn'])
# send iTip reply
@@ -542,7 +542,7 @@ def process_itip_reply(itip_event, policy, recipient_email, sender_email, receiv
try:
sender_attendee = itip_event['xml'].get_attendee_by_email(sender_email)
log.debug(_("Sender Attendee: %r") % (sender_attendee), level=8)
- except Exception, errmsg:
+ except Exception as errmsg:
log.error("Could not find envelope sender attendee: %r" % (errmsg))
return MESSAGE_FORWARD
@@ -565,7 +565,7 @@ def process_itip_reply(itip_event, policy, recipient_email, sender_email, receiv
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, errmsg:
+ except Exception as errmsg:
log.error("Could not find corresponding attende in organizer's copy: %r" % (errmsg))
# append delegated-from attendee ?
@@ -598,7 +598,7 @@ def process_itip_reply(itip_event, policy, recipient_email, sender_email, receiv
existing.update_attendees([existing_attendee])
log.debug(_("Update delegator: %r") % (existing_attendee.to_dict()), level=8)
- except Exception, errmsg:
+ except Exception as errmsg:
log.error("Could not find delegated-to attendee: %r" % (errmsg))
# update the organizer's copy of the object
@@ -693,7 +693,7 @@ def user_dn_from_email_address(email_address):
auth.connect()
# return cached value
- if user_dn_from_email_address.cache.has_key(email_address):
+ if email_address in user_dn_from_email_address.cache:
return user_dn_from_email_address.cache[email_address]
local_domains = auth.list_domains()
@@ -724,7 +724,7 @@ user_dn_from_email_address.cache = {}
def get_matching_invitation_policies(receiving_user, sender_email, type_condition=COND_TYPE_ALL):
# get user's kolabInvitationPolicy settings
- policies = receiving_user['kolabinvitationpolicy'] if receiving_user.has_key('kolabinvitationpolicy') else []
+ policies = receiving_user['kolabinvitationpolicy'] if 'kolabinvitationpolicy' in receiving_user else []
if policies and not isinstance(policies, list):
policies = [policies]
@@ -742,7 +742,7 @@ def get_matching_invitation_policies(receiving_user, sender_email, type_conditio
if domain == '' or domain == '*' or str(sender_email).endswith(domain):
value = value.upper()
- if policy_name_map.has_key(value):
+ if value in policy_name_map:
val = policy_name_map[value]
# append if type condition matches
if val & type_condition:
@@ -767,7 +767,7 @@ def imap_proxy_auth(user_rec):
mail_attribute = mail_attribute.lower()
- if not user_rec.has_key(mail_attribute):
+ if mail_attribute not in user_rec:
log.error(_("User record doesn't have the mailbox attribute %r set" % (mail_attribute)))
return False
@@ -780,7 +780,7 @@ def imap_proxy_auth(user_rec):
imap.disconnect()
imap.connect(login=False)
imap.login_plain(admin_login, admin_password, user_rec[mail_attribute])
- except Exception, errmsg:
+ except Exception as errmsg:
log.error(_("IMAP proxy authentication failed: %r") % (errmsg))
return False
@@ -910,7 +910,7 @@ def find_existing_object(uid, type, recurrence_id, user_rec, lock=False):
try:
msguid = re.search(r"\WUID (\d+)", data[0][0]).group(1)
- except Exception, errmsg:
+ except Exception:
log.error(_("No UID found in IMAP response: %r") % (data[0][0]))
continue
@@ -936,7 +936,7 @@ def find_existing_object(uid, type, recurrence_id, user_rec, lock=False):
setattr(event, '_lock_key', lock_key)
setattr(event, '_msguid', msguid)
- except Exception, errmsg:
+ except Exception:
log.error(_("Failed to parse %s from message %s/%s: %s") % (type, folder, num, traceback.format_exc()))
event = None
master = None
@@ -961,7 +961,7 @@ def check_availability(itip_event, receiving_user):
conflict = False
# return previously detected conflict
- if itip_event.has_key('_conflicts'):
+ if '_conflicts' in itip_event:
return not itip_event['_conflicts']
for folder in list_user_folders(receiving_user, 'event'):
@@ -977,7 +977,7 @@ def check_availability(itip_event, receiving_user):
try:
event = event_from_message(message_from_string(data[0][1]))
- except Exception, errmsg:
+ except Exception as errmsg:
log.error(_("Failed to parse event from message %s/%s: %r") % (folder, num, errmsg))
continue
@@ -1087,12 +1087,12 @@ def store_object(object, user_rec, targetfolder=None, master=None):
oc = object.get_classification()
# use *.confidential/private folder for confidential/private invitations
- if oc == kolabformat.ClassConfidential and user_rec.has_key('_confidential_folder'):
+ if oc == kolabformat.ClassConfidential and '_confidential_folder' in user_rec:
targetfolder = user_rec['_confidential_folder']
- elif oc == kolabformat.ClassPrivate and user_rec.has_key('_private_folder'):
+ elif oc == kolabformat.ClassPrivate and '_private_folder' in user_rec:
targetfolder = user_rec['_private_folder']
# use *.default folder if exists
- elif user_rec.has_key('_default_folder'):
+ elif '_default_folder' in user_rec:
targetfolder = user_rec['_default_folder']
# fallback to any existing folder of specified type
elif targetfolders is not None and len(targetfolders) > 0:
@@ -1122,7 +1122,7 @@ def store_object(object, user_rec, targetfolder=None, master=None):
)
return result
- except Exception, errmsg:
+ except Exception as errmsg:
log.error(_("Failed to save %s to user folder at %r: %r") % (
saveobj.type, targetfolder, errmsg
))
@@ -1160,7 +1160,7 @@ def delete_object(existing):
imap.imap.m.expunge()
return True
- except Exception, errmsg:
+ except Exception as errmsg:
log.error(_("Failed to delete %s from folder %r: %r") % (
existing.type, targetfolder, errmsg
))
@@ -1205,7 +1205,7 @@ def send_update_notification(object, receiving_user, old=None, reply=True, sende
for attendee in object.get_attendees():
parstat = attendee.get_participant_status(True)
- if partstats.has_key(parstat):
+ if parstat in partstats:
partstats[parstat].append(attendee.get_displayname())
else:
partstats['PENDING'].append(attendee.get_displayname())
@@ -1243,7 +1243,7 @@ def send_update_notification(object, receiving_user, old=None, reply=True, sende
if itip_comment is not None:
roundup += "\n" + itip_comment
- for status,attendees in partstats.iteritems():
+ for status,attendees in partstats.items():
if len(attendees) > 0:
roundup += "\n" + participant_status_label(status) + ":\n\t" + "\n\t".join(attendees) + "\n"
else:
diff --git a/wallace/module_optout.py b/wallace/module_optout.py
index 632753f..c710180 100644
--- a/wallace/module_optout.py
+++ b/wallace/module_optout.py
@@ -57,7 +57,7 @@ def execute(*args, **kw):
# 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)
log.debug(_("Testing cb_action_%s()") % (kw['stage']), level=8)
if hasattr(modules, 'cb_action_%s' % (kw['stage'])):
@@ -90,7 +90,7 @@ def execute(*args, **kw):
"Cc": []
}
- for recipient_type in recipients.keys():
+ for recipient_type in recipients:
for recipient in recipients[recipient_type]:
log.debug(
_("Running opt-out consult from envelope sender '%s " + \
@@ -136,7 +136,7 @@ def execute(*args, **kw):
use_this = False
- for recipient_type in _recipients[answer].keys():
+ for recipient_type in _recipients[answer]:
_message.__delitem__(recipient_type)
if not len(_recipients[answer][recipient_type]) == 0:
_message.__setitem__(
@@ -177,7 +177,7 @@ def request(params=None):
try:
f = urllib.urlopen(optout_url, params)
- except Exception, e:
+ except Exception:
log.error(_("Could not send request to optout_url %s") % (optout_url))
return "DEFER"
@@ -185,8 +185,8 @@ def request(params=None):
try:
response_data = json.loads(response)
- except ValueError, e:
+ except ValueError:
# Some data is not JSON
- print "Response data is not JSON"
+ print("Response data is not JSON")
return response_data['result']
diff --git a/wallace/module_resources.py b/wallace/module_resources.py
index 798577d..e29f193 100644
--- a/wallace/module_resources.py
+++ b/wallace/module_resources.py
@@ -58,14 +58,17 @@ COND_NOTIFY = 256
ACT_MANUAL = 1
ACT_ACCEPT = 2
ACT_REJECT = 8
+ACT_STORE = 16
ACT_ACCEPT_AND_NOTIFY = ACT_ACCEPT + COND_NOTIFY
+ACT_STORE_AND_NOTIFY = ACT_STORE + COND_NOTIFY
# noqa: E241
policy_name_map = {
'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
+ 'ACT_ACCEPT_AND_NOTIFY': ACT_ACCEPT_AND_NOTIFY,
+ 'ACT_STORE_AND_NOTIFY': ACT_STORE_AND_NOTIFY
}
# pylint: disable=invalid-name
@@ -705,7 +708,7 @@ def check_availability(itip_events, resource_dns, resources, receiving_attendee=
num_messages = 0
available_resource = None
- for resource in resources.keys():
+ for resource in resources:
# skip this for resource collections
if 'kolabtargetfolder' not in resources[resource]:
continue
@@ -1031,11 +1034,14 @@ def accept_reservation_request(
):
"""
Accepts the given iTip event by booking it into the resource's
- calendar. Then set the attendee status of the given resource to
- ACCEPTED and sends an iTip reply message to the organizer.
+ calendar. Then, depending on the policy, set the attendee status of the given resource to
+ ACCEPTED/TENTATIVE and send an iTip reply message to the organizer, or set the status to
+ NEEDS-ACTION and don't send a reply to the organizer.
"""
owner = get_resource_owner(resource)
confirmation_required = False
+ do_send_response = True
+ partstat = 'ACCEPTED'
if not confirmed and owner:
if invitationpolicy is None:
@@ -1046,9 +1052,13 @@ def accept_reservation_request(
for policy in invitationpolicy:
if policy & ACT_MANUAL and owner['mail']:
confirmation_required = True
+ partstat = 'TENTATIVE'
+ break
+ if policy & ACT_STORE:
+ partstat = 'NEEDS-ACTION'
+ # Do not send an immediate response to the organizer
+ do_send_response = False
break
-
- partstat = 'TENTATIVE' if confirmation_required else 'ACCEPTED'
itip_event['xml'].set_transparency(False)
itip_event['xml'].set_attendee_participant_status(
@@ -1063,7 +1073,7 @@ def accept_reservation_request(
level=8
)
- if saved:
+ if saved and do_send_response:
send_response(delegator['mail'] if delegator else resource['mail'], itip_event, owner)
if owner and confirmation_required:
@@ -1110,7 +1120,6 @@ def save_resource_event(itip_event, resource):
"""
try:
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:
@@ -1132,18 +1141,17 @@ def save_resource_event(itip_event, resource):
else:
imap.set_acl(
- targetfolder,
+ resource['kolabtargetfolder'],
conf.get(conf.get('kolab', 'imap_backend'), 'admin_login'),
"lrswipkxtecda"
)
# append new version
- result = imap.imap.m.append(
- targetfolder,
- None,
- None,
+ result = imap.append(
+ resource['kolabtargetfolder'],
save_event.to_message(creator="Kolab Server <wallace@localhost>").as_string()
)
+
return result
# pylint: disable=broad-except
@@ -1642,16 +1650,21 @@ def send_owner_notification(resource, owner, itip_event, success=True):
if 'preferredlanguage' in owner:
pykolab.translate.setUserLanguage(owner['preferredlanguage'])
- message_text = owner_notification_text(resource, owner, itip_event['xml'], success)
+ message_text = owner_notification_text(resource, owner, itip_event['xml'], success, status)
msg = MIMEText(utils.stripped_message(message_text), _charset='utf-8')
msg['To'] = owner['mail']
msg['From'] = resource['mail']
msg['Date'] = formatdate(localtime=True)
- msg['Subject'] = utils.str2unicode(_('Booking for %s has been %s') % (
- resource['cn'], participant_status_label(status) if success else _('failed')
- ))
+ if status == 'NEEDS-ACTION':
+ msg['Subject'] = utils.str2unicode(_('New booking request for %s') % (
+ resource['cn']
+ ))
+ else:
+ msg['Subject'] = utils.str2unicode(_('Booking for %s has been %s') % (
+ resource['cn'], participant_status_label(status) if success else _('failed')
+ ))
seed = random.randint(0, 6)
alarm_after = (seed * 10) + 60
@@ -1663,19 +1676,37 @@ def send_owner_notification(resource, owner, itip_event, success=True):
signal.alarm(0)
-def owner_notification_text(resource, owner, event, success):
+def owner_notification_text(resource, owner, event, success, status):
organizer = event.get_organizer()
status = event.get_attendee_by_email(resource['mail']).get_participant_status(True)
+ domain = resource['mail'].split('@')[1]
+ url = conf.get('wallace', 'webmail_url')
if success:
- message_text = _(
- """
- The resource booking for %(resource)s by %(orgname)s <%(orgemail)s> has been
- %(status)s for %(date)s.
+ if status == 'NEEDS-ACTION':
+ message_text = _(
+ """
+ The resource booking request is for %(resource)s by %(orgname)s <%(orgemail)s> for %(date)s.
- *** This is an automated message, sent to you as the resource owner. ***
- """
- )
+ *** This is an automated message, sent to you as the resource owner. ***
+ """
+ )
+ else:
+ message_text = _(
+ """
+ The resource booking for %(resource)s by %(orgname)s <%(orgemail)s> has been
+ %(status)s for %(date)s.
+
+ *** This is an automated message, sent to you as the resource owner. ***
+ """
+ )
+
+
+ if url:
+ message_text += (
+ "\n "
+ + _("You can change the status via %(url)s") % { 'url': url } + '?_task=calendar'
+ )
else:
message_text = _(
"""
@@ -1695,7 +1726,8 @@ def owner_notification_text(resource, owner, event, success):
'date': event.get_date_text(),
'status': participant_status_label(status),
'orgname': organizer.name(),
- 'orgemail': organizer.email()
+ 'orgemail': organizer.email(),
+ 'domain': domain
}
diff --git a/wallace/module_signature.py b/wallace/module_signature.py
index dda2d92..c483d93 100644
--- a/wallace/module_signature.py
+++ b/wallace/module_signature.py
@@ -163,7 +163,7 @@ def execute(*args, **kw): # noqa: C901
if not signature_html and not signature_text and signature_rules is not None:
for signature_rule in signature_rules:
try:
- for attr, regex in signature_rule.iteritems():
+ for attr, regex in signature_rule.items():
if attr == "html":
if not os.path.exists(signature_rule['html']):
raise ValueError
diff --git a/wallace/modules.py b/wallace/modules.py
index 3f27bbd..aed60b6 100644
--- a/wallace/modules.py
+++ b/wallace/modules.py
@@ -78,7 +78,7 @@ def list_modules(*args, **kw):
__modules = {}
- for module in modules.keys():
+ for module in modules:
if isinstance(module, tuple):
module_group, module = module
__modules[module_group] = {
@@ -133,10 +133,10 @@ def execute(name, *args, **kw):
log.exception(_("Module %r - Unknown error occurred; %r") % (name, errmsg))
def heartbeat(name, *args, **kw):
- if not modules.has_key(name):
+ if name not in modules:
log.warning(_("No such module %r in modules %r (1).") % (name, modules))
- if modules[name].has_key('heartbeat'):
+ if 'heartbeat' in modules[name]:
return modules[name]['heartbeat'](*args, **kw)
def _sendmail(sender, recipients, msg):
@@ -426,7 +426,7 @@ def register(name, func, group=None, description=None, aliases=[], heartbeat=Non
if isinstance(aliases, basestring):
aliases = [aliases]
- if modules.has_key(module):
+ if module in modules:
log.fatal(_("Module '%s' already registered") % (module))
sys.exit(1)