Changeset View
Standalone View
wallace/module_invitationpolicy.py
Show First 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
from pykolab.xml import event_from_message | from pykolab.xml import event_from_message | ||||
from pykolab.xml import participant_status_label | from pykolab.xml import participant_status_label | ||||
from pykolab.itip import objects_from_message | from pykolab.itip import objects_from_message | ||||
from pykolab.itip import check_event_conflict | from pykolab.itip import check_event_conflict | ||||
from pykolab.itip import send_reply | from pykolab.itip import send_reply | ||||
from pykolab.translate import _ | from pykolab.translate import _ | ||||
# define some contstants used in the code below | # define some contstants used in the code below | ||||
ACT_MANUAL = 1 | ACT_MANUAL = 1 | ||||
Lint: PEP8 E221: multiple spaces before operator | |||||
ACT_ACCEPT = 2 | ACT_ACCEPT = 2 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
ACT_DELEGATE = 4 | ACT_DELEGATE = 4 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
ACT_REJECT = 8 | ACT_REJECT = 8 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
ACT_UPDATE = 16 | ACT_UPDATE = 16 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
ACT_CANCEL_DELETE = 32 | ACT_CANCEL_DELETE = 32 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
ACT_SAVE_TO_FOLDER = 64 | ACT_SAVE_TO_FOLDER = 64 | ||||
COND_IF_AVAILABLE = 128 | COND_IF_AVAILABLE = 128 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
COND_IF_CONFLICT = 256 | COND_IF_CONFLICT = 256 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
COND_TENTATIVE = 512 | COND_TENTATIVE = 512 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
COND_NOTIFY = 1024 | COND_NOTIFY = 1024 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
COND_FORWARD = 2048 | COND_FORWARD = 2048 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
COND_TYPE_EVENT = 4096 | COND_TYPE_EVENT = 4096 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
COND_TYPE_TASK = 8192 | COND_TYPE_TASK = 8192 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
COND_TYPE_ALL = COND_TYPE_EVENT + COND_TYPE_TASK | COND_TYPE_ALL = COND_TYPE_EVENT + COND_TYPE_TASK | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
ACT_TENTATIVE = ACT_ACCEPT + COND_TENTATIVE | ACT_TENTATIVE = ACT_ACCEPT + COND_TENTATIVE | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
ACT_UPDATE_AND_NOTIFY = ACT_UPDATE + COND_NOTIFY | ACT_UPDATE_AND_NOTIFY = ACT_UPDATE + COND_NOTIFY | ||||
ACT_SAVE_AND_FORWARD = ACT_SAVE_TO_FOLDER + COND_FORWARD | ACT_SAVE_AND_FORWARD = ACT_SAVE_TO_FOLDER + COND_FORWARD | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
ACT_CANCEL_DELETE_AND_NOTIFY = ACT_CANCEL_DELETE + COND_NOTIFY | ACT_CANCEL_DELETE_AND_NOTIFY = ACT_CANCEL_DELETE + COND_NOTIFY | ||||
FOLDER_TYPE_ANNOTATION = '/vendor/kolab/folder-type' | FOLDER_TYPE_ANNOTATION = '/vendor/kolab/folder-type' | ||||
MESSAGE_PROCESSED = 1 | MESSAGE_PROCESSED = 1 | ||||
MESSAGE_FORWARD = 2 | MESSAGE_FORWARD = 2 | ||||
Lint: PEP8 E221 multiple spaces before operator Lint: PEP8 E221: multiple spaces before operator | |||||
policy_name_map = { | policy_name_map = { | ||||
# policy values applying to all object types | # policy values applying to all object types | ||||
'ALL_MANUAL': ACT_MANUAL + COND_TYPE_ALL, | 'ALL_MANUAL': ACT_MANUAL + COND_TYPE_ALL, | ||||
'ALL_ACCEPT': ACT_ACCEPT + COND_TYPE_ALL, | 'ALL_ACCEPT': ACT_ACCEPT + COND_TYPE_ALL, | ||||
'ALL_REJECT': ACT_REJECT + COND_TYPE_ALL, | 'ALL_REJECT': ACT_REJECT + COND_TYPE_ALL, | ||||
'ALL_DELEGATE': ACT_DELEGATE + COND_TYPE_ALL, # not implemented | 'ALL_DELEGATE': ACT_DELEGATE + COND_TYPE_ALL, # not implemented | ||||
Lint: PEP8 E501 line too long (86 > 79 characters) Lint: PEP8 E501: line too long (86 > 79 characters) | |||||
'ALL_UPDATE': ACT_UPDATE + COND_TYPE_ALL, | 'ALL_UPDATE': ACT_UPDATE + COND_TYPE_ALL, | ||||
'ALL_UPDATE_AND_NOTIFY': ACT_UPDATE_AND_NOTIFY + COND_TYPE_ALL, | 'ALL_UPDATE_AND_NOTIFY': ACT_UPDATE_AND_NOTIFY + COND_TYPE_ALL, | ||||
'ALL_SAVE_TO_FOLDER': ACT_SAVE_TO_FOLDER + COND_TYPE_ALL, | 'ALL_SAVE_TO_FOLDER': ACT_SAVE_TO_FOLDER + COND_TYPE_ALL, | ||||
'ALL_SAVE_AND_FORWARD': ACT_SAVE_AND_FORWARD + COND_TYPE_ALL, | 'ALL_SAVE_AND_FORWARD': ACT_SAVE_AND_FORWARD + COND_TYPE_ALL, | ||||
'ALL_CANCEL_DELETE': ACT_CANCEL_DELETE + COND_TYPE_ALL, | 'ALL_CANCEL_DELETE': ACT_CANCEL_DELETE + COND_TYPE_ALL, | ||||
'ALL_CANCEL_DELETE_AND_NOTIFY': ACT_CANCEL_DELETE_AND_NOTIFY + COND_TYPE_ALL, | 'ALL_CANCEL_DELETE_AND_NOTIFY': ACT_CANCEL_DELETE_AND_NOTIFY + COND_TYPE_ALL, | ||||
Lint: PEP8 E501 line too long (83 > 79 characters) Lint: PEP8 E501: line too long (83 > 79 characters) | |||||
# event related policy values | # event related policy values | ||||
'EVENT_MANUAL': ACT_MANUAL + COND_TYPE_EVENT, | 'EVENT_MANUAL': ACT_MANUAL + COND_TYPE_EVENT, | ||||
'EVENT_ACCEPT': ACT_ACCEPT + COND_TYPE_EVENT, | 'EVENT_ACCEPT': ACT_ACCEPT + COND_TYPE_EVENT, | ||||
'EVENT_TENTATIVE': ACT_TENTATIVE + COND_TYPE_EVENT, | 'EVENT_TENTATIVE': ACT_TENTATIVE + COND_TYPE_EVENT, | ||||
'EVENT_REJECT': ACT_REJECT + COND_TYPE_EVENT, | 'EVENT_REJECT': ACT_REJECT + COND_TYPE_EVENT, | ||||
'EVENT_DELEGATE': ACT_DELEGATE + COND_TYPE_EVENT, # not implemented | 'EVENT_DELEGATE': ACT_DELEGATE + COND_TYPE_EVENT, # not implemented | ||||
Lint: PEP8 E501 line too long (88 > 79 characters) Lint: PEP8 E501: line too long (88 > 79 characters) | |||||
'EVENT_UPDATE': ACT_UPDATE + COND_TYPE_EVENT, | 'EVENT_UPDATE': ACT_UPDATE + COND_TYPE_EVENT, | ||||
'EVENT_UPDATE_AND_NOTIFY': ACT_UPDATE_AND_NOTIFY + COND_TYPE_EVENT, | 'EVENT_UPDATE_AND_NOTIFY': ACT_UPDATE_AND_NOTIFY + COND_TYPE_EVENT, | ||||
'EVENT_ACCEPT_IF_NO_CONFLICT': ACT_ACCEPT + COND_IF_AVAILABLE + COND_TYPE_EVENT, | 'EVENT_ACCEPT_IF_NO_CONFLICT': ACT_ACCEPT + COND_IF_AVAILABLE + COND_TYPE_EVENT, | ||||
Lint: PEP8 E501 line too long (87 > 79 characters) Lint: PEP8 E501: line too long (87 > 79 characters) | |||||
'EVENT_TENTATIVE_IF_NO_CONFLICT': ACT_ACCEPT + COND_TENTATIVE + COND_IF_AVAILABLE + COND_TYPE_EVENT, | 'EVENT_TENTATIVE_IF_NO_CONFLICT': ACT_ACCEPT + COND_TENTATIVE + COND_IF_AVAILABLE + COND_TYPE_EVENT, | ||||
Lint: PEP8 E501 line too long (104 > 79 characters) Lint: PEP8 E501: line too long (104 > 79 characters) | |||||
'EVENT_DELEGATE_IF_CONFLICT': ACT_DELEGATE + COND_IF_CONFLICT + COND_TYPE_EVENT, | 'EVENT_DELEGATE_IF_CONFLICT': ACT_DELEGATE + COND_IF_CONFLICT + COND_TYPE_EVENT, | ||||
Lint: PEP8 E501 line too long (88 > 79 characters) Lint: PEP8 E501: line too long (88 > 79 characters) | |||||
'EVENT_REJECT_IF_CONFLICT': ACT_REJECT + COND_IF_CONFLICT + COND_TYPE_EVENT, | 'EVENT_REJECT_IF_CONFLICT': ACT_REJECT + COND_IF_CONFLICT + COND_TYPE_EVENT, | ||||
Lint: PEP8 E501 line too long (86 > 79 characters) Lint: PEP8 E501: line too long (86 > 79 characters) | |||||
'EVENT_SAVE_TO_FOLDER': ACT_SAVE_TO_FOLDER + COND_TYPE_EVENT, | 'EVENT_SAVE_TO_FOLDER': ACT_SAVE_TO_FOLDER + COND_TYPE_EVENT, | ||||
'EVENT_SAVE_AND_FORWARD': ACT_SAVE_AND_FORWARD + COND_TYPE_EVENT, | 'EVENT_SAVE_AND_FORWARD': ACT_SAVE_AND_FORWARD + COND_TYPE_EVENT, | ||||
'EVENT_CANCEL_DELETE': ACT_CANCEL_DELETE + COND_TYPE_EVENT, | 'EVENT_CANCEL_DELETE': ACT_CANCEL_DELETE + COND_TYPE_EVENT, | ||||
'EVENT_CANCEL_DELETE_AND_NOTIFY': ACT_CANCEL_DELETE_AND_NOTIFY + COND_TYPE_EVENT, | 'EVENT_CANCEL_DELETE_AND_NOTIFY': ACT_CANCEL_DELETE_AND_NOTIFY + COND_TYPE_EVENT, | ||||
Lint: PEP8 E501 line too long (85 > 79 characters) Lint: PEP8 E501: line too long (85 > 79 characters) | |||||
# task related policy values | # task related policy values | ||||
'TASK_MANUAL': ACT_MANUAL + COND_TYPE_TASK, | 'TASK_MANUAL': ACT_MANUAL + COND_TYPE_TASK, | ||||
'TASK_ACCEPT': ACT_ACCEPT + COND_TYPE_TASK, | 'TASK_ACCEPT': ACT_ACCEPT + COND_TYPE_TASK, | ||||
'TASK_REJECT': ACT_REJECT + COND_TYPE_TASK, | 'TASK_REJECT': ACT_REJECT + COND_TYPE_TASK, | ||||
'TASK_DELEGATE': ACT_DELEGATE + COND_TYPE_TASK, # not implemented | 'TASK_DELEGATE': ACT_DELEGATE + COND_TYPE_TASK, # not implemented | ||||
Lint: PEP8 E501 line too long (87 > 79 characters) Lint: PEP8 E501: line too long (87 > 79 characters) | |||||
'TASK_UPDATE': ACT_UPDATE + COND_TYPE_TASK, | 'TASK_UPDATE': ACT_UPDATE + COND_TYPE_TASK, | ||||
'TASK_UPDATE_AND_NOTIFY': ACT_UPDATE_AND_NOTIFY + COND_TYPE_TASK, | 'TASK_UPDATE_AND_NOTIFY': ACT_UPDATE_AND_NOTIFY + COND_TYPE_TASK, | ||||
'TASK_SAVE_TO_FOLDER': ACT_SAVE_TO_FOLDER + COND_TYPE_TASK, | 'TASK_SAVE_TO_FOLDER': ACT_SAVE_TO_FOLDER + COND_TYPE_TASK, | ||||
'TASK_SAVE_AND_FORWARD': ACT_SAVE_AND_FORWARD + COND_TYPE_TASK, | 'TASK_SAVE_AND_FORWARD': ACT_SAVE_AND_FORWARD + COND_TYPE_TASK, | ||||
'TASK_CANCEL_DELETE': ACT_CANCEL_DELETE + COND_TYPE_TASK, | 'TASK_CANCEL_DELETE': ACT_CANCEL_DELETE + COND_TYPE_TASK, | ||||
'TASK_CANCEL_DELETE_AND_NOTIFY': ACT_CANCEL_DELETE_AND_NOTIFY + COND_TYPE_TASK, | 'TASK_CANCEL_DELETE_AND_NOTIFY': ACT_CANCEL_DELETE_AND_NOTIFY + COND_TYPE_TASK, | ||||
Lint: PEP8 E501 line too long (84 > 79 characters) Lint: PEP8 E501: line too long (84 > 79 characters) | |||||
# legacy values | # legacy values | ||||
'ACT_MANUAL': ACT_MANUAL + COND_TYPE_ALL, | 'ACT_MANUAL': ACT_MANUAL + COND_TYPE_ALL, | ||||
'ACT_ACCEPT': ACT_ACCEPT + COND_TYPE_ALL, | 'ACT_ACCEPT': ACT_ACCEPT + COND_TYPE_ALL, | ||||
'ACT_ACCEPT_IF_NO_CONFLICT': ACT_ACCEPT + COND_IF_AVAILABLE + COND_TYPE_EVENT, | 'ACT_ACCEPT_IF_NO_CONFLICT': ACT_ACCEPT + COND_IF_AVAILABLE + COND_TYPE_EVENT, | ||||
Lint: PEP8 E501 line too long (87 > 79 characters) Lint: PEP8 E501: line too long (87 > 79 characters) | |||||
'ACT_TENTATIVE': ACT_TENTATIVE + COND_TYPE_EVENT, | 'ACT_TENTATIVE': ACT_TENTATIVE + COND_TYPE_EVENT, | ||||
'ACT_TENTATIVE_IF_NO_CONFLICT': ACT_ACCEPT + COND_TENTATIVE + COND_IF_AVAILABLE + COND_TYPE_EVENT, | 'ACT_TENTATIVE_IF_NO_CONFLICT': ACT_ACCEPT + COND_TENTATIVE + COND_IF_AVAILABLE + COND_TYPE_EVENT, | ||||
Lint: PEP8 E501 line too long (104 > 79 characters) Lint: PEP8 E501: line too long (104 > 79 characters) | |||||
'ACT_DELEGATE': ACT_DELEGATE + COND_TYPE_ALL, | 'ACT_DELEGATE': ACT_DELEGATE + COND_TYPE_ALL, | ||||
'ACT_DELEGATE_IF_CONFLICT': ACT_DELEGATE + COND_IF_CONFLICT + COND_TYPE_EVENT, | 'ACT_DELEGATE_IF_CONFLICT': ACT_DELEGATE + COND_IF_CONFLICT + COND_TYPE_EVENT, | ||||
Lint: PEP8 E501 line too long (88 > 79 characters) Lint: PEP8 E501: line too long (88 > 79 characters) | |||||
'ACT_REJECT': ACT_REJECT + COND_TYPE_ALL, | 'ACT_REJECT': ACT_REJECT + COND_TYPE_ALL, | ||||
'ACT_REJECT_IF_CONFLICT': ACT_REJECT + COND_IF_CONFLICT + COND_TYPE_EVENT, | 'ACT_REJECT_IF_CONFLICT': ACT_REJECT + COND_IF_CONFLICT + COND_TYPE_EVENT, | ||||
Lint: PEP8 E501 line too long (86 > 79 characters) Lint: PEP8 E501: line too long (86 > 79 characters) | |||||
'ACT_UPDATE': ACT_UPDATE + COND_TYPE_ALL, | 'ACT_UPDATE': ACT_UPDATE + COND_TYPE_ALL, | ||||
'ACT_UPDATE_AND_NOTIFY': ACT_UPDATE_AND_NOTIFY + COND_TYPE_ALL, | 'ACT_UPDATE_AND_NOTIFY': ACT_UPDATE_AND_NOTIFY + COND_TYPE_ALL, | ||||
'ACT_CANCEL_DELETE': ACT_CANCEL_DELETE + COND_TYPE_ALL, | 'ACT_CANCEL_DELETE': ACT_CANCEL_DELETE + COND_TYPE_ALL, | ||||
'ACT_CANCEL_DELETE_AND_NOTIFY': ACT_CANCEL_DELETE_AND_NOTIFY + COND_TYPE_ALL, | 'ACT_CANCEL_DELETE_AND_NOTIFY': ACT_CANCEL_DELETE_AND_NOTIFY + COND_TYPE_ALL, | ||||
Lint: PEP8 E501 line too long (83 > 79 characters) Lint: PEP8 E501: line too long (83 > 79 characters) | |||||
'ACT_SAVE_TO_CALENDAR': ACT_SAVE_TO_FOLDER + COND_TYPE_EVENT, | 'ACT_SAVE_TO_CALENDAR': ACT_SAVE_TO_FOLDER + COND_TYPE_EVENT, | ||||
'ACT_SAVE_AND_FORWARD': ACT_SAVE_AND_FORWARD + COND_TYPE_EVENT, | '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.iteritems()]) | ||||
Lint: PEP8 E225 missing whitespace around operator Lint: PEP8 E225: missing whitespace around operator | |||||
Lint: PEP8 E501 line too long (92 > 79 characters) Lint: PEP8 E501: line too long (92 > 79 characters) | |||||
object_type_conditons = { | object_type_conditons = { | ||||
'event': COND_TYPE_EVENT, | 'event': COND_TYPE_EVENT, | ||||
'task': COND_TYPE_TASK | 'task': COND_TYPE_TASK | ||||
} | } | ||||
log = pykolab.getLogger('pykolab.wallace') | log = pykolab.getLogger('pykolab.wallace') | ||||
conf = pykolab.getConf() | conf = pykolab.getConf() | ||||
mybasepath = '/var/spool/pykolab/wallace/invitationpolicy/' | mybasepath = '/var/spool/pykolab/wallace/invitationpolicy/' | ||||
auth = None | auth = None | ||||
imap = None | imap = None | ||||
write_locks = [] | write_locks = [] | ||||
def __init__(): | def __init__(): | ||||
Lint: PEP8 E302 expected 2 blank lines, found 1 Lint: PEP8 E302: expected 2 blank lines, found 1 | |||||
modules.register('invitationpolicy', execute, description=description()) | modules.register('invitationpolicy', execute, description=description()) | ||||
def accept(filepath): | def accept(filepath): | ||||
Lint: PEP8 E302 expected 2 blank lines, found 1 Lint: PEP8 E302: expected 2 blank lines, found 1 | |||||
new_filepath = os.path.join( | new_filepath = os.path.join( | ||||
mybasepath, | mybasepath, | ||||
'ACCEPT', | 'ACCEPT', | ||||
os.path.basename(filepath) | os.path.basename(filepath) | ||||
) | ) | ||||
cleanup() | cleanup() | ||||
os.rename(filepath, new_filepath) | os.rename(filepath, new_filepath) | ||||
filepath = new_filepath | filepath = new_filepath | ||||
exec('modules.cb_action_ACCEPT(%r, %r)' % ('invitationpolicy',filepath)) | exec('modules.cb_action_ACCEPT(%r, %r)' % ('invitationpolicy',filepath)) | ||||
Lint: PEP8 E231 missing whitespace after ',' Lint: PEP8 E231: missing whitespace after ',' | |||||
def reject(filepath): | def reject(filepath): | ||||
Lint: PEP8 E302 expected 2 blank lines, found 1 Lint: PEP8 E302: expected 2 blank lines, found 1 | |||||
new_filepath = os.path.join( | new_filepath = os.path.join( | ||||
mybasepath, | mybasepath, | ||||
'REJECT', | 'REJECT', | ||||
os.path.basename(filepath) | os.path.basename(filepath) | ||||
) | ) | ||||
os.rename(filepath, new_filepath) | os.rename(filepath, new_filepath) | ||||
filepath = new_filepath | filepath = new_filepath | ||||
exec('modules.cb_action_REJECT(%r, %r)' % ('invitationpolicy',filepath)) | exec('modules.cb_action_REJECT(%r, %r)' % ('invitationpolicy',filepath)) | ||||
Lint: PEP8 E231 missing whitespace after ',' Lint: PEP8 E231: missing whitespace after ',' | |||||
def description(): | def description(): | ||||
Lint: PEP8 E302 expected 2 blank lines, found 1 Lint: PEP8 E302: expected 2 blank lines, found 1 | |||||
return """Invitation policy execution module.""" | return """Invitation policy execution module.""" | ||||
def cleanup(): | def cleanup(): | ||||
Lint: PEP8 E302 expected 2 blank lines, found 1 Lint: PEP8 E302: expected 2 blank lines, found 1 | |||||
global auth, imap, write_locks | global auth, imap, write_locks | ||||
log.debug("cleanup(): %r, %r" % (auth, imap), level=9) | log.debug("cleanup(): %r, %r" % (auth, imap), level=9) | ||||
auth.disconnect() | auth.disconnect() | ||||
del auth | del auth | ||||
# Disconnect IMAP or we lock the mailbox almost constantly | # Disconnect IMAP or we lock the mailbox almost constantly | ||||
imap.disconnect() | imap.disconnect() | ||||
del imap | del imap | ||||
# remove remaining write locks | # remove remaining write locks | ||||
for key in write_locks: | for key in write_locks: | ||||
remove_write_lock(key, False) | remove_write_lock(key, False) | ||||
def execute(*args, **kw): | def execute(*args, **kw): | ||||
Lint: PEP8 E302 expected 2 blank lines, found 1 Lint: PEP8 E302: expected 2 blank lines, found 1 | |||||
global auth, imap | global auth, imap | ||||
# (re)set language to default | # (re)set language to default | ||||
pykolab.translate.setUserLanguage(conf.get('kolab','default_locale')) | pykolab.translate.setUserLanguage(conf.get('kolab','default_locale')) | ||||
Lint: PEP8 E231 missing whitespace after ',' Lint: PEP8 E231: missing whitespace after ',' | |||||
if not os.path.isdir(mybasepath): | if not os.path.isdir(mybasepath): | ||||
os.makedirs(mybasepath) | os.makedirs(mybasepath) | ||||
for stage in ['incoming', 'ACCEPT', 'REJECT', 'HOLD', 'DEFER', 'locks']: | for stage in ['incoming', 'ACCEPT', 'REJECT', 'HOLD', 'DEFER', 'locks']: | ||||
if not os.path.isdir(os.path.join(mybasepath, stage)): | if not os.path.isdir(os.path.join(mybasepath, stage)): | ||||
os.makedirs(os.path.join(mybasepath, stage)) | os.makedirs(os.path.join(mybasepath, stage)) | ||||
log.debug(_("Invitation policy called for %r, %r") % (args, kw), level=9) | log.debug(_("Invitation policy called for %r, %r") % (args, kw), level=9) | ||||
auth = Auth() | auth = Auth() | ||||
imap = IMAP() | imap = IMAP() | ||||
filepath = args[0] | filepath = args[0] | ||||
# ignore calls on lock files | # ignore calls on lock files | ||||
if '/locks/' in filepath or kw.has_key('stage') and kw['stage'] == 'locks': | if '/locks/' in filepath or kw.has_key('stage') and kw['stage'] == 'locks': | ||||
return False | return False | ||||
log.debug("Invitation policy executing for %r, %r" % (filepath, '/locks/' in filepath), level=8) | log.debug("Invitation policy executing for %r, %r" % (filepath, '/locks/' in filepath), level=8) | ||||
Lint: PEP8 E501 line too long (100 > 79 characters) Lint: PEP8 E501: line too long (100 > 79 characters) | |||||
if kw.has_key('stage'): | if kw.has_key('stage'): | ||||
log.debug(_("Issuing callback after processing to stage %s") % (kw['stage']), level=8) | log.debug(_("Issuing callback after processing to stage %s") % (kw['stage']), level=8) | ||||
Lint: PEP8 E501 line too long (94 > 79 characters) Lint: PEP8 E501: line too long (94 > 79 characters) | |||||
log.debug(_("Testing cb_action_%s()") % (kw['stage']), level=8) | log.debug(_("Testing cb_action_%s()") % (kw['stage']), level=8) | ||||
if hasattr(modules, 'cb_action_%s' % (kw['stage'])): | if hasattr(modules, 'cb_action_%s' % (kw['stage'])): | ||||
log.debug(_("Attempting to execute cb_action_%s()") % (kw['stage']), level=8) | log.debug(_("Attempting to execute cb_action_%s()") % (kw['stage']), level=8) | ||||
Lint: PEP8 E501 line too long (89 > 79 characters) Lint: PEP8 E501: line too long (89 > 79 characters) | |||||
exec( | exec( | ||||
'modules.cb_action_%s(%r, %r)' % ( | 'modules.cb_action_%s(%r, %r)' % ( | ||||
kw['stage'], | kw['stage'], | ||||
'invitationpolicy', | 'invitationpolicy', | ||||
filepath | filepath | ||||
) | ) | ||||
) | ) | ||||
Show All 14 Lines | def execute(*args, **kw): | ||||
# parse full message | # parse full message | ||||
message = Parser().parse(open(filepath, 'r')) | message = Parser().parse(open(filepath, 'r')) | ||||
# invalid message, skip | # invalid message, skip | ||||
if not message.get('X-Kolab-To'): | if not message.get('X-Kolab-To'): | ||||
return filepath | return filepath | ||||
recipients = [address for displayname,address in getaddresses(message.get_all('X-Kolab-To'))] | recipients = [address for displayname,address in getaddresses(message.get_all('X-Kolab-To'))] | ||||
Lint: PEP8 E231 missing whitespace after ',' Lint: PEP8 E231: missing whitespace after ',' | |||||
Lint: PEP8 E501 line too long (97 > 79 characters) Lint: PEP8 E501: line too long (97 > 79 characters) | |||||
sender_email = [address for displayname,address in getaddresses(message.get_all('X-Kolab-From'))][0] | sender_email = [address for displayname,address in getaddresses(message.get_all('X-Kolab-From'))][0] | ||||
Lint: PEP8 E231 missing whitespace after ',' Lint: PEP8 E231: missing whitespace after ',' | |||||
Lint: PEP8 E501 line too long (104 > 79 characters) Lint: PEP8 E501: line too long (104 > 79 characters) | |||||
any_itips = False | any_itips = False | ||||
recipient_email = None | recipient_email = None | ||||
recipient_emails = [] | recipient_emails = [] | ||||
recipient_user_dn = None | recipient_user_dn = None | ||||
# An iTip message may contain multiple events. Later on, test if the message | # An iTip message may contain multiple events. Later on, test if the message | ||||
Lint: PEP8 E501 line too long (80 > 79 characters) Lint: PEP8 E501: line too long (80 > 79 characters) | |||||
# is an iTip message by checking the length of this list. | # is an iTip message by checking the length of this list. | ||||
try: | try: | ||||
itip_events = objects_from_message(message, ['VEVENT','VTODO'], ['REQUEST', 'REPLY', 'CANCEL']) | itip_events = objects_from_message(message, ['VEVENT','VTODO'], ['REQUEST', 'REPLY', 'CANCEL']) | ||||
Lint: PEP8 E231 missing whitespace after ',' Lint: PEP8 E231: missing whitespace after ',' | |||||
Lint: PEP8 E501 line too long (103 > 79 characters) Lint: PEP8 E501: line too long (103 > 79 characters) | |||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error(_("Failed to parse iTip objects from message: %r" % (errmsg))) | log.error(_("Failed to parse iTip objects from message: %r" % (errmsg))) | ||||
Lint: PEP8 E501 line too long (80 > 79 characters) Lint: PEP8 E501: line too long (80 > 79 characters) | |||||
itip_events = [] | itip_events = [] | ||||
if not len(itip_events) > 0: | if not len(itip_events) > 0: | ||||
log.info(_("Message is not an iTip message or does not contain any (valid) iTip objects.")) | log.info(_("Message is not an iTip message or does not contain any (valid) iTip objects.")) | ||||
Lint: PEP8 E501 line too long (99 > 79 characters) Lint: PEP8 E501: line too long (99 > 79 characters) | |||||
else: | else: | ||||
any_itips = True | any_itips = True | ||||
log.debug(_("iTip objects attached to this message contain the following information: %r") % (itip_events), level=9) | log.debug(_("iTip objects attached to this message contain the following information: %r") % (itip_events), level=9) | ||||
Lint: PEP8 E501 line too long (124 > 79 characters) Lint: PEP8 E501: line too long (124 > 79 characters) | |||||
# See if any iTip actually allocates a user. | # 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 x.has_key('attendees') or x.has_key('organizer')]) > 0: | ||||
Lint: PEP8 E501 line too long (114 > 79 characters) Lint: PEP8 E501: line too long (114 > 79 characters) | |||||
auth.connect() | auth.connect() | ||||
# we're looking at the first itip object | # we're looking at the first itip object | ||||
itip_event = itip_events[0] | itip_event = itip_events[0] | ||||
for recipient in recipients: | for recipient in recipients: | ||||
recipient_user_dn = user_dn_from_email_address(recipient) | recipient_user_dn = user_dn_from_email_address(recipient) | ||||
if recipient_user_dn: | if recipient_user_dn: | ||||
receiving_user = auth.get_entry_attributes(None, recipient_user_dn, ['*']) | receiving_user = auth.get_entry_attributes(None, recipient_user_dn, ['*']) | ||||
Lint: PEP8 E501 line too long (90 > 79 characters) Lint: PEP8 E501: line too long (90 > 79 characters) | |||||
recipient_emails = auth.extract_recipient_addresses(receiving_user) | recipient_emails = auth.extract_recipient_addresses(receiving_user) | ||||
Lint: PEP8 E501 line too long (83 > 79 characters) Lint: PEP8 E501: line too long (83 > 79 characters) | |||||
recipient_email = recipient | recipient_email = recipient | ||||
# extend with addresses from delegators | # extend with addresses from delegators | ||||
# (only do this lookup for REPLY messages) | # (only do this lookup for REPLY messages) | ||||
receiving_user['_delegated_mailboxes'] = [] | receiving_user['_delegated_mailboxes'] = [] | ||||
if itip_event['method'] == 'REPLY': | if itip_event['method'] == 'REPLY': | ||||
for _delegator in auth.list_delegators(recipient_user_dn): | for _delegator in auth.list_delegators(recipient_user_dn): | ||||
receiving_user['_delegated_mailboxes'].append(_delegator['_mailbox_basename'].split('@')[0]) | receiving_user['_delegated_mailboxes'].append(_delegator['_mailbox_basename'].split('@')[0]) | ||||
Lint: PEP8 E501 line too long (116 > 79 characters) Lint: PEP8 E501: line too long (116 > 79 characters) | |||||
log.debug(_("Recipient emails for %s: %r") % (recipient_user_dn, recipient_emails), level=8) | log.debug(_("Recipient emails for %s: %r") % (recipient_user_dn, recipient_emails), level=8) | ||||
Lint: PEP8 E501 line too long (108 > 79 characters) Lint: PEP8 E501: line too long (108 > 79 characters) | |||||
break | break | ||||
if not any_itips: | if not any_itips: | ||||
log.debug(_("No itips, no users, pass along %r") % (filepath), level=5) | log.debug(_("No itips, no users, pass along %r") % (filepath), level=5) | ||||
return filepath | return filepath | ||||
elif recipient_email is None: | elif recipient_email is None: | ||||
log.debug(_("iTips, but no users, pass along %r") % (filepath), level=5) | log.debug(_("iTips, but no users, pass along %r") % (filepath), level=5) | ||||
Lint: PEP8 E501 line too long (80 > 79 characters) Lint: PEP8 E501: line too long (80 > 79 characters) | |||||
return filepath | return filepath | ||||
# for replies, the organizer is the recipient | # for replies, the organizer is the recipient | ||||
if itip_event['method'] == 'REPLY': | if itip_event['method'] == 'REPLY': | ||||
organizer_mailto = str(itip_event['organizer']).split(':')[-1] | organizer_mailto = str(itip_event['organizer']).split(':')[-1] | ||||
user_attendees = [organizer_mailto] if organizer_mailto in recipient_emails else [] | user_attendees = [organizer_mailto] if organizer_mailto in recipient_emails else [] | ||||
Lint: PEP8 E501 line too long (91 > 79 characters) Lint: PEP8 E501: line too long (91 > 79 characters) | |||||
else: | else: | ||||
# Limit the attendees to the one that is actually invited with the current message. | # Limit the attendees to the one that is actually invited with the current message. | ||||
Lint: PEP8 E501 line too long (91 > 79 characters) Lint: PEP8 E501: line too long (91 > 79 characters) | |||||
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 itip_event.has_key('attendees') else [])] | ||||
Lint: PEP8 E501 line too long (121 > 79 characters) Lint: PEP8 E501: line too long (121 > 79 characters) | |||||
user_attendees = [a for a in attendees if a in recipient_emails] | user_attendees = [a for a in attendees if a in recipient_emails] | ||||
if itip_event.has_key('organizer'): | if itip_event.has_key('organizer'): | ||||
sender_email = itip_event['xml'].get_organizer().email() | sender_email = itip_event['xml'].get_organizer().email() | ||||
# abort if no attendee matches the envelope recipient | # abort if no attendee matches the envelope recipient | ||||
if len(user_attendees) == 0: | if len(user_attendees) == 0: | ||||
log.info(_("No user attendee matching envelope recipient %s, skip message") % (recipient_email)) | log.info(_("No user attendee matching envelope recipient %s, skip message") % (recipient_email)) | ||||
Lint: PEP8 E501 line too long (104 > 79 characters) Lint: PEP8 E501: line too long (104 > 79 characters) | |||||
return filepath | return filepath | ||||
log.debug(_("Receiving user: %r") % (receiving_user), level=8) | log.debug(_("Receiving user: %r") % (receiving_user), level=8) | ||||
# set recipient_email to the matching attendee mailto: address | # set recipient_email to the matching attendee mailto: address | ||||
recipient_email = user_attendees[0] | recipient_email = user_attendees[0] | ||||
# change gettext language to the preferredlanguage setting of the receiving user | # change gettext language to the preferredlanguage setting of the receiving user | ||||
Lint: PEP8 E501 line too long (84 > 79 characters) Lint: PEP8 E501: line too long (84 > 79 characters) | |||||
if receiving_user.has_key('preferredlanguage'): | if receiving_user.has_key('preferredlanguage'): | ||||
pykolab.translate.setUserLanguage(receiving_user['preferredlanguage']) | pykolab.translate.setUserLanguage(receiving_user['preferredlanguage']) | ||||
# find user's kolabInvitationPolicy settings and the matching policy values | # find user's kolabInvitationPolicy settings and the matching policy values | ||||
type_condition = object_type_conditons.get(itip_event['type'], COND_TYPE_ALL) | type_condition = object_type_conditons.get(itip_event['type'], COND_TYPE_ALL) | ||||
Lint: PEP8 E501 line too long (81 > 79 characters) Lint: PEP8 E501: line too long (81 > 79 characters) | |||||
policies = get_matching_invitation_policies(receiving_user, sender_email, type_condition) | policies = get_matching_invitation_policies(receiving_user, sender_email, type_condition) | ||||
Lint: PEP8 E501 line too long (93 > 79 characters) Lint: PEP8 E501: line too long (93 > 79 characters) | |||||
# select a processing function according to the iTip request method | # select a processing function according to the iTip request method | ||||
method_processing_map = { | method_processing_map = { | ||||
'REQUEST': process_itip_request, | 'REQUEST': process_itip_request, | ||||
'REPLY': process_itip_reply, | 'REPLY': process_itip_reply, | ||||
'CANCEL': process_itip_cancel | 'CANCEL': process_itip_cancel | ||||
} | } | ||||
done = None | done = None | ||||
if method_processing_map.has_key(itip_event['method']): | if method_processing_map.has_key(itip_event['method']): | ||||
processor_func = method_processing_map[itip_event['method']] | processor_func = method_processing_map[itip_event['method']] | ||||
# connect as cyrus-admin | # connect as cyrus-admin | ||||
imap.connect() | imap.connect() | ||||
for policy in policies: | for policy in policies: | ||||
log.debug(_("Apply invitation policy %r for sender %r") % (policy_value_map[policy], sender_email), level=8) | log.debug(_("Apply invitation policy %r for sender %r") % (policy_value_map[policy], sender_email), level=8) | ||||
Lint: PEP8 E501 line too long (120 > 79 characters) Lint: PEP8 E501: line too long (120 > 79 characters) | |||||
done = processor_func(itip_event, policy, recipient_email, sender_email, receiving_user) | done = processor_func(itip_event, policy, recipient_email, sender_email, receiving_user) | ||||
Lint: PEP8 E501 line too long (100 > 79 characters) Lint: PEP8 E501: line too long (100 > 79 characters) | |||||
# matching policy found | # matching policy found | ||||
if done is not None: | if done is not None: | ||||
break | break | ||||
# remove possible write lock from this iteration | # remove possible write lock from this iteration | ||||
remove_write_lock(get_lock_key(receiving_user, itip_event['uid'])) | remove_write_lock(get_lock_key(receiving_user, itip_event['uid'])) | ||||
else: | else: | ||||
log.debug(_("Ignoring '%s' iTip method") % (itip_event['method']), level=8) | log.debug(_("Ignoring '%s' iTip method") % (itip_event['method']), level=8) | ||||
Lint: PEP8 E501 line too long (83 > 79 characters) Lint: PEP8 E501: line too long (83 > 79 characters) | |||||
# message has been processed by the module, remove it | # message has been processed by the module, remove it | ||||
if done == MESSAGE_PROCESSED: | if done == MESSAGE_PROCESSED: | ||||
log.debug(_("iTip message %r consumed by the invitationpolicy module") % (message.get('Message-ID')), level=5) | log.debug(_("iTip message %r consumed by the invitationpolicy module") % (message.get('Message-ID')), level=5) | ||||
Lint: PEP8 E501 line too long (118 > 79 characters) Lint: PEP8 E501: line too long (118 > 79 characters) | |||||
os.unlink(filepath) | os.unlink(filepath) | ||||
cleanup() | cleanup() | ||||
return None | return None | ||||
# accept message into the destination inbox | # accept message into the destination inbox | ||||
accept(filepath) | accept(filepath) | ||||
def process_itip_request(itip_event, policy, recipient_email, sender_email, receiving_user): | def process_itip_request(itip_event, policy, recipient_email, sender_email, receiving_user): | ||||
Lint: PEP8 E501 line too long (92 > 79 characters) Lint: PEP8 E501: line too long (92 > 79 characters) | |||||
""" | """ | ||||
Process an iTip REQUEST message according to the given policy | Process an iTip REQUEST message according to the given policy | ||||
""" | """ | ||||
# if invitation policy is set to MANUAL, pass message along | # if invitation policy is set to MANUAL, pass message along | ||||
if policy & ACT_MANUAL: | if policy & ACT_MANUAL: | ||||
log.info(_("Pass invitation for manual processing")) | log.info(_("Pass invitation for manual processing")) | ||||
return MESSAGE_FORWARD | return MESSAGE_FORWARD | ||||
try: | try: | ||||
receiving_attendee = itip_event['xml'].get_attendee_by_email(recipient_email) | receiving_attendee = itip_event['xml'].get_attendee_by_email(recipient_email) | ||||
Lint: PEP8 E501 line too long (85 > 79 characters) Lint: PEP8 E501: line too long (85 > 79 characters) | |||||
log.debug(_("Receiving Attendee: %r") % (receiving_attendee), level=9) | log.debug(_("Receiving Attendee: %r") % (receiving_attendee), level=9) | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error("Could not find envelope attendee: %r" % (errmsg)) | log.error("Could not find envelope attendee: %r" % (errmsg)) | ||||
return MESSAGE_FORWARD | return MESSAGE_FORWARD | ||||
# process request to participating attendees with RSVP=TRUE or PARTSTAT=NEEDS-ACTION | # process request to participating attendees with RSVP=TRUE or PARTSTAT=NEEDS-ACTION | ||||
Lint: PEP8 E501 line too long (88 > 79 characters) Lint: PEP8 E501: line too long (88 > 79 characters) | |||||
is_task = itip_event['type'] == 'task' | is_task = itip_event['type'] == 'task' | ||||
nonpart = receiving_attendee.get_role() == kolabformat.NonParticipant | nonpart = receiving_attendee.get_role() == kolabformat.NonParticipant | ||||
partstat = receiving_attendee.get_participant_status() | partstat = receiving_attendee.get_participant_status() | ||||
save_object = not nonpart or not partstat == kolabformat.PartNeedsAction | save_object = not nonpart or not partstat == kolabformat.PartNeedsAction | ||||
rsvp = receiving_attendee.get_rsvp() | rsvp = receiving_attendee.get_rsvp() | ||||
scheduling_required = rsvp or partstat == kolabformat.PartNeedsAction | scheduling_required = rsvp or partstat == kolabformat.PartNeedsAction | ||||
respond_with = receiving_attendee.get_participant_status(True) | respond_with = receiving_attendee.get_participant_status(True) | ||||
condition_fulfilled = True | condition_fulfilled = True | ||||
# find existing event in user's calendar | # find existing event in user's calendar | ||||
(existing, master) = find_existing_object(itip_event['uid'], itip_event['type'], itip_event['recurrence-id'], receiving_user, True) | (existing, master) = find_existing_object(itip_event['uid'], itip_event['type'], itip_event['recurrence-id'], receiving_user, True) | ||||
Lint: PEP8 E501 line too long (135 > 79 characters) Lint: PEP8 E501: line too long (135 > 79 characters) | |||||
# compare sequence number to determine a (re-)scheduling request | # compare sequence number to determine a (re-)scheduling request | ||||
if existing is not None: | if existing is not None: | ||||
log.debug(_("Existing %s: %r") % (existing.type, existing), level=9) | log.debug(_("Existing %s: %r") % (existing.type, existing), level=9) | ||||
scheduling_required = itip_event['sequence'] > 0 and itip_event['sequence'] > existing.get_sequence() | scheduling_required = itip_event['sequence'] > 0 and itip_event['sequence'] > existing.get_sequence() | ||||
Lint: PEP8 E501 line too long (109 > 79 characters) Lint: PEP8 E501: line too long (109 > 79 characters) | |||||
save_object = True | save_object = True | ||||
# if scheduling: check availability (skip that for tasks) | # if scheduling: check availability (skip that for tasks) | ||||
if scheduling_required: | if scheduling_required: | ||||
if not is_task and policy & (COND_IF_AVAILABLE | COND_IF_CONFLICT): | if not is_task and policy & (COND_IF_AVAILABLE | COND_IF_CONFLICT): | ||||
condition_fulfilled = check_availability(itip_event, receiving_user) | condition_fulfilled = check_availability(itip_event, receiving_user) | ||||
Lint: PEP8 E501 line too long (80 > 79 characters) Lint: PEP8 E501: line too long (80 > 79 characters) | |||||
if not is_task and policy & COND_IF_CONFLICT: | if not is_task and policy & COND_IF_CONFLICT: | ||||
condition_fulfilled = not condition_fulfilled | condition_fulfilled = not condition_fulfilled | ||||
log.debug(_("Precondition for object %r fulfilled: %r") % (itip_event['uid'], condition_fulfilled), level=5) | log.debug(_("Precondition for object %r fulfilled: %r") % (itip_event['uid'], condition_fulfilled), level=5) | ||||
Lint: PEP8 E501 line too long (116 > 79 characters) Lint: PEP8 E501: line too long (116 > 79 characters) | |||||
if existing: | if existing: | ||||
respond_with = None | respond_with = None | ||||
if policy & ACT_ACCEPT and condition_fulfilled: | if policy & ACT_ACCEPT and condition_fulfilled: | ||||
respond_with = 'TENTATIVE' if policy & COND_TENTATIVE else 'ACCEPTED' | respond_with = 'TENTATIVE' if policy & COND_TENTATIVE else 'ACCEPTED' | ||||
Lint: PEP8 E501 line too long (81 > 79 characters) Lint: PEP8 E501: line too long (81 > 79 characters) | |||||
elif policy & ACT_REJECT and condition_fulfilled: | elif policy & ACT_REJECT and condition_fulfilled: | ||||
respond_with = 'DECLINED' | respond_with = 'DECLINED' | ||||
# TODO: only save declined invitation when a certain config option is set? | # TODO: only save declined invitation when a certain config option is set? | ||||
Lint: PEP8 E501 line too long (86 > 79 characters) Lint: PEP8 E501: line too long (86 > 79 characters) | |||||
elif policy & ACT_DELEGATE and condition_fulfilled: | elif policy & ACT_DELEGATE and condition_fulfilled: | ||||
# TODO: delegate (but to whom?) | # TODO: delegate (but to whom?) | ||||
return None | return None | ||||
# auto-update changes if enabled for this user | # auto-update changes if enabled for this user | ||||
elif policy & ACT_UPDATE and existing: | elif policy & ACT_UPDATE and existing: | ||||
# compare sequence number to avoid outdated updates | # compare sequence number to avoid outdated updates | ||||
if not itip_event['sequence'] == existing.get_sequence(): | if not itip_event['sequence'] == existing.get_sequence(): | ||||
log.info(_("The iTip request sequence (%r) doesn't match the referred object version (%r). Ignoring.") % ( | log.info(_("The iTip request sequence (%r) doesn't match the referred object version (%r). Ignoring.") % ( | ||||
Lint: PEP8 E501 line too long (118 > 79 characters) Lint: PEP8 E501: line too long (118 > 79 characters) | |||||
itip_event['sequence'], existing.get_sequence() | itip_event['sequence'], existing.get_sequence() | ||||
)) | )) | ||||
return None | return None | ||||
log.debug(_("Auto-updating %s %r on iTip REQUEST (no re-scheduling)") % (existing.type, existing.uid), level=8) | log.debug(_("Auto-updating %s %r on iTip REQUEST (no re-scheduling)") % (existing.type, existing.uid), level=8) | ||||
Lint: PEP8 E501 line too long (119 > 79 characters) Lint: PEP8 E501: line too long (119 > 79 characters) | |||||
save_object = True | save_object = True | ||||
rsvp = False | rsvp = False | ||||
# retain task status and percent-complete properties from my old copy | # retain task status and percent-complete properties from my old copy | ||||
if is_task: | if is_task: | ||||
itip_event['xml'].set_status(existing.get_status()) | itip_event['xml'].set_status(existing.get_status()) | ||||
itip_event['xml'].set_percentcomplete(existing.get_percentcomplete()) | itip_event['xml'].set_percentcomplete(existing.get_percentcomplete()) | ||||
Lint: PEP8 E501 line too long (81 > 79 characters) Lint: PEP8 E501: line too long (81 > 79 characters) | |||||
if policy & COND_NOTIFY: | if policy & COND_NOTIFY: | ||||
send_update_notification(itip_event['xml'], receiving_user, existing, False) | send_update_notification(itip_event['xml'], receiving_user, existing, False) | ||||
Lint: PEP8 E501 line too long (88 > 79 characters) Lint: PEP8 E501: line too long (88 > 79 characters) | |||||
# if RSVP, send an iTip REPLY | # if RSVP, send an iTip REPLY | ||||
if rsvp or scheduling_required: | if rsvp or scheduling_required: | ||||
# set attendee's CN from LDAP record if yet missing | # 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 receiving_user.has_key('cn'): | ||||
receiving_attendee.set_name(receiving_user['cn']) | receiving_attendee.set_name(receiving_user['cn']) | ||||
# send iTip reply | # send iTip reply | ||||
if respond_with is not None and not respond_with == 'NEEDS-ACTION': | if respond_with is not None and not respond_with == 'NEEDS-ACTION': | ||||
receiving_attendee.set_participant_status(respond_with) | receiving_attendee.set_participant_status(respond_with) | ||||
send_reply(recipient_email, itip_event, invitation_response_text(itip_event['type']), | send_reply(recipient_email, itip_event, invitation_response_text(itip_event['type']), | ||||
Lint: PEP8 E501 line too long (97 > 79 characters) Lint: PEP8 E501: line too long (97 > 79 characters) | |||||
subject=_('"%(summary)s" has been %(status)s')) | subject=_('"%(summary)s" has been %(status)s')) | ||||
Lint: PEP8 E128 continuation line under-indented for visual indent Lint: PEP8 E128: continuation line under-indented for visual indent | |||||
elif policy & ACT_SAVE_TO_FOLDER: | elif policy & ACT_SAVE_TO_FOLDER: | ||||
# copy the invitation into the user's default folder with PARTSTAT=NEEDS-ACTION | # copy the invitation into the user's default folder with PARTSTAT=NEEDS-ACTION | ||||
Lint: PEP8 E501 line too long (91 > 79 characters) Lint: PEP8 E501: line too long (91 > 79 characters) | |||||
itip_event['xml'].set_attendee_participant_status(receiving_attendee, respond_with or 'NEEDS-ACTION') | itip_event['xml'].set_attendee_participant_status(receiving_attendee, respond_with or 'NEEDS-ACTION') | ||||
Lint: PEP8 E501 line too long (113 > 79 characters) Lint: PEP8 E501: line too long (113 > 79 characters) | |||||
save_object = True | save_object = True | ||||
else: | else: | ||||
# policy doesn't match, pass on to next one | # policy doesn't match, pass on to next one | ||||
return None | return None | ||||
if save_object: | if save_object: | ||||
targetfolder = None | targetfolder = None | ||||
# delete old version from IMAP | # delete old version from IMAP | ||||
if existing: | if existing: | ||||
targetfolder = existing._imap_folder | targetfolder = existing._imap_folder | ||||
delete_object(existing) | delete_object(existing) | ||||
elif master and hasattr(master, '_imap_folder'): | elif master and hasattr(master, '_imap_folder'): | ||||
targetfolder = master._imap_folder | targetfolder = master._imap_folder | ||||
delete_object(master) | delete_object(master) | ||||
if not nonpart or existing: | if not nonpart or existing: | ||||
# save new copy from iTip | # save new copy from iTip | ||||
if store_object(itip_event['xml'], receiving_user, targetfolder, master): | if store_object(itip_event['xml'], receiving_user, targetfolder, master): | ||||
Lint: PEP8 E501 line too long (85 > 79 characters) Lint: PEP8 E501: line too long (85 > 79 characters) | |||||
if policy & COND_FORWARD: | if policy & COND_FORWARD: | ||||
log.debug(_("Forward invitation for notification"), level=5) | log.debug(_("Forward invitation for notification"), level=5) | ||||
Lint: PEP8 E501 line too long (80 > 79 characters) Lint: PEP8 E501: line too long (80 > 79 characters) | |||||
return MESSAGE_FORWARD | return MESSAGE_FORWARD | ||||
else: | else: | ||||
return MESSAGE_PROCESSED | return MESSAGE_PROCESSED | ||||
return None | return None | ||||
def process_itip_reply(itip_event, policy, recipient_email, sender_email, receiving_user): | def process_itip_reply(itip_event, policy, recipient_email, sender_email, receiving_user): | ||||
Lint: PEP8 E501 line too long (90 > 79 characters) Lint: PEP8 E501: line too long (90 > 79 characters) | |||||
""" | """ | ||||
Process an iTip REPLY message according to the given policy | Process an iTip REPLY message according to the given policy | ||||
""" | """ | ||||
# if invitation policy is set to MANUAL, pass message along | # if invitation policy is set to MANUAL, pass message along | ||||
if policy & ACT_MANUAL: | if policy & ACT_MANUAL: | ||||
log.info(_("Pass reply for manual processing")) | log.info(_("Pass reply for manual processing")) | ||||
return MESSAGE_FORWARD | return MESSAGE_FORWARD | ||||
# auto-update is enabled for this user | # auto-update is enabled for this user | ||||
if policy & ACT_UPDATE: | if policy & ACT_UPDATE: | ||||
try: | try: | ||||
sender_attendee = itip_event['xml'].get_attendee_by_email(sender_email) | sender_attendee = itip_event['xml'].get_attendee_by_email(sender_email) | ||||
Lint: PEP8 E501 line too long (83 > 79 characters) Lint: PEP8 E501: line too long (83 > 79 characters) | |||||
log.debug(_("Sender Attendee: %r") % (sender_attendee), level=9) | log.debug(_("Sender Attendee: %r") % (sender_attendee), level=9) | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error("Could not find envelope sender attendee: %r" % (errmsg)) | log.error("Could not find envelope sender attendee: %r" % (errmsg)) | ||||
return MESSAGE_FORWARD | return MESSAGE_FORWARD | ||||
# find existing event in user's calendar | # find existing event in user's calendar | ||||
# sets/checks lock to avoid concurrent wallace processes trying to update the same event simultaneously | # sets/checks lock to avoid concurrent wallace processes trying to update the same event simultaneously | ||||
Lint: PEP8 E501 line too long (111 > 79 characters) Lint: PEP8 E501: line too long (111 > 79 characters) | |||||
(existing, master) = find_existing_object(itip_event['uid'], itip_event['type'], itip_event['recurrence-id'], receiving_user, True) | (existing, master) = find_existing_object(itip_event['uid'], itip_event['type'], itip_event['recurrence-id'], receiving_user, True) | ||||
Lint: PEP8 E501 line too long (139 > 79 characters) Lint: PEP8 E501: line too long (139 > 79 characters) | |||||
if existing: | if existing: | ||||
# compare sequence number to avoid outdated replies? | # compare sequence number to avoid outdated replies? | ||||
if not itip_event['sequence'] == existing.get_sequence(): | if not itip_event['sequence'] == existing.get_sequence(): | ||||
log.info(_("The iTip reply sequence (%r) doesn't match the referred object version (%r). Forwarding to Inbox.") % ( | log.info(_("The iTip reply sequence (%r) doesn't match the referred object version (%r). Forwarding to Inbox.") % ( | ||||
Lint: PEP8 E501 line too long (131 > 79 characters) Lint: PEP8 E501: line too long (131 > 79 characters) | |||||
itip_event['sequence'], existing.get_sequence() | itip_event['sequence'], existing.get_sequence() | ||||
)) | )) | ||||
remove_write_lock(existing._lock_key) | remove_write_lock(existing._lock_key) | ||||
return MESSAGE_FORWARD | return MESSAGE_FORWARD | ||||
log.debug(_("Auto-updating %s %r on iTip REPLY") % (existing.type, existing.uid), level=8) | log.debug(_("Auto-updating %s %r on iTip REPLY") % (existing.type, existing.uid), level=8) | ||||
Lint: PEP8 E501 line too long (102 > 79 characters) Lint: PEP8 E501: line too long (102 > 79 characters) | |||||
updated_attendees = [] | updated_attendees = [] | ||||
try: | try: | ||||
existing.set_attendee_participant_status(sender_email, sender_attendee.get_participant_status(), rsvp=False) | existing.set_attendee_participant_status(sender_email, sender_attendee.get_participant_status(), rsvp=False) | ||||
Lint: PEP8 E501 line too long (124 > 79 characters) Lint: PEP8 E501: line too long (124 > 79 characters) | |||||
existing_attendee = existing.get_attendee(sender_email) | existing_attendee = existing.get_attendee(sender_email) | ||||
updated_attendees.append(existing_attendee) | updated_attendees.append(existing_attendee) | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error("Could not find corresponding attende in organizer's copy: %r" % (errmsg)) | log.error("Could not find corresponding attende in organizer's copy: %r" % (errmsg)) | ||||
Lint: PEP8 E501 line too long (100 > 79 characters) Lint: PEP8 E501: line too long (100 > 79 characters) | |||||
# append delegated-from attendee ? | # append delegated-from attendee ? | ||||
if len(sender_attendee.get_delegated_from()) > 0: | if len(sender_attendee.get_delegated_from()) > 0: | ||||
existing.add_attendee(sender_attendee) | existing.add_attendee(sender_attendee) | ||||
updated_attendees.append(sender_attendee) | updated_attendees.append(sender_attendee) | ||||
else: | else: | ||||
# TODO: accept new participant if ACT_ACCEPT ? | # TODO: accept new participant if ACT_ACCEPT ? | ||||
remove_write_lock(existing._lock_key) | remove_write_lock(existing._lock_key) | ||||
return MESSAGE_FORWARD | return MESSAGE_FORWARD | ||||
# append delegated-to attendee | # append delegated-to attendee | ||||
if len(sender_attendee.get_delegated_to()) > 0: | if len(sender_attendee.get_delegated_to()) > 0: | ||||
try: | try: | ||||
delegatee_email = sender_attendee.get_delegated_to(True)[0] | delegatee_email = sender_attendee.get_delegated_to(True)[0] | ||||
sender_delegatee = itip_event['xml'].get_attendee_by_email(delegatee_email) | sender_delegatee = itip_event['xml'].get_attendee_by_email(delegatee_email) | ||||
Lint: PEP8 E501 line too long (95 > 79 characters) Lint: PEP8 E501: line too long (95 > 79 characters) | |||||
existing_delegatee = existing.find_attendee(delegatee_email) | existing_delegatee = existing.find_attendee(delegatee_email) | ||||
Lint: PEP8 E501 line too long (80 > 79 characters) Lint: PEP8 E501: line too long (80 > 79 characters) | |||||
if not existing_delegatee: | if not existing_delegatee: | ||||
existing.add_attendee(sender_delegatee) | existing.add_attendee(sender_delegatee) | ||||
log.debug(_("Add delegatee: %r") % (sender_delegatee.to_dict()), level=9) | log.debug(_("Add delegatee: %r") % (sender_delegatee.to_dict()), level=9) | ||||
Lint: PEP8 E501 line too long (97 > 79 characters) Lint: PEP8 E501: line too long (97 > 79 characters) | |||||
else: | else: | ||||
existing_delegatee.copy_from(sender_delegatee) | existing_delegatee.copy_from(sender_delegatee) | ||||
log.debug(_("Update existing delegatee: %r") % (existing_delegatee.to_dict()), level=9) | log.debug(_("Update existing delegatee: %r") % (existing_delegatee.to_dict()), level=9) | ||||
Lint: PEP8 E501 line too long (111 > 79 characters) Lint: PEP8 E501: line too long (111 > 79 characters) | |||||
updated_attendees.append(sender_delegatee) | updated_attendees.append(sender_delegatee) | ||||
# copy all parameters from replying attendee (e.g. delegated-to, role, etc.) | # copy all parameters from replying attendee (e.g. delegated-to, role, etc.) | ||||
Lint: PEP8 E501 line too long (96 > 79 characters) Lint: PEP8 E501: line too long (96 > 79 characters) | |||||
existing_attendee.copy_from(sender_attendee) | existing_attendee.copy_from(sender_attendee) | ||||
existing.update_attendees([existing_attendee]) | existing.update_attendees([existing_attendee]) | ||||
log.debug(_("Update delegator: %r") % (existing_attendee.to_dict()), level=9) | log.debug(_("Update delegator: %r") % (existing_attendee.to_dict()), level=9) | ||||
Lint: PEP8 E501 line too long (97 > 79 characters) Lint: PEP8 E501: line too long (97 > 79 characters) | |||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error("Could not find delegated-to attendee: %r" % (errmsg)) | log.error("Could not find delegated-to attendee: %r" % (errmsg)) | ||||
Lint: PEP8 E501 line too long (84 > 79 characters) Lint: PEP8 E501: line too long (84 > 79 characters) | |||||
# update the organizer's copy of the object | # update the organizer's copy of the object | ||||
if update_object(existing, receiving_user, master): | if update_object(existing, receiving_user, master): | ||||
if policy & COND_NOTIFY: | if policy & COND_NOTIFY: | ||||
send_update_notification(existing, receiving_user, existing, True) | send_update_notification(existing, receiving_user, existing, True) | ||||
Lint: PEP8 E501 line too long (86 > 79 characters) Lint: PEP8 E501: line too long (86 > 79 characters) | |||||
# update all other attendee's copies | # update all other attendee's copies | ||||
if conf.get('wallace','invitationpolicy_autoupdate_other_attendees_on_reply'): | if conf.get('wallace','invitationpolicy_autoupdate_other_attendees_on_reply'): | ||||
Lint: PEP8 E231 missing whitespace after ',' Lint: PEP8 E231: missing whitespace after ',' | |||||
Lint: PEP8 E501 line too long (94 > 79 characters) Lint: PEP8 E501: line too long (94 > 79 characters) | |||||
propagate_changes_to_attendees_accounts(existing, updated_attendees) | propagate_changes_to_attendees_accounts(existing, updated_attendees) | ||||
Lint: PEP8 E501 line too long (88 > 79 characters) Lint: PEP8 E501: line too long (88 > 79 characters) | |||||
return MESSAGE_PROCESSED | return MESSAGE_PROCESSED | ||||
else: | 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 reply was not found in the user's folders. Forwarding to Inbox.")) | ||||
Lint: PEP8 E501 line too long (119 > 79 characters) Lint: PEP8 E501: line too long (119 > 79 characters) | |||||
return MESSAGE_FORWARD | return MESSAGE_FORWARD | ||||
return None | return None | ||||
def process_itip_cancel(itip_event, policy, recipient_email, sender_email, receiving_user): | def process_itip_cancel(itip_event, policy, recipient_email, sender_email, receiving_user): | ||||
Lint: PEP8 E501 line too long (91 > 79 characters) Lint: PEP8 E501: line too long (91 > 79 characters) | |||||
""" | """ | ||||
Process an iTip CANCEL message according to the given policy | Process an iTip CANCEL message according to the given policy | ||||
""" | """ | ||||
# if invitation policy is set to MANUAL, pass message along | # if invitation policy is set to MANUAL, pass message along | ||||
if policy & ACT_MANUAL: | if policy & ACT_MANUAL: | ||||
log.info(_("Pass cancellation for manual processing")) | log.info(_("Pass cancellation for manual processing")) | ||||
return MESSAGE_FORWARD | return MESSAGE_FORWARD | ||||
# auto-update the local copy | # auto-update the local copy | ||||
if policy & ACT_UPDATE or policy & ACT_CANCEL_DELETE: | if policy & ACT_UPDATE or policy & ACT_CANCEL_DELETE: | ||||
# find existing object in user's folders | # find existing object in user's folders | ||||
(existing, master) = find_existing_object(itip_event['uid'], itip_event['type'], itip_event['recurrence-id'], receiving_user, True) | (existing, master) = find_existing_object(itip_event['uid'], itip_event['type'], itip_event['recurrence-id'], receiving_user, True) | ||||
Lint: PEP8 E501 line too long (139 > 79 characters) Lint: PEP8 E501: line too long (139 > 79 characters) | |||||
remove_object = policy & ACT_CANCEL_DELETE | remove_object = policy & ACT_CANCEL_DELETE | ||||
if existing: | if existing: | ||||
# on this-and-future cancel requests, set the recurrence until date on the master event | # on this-and-future cancel requests, set the recurrence until date on the master event | ||||
Lint: PEP8 E501 line too long (99 > 79 characters) Lint: PEP8 E501: line too long (99 > 79 characters) | |||||
if itip_event['recurrence-id'] and master and itip_event['xml'].get_thisandfuture(): | if itip_event['recurrence-id'] and master and itip_event['xml'].get_thisandfuture(): | ||||
Lint: PEP8 E501 line too long (96 > 79 characters) Lint: PEP8 E501: line too long (96 > 79 characters) | |||||
rrule = master.get_recurrence() | rrule = master.get_recurrence() | ||||
rrule.set_count(0) | rrule.set_count(0) | ||||
rrule.set_until(existing.get_start() + datetime.timedelta(days=-1)) | rrule.set_until(existing.get_start() + datetime.timedelta(days=-1)) | ||||
Lint: PEP8 E501 line too long (83 > 79 characters) Lint: PEP8 E501: line too long (83 > 79 characters) | |||||
master.set_recurrence(rrule) | master.set_recurrence(rrule) | ||||
existing.set_recurrence_id(existing.get_recurrence_id(), True) | existing.set_recurrence_id(existing.get_recurrence_id(), True) | ||||
remove_object = False | remove_object = False | ||||
# delete the local copy | # delete the local copy | ||||
if remove_object: | if remove_object: | ||||
# remove exception and register an exdate to the main event | # remove exception and register an exdate to the main event | ||||
if master: | if master: | ||||
log.debug(_("Remove cancelled %s instance %s from %r") % (existing.type, itip_event['recurrence-id'], existing.uid), level=8) | log.debug(_("Remove cancelled %s instance %s from %r") % (existing.type, itip_event['recurrence-id'], existing.uid), level=8) | ||||
Lint: PEP8 E501 line too long (145 > 79 characters) Lint: PEP8 E501: line too long (145 > 79 characters) | |||||
master.add_exception_date(existing.get_start()) | master.add_exception_date(existing.get_start()) | ||||
master.del_exception(existing) | master.del_exception(existing) | ||||
success = update_object(master, receiving_user) | success = update_object(master, receiving_user) | ||||
# delete main event | # delete main event | ||||
else: | else: | ||||
success = delete_object(existing) | success = delete_object(existing) | ||||
# update the local copy with STATUS=CANCELLED | # update the local copy with STATUS=CANCELLED | ||||
else: | else: | ||||
log.debug(_("Update cancelled %s %r with STATUS=CANCELLED") % (existing.type, existing.uid), level=8) | log.debug(_("Update cancelled %s %r with STATUS=CANCELLED") % (existing.type, existing.uid), level=8) | ||||
Lint: PEP8 E501 line too long (117 > 79 characters) Lint: PEP8 E501: line too long (117 > 79 characters) | |||||
existing.set_status('CANCELLED') | existing.set_status('CANCELLED') | ||||
existing.set_transparency(True) | existing.set_transparency(True) | ||||
success = update_object(existing, receiving_user, master) | success = update_object(existing, receiving_user, master) | ||||
if success: | if success: | ||||
# send cancellation notification | # send cancellation notification | ||||
if policy & COND_NOTIFY: | if policy & COND_NOTIFY: | ||||
send_cancel_notification(existing, receiving_user, remove_object) | send_cancel_notification(existing, receiving_user, remove_object) | ||||
Lint: PEP8 E501 line too long (85 > 79 characters) Lint: PEP8 E501: line too long (85 > 79 characters) | |||||
return MESSAGE_PROCESSED | return MESSAGE_PROCESSED | ||||
else: | else: | ||||
log.error(_("The object referred by this cancel request 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.")) | ||||
Lint: PEP8 E501 line too long (128 > 79 characters) Lint: PEP8 E501: line too long (128 > 79 characters) | |||||
return MESSAGE_FORWARD | return MESSAGE_FORWARD | ||||
return None | return None | ||||
def user_dn_from_email_address(email_address): | def user_dn_from_email_address(email_address): | ||||
""" | """ | ||||
Resolves the given email address to a Kolab user entity | Resolves the given email address to a Kolab user entity | ||||
""" | """ | ||||
global auth | global auth | ||||
if not auth: | if not auth: | ||||
auth = Auth() | auth = Auth() | ||||
auth.connect() | auth.connect() | ||||
# return cached value | # return cached value | ||||
if user_dn_from_email_address.cache.has_key(email_address): | if user_dn_from_email_address.cache.has_key(email_address): | ||||
return user_dn_from_email_address.cache[email_address] | return user_dn_from_email_address.cache[email_address] | ||||
local_domains = auth.list_domains() | local_domains = auth.list_domains() | ||||
if not local_domains == None: | if local_domains is not None: | ||||
local_domains = list(set(local_domains.keys())) | local_domains = list(set(local_domains.keys())) | ||||
if not email_address.split('@')[1] in local_domains: | if not email_address.split('@')[1] in local_domains: | ||||
user_dn_from_email_address.cache[email_address] = None | user_dn_from_email_address.cache[email_address] = None | ||||
return None | return None | ||||
log.debug(_("Checking if email address %r belongs to a local user") % (email_address), level=8) | log.debug(_("Checking if email address %r belongs to a local user") % (email_address), level=8) | ||||
Lint: PEP8 E501 line too long (99 > 79 characters) Lint: PEP8 E501: line too long (99 > 79 characters) | |||||
user_dn = auth.find_user_dn(email_address, True) | user_dn = auth.find_user_dn(email_address, True) | ||||
if isinstance(user_dn, basestring): | if isinstance(user_dn, basestring): | ||||
log.debug(_("User DN: %r") % (user_dn), level=8) | log.debug(_("User DN: %r") % (user_dn), level=8) | ||||
else: | else: | ||||
log.debug(_("No user record(s) found for %r") % (email_address), level=9) | log.debug(_("No user record(s) found for %r") % (email_address), level=9) | ||||
Lint: PEP8 E501 line too long (81 > 79 characters) Lint: PEP8 E501: line too long (81 > 79 characters) | |||||
# remember this lookup | # remember this lookup | ||||
user_dn_from_email_address.cache[email_address] = user_dn | user_dn_from_email_address.cache[email_address] = user_dn | ||||
return user_dn | return user_dn | ||||
user_dn_from_email_address.cache = {} | user_dn_from_email_address.cache = {} | ||||
def get_matching_invitation_policies(receiving_user, sender_email, type_condition=COND_TYPE_ALL): | def get_matching_invitation_policies(receiving_user, sender_email, type_condition=COND_TYPE_ALL): | ||||
Lint: PEP8 E501 line too long (97 > 79 characters) Lint: PEP8 E501: line too long (97 > 79 characters) | |||||
# get user's kolabInvitationPolicy settings | # get user's kolabInvitationPolicy settings | ||||
policies = receiving_user['kolabinvitationpolicy'] if receiving_user.has_key('kolabinvitationpolicy') else [] | policies = receiving_user['kolabinvitationpolicy'] if receiving_user.has_key('kolabinvitationpolicy') else [] | ||||
Lint: PEP8 E501 line too long (113 > 79 characters) Lint: PEP8 E501: line too long (113 > 79 characters) | |||||
if policies and not isinstance(policies, list): | if policies and not isinstance(policies, list): | ||||
policies = [policies] | policies = [policies] | ||||
if len(policies) == 0: | if len(policies) == 0: | ||||
policies = conf.get_list('wallace', 'kolab_invitation_policy') | policies = conf.get_list('wallace', 'kolab_invitation_policy') | ||||
# match policies agains the given sender_email | # match policies agains the given sender_email | ||||
matches = [] | matches = [] | ||||
for p in policies: | for p in policies: | ||||
if ':' in p: | if ':' in p: | ||||
(value, domain) = p.split(':', 1) | (value, domain) = p.split(':', 1) | ||||
else: | else: | ||||
value = p | value = p | ||||
domain = '' | domain = '' | ||||
if domain == '' or domain == '*' or str(sender_email).endswith(domain): | if domain == '' or domain == '*' or str(sender_email).endswith(domain): | ||||
value = value.upper() | value = value.upper() | ||||
if policy_name_map.has_key(value): | if policy_name_map.has_key(value): | ||||
val = policy_name_map[value] | val = policy_name_map[value] | ||||
# append if type condition matches | # append if type condition matches | ||||
if val & type_condition: | if val & type_condition: | ||||
matches.append(val &~ COND_TYPE_ALL) | matches.append(val &~ COND_TYPE_ALL) | ||||
Lint: PEP8 E225 missing whitespace around operator Lint: PEP8 E225: missing whitespace around operator | |||||
# add manual as default action | # add manual as default action | ||||
if len(matches) == 0: | if len(matches) == 0: | ||||
matches.append(ACT_MANUAL) | matches.append(ACT_MANUAL) | ||||
return matches | return matches | ||||
def imap_proxy_auth(user_rec): | def imap_proxy_auth(user_rec): | ||||
""" | """ | ||||
Perform IMAP login using proxy authentication with admin credentials | Perform IMAP login using proxy authentication with admin credentials | ||||
""" | """ | ||||
global imap | global imap | ||||
mail_attribute = conf.get('cyrus-sasl', 'result_attribute') | mail_attribute = conf.get('cyrus-sasl', 'result_attribute') | ||||
if mail_attribute == None: | if mail_attribute is None: | ||||
mail_attribute = 'mail' | mail_attribute = 'mail' | ||||
mail_attribute = mail_attribute.lower() | mail_attribute = mail_attribute.lower() | ||||
if not user_rec.has_key(mail_attribute): | if not user_rec.has_key(mail_attribute): | ||||
log.error(_("User record doesn't have the mailbox attribute %r set" % (mail_attribute))) | log.error(_("User record doesn't have the mailbox attribute %r set" % (mail_attribute))) | ||||
Lint: PEP8 E501 line too long (96 > 79 characters) Lint: PEP8 E501: line too long (96 > 79 characters) | |||||
return False | return False | ||||
# do IMAP prox auth with the given user | # do IMAP prox auth with the given user | ||||
backend = conf.get('kolab', 'imap_backend') | backend = conf.get('kolab', 'imap_backend') | ||||
admin_login = conf.get(backend, 'admin_login') | admin_login = conf.get(backend, 'admin_login') | ||||
admin_password = conf.get(backend, 'admin_password') | admin_password = conf.get(backend, 'admin_password') | ||||
try: | try: | ||||
Show All 10 Lines | |||||
def list_user_folders(user_rec, type): | def list_user_folders(user_rec, type): | ||||
""" | """ | ||||
Get a list of the given user's private calendar/tasks folders | Get a list of the given user's private calendar/tasks folders | ||||
""" | """ | ||||
global imap | global imap | ||||
# return cached list | # return cached list | ||||
if user_rec.has_key('_imap_folders'): | if user_rec.has_key('_imap_folders'): | ||||
return user_rec['_imap_folders']; | return user_rec['_imap_folders']; | ||||
Lint: PEP8 E703 statement ends with a semicolon Lint: PEP8 E703: statement ends with a semicolon | |||||
result = [] | result = [] | ||||
if not imap_proxy_auth(user_rec): | if not imap_proxy_auth(user_rec): | ||||
return result | return result | ||||
folders = imap.list_folders('*') | folders = imap.list_folders('*') | ||||
log.debug(_("List %r folders for user %r: %r") % (type, user_rec['mail'], folders), level=8) | log.debug(_("List %r folders for user %r: %r") % (type, user_rec['mail'], folders), level=8) | ||||
Lint: PEP8 E501 line too long (96 > 79 characters) Lint: PEP8 E501: line too long (96 > 79 characters) | |||||
(ns_personal, ns_other, ns_shared) = imap.namespaces() | (ns_personal, ns_other, ns_shared) = imap.namespaces() | ||||
for folder in folders: | for folder in folders: | ||||
# exclude shared and other user's namespace | # exclude shared and other user's namespace | ||||
if not ns_other is None and folder.startswith(ns_other) and user_rec.has_key('_delegated_mailboxes'): | if not ns_other is None and folder.startswith(ns_other) and user_rec.has_key('_delegated_mailboxes'): | ||||
Lint: PEP8 E714 test for object identity should be 'is not' Lint: PEP8 E714: test for object identity should be 'is not' | |||||
Lint: PEP8 E501 line too long (109 > 79 characters) Lint: PEP8 E501: line too long (109 > 79 characters) | |||||
# allow shared folders from delegators | # allow shared folders from delegators | ||||
if len([_mailbox for _mailbox in user_rec['_delegated_mailboxes'] if folder.startswith(ns_other + _mailbox + '/')]) == 0: | if len([_mailbox for _mailbox in user_rec['_delegated_mailboxes'] if folder.startswith(ns_other + _mailbox + '/')]) == 0: | ||||
Lint: PEP8 E501 line too long (133 > 79 characters) Lint: PEP8 E501: line too long (133 > 79 characters) | |||||
continue; | continue; | ||||
Lint: PEP8 E703 statement ends with a semicolon Lint: PEP8 E703: statement ends with a semicolon | |||||
# TODO: list shared folders the user has write privileges ? | # TODO: list shared folders the user has write privileges ? | ||||
if not ns_shared is None and len([_ns for _ns in ns_shared if folder.startswith(_ns)]) > 0: | if not ns_shared is None and len([_ns for _ns in ns_shared if folder.startswith(_ns)]) > 0: | ||||
Lint: PEP8 E714 test for object identity should be 'is not' Lint: PEP8 E714: test for object identity should be 'is not' | |||||
Lint: PEP8 E501 line too long (99 > 79 characters) Lint: PEP8 E501: line too long (99 > 79 characters) | |||||
continue; | continue; | ||||
Lint: PEP8 E703 statement ends with a semicolon Lint: PEP8 E703: statement ends with a semicolon | |||||
metadata = imap.get_metadata(folder) | metadata = imap.get_metadata(folder) | ||||
log.debug(_("IMAP metadata for %r: %r") % (folder, metadata), level=9) | log.debug(_("IMAP metadata for %r: %r") % (folder, metadata), level=9) | ||||
if metadata.has_key(folder) and ( \ | if metadata.has_key(folder) and ( \ | ||||
Lint: PEP8 E502 the backslash is redundant between brackets Lint: PEP8 E502: the backslash is redundant between brackets | |||||
metadata[folder].has_key('/shared' + FOLDER_TYPE_ANNOTATION) and metadata[folder]['/shared' + FOLDER_TYPE_ANNOTATION].startswith(type) \ | metadata[folder].has_key('/shared' + FOLDER_TYPE_ANNOTATION) and metadata[folder]['/shared' + FOLDER_TYPE_ANNOTATION].startswith(type) \ | ||||
Lint: PEP8 E501 line too long (148 > 79 characters) Lint: PEP8 E501: line too long (148 > 79 characters) | |||||
Lint: PEP8 E502 the backslash is redundant between brackets Lint: PEP8 E502: the backslash is redundant between brackets | |||||
or metadata[folder].has_key('/private' + FOLDER_TYPE_ANNOTATION) and metadata[folder]['/private' + FOLDER_TYPE_ANNOTATION].startswith(type)): | or metadata[folder].has_key('/private' + FOLDER_TYPE_ANNOTATION) and metadata[folder]['/private' + FOLDER_TYPE_ANNOTATION].startswith(type)): | ||||
Lint: PEP8 E125 continuation line with same indent as next logical line Lint: PEP8 E125: continuation line with same indent as next logical line | |||||
Lint: PEP8 E501 line too long (153 > 79 characters) Lint: PEP8 E501: line too long (153 > 79 characters) | |||||
result.append(folder) | result.append(folder) | ||||
if metadata[folder].has_key('/private' + FOLDER_TYPE_ANNOTATION): | if metadata[folder].has_key('/private' + FOLDER_TYPE_ANNOTATION): | ||||
# store default folder in user record | # store default folder in user record | ||||
if metadata[folder]['/private' + FOLDER_TYPE_ANNOTATION].endswith('.default'): | if metadata[folder]['/private' + FOLDER_TYPE_ANNOTATION].endswith('.default'): | ||||
Lint: PEP8 E501 line too long (94 > 79 characters) Lint: PEP8 E501: line too long (94 > 79 characters) | |||||
user_rec['_default_folder'] = folder | user_rec['_default_folder'] = folder | ||||
# store private and confidential folders in user record | # store private and confidential folders in user record | ||||
if metadata[folder]['/private' + FOLDER_TYPE_ANNOTATION].endswith('.confidential') and not user_rec.has_key('_confidential_folder'): | if metadata[folder]['/private' + FOLDER_TYPE_ANNOTATION].endswith('.confidential') and not user_rec.has_key('_confidential_folder'): | ||||
Lint: PEP8 E501 line too long (148 > 79 characters) Lint: PEP8 E501: line too long (148 > 79 characters) | |||||
user_rec['_confidential_folder'] = folder | user_rec['_confidential_folder'] = folder | ||||
if metadata[folder]['/private' + FOLDER_TYPE_ANNOTATION].endswith('.private') and not user_rec.has_key('_private_folder'): | if metadata[folder]['/private' + FOLDER_TYPE_ANNOTATION].endswith('.private') and not user_rec.has_key('_private_folder'): | ||||
Lint: PEP8 E501 line too long (138 > 79 characters) Lint: PEP8 E501: line too long (138 > 79 characters) | |||||
user_rec['_private_folder'] = folder | user_rec['_private_folder'] = folder | ||||
# cache with user record | # cache with user record | ||||
user_rec['_imap_folders'] = result | user_rec['_imap_folders'] = result | ||||
return result | return result | ||||
def find_existing_object(uid, type, recurrence_id, 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) | Search user's private folders for the given object (by UID+type) | ||||
""" | """ | ||||
global imap | global imap | ||||
lock_key = None | lock_key = None | ||||
if lock: | if lock: | ||||
lock_key = get_lock_key(user_rec, uid) | lock_key = get_lock_key(user_rec, uid) | ||||
set_write_lock(lock_key) | set_write_lock(lock_key) | ||||
event = None | event = None | ||||
master = None | master = None | ||||
for folder in list_user_folders(user_rec, type): | for folder in list_user_folders(user_rec, type): | ||||
log.debug(_("Searching folder %r for %s %r") % (folder, type, uid), level=8) | log.debug(_("Searching folder %r for %s %r") % (folder, type, uid), level=8) | ||||
Lint: PEP8 E501 line too long (84 > 79 characters) Lint: PEP8 E501: line too long (84 > 79 characters) | |||||
imap.imap.m.select(imap.folder_utf7(folder)) | imap.imap.m.select(imap.folder_utf7(folder)) | ||||
res, data = imap.imap.m.search(None, '(UNDELETED HEADER SUBJECT "%s")' % (uid)) | res, data = imap.imap.m.search(None, '(UNDELETED HEADER SUBJECT "%s")' % (uid)) | ||||
Lint: PEP8 E501 line too long (87 > 79 characters) Lint: PEP8 E501: line too long (87 > 79 characters) | |||||
for num in reversed(data[0].split()): | for num in reversed(data[0].split()): | ||||
res, data = imap.imap.m.fetch(num, '(UID RFC822)') | res, data = imap.imap.m.fetch(num, '(UID RFC822)') | ||||
try: | try: | ||||
msguid = re.search(r"\WUID (\d+)", data[0][0]).group(1) | msguid = re.search(r"\WUID (\d+)", data[0][0]).group(1) | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error(_("No UID found in IMAP response: %r") % (data[0][0])) | log.error(_("No UID found in IMAP response: %r") % (data[0][0])) | ||||
Lint: PEP8 E501 line too long (80 > 79 characters) Lint: PEP8 E501: line too long (80 > 79 characters) | |||||
continue | continue | ||||
try: | try: | ||||
if type == 'task': | if type == 'task': | ||||
event = todo_from_message(message_from_string(data[0][1])) | event = todo_from_message(message_from_string(data[0][1])) | ||||
else: | else: | ||||
event = event_from_message(message_from_string(data[0][1])) | event = event_from_message(message_from_string(data[0][1])) | ||||
# find instance in a recurring series | # find instance in a recurring series | ||||
if recurrence_id and (event.is_recurring() or event.has_exceptions() or event.get_recurrence_id()): | if recurrence_id and (event.is_recurring() or event.has_exceptions() or event.get_recurrence_id()): | ||||
Lint: PEP8 E501 line too long (115 > 79 characters) Lint: PEP8 E501: line too long (115 > 79 characters) | |||||
master = event | master = event | ||||
event = master.get_instance(recurrence_id) | event = master.get_instance(recurrence_id) | ||||
setattr(master, '_imap_folder', folder) | setattr(master, '_imap_folder', folder) | ||||
setattr(master, '_msguid', msguid) | setattr(master, '_msguid', msguid) | ||||
# return master, even if instance is not found | # return master, even if instance is not found | ||||
if not event and master.uid == uid: | if not event and master.uid == uid: | ||||
return (event, master) | return (event, master) | ||||
if event is not None: | if event is not None: | ||||
setattr(event, '_imap_folder', folder) | setattr(event, '_imap_folder', folder) | ||||
setattr(event, '_lock_key', lock_key) | setattr(event, '_lock_key', lock_key) | ||||
setattr(event, '_msguid', msguid) | setattr(event, '_msguid', msguid) | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error(_("Failed to parse %s from message %s/%s: %s") % (type, folder, num, traceback.format_exc())) | log.error(_("Failed to parse %s from message %s/%s: %s") % (type, folder, num, traceback.format_exc())) | ||||
Lint: PEP8 E501 line too long (119 > 79 characters) Lint: PEP8 E501: line too long (119 > 79 characters) | |||||
event = None | event = None | ||||
master = None | master = None | ||||
continue | continue | ||||
if event and event.uid == uid: | if event and event.uid == uid: | ||||
return (event, master) | return (event, master) | ||||
if lock_key is not None: | if lock_key is not None: | ||||
remove_write_lock(lock_key) | remove_write_lock(lock_key) | ||||
return (event, master) | return (event, master) | ||||
def check_availability(itip_event, receiving_user): | def check_availability(itip_event, receiving_user): | ||||
""" | """ | ||||
For the receiving user, determine if the event in question is in conflict. | For the receiving user, determine if the event in question is in conflict. | ||||
Lint: PEP8 E501 line too long (82 > 79 characters) Lint: PEP8 E501: line too long (82 > 79 characters) | |||||
""" | """ | ||||
start = time.time() | start = time.time() | ||||
num_messages = 0 | num_messages = 0 | ||||
conflict = False | conflict = False | ||||
# return previously detected conflict | # return previously detected conflict | ||||
if itip_event.has_key('_conflicts'): | if itip_event.has_key('_conflicts'): | ||||
return not itip_event['_conflicts'] | return not itip_event['_conflicts'] | ||||
for folder in list_user_folders(receiving_user, 'event'): | for folder in list_user_folders(receiving_user, 'event'): | ||||
log.debug(_("Listing events from folder %r") % (folder), level=8) | log.debug(_("Listing events from folder %r") % (folder), level=8) | ||||
imap.imap.m.select(imap.folder_utf7(folder)) | imap.imap.m.select(imap.folder_utf7(folder)) | ||||
res, 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")') | ||||
Lint: PEP8 E501 line too long (111 > 79 characters) Lint: PEP8 E501: line too long (111 > 79 characters) | |||||
num_messages += len(data[0].split()) | num_messages += len(data[0].split()) | ||||
for num in reversed(data[0].split()): | for num in reversed(data[0].split()): | ||||
event = None | event = None | ||||
res, data = imap.imap.m.fetch(num, '(RFC822)') | res, data = imap.imap.m.fetch(num, '(RFC822)') | ||||
try: | try: | ||||
event = event_from_message(message_from_string(data[0][1])) | event = event_from_message(message_from_string(data[0][1])) | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error(_("Failed to parse event from message %s/%s: %r") % (folder, num, errmsg)) | log.error(_("Failed to parse event from message %s/%s: %r") % (folder, num, errmsg)) | ||||
Lint: PEP8 E501 line too long (100 > 79 characters) Lint: PEP8 E501: line too long (100 > 79 characters) | |||||
continue | continue | ||||
if event and event.uid: | if event and event.uid: | ||||
conflict = check_event_conflict(event, itip_event) | conflict = check_event_conflict(event, itip_event) | ||||
if conflict: | if conflict: | ||||
log.info(_("Existing event %r conflicts with invitation %r") % (event.uid, itip_event['uid'])) | log.info(_("Existing event %r conflicts with invitation %r") % (event.uid, itip_event['uid'])) | ||||
Lint: PEP8 E501 line too long (114 > 79 characters) Lint: PEP8 E501: line too long (114 > 79 characters) | |||||
break | break | ||||
if conflict: | if conflict: | ||||
break | break | ||||
end = time.time() | end = time.time() | ||||
log.debug(_("start: %r, end: %r, total: %r, messages: %d") % (start, end, (end-start), num_messages), level=9) | log.debug(_("start: %r, end: %r, total: %r, messages: %d") % (start, end, (end-start), num_messages), level=9) | ||||
Lint: PEP8 E501 line too long (114 > 79 characters) Lint: PEP8 E501: line too long (114 > 79 characters) | |||||
# remember the result of this check for further iterations | # remember the result of this check for further iterations | ||||
itip_event['_conflicts'] = conflict | itip_event['_conflicts'] = conflict | ||||
return not conflict | return not conflict | ||||
def set_write_lock(key, wait=True): | def set_write_lock(key, wait=True): | ||||
""" | """ | ||||
Set a write-lock for the given key and wait if such a lock already exists | Set a write-lock for the given key and wait if such a lock already exists | ||||
Lint: PEP8 E501 line too long (81 > 79 characters) Lint: PEP8 E501: line too long (81 > 79 characters) | |||||
""" | """ | ||||
if not os.path.isdir(mybasepath): | if not os.path.isdir(mybasepath): | ||||
os.makedirs(mybasepath) | os.makedirs(mybasepath) | ||||
if not os.path.isdir(os.path.join(mybasepath, 'locks')): | if not os.path.isdir(os.path.join(mybasepath, 'locks')): | ||||
os.makedirs(os.path.join(mybasepath, 'locks')) | os.makedirs(os.path.join(mybasepath, 'locks')) | ||||
filename = os.path.join(mybasepath, 'locks', key + '.lock') | filename = os.path.join(mybasepath, 'locks', key + '.lock') | ||||
locktime = 0 | locktime = 0 | ||||
if os.path.isfile(filename): | if os.path.isfile(filename): | ||||
locktime = os.path.getmtime(filename) | locktime = os.path.getmtime(filename) | ||||
# wait if file lock is in place | # wait if file lock is in place | ||||
while time.time() < locktime + 300: | while time.time() < locktime + 300: | ||||
if not wait: | if not wait: | ||||
return False | return False | ||||
log.debug(_("%r is locked, waiting...") % (key), level=9) | log.debug(_("%r is locked, waiting...") % (key), level=9) | ||||
time.sleep(0.5) | time.sleep(0.5) | ||||
locktime = os.path.getmtime(filename) if os.path.isfile(filename) else 0 | locktime = os.path.getmtime(filename) if os.path.isfile(filename) else 0 | ||||
Lint: PEP8 E501 line too long (80 > 79 characters) Lint: PEP8 E501: line too long (80 > 79 characters) | |||||
# touch the file | # touch the file | ||||
if os.path.isfile(filename): | if os.path.isfile(filename): | ||||
os.utime(filename, None) | os.utime(filename, None) | ||||
else: | else: | ||||
open(filename, 'w').close() | open(filename, 'w').close() | ||||
# register active lock | # register active lock | ||||
Show All 29 Lines | def update_object(object, user_rec, master=None): | ||||
# updating a single instance only: use master event | # updating a single instance only: use master event | ||||
if object.get_recurrence_id() and master: | if object.get_recurrence_id() and master: | ||||
saveobj = master | saveobj = master | ||||
if hasattr(saveobj, '_imap_folder'): | if hasattr(saveobj, '_imap_folder'): | ||||
if delete_object(saveobj): | if delete_object(saveobj): | ||||
saveobj.set_lastmodified() # update last-modified timestamp | saveobj.set_lastmodified() # update last-modified timestamp | ||||
success = store_object(object, user_rec, saveobj._imap_folder, master) | success = store_object(object, user_rec, saveobj._imap_folder, master) | ||||
Lint: PEP8 E501 line too long (82 > 79 characters) Lint: PEP8 E501: line too long (82 > 79 characters) | |||||
# remove write lock for this event | # remove write lock for this event | ||||
if hasattr(saveobj, '_lock_key') and saveobj._lock_key is not None: | if hasattr(saveobj, '_lock_key') and saveobj._lock_key is not None: | ||||
remove_write_lock(saveobj._lock_key) | remove_write_lock(saveobj._lock_key) | ||||
return success | return success | ||||
def store_object(object, user_rec, targetfolder=None, master=None): | def store_object(object, user_rec, targetfolder=None, master=None): | ||||
""" | """ | ||||
Append the given object to the user's default calendar/tasklist | Append the given object to the user's default calendar/tasklist | ||||
""" | """ | ||||
# find default calendar folder to save object to if no target folder | # find calendar folder to save object to if not specified | ||||
# has already been specified. | |||||
if targetfolder is None: | if targetfolder is None: | ||||
targetfolders = list_user_folders(user_rec, object.type) | targetfolders = list_user_folders(user_rec, object.type) | ||||
oc = object.get_classification() | |||||
if not targetfolders == None and len(targetfolders) > 0: | # use *.confidential/private folder for confidential/private invitations | ||||
Lint: PEP8 E501 line too long (80 > 79 characters) Lint: PEP8 E501: line too long (80 > 79 characters) | |||||
targetfolder = targetfolders[0] | if oc == kolabformat.ClassConfidential and user_rec.has_key('_confidential_folder'): | ||||
Lint: PEP8 W601 .has_key() is deprecated, use 'in' Lint: PEP8 W601: .has_key() is deprecated, use 'in' | |||||
Lint: PEP8 E501 line too long (92 > 79 characters) Lint: PEP8 E501: line too long (92 > 79 characters) | |||||
if targetfolder is None: | |||||
if user_rec.has_key('_default_folder'): | |||||
targetfolder = user_rec['_default_folder'] | |||||
# use *.confidential folder for invitations classified as confidential | |||||
if object.get_classification() == kolabformat.ClassConfidential and user_rec.has_key('_confidential_folder'): | |||||
targetfolder = user_rec['_confidential_folder'] | targetfolder = user_rec['_confidential_folder'] | ||||
elif object.get_classification() == kolabformat.ClassPrivate and user_rec.has_key('_private_folder'): | elif oc == kolabformat.ClassPrivate and user_rec.has_key('_private_folder'): | ||||
Lint: PEP8 W601 .has_key() is deprecated, use 'in' Lint: PEP8 W601: .has_key() is deprecated, use 'in' | |||||
Lint: PEP8 E501 line too long (84 > 79 characters) Lint: PEP8 E501: line too long (84 > 79 characters) | |||||
targetfolder = user_rec['_private_folder'] | targetfolder = user_rec['_private_folder'] | ||||
# use *.default folder if exists | |||||
elif user_rec.has_key('_default_folder'): | |||||
Lint: PEP8 W601 .has_key() is deprecated, use 'in' Lint: PEP8 W601: .has_key() is deprecated, use 'in' | |||||
targetfolder = user_rec['_default_folder'] | |||||
# fallback to any existing folder of specified type | |||||
elif targetfolders is not None and len(targetfolders) > 0: | |||||
targetfolder = targetfolders[0] | |||||
if targetfolder == None: | if targetfolder is None: | ||||
log.error(_("Failed to save %s: no target folder found for user %r") % (object.type, user_rec['mail'])) | log.error(_("Failed to save %s: no target folder found for user %r") % (object.type, user_rec['mail'])) | ||||
Lint: PEP8 E501 line too long (111 > 79 characters) Lint: PEP8 E501: line too long (111 > 79 characters) | |||||
return False | return False | ||||
saveobj = object | saveobj = object | ||||
# updating a single instance only: add exception to master event | # updating a single instance only: add exception to master event | ||||
if object.get_recurrence_id() and master: | if object.get_recurrence_id() and master: | ||||
object.set_lastmodified() # update last-modified timestamp | object.set_lastmodified() # update last-modified timestamp | ||||
master.add_exception(object) | master.add_exception(object) | ||||
saveobj = master | saveobj = master | ||||
log.debug(_("Save %s %r to user folder %r") % (saveobj.type, saveobj.uid, targetfolder), level=8) | log.debug(_("Save %s %r to user folder %r") % (saveobj.type, saveobj.uid, targetfolder), level=8) | ||||
Lint: PEP8 E501 line too long (101 > 79 characters) Lint: PEP8 E501: line too long (101 > 79 characters) | |||||
try: | try: | ||||
imap.imap.m.select(imap.folder_utf7(targetfolder)) | imap.imap.m.select(imap.folder_utf7(targetfolder)) | ||||
result = imap.imap.m.append( | result = imap.imap.m.append( | ||||
imap.folder_utf7(targetfolder), | imap.folder_utf7(targetfolder), | ||||
None, | None, | ||||
None, | None, | ||||
saveobj.to_message(creator="Kolab Server <wallace@localhost>").as_string() | saveobj.to_message(creator="Kolab Server <wallace@localhost>").as_string() | ||||
Lint: PEP8 E501 line too long (86 > 79 characters) Lint: PEP8 E501: line too long (86 > 79 characters) | |||||
) | ) | ||||
return result | return result | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error(_("Failed to save %s to user folder at %r: %r") % ( | log.error(_("Failed to save %s to user folder at %r: %r") % ( | ||||
saveobj.type, targetfolder, errmsg | saveobj.type, targetfolder, errmsg | ||||
)) | )) | ||||
Show All 13 Lines | try: | ||||
# delete by IMAP UID | # delete by IMAP UID | ||||
if msguid is not None: | if msguid is not None: | ||||
log.debug(_("Delete %s %r in %r by UID: %r") % ( | log.debug(_("Delete %s %r in %r by UID: %r") % ( | ||||
existing.type, existing.uid, targetfolder, msguid | existing.type, existing.uid, targetfolder, msguid | ||||
), level=8) | ), level=8) | ||||
imap.imap.m.uid('store', msguid, '+FLAGS', '(\\Deleted)') | imap.imap.m.uid('store', msguid, '+FLAGS', '(\\Deleted)') | ||||
else: | else: | ||||
res, data = imap.imap.m.search(None, '(HEADER SUBJECT "%s")' % existing.uid) | res, data = imap.imap.m.search(None, '(HEADER SUBJECT "%s")' % existing.uid) | ||||
Lint: PEP8 E501 line too long (88 > 79 characters) Lint: PEP8 E501: line too long (88 > 79 characters) | |||||
log.debug(_("Delete %s %r in %r: %r") % ( | log.debug(_("Delete %s %r in %r: %r") % ( | ||||
existing.type, existing.uid, targetfolder, data | existing.type, existing.uid, targetfolder, data | ||||
), level=8) | ), level=8) | ||||
for num in data[0].split(): | for num in data[0].split(): | ||||
imap.imap.m.store(num, '+FLAGS', '(\\Deleted)') | imap.imap.m.store(num, '+FLAGS', '(\\Deleted)') | ||||
imap.imap.m.expunge() | imap.imap.m.expunge() | ||||
return True | return True | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error(_("Failed to delete %s from folder %r: %r") % ( | log.error(_("Failed to delete %s from folder %r: %r") % ( | ||||
existing.type, targetfolder, errmsg | existing.type, targetfolder, errmsg | ||||
)) | )) | ||||
return False | return False | ||||
def send_update_notification(object, receiving_user, old=None, reply=True): | def send_update_notification(object, receiving_user, old=None, reply=True): | ||||
""" | """ | ||||
Send a (consolidated) notification about the current participant status to organizer | Send a (consolidated) notification about the current participant status to organizer | ||||
Lint: PEP8 E501 line too long (92 > 79 characters) Lint: PEP8 E501: line too long (92 > 79 characters) | |||||
""" | """ | ||||
global auth | global auth | ||||
import smtplib | import smtplib | ||||
from email.MIMEText import MIMEText | from email.MIMEText import MIMEText | ||||
from email.Utils import formatdate | from email.Utils import formatdate | ||||
from email.header import Header | from email.header import Header | ||||
from email import charset | from email import charset | ||||
# encode unicode strings with quoted-printable | # encode unicode strings with quoted-printable | ||||
charset.add_charset('utf-8', charset.SHORTEST, charset.QP) | charset.add_charset('utf-8', charset.SHORTEST, charset.QP) | ||||
organizer = object.get_organizer() | organizer = object.get_organizer() | ||||
orgemail = organizer.email() | orgemail = organizer.email() | ||||
orgname = organizer.name() | orgname = organizer.name() | ||||
if reply: | if reply: | ||||
log.debug(_("Compose participation status summary for %s %r to user %r") % ( | log.debug(_("Compose participation status summary for %s %r to user %r") % ( | ||||
Lint: PEP8 E501 line too long (84 > 79 characters) Lint: PEP8 E501: line too long (84 > 79 characters) | |||||
object.type, object.uid, receiving_user['mail'] | object.type, object.uid, receiving_user['mail'] | ||||
), level=8) | ), level=8) | ||||
auto_replies_expected = 0 | auto_replies_expected = 0 | ||||
auto_replies_received = 0 | auto_replies_received = 0 | ||||
partstats = { 'ACCEPTED':[], 'TENTATIVE':[], 'DECLINED':[], 'DELEGATED':[], 'IN-PROCESS':[], 'COMPLETED':[], 'PENDING':[] } | partstats = { 'ACCEPTED':[], 'TENTATIVE':[], 'DECLINED':[], 'DELEGATED':[], 'IN-PROCESS':[], 'COMPLETED':[], 'PENDING':[] } | ||||
Lint: PEP8 E201 whitespace after '{' Lint: PEP8 E201: whitespace after '{' | |||||
Lint: PEP8 E231 missing whitespace after ':' Lint: PEP8 E231: missing whitespace after ':' | |||||
Lint: PEP8 E231 missing whitespace after ':' Lint: PEP8 E231: missing whitespace after ':' | |||||
Lint: PEP8 E231 missing whitespace after ':' Lint: PEP8 E231: missing whitespace after ':' | |||||
Lint: PEP8 E231 missing whitespace after ':' Lint: PEP8 E231: missing whitespace after ':' | |||||
Lint: PEP8 E501 line too long (131 > 79 characters) Lint: PEP8 E501: line too long (131 > 79 characters) | |||||
Lint: PEP8 E231 missing whitespace after ':' Lint: PEP8 E231: missing whitespace after ':' | |||||
Lint: PEP8 E231 missing whitespace after ':' Lint: PEP8 E231: missing whitespace after ':' | |||||
Lint: PEP8 E231 missing whitespace after ':' Lint: PEP8 E231: missing whitespace after ':' | |||||
Lint: PEP8 E202 whitespace before '}' Lint: PEP8 E202: whitespace before '}' | |||||
for attendee in object.get_attendees(): | for attendee in object.get_attendees(): | ||||
parstat = attendee.get_participant_status(True) | parstat = attendee.get_participant_status(True) | ||||
if partstats.has_key(parstat): | if partstats.has_key(parstat): | ||||
partstats[parstat].append(attendee.get_displayname()) | partstats[parstat].append(attendee.get_displayname()) | ||||
else: | else: | ||||
partstats['PENDING'].append(attendee.get_displayname()) | partstats['PENDING'].append(attendee.get_displayname()) | ||||
# look-up kolabinvitationpolicy for this attendee | # look-up kolabinvitationpolicy for this attendee | ||||
if attendee.get_cutype() == kolabformat.CutypeResource: | if attendee.get_cutype() == kolabformat.CutypeResource: | ||||
resource_dns = auth.find_resource(attendee.get_email()) | resource_dns = auth.find_resource(attendee.get_email()) | ||||
if isinstance(resource_dns, list): | if isinstance(resource_dns, list): | ||||
attendee_dn = resource_dns[0] if len(resource_dns) > 0 else None | attendee_dn = resource_dns[0] if len(resource_dns) > 0 else None | ||||
Lint: PEP8 E501 line too long (84 > 79 characters) Lint: PEP8 E501: line too long (84 > 79 characters) | |||||
else: | else: | ||||
attendee_dn = resource_dns | attendee_dn = resource_dns | ||||
else: | else: | ||||
attendee_dn = user_dn_from_email_address(attendee.get_email()) | attendee_dn = user_dn_from_email_address(attendee.get_email()) | ||||
if attendee_dn: | if attendee_dn: | ||||
attendee_rec = auth.get_entry_attributes(None, attendee_dn, ['kolabinvitationpolicy']) | attendee_rec = auth.get_entry_attributes(None, attendee_dn, ['kolabinvitationpolicy']) | ||||
Lint: PEP8 E501 line too long (102 > 79 characters) Lint: PEP8 E501: line too long (102 > 79 characters) | |||||
if is_auto_reply(attendee_rec, orgemail, object.type): | if is_auto_reply(attendee_rec, orgemail, object.type): | ||||
auto_replies_expected += 1 | auto_replies_expected += 1 | ||||
if not parstat == 'NEEDS-ACTION': | if not parstat == 'NEEDS-ACTION': | ||||
auto_replies_received += 1 | auto_replies_received += 1 | ||||
# skip notification until we got replies from all automatically responding attendees | # skip notification until we got replies from all automatically responding attendees | ||||
Lint: PEP8 E501 line too long (92 > 79 characters) Lint: PEP8 E501: line too long (92 > 79 characters) | |||||
if auto_replies_received < auto_replies_expected: | if auto_replies_received < auto_replies_expected: | ||||
log.debug(_("Waiting for more automated replies (got %d of %d); skipping notification") % ( | log.debug(_("Waiting for more automated replies (got %d of %d); skipping notification") % ( | ||||
Lint: PEP8 E501 line too long (103 > 79 characters) Lint: PEP8 E501: line too long (103 > 79 characters) | |||||
auto_replies_received, auto_replies_expected | auto_replies_received, auto_replies_expected | ||||
), level=8) | ), level=8) | ||||
return | return | ||||
roundup = '' | roundup = '' | ||||
for status,attendees in partstats.iteritems(): | for status,attendees in partstats.iteritems(): | ||||
Lint: PEP8 E231 missing whitespace after ',' Lint: PEP8 E231: missing whitespace after ',' | |||||
if len(attendees) > 0: | if len(attendees) > 0: | ||||
roundup += "\n" + participant_status_label(status) + ":\n" + "\n".join(attendees) + "\n" | roundup += "\n" + participant_status_label(status) + ":\n" + "\n".join(attendees) + "\n" | ||||
Lint: PEP8 E501 line too long (104 > 79 characters) Lint: PEP8 E501: line too long (104 > 79 characters) | |||||
else: | else: | ||||
roundup = "\n" + _("Changes submitted by %s have been automatically applied.") % (orgname if orgname else orgemail) | roundup = "\n" + _("Changes submitted by %s have been automatically applied.") % (orgname if orgname else orgemail) | ||||
Lint: PEP8 E501 line too long (123 > 79 characters) Lint: PEP8 E501: line too long (123 > 79 characters) | |||||
# list properties changed from previous version | # list properties changed from previous version | ||||
if old: | if old: | ||||
diff = xmlutils.compute_diff(old.to_dict(), object.to_dict()) | diff = xmlutils.compute_diff(old.to_dict(), object.to_dict()) | ||||
if len(diff) > 1: | if len(diff) > 1: | ||||
roundup += "\n" | roundup += "\n" | ||||
for change in diff: | for change in diff: | ||||
if not change['property'] in ['created','lastmodified-date','sequence']: | if not change['property'] in ['created','lastmodified-date','sequence']: | ||||
Lint: PEP8 E231 missing whitespace after ',' Lint: PEP8 E231: missing whitespace after ',' | |||||
Lint: PEP8 E231 missing whitespace after ',' Lint: PEP8 E231: missing whitespace after ',' | |||||
Lint: PEP8 E501 line too long (92 > 79 characters) Lint: PEP8 E501: line too long (92 > 79 characters) | |||||
new_value = xmlutils.property_to_string(change['property'], change['new']) if change['new'] else _("(removed)") | new_value = xmlutils.property_to_string(change['property'], change['new']) if change['new'] else _("(removed)") | ||||
Lint: PEP8 E501 line too long (135 > 79 characters) Lint: PEP8 E501: line too long (135 > 79 characters) | |||||
if new_value: | if new_value: | ||||
roundup += "\n- %s: %s" % (xmlutils.property_label(change['property']), new_value) | roundup += "\n- %s: %s" % (xmlutils.property_label(change['property']), new_value) | ||||
Lint: PEP8 E501 line too long (110 > 79 characters) Lint: PEP8 E501: line too long (110 > 79 characters) | |||||
# compose different notification texts for events/tasks | # compose different notification texts for events/tasks | ||||
if object.type == 'task': | if object.type == 'task': | ||||
message_text = _(""" | message_text = _(""" | ||||
The assignment for '%(summary)s' has been updated in your tasklist. | The assignment for '%(summary)s' has been updated in your tasklist. | ||||
%(roundup)s | %(roundup)s | ||||
""") % { | """) % { | ||||
'summary': object.get_summary(), | 'summary': object.get_summary(), | ||||
'roundup': roundup | 'roundup': roundup | ||||
} | } | ||||
else: | else: | ||||
message_text = _(""" | message_text = _(""" | ||||
The event '%(summary)s' at %(start)s has been updated in your calendar. | The event '%(summary)s' at %(start)s has been updated in your calendar. | ||||
Lint: PEP8 E501 line too long (83 > 79 characters) Lint: PEP8 E501: line too long (83 > 79 characters) | |||||
%(roundup)s | %(roundup)s | ||||
""") % { | """) % { | ||||
'summary': object.get_summary(), | 'summary': object.get_summary(), | ||||
'start': xmlutils.property_to_string('start', object.get_start()), | 'start': xmlutils.property_to_string('start', object.get_start()), | ||||
'roundup': roundup | 'roundup': roundup | ||||
} | } | ||||
if object.get_recurrence_id(): | if object.get_recurrence_id(): | ||||
message_text += _("NOTE: This update only refers to this single occurrence!") + "\n" | message_text += _("NOTE: This update only refers to this single occurrence!") + "\n" | ||||
Lint: PEP8 E501 line too long (92 > 79 characters) Lint: PEP8 E501: line too long (92 > 79 characters) | |||||
message_text += "\n" + _("*** This is an automated message. Please do not reply. ***") | message_text += "\n" + _("*** This is an automated message. Please do not reply. ***") | ||||
Lint: PEP8 E501 line too long (90 > 79 characters) Lint: PEP8 E501: line too long (90 > 79 characters) | |||||
# compose mime message | # compose mime message | ||||
msg = MIMEText(utils.stripped_message(message_text), _charset='utf-8') | msg = MIMEText(utils.stripped_message(message_text), _charset='utf-8') | ||||
msg['To'] = receiving_user['mail'] | msg['To'] = receiving_user['mail'] | ||||
msg['Date'] = formatdate(localtime=True) | msg['Date'] = formatdate(localtime=True) | ||||
msg['Subject'] = utils.str2unicode(_('"%s" has been updated') % (object.get_summary())) | msg['Subject'] = utils.str2unicode(_('"%s" has been updated') % (object.get_summary())) | ||||
Lint: PEP8 E501 line too long (91 > 79 characters) Lint: PEP8 E501: line too long (91 > 79 characters) | |||||
msg['From'] = Header(utils.str2unicode('%s' % orgname) if orgname else '') | msg['From'] = Header(utils.str2unicode('%s' % orgname) if orgname else '') | ||||
msg['From'].append("<%s>" % orgemail) | msg['From'].append("<%s>" % orgemail) | ||||
smtp = smtplib.SMTP("localhost", 10027) | smtp = smtplib.SMTP("localhost", 10027) | ||||
if conf.debuglevel > 8: | if conf.debuglevel > 8: | ||||
smtp.set_debuglevel(True) | smtp.set_debuglevel(True) | ||||
success = False | success = False | ||||
retries = 5 | retries = 5 | ||||
while not success and retries > 0: | while not success and retries > 0: | ||||
try: | try: | ||||
success = smtp.sendmail(orgemail, receiving_user['mail'], msg.as_string()) | success = smtp.sendmail(orgemail, receiving_user['mail'], msg.as_string()) | ||||
Lint: PEP8 E501 line too long (86 > 79 characters) Lint: PEP8 E501: line too long (86 > 79 characters) | |||||
log.debug(_("Sent update notification to %r: %r") % (receiving_user['mail'], success), level=8) | log.debug(_("Sent update notification to %r: %r") % (receiving_user['mail'], success), level=8) | ||||
Lint: PEP8 E501 line too long (107 > 79 characters) Lint: PEP8 E501: line too long (107 > 79 characters) | |||||
smtp.quit() | smtp.quit() | ||||
break | break | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error(_("SMTP sendmail error: %r") % (errmsg)) | log.error(_("SMTP sendmail error: %r") % (errmsg)) | ||||
time.sleep(10) | time.sleep(10) | ||||
retries -= 1 | retries -= 1 | ||||
Show All 18 Lines | def send_cancel_notification(object, receiving_user, deleted=False): | ||||
), level=8) | ), level=8) | ||||
organizer = object.get_organizer() | organizer = object.get_organizer() | ||||
orgemail = organizer.email() | orgemail = organizer.email() | ||||
orgname = organizer.name() | orgname = organizer.name() | ||||
# compose different notification texts for events/tasks | # compose different notification texts for events/tasks | ||||
if object.type == 'task': | if object.type == 'task': | ||||
message_text = _("The assignment for '%(summary)s' has been cancelled by %(organizer)s.") % { | message_text = _("The assignment for '%(summary)s' has been cancelled by %(organizer)s.") % { | ||||
Lint: PEP8 E501 line too long (101 > 79 characters) Lint: PEP8 E501: line too long (101 > 79 characters) | |||||
'summary': object.get_summary(), | 'summary': object.get_summary(), | ||||
'organizer': orgname if orgname else orgemail | 'organizer': orgname if orgname else orgemail | ||||
} | } | ||||
if deleted: | if deleted: | ||||
message_text += " " + _("The copy in your tasklist has been removed accordingly.") | message_text += " " + _("The copy in your tasklist has been removed accordingly.") | ||||
Lint: PEP8 E501 line too long (94 > 79 characters) Lint: PEP8 E501: line too long (94 > 79 characters) | |||||
else: | else: | ||||
message_text += " " + _("The copy in your tasklist has been marked as cancelled accordingly.") | message_text += " " + _("The copy in your tasklist has been marked as cancelled accordingly.") | ||||
Lint: PEP8 E501 line too long (106 > 79 characters) Lint: PEP8 E501: line too long (106 > 79 characters) | |||||
else: | else: | ||||
message_text = _("The event '%(summary)s' at %(start)s has been cancelled by %(organizer)s.") % { | message_text = _("The event '%(summary)s' at %(start)s has been cancelled by %(organizer)s.") % { | ||||
Lint: PEP8 E501 line too long (105 > 79 characters) Lint: PEP8 E501: line too long (105 > 79 characters) | |||||
'summary': object.get_summary(), | 'summary': object.get_summary(), | ||||
'start': xmlutils.property_to_string('start', object.get_start()), | 'start': xmlutils.property_to_string('start', object.get_start()), | ||||
'organizer': orgname if orgname else orgemail | 'organizer': orgname if orgname else orgemail | ||||
} | } | ||||
if deleted: | if deleted: | ||||
message_text += " " + _("The copy in your calendar has been removed accordingly.") | message_text += " " + _("The copy in your calendar has been removed accordingly.") | ||||
Lint: PEP8 E501 line too long (94 > 79 characters) Lint: PEP8 E501: line too long (94 > 79 characters) | |||||
else: | else: | ||||
message_text += " " + _("The copy in your calendar has been marked as cancelled accordingly.") | message_text += " " + _("The copy in your calendar has been marked as cancelled accordingly.") | ||||
Lint: PEP8 E501 line too long (106 > 79 characters) Lint: PEP8 E501: line too long (106 > 79 characters) | |||||
if object.get_recurrence_id(): | if object.get_recurrence_id(): | ||||
message_text += "\n" + _("NOTE: This cancellation only refers to this single occurrence!") | message_text += "\n" + _("NOTE: This cancellation only refers to this single occurrence!") | ||||
Lint: PEP8 E501 line too long (98 > 79 characters) Lint: PEP8 E501: line too long (98 > 79 characters) | |||||
message_text += "\n\n" + _("*** This is an automated message. Please do not reply. ***") | message_text += "\n\n" + _("*** This is an automated message. Please do not reply. ***") | ||||
Lint: PEP8 E501 line too long (92 > 79 characters) Lint: PEP8 E501: line too long (92 > 79 characters) | |||||
# compose mime message | # compose mime message | ||||
msg = MIMEText(utils.stripped_message(message_text), _charset='utf-8') | msg = MIMEText(utils.stripped_message(message_text), _charset='utf-8') | ||||
msg['To'] = receiving_user['mail'] | msg['To'] = receiving_user['mail'] | ||||
msg['Date'] = formatdate(localtime=True) | msg['Date'] = formatdate(localtime=True) | ||||
msg['Subject'] = utils.str2unicode(_('"%s" has been cancelled') % (object.get_summary())) | msg['Subject'] = utils.str2unicode(_('"%s" has been cancelled') % (object.get_summary())) | ||||
Lint: PEP8 E501 line too long (93 > 79 characters) Lint: PEP8 E501: line too long (93 > 79 characters) | |||||
msg['From'] = Header(utils.str2unicode('%s' % orgname) if orgname else '') | msg['From'] = Header(utils.str2unicode('%s' % orgname) if orgname else '') | ||||
msg['From'].append("<%s>" % orgemail) | msg['From'].append("<%s>" % orgemail) | ||||
smtp = smtplib.SMTP("localhost", 10027) | smtp = smtplib.SMTP("localhost", 10027) | ||||
if conf.debuglevel > 8: | if conf.debuglevel > 8: | ||||
smtp.set_debuglevel(True) | smtp.set_debuglevel(True) | ||||
try: | try: | ||||
smtp.sendmail(orgemail, receiving_user['mail'], msg.as_string()) | smtp.sendmail(orgemail, receiving_user['mail'], msg.as_string()) | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error(_("SMTP sendmail error: %r") % (errmsg)) | log.error(_("SMTP sendmail error: %r") % (errmsg)) | ||||
smtp.quit() | smtp.quit() | ||||
def is_auto_reply(user, sender_email, type): | def is_auto_reply(user, sender_email, type): | ||||
accept_available = False | accept_available = False | ||||
accept_conflicts = False | accept_conflicts = False | ||||
for policy in get_matching_invitation_policies(user, sender_email, object_type_conditons.get(type, COND_TYPE_EVENT)): | for policy in get_matching_invitation_policies(user, sender_email, object_type_conditons.get(type, COND_TYPE_EVENT)): | ||||
Lint: PEP8 E501 line too long (121 > 79 characters) Lint: PEP8 E501: line too long (121 > 79 characters) | |||||
if policy & (ACT_ACCEPT | ACT_REJECT | ACT_DELEGATE): | if policy & (ACT_ACCEPT | ACT_REJECT | ACT_DELEGATE): | ||||
if check_policy_condition(policy, True): | if check_policy_condition(policy, True): | ||||
accept_available = True | accept_available = True | ||||
if check_policy_condition(policy, False): | if check_policy_condition(policy, False): | ||||
accept_conflicts = True | accept_conflicts = True | ||||
# we have both cases covered by a policy | # we have both cases covered by a policy | ||||
if accept_available and accept_conflicts: | if accept_available and accept_conflicts: | ||||
Show All 12 Lines | if policy & (COND_IF_AVAILABLE | COND_IF_CONFLICT): | ||||
condition_fulfilled = available | condition_fulfilled = available | ||||
if policy & COND_IF_CONFLICT: | if policy & COND_IF_CONFLICT: | ||||
condition_fulfilled = not condition_fulfilled | condition_fulfilled = not condition_fulfilled | ||||
return condition_fulfilled | return condition_fulfilled | ||||
def propagate_changes_to_attendees_accounts(object, updated_attendees=None): | def propagate_changes_to_attendees_accounts(object, updated_attendees=None): | ||||
""" | """ | ||||
Find and update copies of this object in all attendee's personal folders | Find and update copies of this object in all attendee's personal folders | ||||
Lint: PEP8 E501 line too long (80 > 79 characters) Lint: PEP8 E501: line too long (80 > 79 characters) | |||||
""" | """ | ||||
recurrence_id = object.get_recurrence_id() | recurrence_id = object.get_recurrence_id() | ||||
for attendee in object.get_attendees(): | for attendee in object.get_attendees(): | ||||
attendee_user_dn = user_dn_from_email_address(attendee.get_email()) | attendee_user_dn = user_dn_from_email_address(attendee.get_email()) | ||||
if attendee_user_dn: | if attendee_user_dn: | ||||
attendee_user = auth.get_entry_attributes(None, attendee_user_dn, ['*']) | attendee_user = auth.get_entry_attributes(None, attendee_user_dn, ['*']) | ||||
Lint: PEP8 E501 line too long (84 > 79 characters) Lint: PEP8 E501: line too long (84 > 79 characters) | |||||
(attendee_object, master_object) = find_existing_object(object.uid, object.type, recurrence_id, 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 | ||||
Lint: PEP8 E501 line too long (154 > 79 characters) Lint: PEP8 E501: line too long (154 > 79 characters) | |||||
if attendee_object: | if attendee_object: | ||||
# find attendee's entry by one of its email addresses | # find attendee's entry by one of its email addresses | ||||
attendee_emails = auth.extract_recipient_addresses(attendee_user) | attendee_emails = auth.extract_recipient_addresses(attendee_user) | ||||
Lint: PEP8 E501 line too long (81 > 79 characters) Lint: PEP8 E501: line too long (81 > 79 characters) | |||||
for attendee_email in attendee_emails: | for attendee_email in attendee_emails: | ||||
try: | try: | ||||
attendee_entry = attendee_object.get_attendee_by_email(attendee_email) | attendee_entry = attendee_object.get_attendee_by_email(attendee_email) | ||||
Lint: PEP8 E501 line too long (94 > 79 characters) Lint: PEP8 E501: line too long (94 > 79 characters) | |||||
except: | except: | ||||
attendee_entry = None | attendee_entry = None | ||||
if attendee_entry: | if attendee_entry: | ||||
break | break | ||||
# copy all attendees from master object (covers additions and removals) | # copy all attendees from master object (covers additions and removals) | ||||
Lint: PEP8 E501 line too long (87 > 79 characters) Lint: PEP8 E501: line too long (87 > 79 characters) | |||||
new_attendees = []; | new_attendees = []; | ||||
Lint: PEP8 E703 statement ends with a semicolon Lint: PEP8 E703: statement ends with a semicolon | |||||
for a in object.get_attendees(): | for a in object.get_attendees(): | ||||
# keep my own entry intact | # keep my own entry intact | ||||
if attendee_entry is not None and attendee_entry.get_email() == a.get_email(): | if attendee_entry is not None and attendee_entry.get_email() == a.get_email(): | ||||
Lint: PEP8 E501 line too long (98 > 79 characters) Lint: PEP8 E501: line too long (98 > 79 characters) | |||||
new_attendees.append(attendee_entry) | new_attendees.append(attendee_entry) | ||||
else: | else: | ||||
new_attendees.append(a) | new_attendees.append(a) | ||||
attendee_object.set_attendees(new_attendees) | attendee_object.set_attendees(new_attendees) | ||||
if updated_attendees and not recurrence_id: | 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) | 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) | ||||
Lint: PEP8 E501 line too long (173 > 79 characters) Lint: PEP8 E501: line too long (173 > 79 characters) | |||||
attendee_object.update_attendees(updated_attendees, False) | attendee_object.update_attendees(updated_attendees, False) | ||||
success = update_object(attendee_object, attendee_user, master_object) | success = update_object(attendee_object, attendee_user, master_object) | ||||
Lint: PEP8 E501 line too long (86 > 79 characters) Lint: PEP8 E501: line too long (86 > 79 characters) | |||||
log.debug(_("Updated %s's copy of %r: %r") % (attendee_user['mail'], object.uid, success), level=8) | log.debug(_("Updated %s's copy of %r: %r") % (attendee_user['mail'], object.uid, success), level=8) | ||||
Lint: PEP8 E501 line too long (115 > 79 characters) Lint: PEP8 E501: line too long (115 > 79 characters) | |||||
else: | else: | ||||
log.debug(_("Attendee %s's copy of %r not found") % (attendee_user['mail'], object.uid), level=8) | log.debug(_("Attendee %s's copy of %r not found") % (attendee_user['mail'], object.uid), level=8) | ||||
Lint: PEP8 E501 line too long (113 > 79 characters) Lint: PEP8 E501: line too long (113 > 79 characters) | |||||
else: | else: | ||||
log.debug(_("Attendee %r not found in LDAP") % (attendee.get_email()), level=8) | log.debug(_("Attendee %r not found in LDAP") % (attendee.get_email()), level=8) | ||||
Lint: PEP8 E501 line too long (91 > 79 characters) Lint: PEP8 E501: line too long (91 > 79 characters) | |||||
def invitation_response_text(type): | def invitation_response_text(type): | ||||
footer = "\n\n" + _("*** This is an automated message. Please do not reply. ***") | footer = "\n\n" + _("*** This is an automated message. Please do not reply. ***") | ||||
Lint: PEP8 E501 line too long (85 > 79 characters) Lint: PEP8 E501: line too long (85 > 79 characters) | |||||
if type == 'task': | if type == 'task': | ||||
return _("%(name)s has %(status)s your assignment for %(summary)s.") + footer | return _("%(name)s has %(status)s your assignment for %(summary)s.") + footer | ||||
Lint: PEP8 E501 line too long (85 > 79 characters) Lint: PEP8 E501: line too long (85 > 79 characters) | |||||
else: | else: | ||||
return _("%(name)s has %(status)s your invitation for %(summary)s.") + footer | return _("%(name)s has %(status)s your invitation for %(summary)s.") + footer | ||||
Lint: PEP8 E501 line too long (85 > 79 characters) Lint: PEP8 E501: line too long (85 > 79 characters) |
multiple spaces before operator