/**
  * 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
  * @param boolean Request RSVP
  * @return boolean True on success, false on failure
  */
 public function send_itip_message($event, $method, $recipient, $subject, $bodytext, $message = null, $rsvp = true)
 {
     if (!$this->sender['name']) {
         $this->sender['name'] = $this->sender['email'];
     }
     if (!$message) {
         libcalendaring::identify_recurrence_instance($event);
         $message = $this->compose_itip_message($event, $method, $rsvp);
     }
     $mailto = rcube_utils::idn_to_ascii($recipient['email']);
     $headers = $message->headers();
     $headers['To'] = format_email_recipient($mailto, $recipient['name']);
     $headers['Subject'] = $this->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']);
     }
     $recurrence_info = '';
     if (!empty($event['recurrence_id'])) {
         $recurrence_info = "\n\n** " . $this->gettext($event['thisandfuture'] ? 'itipmessagefutureoccurrence' : 'itipmessagesingleoccurrence') . ' **';
     } else {
         if (!empty($event['recurrence'])) {
             $recurrence_info = sprintf("\n%s: %s", $this->gettext('recurring'), $this->lib->recurrence_text($event['recurrence']));
         }
     }
     $mailbody = $this->gettext(array('name' => $bodytext, 'vars' => array('title' => $event['title'], 'date' => $this->lib->event_date_text($event, true) . $recurrence_info, 'attendees' => join(",\n ", $attendees_list), 'sender' => $this->sender['name'], 'organizer' => $this->sender['name'])));
     // if (!empty($event['comment'])) {
     //     $mailbody .= "\n\n" . $this->gettext('itipsendercomment') . $event['comment'];
     // }
     // append links for direct invitation replies
     if ($method == 'REQUEST' && $rsvp && ($token = $this->store_invitation($event, $recipient['email']))) {
         $mailbody .= "\n\n" . $this->gettext(array('name' => 'invitationattendlinks', 'vars' => array('url' => $this->plugin->get_url(array('action' => 'attend', 't' => $token)))));
     } else {
         if ($method == 'CANCEL' && $event['cancelled']) {
             $this->cancel_itip_invitation($event);
         }
     }
     $message->headers($headers, true);
     $message->setTXTBody(rcube_mime::format_flowed($mailbody, 79));
     if ($this->rc->config->get('libcalendaring_itip_debug', false)) {
         rcmail::console('iTip ' . $method, $message->txtHeaders() . "\n\r" . $message->get());
     }
     // finally send the message
     $this->itip_send = true;
     $sent = $this->rc->deliver_message($message, $headers['X-Sender'], $mailto, $smtp_error);
     $this->itip_send = false;
     return $sent;
 }
