Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117879733
module_resources.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
27 KB
Referenced Files
None
Subscribers
None
module_resources.py
View Options
# -*- coding: utf-8 -*-
# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
#
# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3 or, at your option, any later version
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
import
datetime
import
icalendar
import
json
import
os
import
pytz
import
random
import
tempfile
import
time
from
urlparse
import
urlparse
import
urllib
from
email
import
message_from_file
from
email
import
message_from_string
from
email.utils
import
formataddr
from
email.utils
import
getaddresses
import
modules
import
pykolab
from
pykolab.auth
import
Auth
from
pykolab.conf
import
Conf
from
pykolab.imap
import
IMAP
from
pykolab.xml
import
event_from_ical
from
pykolab.xml
import
event_from_string
from
pykolab.xml
import
to_dt
from
pykolab.translate
import
_
log
=
pykolab
.
getLogger
(
'pykolab.wallace'
)
conf
=
pykolab
.
getConf
()
mybasepath
=
'/var/spool/pykolab/wallace/resources/'
auth
=
None
imap
=
None
def
__init__
():
modules
.
register
(
'resources'
,
execute
,
description
=
description
())
def
accept
(
filepath
):
new_filepath
=
os
.
path
.
join
(
mybasepath
,
'ACCEPT'
,
os
.
path
.
basename
(
filepath
)
)
os
.
rename
(
filepath
,
new_filepath
)
filepath
=
new_filepath
exec
(
'modules.cb_action_ACCEPT(
%r
,
%r
)'
%
(
'resources'
,
filepath
))
def
description
():
return
"""Resource management module."""
def
execute
(
*
args
,
**
kw
):
if
not
os
.
path
.
isdir
(
mybasepath
):
os
.
makedirs
(
mybasepath
)
for
stage
in
[
'incoming'
,
'ACCEPT'
,
'REJECT'
,
'HOLD'
,
'DEFER'
]:
if
not
os
.
path
.
isdir
(
os
.
path
.
join
(
mybasepath
,
stage
)):
os
.
makedirs
(
os
.
path
.
join
(
mybasepath
,
stage
))
log
.
debug
(
_
(
"Resource Management called for
%r
,
%r
"
)
%
(
args
,
kw
),
level
=
9
)
auth
=
Auth
()
auth
.
connect
()
imap
=
IMAP
()
imap
.
connect
()
# TODO: Test for correct call.
filepath
=
args
[
0
]
if
kw
.
has_key
(
'stage'
):
log
.
debug
(
_
(
"Issuing callback after processing to stage
%s
"
)
%
(
kw
[
'stage'
]
),
level
=
8
)
log
.
debug
(
_
(
"Testing cb_action_
%s
()"
)
%
(
kw
[
'stage'
]),
level
=
8
)
if
hasattr
(
modules
,
'cb_action_
%s
'
%
(
kw
[
'stage'
])):
log
.
debug
(
_
(
"Attempting to execute cb_action_
%s
()"
)
%
(
kw
[
'stage'
]),
level
=
8
)
exec
(
'modules.cb_action_
%s
(
%r
,
%r
)'
%
(
kw
[
'stage'
],
'resources'
,
filepath
)
)
return
else
:
# Move to incoming
new_filepath
=
os
.
path
.
join
(
mybasepath
,
'incoming'
,
os
.
path
.
basename
(
filepath
)
)
os
.
rename
(
filepath
,
new_filepath
)
filepath
=
new_filepath
message
=
message_from_file
(
open
(
filepath
,
'r'
))
any_itips
=
False
any_resources
=
False
possibly_any_resources
=
True
# An iTip message may contain multiple events. Later on, test if the message
# is an iTip message by checking the length of this list.
itip_events
=
itip_events_from_message
(
message
)
if
not
len
(
itip_events
)
>
0
:
log
.
info
(
_
(
"Message is not an iTip message or does not contain any "
+
\
"(valid) iTip."
)
)
else
:
any_itips
=
True
log
.
debug
(
_
(
"iTip events attached to this message contain the "
+
\
"following information:
%r
"
)
%
(
itip_events
),
level
=
9
)
if
any_itips
:
# See if any iTip actually allocates a resource.
if
len
([
x
[
'resources'
]
for
x
in
itip_events
if
x
.
has_key
(
'resources'
)])
==
0
:
if
len
([
x
[
'attendees'
]
for
x
in
itip_events
if
x
.
has_key
(
'attendees'
)])
==
0
:
possibly_any_resources
=
False
else
:
possibly_any_resources
=
False
if
possibly_any_resources
:
recipients
=
{
"To"
:
getaddresses
(
message
.
get_all
(
'To'
,
[])),
"Cc"
:
getaddresses
(
message
.
get_all
(
'Cc'
,
[]))
# TODO: Are those all recipient addresses?
}
log
.
debug
(
"Recipients:
%r
"
%
recipients
)
for
recipient
in
recipients
[
'Cc'
]
+
recipients
[
'To'
]:
if
not
len
(
resource_record_from_email_address
(
recipient
[
1
]))
==
0
:
any_resources
=
True
if
any_resources
:
if
not
any_itips
:
log
.
debug
(
_
(
"Not an iTip message, but sent to resource nonetheless. Reject message"
),
level
=
5
)
reject
(
filepath
)
return
else
:
# Continue. Resources and iTips. We like.
pass
else
:
if
not
any_itips
:
log
.
debug
(
_
(
"No itips, no resources, pass along"
),
level
=
5
)
accept
(
filepath
)
return
else
:
log
.
debug
(
_
(
"iTips, but no resources, pass along"
),
level
=
5
)
accept
(
filepath
)
return
# A simple list of merely resource entry IDs that hold any relevance to the
# iTip events
resource_records
=
resource_records_from_itip_events
(
itip_events
)
# Get the resource details, which includes details on the IMAP folder
resources
=
{}
for
resource_record
in
list
(
set
(
resource_records
)):
# Get the attributes for the record
# See if it is a resource collection
# If it is, expand to individual resources
# If it is not, ...
resource_attrs
=
auth
.
get_entry_attributes
(
None
,
resource_record
,
[
'*'
])
if
not
'kolabsharedfolder'
in
[
x
.
lower
()
for
x
in
resource_attrs
[
'objectclass'
]]:
if
resource_attrs
.
has_key
(
'uniquemember'
):
resources
[
resource_record
]
=
resource_attrs
for
uniquemember
in
resource_attrs
[
'uniquemember'
]:
resource_attrs
=
auth
.
get_entry_attributes
(
None
,
uniquemember
,
[
'*'
]
)
if
'kolabsharedfolder'
in
[
x
.
lower
()
for
x
in
resource_attrs
[
'objectclass'
]]:
resources
[
uniquemember
]
=
resource_attrs
resources
[
uniquemember
][
'memberof'
]
=
resource_record
else
:
resources
[
resource_record
]
=
resource_attrs
log
.
debug
(
_
(
"Resources:
%r
"
)
%
(
resources
),
level
=
8
)
# For each resource, determine if any of the events in question is in
# conflict.
#
# Store the (first) conflicting event(s) alongside the resource information.
start
=
time
.
time
()
for
resource
in
resources
.
keys
():
if
not
resources
[
resource
]
.
has_key
(
'kolabtargetfolder'
):
continue
mailbox
=
resources
[
resource
][
'kolabtargetfolder'
]
resources
[
resource
][
'conflict'
]
=
False
resources
[
resource
][
'conflicting_events'
]
=
[]
log
.
debug
(
_
(
"Checking events in resource folder
%r
"
)
%
(
mailbox
),
level
=
8
)
try
:
imap
.
imap
.
m
.
select
(
mailbox
)
except
:
log
.
error
(
_
(
"Mailbox for resource
%r
doesn't exist"
)
%
(
resource
))
continue
typ
,
data
=
imap
.
imap
.
m
.
search
(
None
,
'ALL'
)
num_messages
=
len
(
data
[
0
]
.
split
())
for
num
in
data
[
0
]
.
split
():
# For efficiency, makes the routine non-deterministic
if
resources
[
resource
][
'conflict'
]:
continue
log
.
debug
(
_
(
"Fetching message UID
%r
from folder
%r
"
)
%
(
num
,
mailbox
),
level
=
9
)
typ
,
data
=
imap
.
imap
.
m
.
fetch
(
num
,
'(RFC822)'
)
event_message
=
message_from_string
(
data
[
0
][
1
])
if
event_message
.
is_multipart
():
for
part
in
event_message
.
walk
():
if
part
.
get_content_type
()
==
"application/calendar+xml"
:
payload
=
part
.
get_payload
(
decode
=
True
)
event
=
pykolab
.
xml
.
event_from_string
(
payload
)
for
itip
in
itip_events
:
_es
=
to_dt
(
event
.
get_start
())
_is
=
to_dt
(
itip
[
'start'
]
.
dt
)
_ee
=
to_dt
(
event
.
get_end
())
_ie
=
to_dt
(
itip
[
'end'
]
.
dt
)
if
_es
<
_is
:
if
_es
<=
_ie
:
if
_ee
<=
_is
:
conflict
=
False
else
:
conflict
=
True
else
:
conflict
=
True
elif
_es
==
_is
:
conflict
=
True
else
:
# _es > _is
if
_es
<=
_ie
:
conflict
=
True
else
:
conflict
=
False
if
conflict
:
log
.
info
(
_
(
"Event
%r
conflicts with event "
+
\
"
%r
"
)
%
(
itip
[
'xml'
]
.
get_uid
(),
event
.
get_uid
()
)
)
resources
[
resource
][
'conflicting_events'
]
.
append
(
event
)
resources
[
resource
][
'conflict'
]
=
True
end
=
time
.
time
()
log
.
debug
(
_
(
"start:
%r
, end:
%r
, total:
%r
, messages:
%r
"
)
%
(
start
,
end
,
(
end
-
start
),
num_messages
),
level
=
1
)
for
resource
in
resources
.
keys
():
log
.
debug
(
_
(
"Polling for resource
%r
"
)
%
(
resource
),
level
=
9
)
if
not
resources
.
has_key
(
resource
):
log
.
debug
(
_
(
"Resource
%r
has been popped from the list"
)
%
(
resource
),
level
=
9
)
continue
if
not
resources
[
resource
]
.
has_key
(
'conflicting_events'
):
log
.
debug
(
_
(
"Resource is a collection"
),
level
=
9
)
continue
if
len
(
resources
[
resource
][
'conflicting_events'
])
>
0
:
# This is the event being conflicted with!
for
itip_event
in
itip_events
:
# Now we have the event that was conflicting
if
resources
[
resource
][
'mail'
]
in
[
a
.
get_email
()
for
a
in
itip_event
[
'xml'
]
.
get_attendees
()]:
itip_event
[
'xml'
]
.
set_attendee_participant_status
(
[
a
for
a
in
itip_event
[
'xml'
]
.
get_attendees
()
if
a
.
get_email
()
==
resources
[
resource
][
'mail'
]][
0
],
"DECLINED"
)
send_response
(
resources
[
resource
][
'mail'
],
itip_events
)
# TODO: Accept the message to the other attendees
else
:
# This must have been a resource collection originally.
# We have inserted the reference to the original resource
# record in 'memberof'.
if
resources
[
resource
]
.
has_key
(
'memberof'
):
original_resource
=
resources
[
resources
[
resource
][
'memberof'
]]
_target_resource
=
resources
[
original_resource
[
'uniquemember'
][
random
.
randint
(
0
,(
len
(
original_resource
[
'uniquemember'
])
-
1
))]]
# unset all
for
_r
in
original_resource
[
'uniquemember'
]:
del
resources
[
_r
]
if
original_resource
[
'mail'
]
in
[
a
.
get_email
()
for
a
in
itip_event
[
'xml'
]
.
get_attendees
()]:
itip_event
[
'xml'
]
.
set_attendee_participant_status
(
[
a
for
a
in
itip_event
[
'xml'
]
.
get_attendees
()
if
a
.
get_email
()
==
original_resource
[
'mail'
]][
0
],
"DECLINED"
)
send_response
(
original_resource
[
'mail'
],
itip_events
)
# TODO: Accept the message to the other attendees
else
:
# No conflicts, go accept
for
itip_event
in
itip_events
:
if
resources
[
resource
][
'mail'
]
in
[
a
.
get_email
()
for
a
in
itip_event
[
'xml'
]
.
get_attendees
()]:
itip_event
[
'xml'
]
.
set_attendee_participant_status
(
[
a
for
a
in
itip_event
[
'xml'
]
.
get_attendees
()
if
a
.
get_email
()
==
resources
[
resource
][
'mail'
]][
0
],
"ACCEPTED"
)
log
.
debug
(
_
(
"Adding event to
%r
"
)
%
(
resources
[
resource
][
'kolabtargetfolder'
]
),
level
=
9
)
imap
.
imap
.
m
.
setacl
(
resources
[
resource
][
'kolabtargetfolder'
],
"cyrus-admin"
,
"lrswipkxtecda"
)
imap
.
imap
.
m
.
append
(
resources
[
resource
][
'kolabtargetfolder'
],
None
,
None
,
itip_event
[
'xml'
]
.
to_message
()
.
as_string
()
)
send_response
(
resources
[
resource
][
'mail'
],
itip_event
)
else
:
# This must have been a resource collection originally.
# We have inserted the reference to the original resource
# record in 'memberof'.
if
resources
[
resource
]
.
has_key
(
'memberof'
):
original_resource
=
resources
[
resources
[
resource
][
'memberof'
]]
# Randomly selects a target resource from the resource
# collection.
_target_resource
=
resources
[
original_resource
[
'uniquemember'
][
random
.
randint
(
0
,(
len
(
original_resource
[
'uniquemember'
])
-
1
))]]
# Remove all resources from the collection.
for
_r
in
original_resource
[
'uniquemember'
]:
del
resources
[
_r
]
if
original_resource
[
'mail'
]
in
[
a
.
get_email
()
for
a
in
itip_event
[
'xml'
]
.
get_attendees
()]:
#
# Delegate:
#
# - delegator: the original resource collection
# - delegatee: the target resource
#
itip_event
[
'xml'
]
.
delegate
(
original_resource
[
'mail'
],
_target_resource
[
'mail'
]
)
itip_event
[
'xml'
]
.
set_attendee_participant_status
(
[
a
for
a
in
itip_event
[
'xml'
]
.
get_attendees
()
if
a
.
get_email
()
==
_target_resource
[
'mail'
]][
0
],
"ACCEPTED"
)
log
.
debug
(
_
(
"Adding event to
%r
"
)
%
(
_target_resource
[
'kolabtargetfolder'
]
),
level
=
9
)
# TODO: The Cyrus IMAP (or Dovecot) Administrator login
# name comes from configuration.
imap
.
imap
.
m
.
setacl
(
_target_resource
[
'kolabtargetfolder'
],
"cyrus-admin"
,
"lrswipkxtecda"
)
imap
.
imap
.
m
.
append
(
_target_resource
[
'kolabtargetfolder'
],
None
,
None
,
itip_event
[
'xml'
]
.
to_message
()
.
as_string
()
)
send_response
(
original_resource
[
'mail'
],
itip_event
)
# Disconnect IMAP or we lock the mailbox almost constantly
imap
.
disconnect
()
del
imap
os
.
unlink
(
filepath
)
def
itip_events_from_message
(
message
):
"""
Obtain the iTip payload from email.message <message>
"""
# Placeholder for any itip_events found in the message.
itip_events
=
[]
# iTip methods we are actually interested in. Other methods will be ignored.
itip_methods
=
[
"REQUEST"
,
"REPLY"
,
"ADD"
,
"CANCEL"
]
# TODO: Are all iTip messages multipart? RFC 6047, section 2.4 states "A
# MIME body part containing content information that conforms to this
# document MUST have (...)" but does not state whether an iTip message must
# therefore also be multipart.
if
message
.
is_multipart
():
# Check each part
for
part
in
message
.
walk
():
# The iTip part MUST be Content-Type: text/calendar (RFC 6047,
# section 2.4)
if
part
.
get_content_type
()
==
"text/calendar"
:
if
not
part
.
get_param
(
'method'
)
in
itip_methods
:
log
.
error
(
_
(
"Method
%r
not really interesting for us."
)
%
(
part
.
get_param
(
'method'
)
)
)
# Get the itip_payload
itip_payload
=
part
.
get_payload
(
decode
=
True
)
log
.
debug
(
_
(
"Raw iTip payload:
%s
"
)
%
(
itip_payload
))
# Python iCalendar prior to 3.0 uses "from_string".
if
hasattr
(
icalendar
.
Calendar
,
'from_ical'
):
cal
=
icalendar
.
Calendar
.
from_ical
(
itip_payload
)
elif
hasattr
(
icalendar
.
Calendar
,
'from_string'
):
cal
=
icalendar
.
Calendar
.
from_string
(
itip_payload
)
# If we can't read it, we're out
else
:
log
.
error
(
_
(
"Could not read iTip from message."
))
return
[]
for
c
in
cal
.
walk
():
if
c
.
name
==
"VEVENT"
:
itip
=
{}
# From the event, take the following properties:
#
# - start
# - end (if any)
# - duration (if any)
# - organizer
# - attendees (if any)
# - resources (if any)
# - TODO: recurrence rules (if any)
# Where are these stored actually?
#
if
c
.
has_key
(
'dtstart'
):
itip
[
'start'
]
=
c
[
'dtstart'
]
else
:
log
.
error
(
_
(
"iTip event without a start"
))
continue
if
c
.
has_key
(
'dtend'
):
itip
[
'end'
]
=
c
[
'dtend'
]
if
c
.
has_key
(
'duration'
):
itip
[
'duration'
]
=
c
[
'duration'
]
itip
[
'organizer'
]
=
c
[
'organizer'
]
itip
[
'attendees'
]
=
c
[
'attendee'
]
if
c
.
has_key
(
'resources'
):
itip
[
'resources'
]
=
c
[
'resources'
]
itip
[
'raw'
]
=
itip_payload
itip
[
'xml'
]
=
event_from_ical
(
c
.
to_ical
())
itip_events
.
append
(
itip
)
# end if c.name == "VEVENT"
# end for c in cal.walk()
# end if part.get_content_type() == "text/calendar"
# end for part in message.walk()
else
:
# if message.is_multipart()
log
.
debug
(
_
(
"Message is not an iTip message (non-multipart message)"
),
level
=
5
)
return
itip_events
def
reject
(
filepath
):
new_filepath
=
os
.
path
.
join
(
mybasepath
,
'REJECT'
,
os
.
path
.
basename
(
filepath
)
)
os
.
rename
(
filepath
,
new_filepath
)
filepath
=
new_filepath
exec
(
'modules.cb_action_REJECT(
%r
,
%r
)'
%
(
'resources'
,
filepath
))
def
resource_record_from_email_address
(
email_address
):
auth
=
Auth
()
auth
.
connect
()
resource_records
=
[]
log
.
debug
(
_
(
"Checking if email address
%r
belongs to a resource (collection)"
)
%
(
email_address
),
level
=
8
)
resource_records
=
auth
.
find_resource
(
email_address
)
if
isinstance
(
resource_records
,
list
):
if
len
(
resource_records
)
==
0
:
log
.
debug
(
_
(
"No resource (collection) records found for
%r
"
)
%
(
email_address
),
level
=
9
)
else
:
log
.
debug
(
_
(
"Resource record(s):
%r
"
)
%
(
resource_records
),
level
=
8
)
elif
isinstance
(
resource_records
,
basestring
):
log
.
debug
(
_
(
"Resource record:
%r
"
)
%
(
resource_records
),
level
=
8
)
resource_records
=
[
resource_records
]
return
resource_records
def
resource_records_from_itip_events
(
itip_events
):
"""
Given a list of itip_events, determine which resources have been
invited as attendees and/or resources.
"""
auth
=
Auth
()
auth
.
connect
()
resource_records
=
[]
log
.
debug
(
_
(
"Raw itip_events:
%r
"
)
%
(
itip_events
),
level
=
9
)
attendees_raw
=
[]
for
list_attendees_raw
in
[
x
for
x
in
[
y
[
'attendees'
]
for
y
in
itip_events
if
y
.
has_key
(
'attendees'
)
and
isinstance
(
y
[
'attendees'
],
list
)]]:
attendees_raw
.
extend
(
list_attendees_raw
)
for
list_attendees_raw
in
[
y
[
'attendees'
]
for
y
in
itip_events
if
y
.
has_key
(
'attendees'
)
and
isinstance
(
y
[
'attendees'
],
basestring
)]:
attendees_raw
.
append
(
list_attendees_raw
)
log
.
debug
(
_
(
"Raw set of attendees:
%r
"
)
%
(
attendees_raw
),
level
=
9
)
# TODO: Resources are actually not implemented in the format. We reset this
# list later.
resources_raw
=
[]
for
list_resources_raw
in
[
x
for
x
in
[
y
[
'resources'
]
for
y
in
itip_events
if
y
.
has_key
(
'resources'
)]]:
resources_raw
.
extend
(
list_resources_raw
)
log
.
debug
(
_
(
"Raw set of resources:
%r
"
)
%
(
resources_raw
),
level
=
9
)
# TODO: We expect the format of an attendee line to literally be:
#
# ATTENDEE:RSVP=TRUE;ROLE=REQ-PARTICIPANT;MAILTO:lydia.bossers@kolabsys.com
#
# which makes the attendees_raw contain:
#
# RSVP=TRUE;ROLE=REQ-PARTICIPANT;MAILTO:lydia.bossers@kolabsys.com
#
attendees
=
[
x
.
split
(
':'
)[
-
1
]
for
x
in
attendees_raw
]
for
attendee
in
attendees
:
log
.
debug
(
_
(
"Checking if attendee
%r
is a resource (collection)"
)
%
(
attendee
),
level
=
8
)
_resource_records
=
auth
.
find_resource
(
attendee
)
if
isinstance
(
_resource_records
,
list
):
if
len
(
_resource_records
)
==
0
:
log
.
debug
(
_
(
"No resource (collection) records found for
%r
"
)
%
(
attendee
),
level
=
9
)
else
:
log
.
debug
(
_
(
"Resource record(s):
%r
"
)
%
(
_resource_records
),
level
=
8
)
resource_records
.
extend
(
_resource_records
)
elif
isinstance
(
_resource_records
,
basestring
):
log
.
debug
(
_
(
"Resource record:
%r
"
)
%
(
_resource_records
),
level
=
8
)
resource_records
.
append
(
_resource_records
)
else
:
log
.
warning
(
_
(
"Resource reservation made but no resource records found"
)
)
# TODO: Escape the non-implementation of the free-form, undefined RESOURCES
# list(s) in iTip. We don't know how to handle this yet!
resources_raw
=
[]
# TODO: We expect the format of an resource line to literally be:
#
# RESOURCES:MAILTO:resource-car@kolabsys.com
#
# which makes the resources_raw contain:
#
# MAILTO:resource-car@kolabsys.com
#
resources
=
[
x
.
split
(
':'
)[
-
1
]
for
x
in
resources_raw
]
for
resource
in
resources
:
log
.
debug
(
_
(
"Checking if resource
%r
is a resource (collection)"
)
%
(
resource
),
level
=
8
)
_resource_records
=
auth
.
find_resource
(
resource
)
if
isinstance
(
_resource_records
,
list
):
if
len
(
_resource_records
)
==
0
:
log
.
debug
(
_
(
"No resource (collection) records found for
%r
"
)
%
(
resource
),
level
=
8
)
else
:
log
.
debug
(
_
(
"Resource record(s):
%r
"
)
%
(
_resource_records
),
level
=
8
)
resource_records
.
extend
(
_resource_records
)
elif
isinstance
(
_resource_records
,
basestring
):
resource_records
.
append
(
_resource_records
)
log
.
debug
(
_
(
"Resource record:
%r
"
)
%
(
_resource_records
),
level
=
8
)
else
:
log
.
warning
(
_
(
"Resource reservation made but no resource records found"
)
)
log
.
debug
(
_
(
"The following resources are being referred to in the "
+
\
"iTip:
%r
"
)
%
(
resource_records
),
level
=
8
)
return
resource_records
def
send_response
(
from_address
,
itip_events
):
import
smtplib
smtp
=
smtplib
.
SMTP
(
"localhost"
,
10027
)
if
conf
.
debuglevel
>
8
:
smtp
.
set_debuglevel
(
True
)
if
isinstance
(
itip_events
,
dict
):
itip_events
=
[
itip_events
]
for
itip_event
in
itip_events
:
attendee
=
[
a
for
a
in
itip_event
[
'xml'
]
.
get_attendees
()
if
a
.
get_email
()
==
from_address
][
0
]
participant_status
=
itip_event
[
'xml'
]
.
get_ical_attendee_participant_status
(
attendee
)
if
participant_status
==
"DELEGATED"
:
# Extra actions to take
delegator
=
[
a
for
a
in
itip_event
[
'xml'
]
.
get_attendees
()
if
a
.
get_email
()
==
from_address
][
0
]
delegatee
=
[
a
for
a
in
itip_event
[
'xml'
]
.
get_attendees
()
if
from_address
in
[
b
.
email
()
for
b
in
a
.
get_delegated_from
()]][
0
]
itip_event
[
'xml'
]
.
event
.
setAttendees
([
delegator
,
delegatee
])
message
=
itip_event
[
'xml'
]
.
to_message_itip
(
delegatee
.
get_email
(),
method
=
"REPLY"
,
participant_status
=
itip_event
[
'xml'
]
.
get_ical_attendee_participant_status
(
delegatee
))
smtp
.
sendmail
(
message
[
'From'
],
message
[
'To'
],
message
.
as_string
())
itip_event
[
'xml'
]
.
event
.
setAttendees
([
a
for
a
in
itip_event
[
'xml'
]
.
get_attendees
()
if
a
.
get_email
()
==
from_address
])
message
=
itip_event
[
'xml'
]
.
to_message_itip
(
from_address
,
method
=
"REPLY"
,
participant_status
=
participant_status
)
smtp
.
sendmail
(
message
[
'From'
],
message
[
'To'
],
message
.
as_string
())
smtp
.
quit
()
File Metadata
Details
Attached
Mime Type
text/x-script.python
Expires
Sun, Apr 5, 11:07 PM (2 w, 1 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
51/44/d5b6b0c3f52f576f9f879099ddd5
Default Alt Text
module_resources.py (27 KB)
Attached To
Mode
rP pykolab
Attached
Detach File
Event Timeline