/** */ protected function _notify(Horde_Notification_Handler $handler, Horde_Notification_Listener $listener) { if ($listener instanceof Horde_Notification_Listener_Status && ($ob = $GLOBALS['injector']->getInstance('IMP_Factory_Imap'))) { /* Display IMAP alerts. */ foreach ($ob->alerts() as $alert) { $handler->push($alert, 'horde.warning'); } } }
/** */ public function create(Horde_Injector $injector) { global $registry; if (isset($this->_notify)) { return $this->_notify; } $this->_notify = new Horde_Notification_Handler(new Horde_Core_Notification_Storage_Session()); $this->_notify->addType('default', '*', 'Horde_Core_Notification_Event_Status'); $this->_notify->addType('status', 'horde.*', 'Horde_Core_Notification_Event_Status'); $this->_notify->addDecorator(new Horde_Notification_Handler_Decorator_Alarm($injector->getInstance('Horde_Core_Factory_Alarm'), $registry->getAuth())); $this->_notify->addDecorator(new Horde_Core_Notification_Handler_Decorator_Hordelog()); return $this->_notify; }
/** */ public function notify(array $options = array()) { if ($this->_apps) { foreach ($this->_apps as $key => $val) { if (!$val) { $this->addAppHandler($key); } } $this->_apps = false; } return parent::notify($options); }
/** * Parses a comma separated list of names and e-mail addresses into a list * of attendees. * * @param string $newAttendees A comma separated * attendee list. * @param Horde_Notification_Handler $notification A notification handler. * * @return Kronolith_Attendee_List The parsed attendee list. */ public static function parse($newAttendees, Horde_Notification_Handler $notification) { $attendees = new self(); if (empty($newAttendees)) { return $attendees; } /* Parse the address without validation to see what we can get out of * it. We allow email addresses (john@example.com), email address with * user information (John Doe <*****@*****.**>), and plain names * (John Doe). */ $parser = new Horde_Mail_Rfc822(); $result = $parser->parseAddressList($newAttendees); $result->setIteratorFilter(Horde_Mail_Rfc822_List::HIDE_GROUPS); foreach ($result as $newAttendee) { if (!$newAttendee->valid) { // If we can't even get a mailbox out of the address, then it // is likely unuseable. Reject it entirely. $notification->push(sprintf(_("Unable to recognize \"%s\" as an email address."), $newAttendee), 'horde.error'); continue; } // If there is only a mailbox part, then it is just a local name. if (is_null($newAttendee->host)) { $email = null; $name = $newAttendee->bare_address; } else { // Build a full email address again and validate it. try { $parser->parseAddressList($newAttendee->writeAddress(true)); } catch (Horde_Mail_Exception $e) { $notification->push($e, 'horde.error'); continue; } $email = $newAttendee->bare_address; $name = $newAttendee->label != $newAttendee->bare_address ? $newAttendee->label : ''; } $attendees->add(new Kronolith_Attendee(array('email' => $email, 'role' => Kronolith::PART_REQUIRED, 'response' => Kronolith::RESPONSE_NONE, 'name' => $name))); } return $attendees; }
/** * 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'); } }
/** */ protected function _notify(Horde_Notification_Handler $handler, Horde_Notification_Listener $listener) { global $injector, $prefs, $session; if (!$prefs->getValue('newmail_notify') || !$listener instanceof Horde_Notification_Listener_Status) { return; } /* Rate limit. If rate limit is not yet set, this is the initial * login so skip. */ $curr = time(); $ratelimit = $session->get('imp', self::SESS_RATELIMIT); if ($ratelimit && $ratelimit + self::RATELIMIT > $curr) { return; } $session->set('imp', self::SESS_RATELIMIT, $curr); if (!$ratelimit) { return; } $ajax_queue = $injector->getInstance('IMP_Ajax_Queue'); $imp_imap = $injector->getInstance('IMP_Factory_Imap')->create(); $recent = array(); try { foreach ($imp_imap->status($injector->getInstance('IMP_Ftree')->poll->getPollList(), Horde_Imap_Client::STATUS_RECENT_TOTAL, array('sort' => true)) as $key => $val) { if (!empty($val['recent_total'])) { /* Open the mailbox R/W so we ensure the 'recent' flag is * cleared. */ $imp_imap->openMailbox($key, Horde_Imap_Client::OPEN_READWRITE); $mbox = IMP_Mailbox::get($key); $recent[$mbox->display] = $val['recent_total']; $ajax_queue->poll($mbox); } } } catch (Exception $e) { } if (empty($recent)) { return; } $recent_sum = array_sum($recent); reset($recent); switch (count($recent)) { case 1: $mbox_list = key($recent); break; case 2: $mbox_list = implode(_(" and "), array_keys($recent)); break; default: $akeys = array_keys($recent); $mbox_list = $akeys[0] . ', ' . $akeys[1] . ', ' . _("and") . ' ' . $akeys[2]; if ($addl_mbox = count($recent) - 3) { $mbox_list .= ' (' . sprintf(ngettext("and %d more mailbox", "and %d more mailboxes", $addl_mbox), $addl_mbox) . ')'; } break; } $text = sprintf(ngettext("You have %d new mail message in %s.", "You have %d new mail messages in %s.", $recent_sum), $recent_sum, $mbox_list); /* Status notification. */ $handler->push($text, 'horde.message'); /* Web notifications. */ $handler->attach('webnotification', null, 'Horde_Core_Notification_Listener_Webnotification'); $handler->push(Horde_Core_Notification_Event_Webnotification::createEvent($text, array('icon' => strval(Horde_Themes::img('unseen.png')))), 'webnotification'); if ($audio = $prefs->getValue('newmail_audio')) { $handler->attach('audio'); $handler->push(Horde_Themes::sound($audio), 'audio'); } }
public function testMethodClearHasPostconditionThatAllUnattachedEventsHaveBeenClearedFromStorageIfNoListenerWasSpecified() { $storage = $this->getMock('Horde_Notification_Storage_Interface'); $storage->expects($this->once())->method('clear')->with('_unattached'); $handler = new Horde_Notification_Handler($storage); $handler->clear(); }
/** * 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 * @param array $cancellations If $action is 'CANCEL', but it is due to * removing attendees and not canceling the * entire event, these are the email addresses * of the uninvited attendees and are the ONLY * people that will receive the CANCEL iTIP. * @since 4.2.10 * */ public static function sendITipNotifications(Kronolith_Event $event, Horde_Notification_Handler $notification, $action, Horde_Date $instance = null, $range = null, array $cancellations = array()) { 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(); if ($action == self::ITIP_CANCEL && !empty($cancellations)) { $mail_attendees = $cancellations; } else { $mail_attendees = $event->attendees; } foreach ($mail_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['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; } $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'); } } }
/** * Modifies the global notification handler. * * @param Horde_Notification_Handler $handler A notification handler. */ public function setupNotification(Horde_Notification_Handler $handler) { $handler->addDecorator(new IMP_Notification_Handler_Decorator_ImapAlerts()); $handler->addDecorator(new IMP_Notification_Handler_Decorator_NewmailNotify()); $handler->addType('status', 'imp.*', 'IMP_Notification_Event_Status'); }
/** * @deprecated */ public function addApplicationHandlers() { return $this->_notify->attachAllAppHandlers(); }