示例#2
0
 /**
  * Send out an invitation/notification to all event attendees
  */
 private function notify_attendees($event, $old, $action = 'edit', $comment = null, $rsvp = null)
 {
     if ($action == 'remove' || $event['status'] == 'CANCELLED' && $old['status'] != $event['status']) {
         $event['cancelled'] = true;
         $is_cancelled = true;
     }
     if ($rsvp === null) {
         $rsvp = !$old || $event['sequence'] > $old['sequence'];
     }
     $itip = $this->load_itip();
     $emails = $this->get_user_emails();
     $itip_notify = (int) $this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']);
     // add comment to the iTip attachment
     $event['comment'] = $comment;
     // set a valid recurrence-id if this is a recurrence instance
     libcalendaring::identify_recurrence_instance($event);
     // compose multipart message using PEAR:Mail_Mime
     $method = $action == 'remove' ? 'CANCEL' : 'REQUEST';
     $message = $itip->compose_itip_message($event, $method, $rsvp);
     // list existing attendees from $old event
     $old_attendees = array();
     foreach ((array) $old['attendees'] as $attendee) {
         $old_attendees[] = $attendee['email'];
     }
     // send to every attendee
     $sent = 0;
     $current = array();
     foreach ((array) $event['attendees'] as $attendee) {
         $current[] = strtolower($attendee['email']);
         // skip myself for obvious reasons
         if (!$attendee['email'] || in_array(strtolower($attendee['email']), $emails)) {
             continue;
         }
         // skip if notification is disabled for this attendee
         if ($attendee['noreply'] && $itip_notify & 2) {
             continue;
         }
         // skip if this attendee has delegated and set RSVP=FALSE
         if ($attendee['status'] == 'DELEGATED' && $attendee['rsvp'] === false) {
             continue;
         }
         // which template to use for mail text
         $is_new = !in_array($attendee['email'], $old_attendees);
         $is_rsvp = $is_new || $event['sequence'] > $old['sequence'];
         $bodytext = $is_cancelled ? 'eventcancelmailbody' : ($is_new ? 'invitationmailbody' : 'eventupdatemailbody');
         $subject = $is_cancelled ? 'eventcancelsubject' : ($is_new ? 'invitationsubject' : ($event['title'] ? 'eventupdatesubject' : 'eventupdatesubjectempty'));
         $event['comment'] = $comment;
         // finally send the message
         if ($itip->send_itip_message($event, $method, $attendee, $subject, $bodytext, $message, $is_rsvp)) {
             $sent++;
         } else {
             $sent = -100;
         }
     }
     // TODO: on change of a recurring (main) event, also send updates to differing attendess of recurrence exceptions
     // send CANCEL message to removed attendees
     foreach ((array) $old['attendees'] as $attendee) {
         if ($attendee['role'] == 'ORGANIZER' || !$attendee['email'] || in_array(strtolower($attendee['email']), $current)) {
             continue;
         }
         $vevent = $old;
         $vevent['cancelled'] = $is_cancelled;
         $vevent['attendees'] = array($attendee);
         $vevent['comment'] = $comment;
         if ($itip->send_itip_message($vevent, 'CANCEL', $attendee, 'eventcancelsubject', 'eventcancelmailbody')) {
             $sent++;
         } else {
             $sent = -100;
         }
     }
     return $sent;
 }
 /**
  * Convert sql record into a rcube style event object
  */
 private function _read_postprocess($event)
 {
     $free_busy_map = array_flip($this->free_busy_map);
     $sensitivity_map = array_flip($this->sensitivity_map);
     $event['id'] = $event['event_id'];
     $event['start'] = new DateTime($event['start']);
     $event['end'] = new DateTime($event['end']);
     $event['allday'] = intval($event['all_day']);
     $event['created'] = new DateTime($event['created']);
     $event['changed'] = new DateTime($event['changed']);
     $event['free_busy'] = $free_busy_map[$event['free_busy']];
     $event['sensitivity'] = $sensitivity_map[$event['sensitivity']];
     $event['calendar'] = $event['calendar_id'];
     $event['recurrence_id'] = intval($event['recurrence_id']);
     $event['isexception'] = intval($event['isexception']);
     // parse recurrence rule
     if ($event['recurrence'] && preg_match_all('/([A-Z]+)=([^;]+);?/', $event['recurrence'], $m, PREG_SET_ORDER)) {
         $event['recurrence'] = array();
         foreach ($m as $rr) {
             if (is_numeric($rr[2])) {
                 $rr[2] = intval($rr[2]);
             } else {
                 if ($rr[1] == 'UNTIL') {
                     $rr[2] = date_create($rr[2]);
                 } else {
                     if ($rr[1] == 'RDATE') {
                         $rr[2] = array_map('date_create', explode(',', $rr[2]));
                     } else {
                         if ($rr[1] == 'EXDATE') {
                             $rr[2] = array_map('date_create', explode(',', $rr[2]));
                         }
                     }
                 }
             }
             $event['recurrence'][$rr[1]] = $rr[2];
         }
     }
     if ($event['recurrence_id']) {
         libcalendaring::identify_recurrence_instance($event);
     }
     if (strlen($event['instance'])) {
         $event['_instance'] = $event['instance'];
         if (empty($event['recurrence_id'])) {
             $event['recurrence_date'] = rcube_utils::anytodatetime($event['_instance'], $event['start']->getTimezone());
         }
     }
     if ($event['_attachments'] > 0) {
         $event['attachments'] = (array) $this->list_attachments($event);
     }
     // decode serialized event attendees
     if (strlen($event['attendees'])) {
         $event['attendees'] = $this->unserialize_attendees($event['attendees']);
     } else {
         $event['attendees'] = array();
     }
     // decode serialized alarms
     if ($event['alarms']) {
         $event['valarms'] = $this->unserialize_alarms($event['alarms']);
     }
     unset($event['event_id'], $event['calendar_id'], $event['notifyat'], $event['all_day'], $event['instance'], $event['_attachments']);
     return $event;
 }