Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117751777
calendar_itip.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
10 KB
Referenced Files
None
Subscribers
None
calendar_itip.php
View Options
<?php
/**
* iTIP functions for the Calendar plugin
*
* Class providing functionality to manage iTIP invitations
*
* @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com>
* @package @package_name@
*
* Copyright (C) 2011, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class
calendar_itip
{
private
$rc
;
private
$cal
;
private
$event
;
function
__construct
(
$cal
)
{
$this
->
cal
=
$cal
;
$this
->
rc
=
$cal
->
rc
;
$this
->
sender
=
$this
->
rc
->
user
->
get_identity
();
}
/**
* Send an iTip mail message
*
* @param array Event object to send
* @param string iTip method (REQUEST|REPLY|CANCEL)
* @param array Hash array with recipient data (name, email)
* @param string Mail subject
* @param string Mail body text label
* @param object Mail_mime object with message data
* @return boolean True on success, false on failure
*/
public
function
send_itip_message
(
$event
,
$method
,
$recipient
,
$subject
,
$bodytext
,
$message
=
null
)
{
if
(!
$this
->
sender
[
'name'
])
$this
->
sender
[
'name'
]
=
$this
->
sender
[
'email'
];
if
(!
$message
)
$message
=
$this
->
compose_itip_message
(
$event
,
$method
);
$mailto
=
rcube_idn_to_ascii
(
$recipient
[
'email'
]);
$headers
=
$message
->
headers
();
$headers
[
'To'
]
=
format_email_recipient
(
$mailto
,
$recipient
[
'name'
]);
$headers
[
'Subject'
]
=
$this
->
cal
->
gettext
(
array
(
'name'
=>
$subject
,
'vars'
=>
array
(
'title'
=>
$event
[
'title'
],
'name'
=>
$this
->
sender
[
'name'
])
));
// compose a list of all event attendees
$attendees_list
=
array
();
foreach
((
array
)
$event
[
'attendees'
]
as
$attendee
)
{
$attendees_list
[]
=
(
$attendee
[
'name'
]
&&
$attendee
[
'email'
])
?
$attendee
[
'name'
]
.
' <'
.
$attendee
[
'email'
]
.
'>'
:
(
$attendee
[
'name'
]
?
$attendee
[
'name'
]
:
$attendee
[
'email'
]);
}
$mailbody
=
$this
->
cal
->
gettext
(
array
(
'name'
=>
$bodytext
,
'vars'
=>
array
(
'title'
=>
$event
[
'title'
],
'date'
=>
$this
->
cal
->
event_date_text
(
$event
,
true
),
'attendees'
=>
join
(
', '
,
$attendees_list
),
'sender'
=>
$this
->
sender
[
'name'
],
'organizer'
=>
$this
->
sender
[
'name'
],
)
));
// append links for direct invitation replies
if
(
$method
==
'REQUEST'
&&
(
$token
=
$this
->
store_invitation
(
$event
,
$recipient
[
'email'
])))
{
$mailbody
.=
"
\n\n
"
.
$this
->
cal
->
gettext
(
array
(
'name'
=>
'invitationattendlinks'
,
'vars'
=>
array
(
'url'
=>
$this
->
cal
->
get_url
(
array
(
'action'
=>
'attend'
,
't'
=>
$token
))),
));
}
else
if
(
$method
==
'CANCEL'
)
{
$this
->
cancel_itip_invitation
(
$event
);
}
$message
->
headers
(
$headers
,
true
);
$message
->
setTXTBody
(
rcube_mime
::
format_flowed
(
$mailbody
,
79
));
// finally send the message
return
rcmail_deliver_message
(
$message
,
$headers
[
'X-Sender'
],
$mailto
,
$smtp_error
);
}
/**
* Helper function to build a Mail_mime object to send an iTip message
*
* @param array Event object to send
* @param string iTip method (REQUEST|REPLY|CANCEL)
* @return object Mail_mime object with message data
*/
public
function
compose_itip_message
(
$event
,
$method
)
{
$from
=
rcube_idn_to_ascii
(
$this
->
sender
[
'email'
]);
$sender
=
format_email_recipient
(
$from
,
$this
->
sender
[
'name'
]);
// compose multipart message using PEAR:Mail_Mime
$message
=
new
Mail_mime
(
"
\r\n
"
);
$message
->
setParam
(
'text_encoding'
,
'quoted-printable'
);
$message
->
setParam
(
'head_encoding'
,
'quoted-printable'
);
$message
->
setParam
(
'head_charset'
,
RCMAIL_CHARSET
);
$message
->
setParam
(
'text_charset'
,
RCMAIL_CHARSET
.
";
\r\n
format=flowed"
);
// compose common headers array
$headers
=
array
(
'From'
=>
$sender
,
'Date'
=>
rcmail_user_date
(),
'Message-ID'
=>
rcmail_gen_message_id
(),
'X-Sender'
=>
$from
,
);
if
(
$agent
=
$this
->
rc
->
config
->
get
(
'useragent'
))
$headers
[
'User-Agent'
]
=
$agent
;
$message
->
headers
(
$headers
);
// attach ics file for this event
$ical
=
$this
->
cal
->
get_ical
();
$ics
=
$ical
->
export
(
array
(
$event
),
$method
);
$message
->
addAttachment
(
$ics
,
'text/calendar'
,
'event.ics'
,
false
,
'8bit'
,
'attachment'
,
RCMAIL_CHARSET
.
"; method="
.
$method
);
return
$message
;
}
/**
* Find invitation record by token
*
* @param string Invitation token
* @return mixed Invitation record as hash array or False if not found
*/
public
function
get_invitation
(
$token
)
{
if
(
$parts
=
$this
->
decode_token
(
$token
))
{
$result
=
$this
->
rc
->
db
->
query
(
"SELECT * FROM itipinvitations WHERE token=?"
,
$parts
[
'base'
]);
if
(
$result
&&
(
$rec
=
$this
->
rc
->
db
->
fetch_assoc
(
$result
)))
{
$rec
[
'event'
]
=
unserialize
(
$rec
[
'event'
]);
$rec
[
'attendee'
]
=
$parts
[
'attendee'
];
return
$rec
;
}
}
return
false
;
}
/**
* Update the attendee status of the given invitation record
*
* @param array Invitation record as fetched with calendar_itip::get_invitation()
* @param string Attendee email address
* @param string New attendee status
*/
public
function
update_invitation
(
$invitation
,
$email
,
$newstatus
)
{
if
(
is_string
(
$invitation
))
$invitation
=
$this
->
get_invitation
(
$invitation
);
if
(
$invitation
[
'token'
]
&&
$invitation
[
'event'
])
{
// update attendee record in event data
foreach
(
$invitation
[
'event'
][
'attendees'
]
as
$i
=>
$attendee
)
{
if
(
$attendee
[
'role'
]
==
'ORGANIZER'
)
{
$organizer
=
$attendee
;
}
else
if
(
$attendee
[
'email'
]
==
$email
)
{
// nothing to be done here
if
(
$attendee
[
'status'
]
==
$newstatus
)
return
true
;
$invitation
[
'event'
][
'attendees'
][
$i
][
'status'
]
=
$newstatus
;
$this
->
sender
=
$attendee
;
}
}
$invitation
[
'event'
][
'changed'
]
=
time
();
// send iTIP REPLY message to organizer
if
(
$organizer
)
{
$status
=
strtolower
(
$newstatus
);
if
(
$this
->
send_itip_message
(
$invitation
[
'event'
],
'REPLY'
,
$organizer
,
'itipsubject'
.
$status
,
'itipmailbody'
.
$status
))
$this
->
rc
->
output
->
command
(
'display_message'
,
$this
->
cal
->
gettext
(
array
(
'name'
=>
'sentresponseto'
,
'vars'
=>
array
(
'mailto'
=>
$organizer
[
'name'
]
?
$organizer
[
'name'
]
:
$organizer
[
'email'
]))),
'confirmation'
);
else
$this
->
rc
->
output
->
command
(
'display_message'
,
$this
->
cal
->
gettext
(
'itipresponseerror'
),
'error'
);
}
// update record in DB
$query
=
$this
->
rc
->
db
->
query
(
"UPDATE itipinvitations
SET event=?
WHERE token=?"
,
self
::
serialize_event
(
$invitation
[
'event'
]),
$invitation
[
'token'
]
);
if
(
$this
->
rc
->
db
->
affected_rows
(
$query
))
return
true
;
}
return
false
;
}
/**
* Create iTIP invitation token for later replies via URL
*
* @param array Hash array with event properties
* @param string Attendee email address
* @return string Invitation token
*/
public
function
store_invitation
(
$event
,
$attendee
)
{
static
$stored
=
array
();
if
(!
$event
[
'uid'
]
||
!
$attendee
)
return
false
;
// generate token for this invitation
$token
=
$this
->
generate_token
(
$event
,
$attendee
);
$base
=
substr
(
$token
,
0
,
40
);
// already stored this
if
(
$stored
[
$base
])
return
$token
;
// @TODO: REPLACE works only with MySQL
$query
=
$this
->
rc
->
db
->
query
(
"REPLACE INTO itipinvitations
(token, event_uid, user_id, event, expires)
VALUES(?, ?, ?, ?, ?)"
,
$base
,
$event
[
'uid'
],
$this
->
rc
->
user
->
ID
,
self
::
serialize_event
(
$event
),
date
(
'Y-m-d H:i:s'
,
$event
[
'end'
]
+
86400
*
2
)
);
if
(
$this
->
rc
->
db
->
affected_rows
(
$query
))
{
$stored
[
$base
]
=
1
;
return
$token
;
}
return
false
;
}
/**
* Mark invitations for the given event as cancelled
*
* @param array Hash array with event properties
*/
public
function
cancel_itip_invitation
(
$event
)
{
// flag invitation record as cancelled
$this
->
rc
->
db
->
query
(
"UPDATE itipinvitations
SET cancelled=1
WHERE event_uid=? AND user_id=?"
,
$event
[
'uid'
],
$this
->
rc
->
user
->
ID
);
}
/**
* Generate an invitation request token for the given event and attendee
*
* @param array Event hash array
* @param string Attendee email address
*/
public
function
generate_token
(
$event
,
$attendee
)
{
$base
=
sha1
(
$event
[
'uid'
]
.
';'
.
$this
->
rc
->
user
->
ID
);
$mail
=
base64_encode
(
$attendee
);
$hash
=
substr
(
md5
(
$base
.
$mail
.
$this
->
rc
->
config
->
get
(
'des_key'
)),
0
,
6
);
return
"$base.$mail.$hash"
;
}
/**
* Decode the given iTIP request token and return its parts
*
* @param string Request token to decode
* @return mixed Hash array with parts or False if invalid
*/
public
function
decode_token
(
$token
)
{
list
(
$base
,
$mail
,
$hash
)
=
explode
(
'.'
,
$token
);
// validate and return parts
if
(
$mail
&&
$hash
&&
$hash
==
substr
(
md5
(
$base
.
$mail
.
$this
->
rc
->
config
->
get
(
'des_key'
)),
0
,
6
))
{
return
array
(
'base'
=>
$base
,
'attendee'
=>
base64_decode
(
$mail
));
}
return
false
;
}
/**
* Helper method to serialize the given event for storing in invitations table
*/
private
static
function
serialize_event
(
$event
)
{
$ev
=
$event
;
$ev
[
'description'
]
=
abbreviate_string
(
$ev
[
'description'
],
100
);
unset
(
$ev
[
'attachments'
]);
return
serialize
(
$ev
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, Apr 4, 3:26 AM (1 d, 14 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
55/45/703dfcebc07ee57d8ab1a4d57bfc
Default Alt Text
calendar_itip.php (10 KB)
Attached To
Mode
rRPK roundcubemail-plugins-kolab
Attached
Detach File
Event Timeline