Mercurial > hg > rc1
comparison plugins/calendar/lib/calendar_itip.php @ 3:f6fe4b6ae66a
calendar plugin nearly as distributed
| author | Charlie Root |
|---|---|
| date | Sat, 13 Jan 2018 08:56:12 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 2:c828b0fd4a6e | 3:f6fe4b6ae66a |
|---|---|
| 1 <?php | |
| 2 | |
| 3 require_once realpath(__DIR__ . '/../../libcalendaring/lib/libcalendaring_itip.php'); | |
| 4 | |
| 5 /** | |
| 6 * iTIP functions for the Calendar plugin | |
| 7 * | |
| 8 * Class providing functionality to manage iTIP invitations | |
| 9 * | |
| 10 * @version @package_version@ | |
| 11 * @author Thomas Bruederli <bruederli@kolabsys.com> | |
| 12 * @package @package_name@ | |
| 13 * | |
| 14 * Copyright (C) 2011, Kolab Systems AG <contact@kolabsys.com> | |
| 15 * | |
| 16 * This program is free software: you can redistribute it and/or modify | |
| 17 * it under the terms of the GNU Affero General Public License as | |
| 18 * published by the Free Software Foundation, either version 3 of the | |
| 19 * License, or (at your option) any later version. | |
| 20 * | |
| 21 * This program is distributed in the hope that it will be useful, | |
| 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 24 * GNU Affero General Public License for more details. | |
| 25 * | |
| 26 * You should have received a copy of the GNU Affero General Public License | |
| 27 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 28 */ | |
| 29 class calendar_itip extends libcalendaring_itip | |
| 30 { | |
| 31 /** | |
| 32 * Constructor to set text domain to calendar | |
| 33 */ | |
| 34 function __construct($plugin, $domain = 'calendar') | |
| 35 { | |
| 36 parent::__construct($plugin, $domain); | |
| 37 | |
| 38 $this->db_itipinvitations = $this->rc->db->table_name('itipinvitations', true); | |
| 39 } | |
| 40 | |
| 41 /** | |
| 42 * Handler for calendar/itip-status requests | |
| 43 */ | |
| 44 public function get_itip_status($event, $existing = null) | |
| 45 { | |
| 46 $status = parent::get_itip_status($event, $existing); | |
| 47 | |
| 48 // don't ask for deleting events when declining | |
| 49 if ($this->rc->config->get('kolab_invitation_calendars')) | |
| 50 $status['saved'] = false; | |
| 51 | |
| 52 return $status; | |
| 53 } | |
| 54 | |
| 55 /** | |
| 56 * Find invitation record by token | |
| 57 * | |
| 58 * @param string Invitation token | |
| 59 * @return mixed Invitation record as hash array or False if not found | |
| 60 */ | |
| 61 public function get_invitation($token) | |
| 62 { | |
| 63 if ($parts = $this->decode_token($token)) { | |
| 64 $result = $this->rc->db->query("SELECT * FROM $this->db_itipinvitations WHERE `token` = ?", $parts['base']); | |
| 65 if ($result && ($rec = $this->rc->db->fetch_assoc($result))) { | |
| 66 $rec['event'] = unserialize($rec['event']); | |
| 67 $rec['attendee'] = $parts['attendee']; | |
| 68 return $rec; | |
| 69 } | |
| 70 } | |
| 71 | |
| 72 return false; | |
| 73 } | |
| 74 | |
| 75 /** | |
| 76 * Update the attendee status of the given invitation record | |
| 77 * | |
| 78 * @param array Invitation record as fetched with calendar_itip::get_invitation() | |
| 79 * @param string Attendee email address | |
| 80 * @param string New attendee status | |
| 81 */ | |
| 82 public function update_invitation($invitation, $email, $newstatus) | |
| 83 { | |
| 84 if (is_string($invitation)) | |
| 85 $invitation = $this->get_invitation($invitation); | |
| 86 | |
| 87 if ($invitation['token'] && $invitation['event']) { | |
| 88 // update attendee record in event data | |
| 89 foreach ($invitation['event']['attendees'] as $i => $attendee) { | |
| 90 if ($attendee['role'] == 'ORGANIZER') { | |
| 91 $organizer = $attendee; | |
| 92 } | |
| 93 else if ($attendee['email'] == $email) { | |
| 94 // nothing to be done here | |
| 95 if ($attendee['status'] == $newstatus) | |
| 96 return true; | |
| 97 | |
| 98 $invitation['event']['attendees'][$i]['status'] = $newstatus; | |
| 99 $this->sender = $attendee; | |
| 100 } | |
| 101 } | |
| 102 $invitation['event']['changed'] = new DateTime(); | |
| 103 | |
| 104 // send iTIP REPLY message to organizer | |
| 105 if ($organizer) { | |
| 106 $status = strtolower($newstatus); | |
| 107 if ($this->send_itip_message($invitation['event'], 'REPLY', $organizer, 'itipsubject' . $status, 'itipmailbody' . $status)) | |
| 108 $this->rc->output->command('display_message', $this->plugin->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $organizer['name'] ? $organizer['name'] : $organizer['email']))), 'confirmation'); | |
| 109 else | |
| 110 $this->rc->output->command('display_message', $this->plugin->gettext('itipresponseerror'), 'error'); | |
| 111 } | |
| 112 | |
| 113 // update record in DB | |
| 114 $query = $this->rc->db->query( | |
| 115 "UPDATE $this->db_itipinvitations | |
| 116 SET `event` = ? | |
| 117 WHERE `token` = ?", | |
| 118 self::serialize_event($invitation['event']), | |
| 119 $invitation['token'] | |
| 120 ); | |
| 121 | |
| 122 if ($this->rc->db->affected_rows($query)) | |
| 123 return true; | |
| 124 } | |
| 125 | |
| 126 return false; | |
| 127 } | |
| 128 | |
| 129 | |
| 130 /** | |
| 131 * Create iTIP invitation token for later replies via URL | |
| 132 * | |
| 133 * @param array Hash array with event properties | |
| 134 * @param string Attendee email address | |
| 135 * @return string Invitation token | |
| 136 */ | |
| 137 public function store_invitation($event, $attendee) | |
| 138 { | |
| 139 static $stored = array(); | |
| 140 | |
| 141 if (!$event['uid'] || !$attendee) | |
| 142 return false; | |
| 143 | |
| 144 // generate token for this invitation | |
| 145 $token = $this->generate_token($event, $attendee); | |
| 146 $base = substr($token, 0, 40); | |
| 147 | |
| 148 // already stored this | |
| 149 if ($stored[$base]) | |
| 150 return $token; | |
| 151 | |
| 152 // delete old entry | |
| 153 $this->rc->db->query("DELETE FROM $this->db_itipinvitations WHERE `token` = ?", $base); | |
| 154 | |
| 155 $event_uid = $event['uid'] . ($event['_instance'] ? '-' . $event['_instance'] : ''); | |
| 156 | |
| 157 $query = $this->rc->db->query( | |
| 158 "INSERT INTO $this->db_itipinvitations | |
| 159 (`token`, `event_uid`, `user_id`, `event`, `expires`) | |
| 160 VALUES(?, ?, ?, ?, ?)", | |
| 161 $base, | |
| 162 $event_uid, | |
| 163 $this->rc->user->ID, | |
| 164 self::serialize_event($event), | |
| 165 date('Y-m-d H:i:s', $event['end']->format('U') + 86400 * 2) | |
| 166 ); | |
| 167 | |
| 168 if ($this->rc->db->affected_rows($query)) { | |
| 169 $stored[$base] = 1; | |
| 170 return $token; | |
| 171 } | |
| 172 | |
| 173 return false; | |
| 174 } | |
| 175 | |
| 176 /** | |
| 177 * Mark invitations for the given event as cancelled | |
| 178 * | |
| 179 * @param array Hash array with event properties | |
| 180 */ | |
| 181 public function cancel_itip_invitation($event) | |
| 182 { | |
| 183 $event_uid = $event['uid'] . ($event['_instance'] ? '-' . $event['_instance'] : ''); | |
| 184 | |
| 185 // flag invitation record as cancelled | |
| 186 $this->rc->db->query( | |
| 187 "UPDATE $this->db_itipinvitations | |
| 188 SET `cancelled` = 1 | |
| 189 WHERE `event_uid` = ? AND `user_id` = ?", | |
| 190 $event_uid, | |
| 191 $this->rc->user->ID | |
| 192 ); | |
| 193 } | |
| 194 | |
| 195 /** | |
| 196 * Generate an invitation request token for the given event and attendee | |
| 197 * | |
| 198 * @param array Event hash array | |
| 199 * @param string Attendee email address | |
| 200 */ | |
| 201 public function generate_token($event, $attendee) | |
| 202 { | |
| 203 $event_uid = $event['uid'] . ($event['_instance'] ? '-' . $event['_instance'] : ''); | |
| 204 $base = sha1($event_uid . ';' . $this->rc->user->ID); | |
| 205 $mail = base64_encode($attendee); | |
| 206 $hash = substr(md5($base . $mail . $this->rc->config->get('des_key')), 0, 6); | |
| 207 | |
| 208 return "$base.$mail.$hash"; | |
| 209 } | |
| 210 | |
| 211 /** | |
| 212 * Decode the given iTIP request token and return its parts | |
| 213 * | |
| 214 * @param string Request token to decode | |
| 215 * @return mixed Hash array with parts or False if invalid | |
| 216 */ | |
| 217 public function decode_token($token) | |
| 218 { | |
| 219 list($base, $mail, $hash) = explode('.', $token); | |
| 220 | |
| 221 // validate and return parts | |
| 222 if ($mail && $hash && $hash == substr(md5($base . $mail . $this->rc->config->get('des_key')), 0, 6)) { | |
| 223 return array('base' => $base, 'attendee' => base64_decode($mail)); | |
| 224 } | |
| 225 | |
| 226 return false; | |
| 227 } | |
| 228 | |
| 229 /** | |
| 230 * Helper method to serialize the given event for storing in invitations table | |
| 231 */ | |
| 232 private static function serialize_event($event) | |
| 233 { | |
| 234 $ev = $event; | |
| 235 $ev['description'] = abbreviate_string($ev['description'], 100); | |
| 236 unset($ev['attachments']); | |
| 237 return serialize($ev); | |
| 238 } | |
| 239 | |
| 240 } |
