/** * Handle meeting responses. * * @param array $response The response data. Contains: * - requestid: The identifier of the meeting request. Used by the server * to fetch the original meeting request details. * - response: The user's response to the request. One of the response * code constants. * - folderid: The collection id that contains the meeting request. * - * * @return string The UID of any created calendar entries, otherwise false. * @throws Horde_ActiveSync_Exception, Horde_Exception_NotFound */ public function meetingResponse(array $response) { if (empty($response['folderid']) || empty($response['requestid']) || empty($response['response'])) { throw new Horde_ActiveSync_Exception('Invalid meeting response.'); } // First thing we need is to obtain the meeting request. $imap_message = $this->_imap->getImapMessage($response['folderid'], $response['requestid']); if (empty($imap_message)) { throw new Horde_Exception_NotFound(); } $imap_message = $imap_message[$response['requestid']]; // Find the request if (!($part = $imap_message->hasiCalendar())) { $this->_logger->err('Unable to find the meeting request.'); throw new Horde_Exception_NotFound(); } // Parse the vCal $vCal = new Horde_Icalendar(); $data = $part->getContents(); if (!$vCal->parsevCalendar($data, 'VCALENDAR', $part->getCharset())) { throw new Horde_ActiveSync_Exception('Unknown error parsing vCal data.'); } if (!($vEvent = $vCal->findComponent('vEvent'))) { throw new Horde_ActiveSync_Exception('Unknown error locating vEvent.'); } // Create an event from the vEvent. // Note we don't use self::changeMessage since we don't want to treat // this as an incoming message addition from the PIM. Otherwise, the // message may not get synched back to the PIM. try { $uid = $this->_connector->calendar_import_vevent($vEvent); } catch (Horde_Exception $e) { $this->_logger->err($e->getMessage()); throw new Horde_ActiveSync_Exception($e); } // Start building the iTip response email. try { $organizer = parse_url($vEvent->getAttribute('ORGANIZER')); $organizer = $organizer['path']; } catch (Horde_Icalendar_Exception $e) { $this->_logger->err('Unable to find organizer.'); throw new Horde_ActiveSync_Exception($e); } $ident = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($this->_user); $cn = $ident->getValue('fullname'); $email = $ident->getValue('from_addr'); // Can't use Horde_Itip_Resource_Identity since it takes an IMP identity $resource = new Horde_Itip_Resource_Base($email, $cn); switch ($response['response']) { case Horde_ActiveSync_Request_MeetingResponse::RESPONSE_ACCEPTED: $type = new Horde_Itip_Response_Type_Accept($resource); break; case Horde_ActiveSync_Request_MeetingResponse::RESPONSE_DECLINED: $type = new Horde_Itip_Response_Type_Decline($resource); break; case Horde_ActiveSync_Request_MeetingResponse::RESPONSE_TENTATIVE: $type = new Horde_Itip_Response_Type_Tentative($resource); break; } // Delete the original request. EAS Specs require this. Most clients // will remove the email from the UI as soon as the response is sent. // Failure to remove it from the server will result in an inconsistent // sync state. $this->_imap->deleteMessages(array($response['requestid']), $response['folderid']); return $uid; }
/** * Handle meeting responses. * * @param array $response The response data. Contains: * - requestid: The identifier of the meeting request. Used by the server * to fetch the original meeting request details. * - response: The user's response to the request. One of the response * code constants. * - folderid: The collection id that contains the meeting request. * - * * @return string The UID of any created calendar entries, otherwise false. * @throws Horde_ActiveSync_Exception, Horde_Exception_NotFound */ public function meetingResponse(array $response) { global $injector; if (empty($response['folderid']) || empty($response['requestid']) || empty($response['response'])) { throw new Horde_ActiveSync_Exception('Invalid meeting response.'); } // First thing we need is to obtain the meeting request. $imap_message = $this->_imap->getImapMessage($response['folderid'], $response['requestid']); if (empty($imap_message)) { throw new Horde_Exception_NotFound(); } $imap_message = $imap_message[$response['requestid']]; // Find the request if (!($part = $imap_message->hasiCalendar())) { $this->_logger->err('Unable to find the meeting request.'); throw new Horde_Exception_NotFound(); } // Parse the vCal $vCal = new Horde_Icalendar(); $data = $part->getContents(); if (!$vCal->parsevCalendar($data, 'VCALENDAR', $part->getCharset())) { throw new Horde_ActiveSync_Exception('Unknown error parsing vCal data.'); } if (!($vEvent = $vCal->findComponent('vEvent'))) { throw new Horde_ActiveSync_Exception('Unknown error locating vEvent.'); } // Update the vCal so the response will be reflected when imported. $ident = $injector->getInstance('Horde_Core_Factory_Identity')->create($this->_user); $cn = $ident->getValue('fullname'); $email = $ident->getValue('from_addr'); switch ($response['response']) { case Horde_ActiveSync_Request_MeetingResponse::RESPONSE_ACCEPTED: $itip_response = 'ACCEPTED'; break; case Horde_ActiveSync_Request_MeetingResponse::RESPONSE_TENTATIVE: $itip_response = 'TENTATIVE'; break; case Horde_ActiveSync_Request_MeetingResponse::RESPONSE_DECLINED: $itip_response = 'DECLINED'; } $vEvent->updateAttendee($email, $itip_response); // Create an event from the vEvent. // Note we don't use self::changeMessage since we don't want to treat // this as an incoming message addition from the PIM. Otherwise, the // message may not get synched back to the PIM. try { $uid = $this->_connector->calendar_import_vevent($vEvent); } catch (Horde_Exception $e) { $this->_logger->err($e->getMessage()); throw new Horde_ActiveSync_Exception($e); } if (!empty($response['sendresponse'])) { if ($response['sendresponse'] !== true) { $comment = $response['sendresponse']->data; if ($response['sendresponse']->type == Horde_ActiveSync::BODYPREF_TYPE_HTML) { $comment = Horde_Text_Filter::filter($comment, 'Html2text', array('charset' => 'UTF-8', 'nestingLimit' => 1000)); } } else { $comment = ''; } // Start building the iTip response email. try { $organizer = parse_url($vEvent->getAttribute('ORGANIZER')); $organizer = $organizer['path']; } catch (Horde_Icalendar_Exception $e) { $this->_logger->err('Unable to find organizer.'); throw new Horde_ActiveSync_Exception($e); } $ident = $injector->getInstance('Horde_Core_Factory_Identity')->create($event->creator); if (!$ident->getValue('from_addr')) { throw new Horde_ActiveSync_Exception(_("You do not have an email address configured in your Personal Information Preferences.")); } $resource = new Horde_Itip_Resource_Identity($ident, $vEvent->getAttribute('ATTENDEE'), (string) $ident->getFromAddress()); switch ($response['response']) { case Horde_ActiveSync_Request_MeetingResponse::RESPONSE_ACCEPTED: $type = new Horde_Itip_Response_Type_Accept($resource, $comment); break; case Horde_ActiveSync_Request_MeetingResponse::RESPONSE_DECLINED: $type = new Horde_Itip_Response_Type_Decline($resource, $comment); break; case Horde_ActiveSync_Request_MeetingResponse::RESPONSE_TENTATIVE: $type = new Horde_Itip_Response_Type_Tentative($resource, $comment); break; } try { // Send the reply. Horde_Itip::factory($vEvent, $resource)->sendMultiPartResponse($type, new Horde_Core_Itip_Response_Options_Horde('UTF-8', array()), $injector->getInstance('Horde_Mail')); $this->_logger->info('Reply sent.'); } catch (Horde_Itip_Exception $e) { $this->_logger->err(sprintf(_("Error sending reply: %s."), $e->getMessage()), 'horde.error'); } } // Delete the original request. EAS Specs require this. Most clients // will remove the email from the UI as soon as the response is sent. // Failure to remove it from the server will result in an inconsistent // sync state. try { $this->_imap->deleteMessages(array($response['requestid']), $response['folderid']); } catch (Horde_ActiveSync_Exception $e) { $this->_logger->err($e->getMessage()); } return $uid; }