/** * Sends out iTip task notification to the assignee. * * Can be used to send task invitations, updates, and cancellations. * * @param Nag_Task $task The task in question. * @param Horde_Notification_Handler $notification * A notification object used to show result status. * @param integer $action * The type of notification to send. One of the Nag::ITIP_* values. * @param Horde_Date $instance * If cancelling a single instance of a recurring task, the date of * this instance. * @param string $range The range parameter if this is a recurring event. * Possible values are self::RANGE_THISANDFUTURE */ public static function sendITipNotifications(Nag_Task $task, Horde_Notification_Handler $notification, $action, Horde_Date $instance = null, $range = null) { global $injector, $registry, $nag_shares; if (!$task->assignee) { return; } $ident = $injector->getInstance('Horde_Core_Factory_Identity')->create($task->creator); if (!$ident->getValue('from_addr')) { $notification->push(sprintf(_("You do not have an email address configured in your Personal Information Preferences. You must set one %shere%s before event notifications can be sent."), $registry->getServiceLink('prefs', 'kronolith')->add(array('app' => 'horde', 'group' => 'identities'))->link(), '</a>'), 'horde.error', array('content.raw')); return; } // Generate image mime part first and only once, because we // need the Content-ID. $image = self::getImagePart('big_invitation.png'); $share = $nag_shares->getShare($task->tasklist); $view = new Horde_View(array('templatePath' => NAG_TEMPLATES . '/itip')); new Horde_View_Helper_Text($view); $view->identity = $ident; $view->task = $task; $view->imageId = $image->getContentId(); $email = Nag::getUserEmail($task->assignee); if (strpos($email, '@') === false) { continue; } /* Determine all notification-specific strings. */ $method = 'REQUEST'; switch ($action) { case self::ITIP_CANCEL: /* Cancellation. */ $method = 'CANCEL'; $filename = 'task-cancellation.ics'; $view->subject = sprintf(_("Cancelled: %s"), $task->name); if (empty($instance)) { $view->header = sprintf(_("%s has cancelled \"%s\"."), $ident->getName(), $task->name); } else { $view->header = sprintf(_("%s has cancelled an instance of the recurring \"%s\"."), $ident->getName(), $task->name); } break; case self::ITIP_UPDATE: if (!empty($task->organizer) && $task->organizer != Nag::getUserEmail($task->creator)) { // Sending a progress update. $method = 'REPLY'; } else { $method = 'UPDATE'; } case self::ITIP_REQUEST: default: if (empty($task->status) || $task->status == self::RESPONSE_NONE) { /* Invitation. */ $filename = 'task-invitation.ics'; $view->subject = $task->name; $view->header = sprintf(_("%s wishes to make you aware of \"%s\"."), $ident->getName(), $task->name); } else { $filename = 'task-update.ics'; $view->subject = sprintf(_("Updated: %s."), $task->name); $view->header = sprintf(_("%s wants to notify you about changes of \"%s\"."), $ident->getName(), $task->name); } break; } $view->attendees = $email; $view->organizer = empty($task->organizer) ? $registry->convertUserName($task->creator, false) : $task->organizer; /* Build the iCalendar data */ $iCal = new Horde_Icalendar(); $iCal->setAttribute('METHOD', $method); $vevent = $task->toiCalendar($iCal); $iCal->addComponent($vevent); /* text/calendar part */ $ics = new Horde_Mime_Part(); $ics->setType('text/calendar'); $ics->setContents($iCal->exportvCalendar()); $ics->setName($filename); $ics->setContentTypeParameter('METHOD', $method); $ics->setCharset('UTF-8'); $ics->setEOL("\r\n"); /* application/ics part */ $ics2 = clone $ics; $ics2->setType('application/ics'); /* multipart/mixed part */ $multipart = new Horde_Mime_Part(); $multipart->setType('multipart/mixed'); $inner = self::buildMimeMessage($view, 'notification', $image); $inner->addPart($ics); $multipart->addPart($inner); $multipart->addPart($ics2); $recipient = $method != 'REPLY' ? new Horde_Mail_Rfc822_Address($email) : new Horde_Mail_Rfc822_Address($task->organizer); $mail = new Horde_Mime_Mail(array('Subject' => $view->subject, 'To' => $recipient, 'From' => $ident->getDefaultFromAddress(true), 'User-Agent' => 'Nag ' . $registry->getVersion())); $mail->setBasePart($multipart); try { $mail->send($injector->getInstance('Horde_Mail')); $notification->push(sprintf(_("The task request notification to %s was successfully sent."), $recipient), 'horde.success'); } catch (Horde_Mime_Exception $e) { $notification->push(sprintf(_("There was an error sending a task request notification to %s: %s"), $recipient, $e->getMessage(), $e->getCode()), 'horde.error'); } }
$comments = $htmlpart->replaceEOL(Horde_Util::getFormData('ecard_comments')); if (!Horde_Util::getFormData('rtemode')) { $comments = '<pre>' . htmlspecialchars($comments, ENT_COMPAT, 'UTF-8') . '</pre>'; } $htmlpart->setContents('<html>' . $img_tag . $comments . '</html>'); $related->setContentTypeParameter('start', $htmlpart->setContentID()); $related->addPart($htmlpart); $related->addPart($imgpart); /* Create the multipart/alternative part. */ $alternative = new Horde_Mime_Part(); $alternative->setType('multipart/alternative'); $alternative->addPart($textpart); $alternative->addPart($related); /* Add them to the mail message */ $alt = new Horde_Mime_Mail(array('Subject' => _("Ecard - ") . Horde_Util::getFormData('image_desc'), 'To' => $to, 'From' => $from)); $alt->setBasePart($alternative); /* Send. */ try { $alt->send($injector->getInstance('Horde_Mail')); } catch (Horde_Mime_Exception $e) { $notification->push(sprintf(_("There was an error sending your message: %s"), $e->getMessage()), 'horde.error'); } echo Horde::wrapInlineScript(array('window.close();')); exit; } $title = sprintf(_("Send Ecard :: %s"), $image->filename); /* Set up the form object. */ $vars = Horde_Variables::getDefaultVariables(); $vars->set('actionID', 'send'); $vars->set('image_desc', strlen($image->caption) ? $image->caption : $image->filename); $form = new Ansel_Form_Ecard($vars, $title);
/** * Notifies about an alarm by e-mail. * * @param array $alarm An alarm hash. * * @throws Horde_Alarm_Exception */ public function notify(array $alarm) { if (!empty($alarm['internal']['mail']['sent'])) { return; } if (empty($alarm['params']['mail']['email'])) { if (empty($alarm['user'])) { return; } $email = $this->_identity->create($alarm['user'])->getDefaultFromAddress(true); } else { $email = $alarm['params']['mail']['email']; } try { $mail = new Horde_Mime_Mail(array('Subject' => $alarm['title'], 'To' => $email, 'From' => $email, 'Auto-Submitted' => 'auto-generated', 'X-Horde-Alarm' => $alarm['title'])); if (isset($alarm['params']['mail']['mimepart'])) { $mail->setBasePart($alarm['params']['mail']['mimepart']); } elseif (empty($alarm['params']['mail']['body'])) { $mail->setBody($alarm['text']); } else { $mail->setBody($alarm['params']['mail']['body']); } $mail->send($this->_mail); } catch (Horde_Mime_Exception $e) { throw new Horde_Alarm_Exception($e); } $alarm['internal']['mail']['sent'] = true; $this->alarm->internal($alarm['id'], $alarm['user'], $alarm['internal']); }
/** * Sends email notifications that a event has been added, edited, or * deleted to users that want such notifications. * * @param Kronolith_Event $event An event. * @param string $action The event action. One of "add", "edit", * or "delete". * * @throws Horde_Mime_Exception * @throws Kronolith_Exception */ public static function sendNotification($event, $action) { global $injector, $prefs, $registry; if (!in_array($action, array('add', 'edit', 'delete'))) { throw new Kronolith_Exception('Unknown event action: ' . $action); } // @TODO: Send notifications to the email addresses stored in the // resource object? if ($event->calendarType == 'resource') { return; } $groups = $injector->getInstance('Horde_Group'); $calendar = $event->calendar; $recipients = array(); try { $share = $injector->getInstance('Kronolith_Shares')->getShare($calendar); } catch (Horde_Share_Exception $e) { throw new Kronolith_Exception($e); } $owner = $share->get('owner'); if ($owner) { $recipients[$owner] = self::_notificationPref($owner, 'owner'); } $senderIdentity = $injector->getInstance('Horde_Core_Factory_Identity')->create($event->creator ?: $owner); foreach ($share->listUsers(Horde_Perms::READ) as $user) { if (empty($recipients[$user])) { $recipients[$user] = self::_notificationPref($user, 'read', $calendar); } } foreach ($share->listGroups(Horde_Perms::READ) as $group) { try { $group_users = $groups->listUsers($group); } catch (Horde_Group_Exception $e) { Horde::log($e, 'ERR'); continue; } foreach ($group_users as $user) { if (empty($recipients[$user])) { $recipients[$user] = self::_notificationPref($user, 'read', $calendar); } } } $addresses = array(); foreach ($recipients as $user => $vals) { if (!$vals) { continue; } $identity = $injector->getInstance('Horde_Core_Factory_Identity')->create($user); $email = $identity->getValue('from_addr'); if (strpos($email, '@') === false) { continue; } if (!isset($addresses[$vals['lang']][$vals['tf']][$vals['df']])) { $addresses[$vals['lang']][$vals['tf']][$vals['df']] = array(); } $tmp = new Horde_Mail_Rfc822_Address($email); $tmp->personal = $identity->getValue('fullname'); $addresses[$vals['lang']][$vals['tf']][$vals['df']][] = strval($tmp); } if (!$addresses) { return; } $image = self::getImagePart('big_new.png'); $view = new Horde_View(array('templatePath' => KRONOLITH_TEMPLATES . '/update')); $view->event = $event; $view->calendar = Kronolith::getLabel($share); $view->imageId = $image->getContentId(); if (!$prefs->isLocked('event_notification')) { $view->prefsUrl = Horde::url($registry->getServiceLink('prefs', 'kronolith'), true)->remove(session_name()); } new Horde_View_Helper_Text($view); foreach ($addresses as $lang => $twentyFour) { $registry->setLanguageEnvironment($lang); switch ($action) { case 'add': $subject = _("Event added:"); break; case 'edit': $subject = _("Event edited:"); break; case 'delete': $subject = _("Event deleted:"); break; } foreach ($twentyFour as $tf => $dateFormat) { foreach ($dateFormat as $df => $df_recipients) { $view->header = $subject . ' ' . $event->title; $mail = new Horde_Mime_Mail(array('Subject' => $view->header, 'To' => implode(',', $df_recipients), 'From' => $senderIdentity->getDefaultFromAddress(true), 'User-Agent' => 'Kronolith ' . $registry->getVersion())); $multipart = self::buildMimeMessage($view, 'notification', $image); $mail->setBasePart($multipart); Horde::log(sprintf('Sending event notifications for %s to %s', $event->title, implode(', ', $df_recipients)), 'DEBUG'); $mail->send($injector->getInstance('Horde_Mail')); } } } }
/** * Sends out iTip event notifications to all attendees of a specific * event. * * Can be used to send event invitations, event updates as well as event * cancellations. * * @param Kronolith_Event $event * The event in question. * @param Horde_Notification_Handler $notification * A notification object used to show result status. * @param integer $action * The type of notification to send. One of the Kronolith::ITIP_* * values. * @param Horde_Date $instance * If cancelling a single instance of a recurring event, the date of * this instance. * @param string $range The range parameter if this is a recurring event. * Possible values are self::RANGE_THISANDFUTURE */ public static function sendITipNotifications(Kronolith_Event $event, Horde_Notification_Handler $notification, $action, Horde_Date $instance = null, $range = null) { global $injector, $registry; if (!$event->attendees) { return; } $ident = $injector->getInstance('Horde_Core_Factory_Identity')->create($event->creator); if (!$ident->getValue('from_addr')) { $notification->push(sprintf(_("You do not have an email address configured in your Personal Information Preferences. You must set one %shere%s before event notifications can be sent."), $registry->getServiceLink('prefs', 'kronolith')->add(array('app' => 'horde', 'group' => 'identities'))->link(), '</a>'), 'horde.error', array('content.raw')); return; } // Generate image mime part first and only once, because we // need the Content-ID. $image = self::getImagePart('big_invitation.png'); $share = $injector->getInstance('Kronolith_Shares')->getShare($event->calendar); $view = new Horde_View(array('templatePath' => KRONOLITH_TEMPLATES . '/itip')); new Horde_View_Helper_Text($view); $view->identity = $ident; $view->event = $event; $view->imageId = $image->getContentId(); foreach ($event->attendees as $email => $status) { /* Don't bother sending an invitation/update if the recipient does * not need to participate, or has declined participating, or * doesn't have an email address. */ if (strpos($email, '@') === false || $status['attendance'] == self::PART_NONE || $status['response'] == self::RESPONSE_DECLINED) { continue; } /* Determine all notification-specific strings. */ switch ($action) { case self::ITIP_CANCEL: /* Cancellation. */ $method = 'CANCEL'; $filename = 'event-cancellation.ics'; $view->subject = sprintf(_("Cancelled: %s"), $event->getTitle()); if (empty($instance)) { $view->header = sprintf(_("%s has cancelled \"%s\"."), $ident->getName(), $event->getTitle()); } else { $view->header = sprintf(_("%s has cancelled an instance of the recurring \"%s\"."), $ident->getName(), $event->getTitle()); } break; case self::ITIP_REQUEST: default: $method = 'REQUEST'; if ($status['response'] == self::RESPONSE_NONE) { /* Invitation. */ $filename = 'event-invitation.ics'; $view->subject = $event->getTitle(); $view->header = sprintf(_("%s wishes to make you aware of \"%s\"."), $ident->getName(), $event->getTitle()); } else { /* Update. */ $filename = 'event-update.ics'; $view->subject = sprintf(_("Updated: %s."), $event->getTitle()); $view->header = sprintf(_("%s wants to notify you about changes of \"%s\"."), $ident->getName(), $event->getTitle()); } break; } if ($event->attendees) { $view->attendees = strval(self::getAttendeeEmailList($event->attendees)); $view->organizer = $registry->convertUserName($event->creator, false); } if ($action == self::ITIP_REQUEST) { $attend_link = Horde::url('attend.php', true, -1)->add(array('c' => $event->calendar, 'e' => $event->id, 'u' => $email)); $view->linkAccept = (string) $attend_link->add('a', 'accept'); $view->linkTentative = (string) $attend_link->add('a', 'tentative'); $view->linkDecline = (string) $attend_link->add('a', 'decline'); } /* Build the iCalendar data */ $iCal = new Horde_Icalendar(); $iCal->setAttribute('METHOD', $method); $iCal->setAttribute('X-WR-CALNAME', $share->get('name')); $vevent = $event->toiCalendar($iCal); if ($action == self::ITIP_CANCEL && !empty($instance)) { // Recurring event instance deletion, need to specify the // RECURRENCE-ID but NOT the EXDATE. foreach ($vevent as &$ve) { try { $uid = $ve->getAttribute('UID'); } catch (Horde_Icalendar_Exception $e) { continue; } if ($event->uid == $uid) { $ve->setAttribute('RECURRENCE-ID', $instance); if (!empty($range)) { $ve->setParameter('RECURRENCE-ID', array('RANGE' => $range)); } $ve->setAttribute('DTSTART', $instance, array(), false); $diff = $event->end->timestamp() - $event->start->timestamp(); $end = clone $instance; $end->sec += $diff; $ve->setAttribute('DTEND', $end, array(), false); $ve->removeAttribute('EXDATE'); break; } } } $iCal->addComponent($vevent); /* text/calendar part */ $ics = new Horde_Mime_Part(); $ics->setType('text/calendar'); $ics->setContents($iCal->exportvCalendar()); $ics->setName($filename); $ics->setContentTypeParameter('METHOD', $method); $ics->setCharset('UTF-8'); $ics->setEOL("\r\n"); /* application/ics part */ $ics2 = clone $ics; $ics2->setType('application/ics'); /* multipart/mixed part */ $multipart = new Horde_Mime_Part(); $multipart->setType('multipart/mixed'); $inner = self::buildMimeMessage($view, 'notification', $image); $inner->addPart($ics); $multipart->addPart($inner); $multipart->addPart($ics2); $recipient = new Horde_Mail_Rfc822_Address($email); if (!empty($status['name'])) { $recipient->personal = $status['name']; } $mail = new Horde_Mime_Mail(array('Subject' => $view->subject, 'To' => $recipient, 'From' => $ident->getDefaultFromAddress(true), 'User-Agent' => 'Kronolith ' . $registry->getVersion())); $mail->setBasePart($multipart); try { $mail->send($injector->getInstance('Horde_Mail')); $notification->push(sprintf(_("The event notification to %s was successfully sent."), $recipient), 'horde.success'); } catch (Horde_Mime_Exception $e) { $notification->push(sprintf(_("There was an error sending an event notification to %s: %s"), $recipient, $e->getMessage(), $e->getCode()), 'horde.error'); } } }