/**
  * send notification to a single attender
  * 
  * @param Calendar_Model_Attender    $_attender
  * @param Calendar_Model_Event       $_event
  * @param Tinebase_Model_FullAccount $_updater
  * @param Sting                      $_action
  * @param String                     $_notificationLevel
  * @param array                      $_updates
  * @param array                      $attachs
  * @return void
  */
 public function sendNotificationToAttender($_attender, $_event, $_updater, $_action, $_notificationLevel, $_updates = NULL, $attachs = FALSE)
 {
     try {
         // find organizer account
         if ($_event->organizer && $_event->resolveOrganizer()->account_id) {
             $organizer = Tinebase_User::getInstance()->getFullUserById($_event->resolveOrganizer()->account_id);
         } else {
             // use creator as organizer
             $organizer = Tinebase_User::getInstance()->getFullUserById($_event->created_by);
         }
         // get prefered language, timezone and notification level
         $prefUser = $_attender->getUserAccountId();
         $locale = Tinebase_Translation::getLocale(Tinebase_Core::getPreference()->getValueForUser(Tinebase_Preference::LOCALE, $prefUser ? $prefUser : $organizer->getId()));
         $timezone = Tinebase_Core::getPreference()->getValueForUser(Tinebase_Preference::TIMEZONE, $prefUser ? $prefUser : $organizer->getId());
         $translate = Tinebase_Translation::getTranslation('Calendar', $locale);
         // check if user wants this notification
         $sendLevel = $prefUser ? Tinebase_Core::getPreference('Calendar')->getValueForUser(Calendar_Preference::NOTIFICATION_LEVEL, $prefUser) : 100;
         $sendOnOwnActions = $prefUser ? Tinebase_Core::getPreference('Calendar')->getValueForUser(Calendar_Preference::SEND_NOTIFICATION_OF_OWN_ACTIONS, $prefUser) : 0;
         // NOTE: organizer gets mails unless she set notificationlevel to NONE
         if ($prefUser == $_updater->getId() && !$sendOnOwnActions || $sendLevel < $_notificationLevel && ($prefUser != $organizer->getId() || $sendLevel == self::NOTIFICATION_LEVEL_NONE)) {
             return;
         }
         // get date strings
         $startDateString = Tinebase_Translation::dateToStringInTzAndLocaleFormat($_event->dtstart, $timezone, $locale);
         $endDateString = Tinebase_Translation::dateToStringInTzAndLocaleFormat($_event->dtend, $timezone, $locale);
         switch ($_action) {
             case 'alarm':
                 $messageSubject = sprintf($translate->_('Alarm for event "%1$s" at %2$s'), $_event->summary, $startDateString);
                 break;
             case 'created':
                 $messageSubject = sprintf($translate->_('Event invitation "%1$s" at %2$s'), $_event->summary, $startDateString);
                 $method = Calendar_Model_iMIP::METHOD_REQUEST;
                 break;
             case 'deleted':
                 $messageSubject = sprintf($translate->_('Event "%1$s" at %2$s has been canceled'), $_event->summary, $startDateString);
                 $method = Calendar_Model_iMIP::METHOD_CANCEL;
                 break;
             case 'changed':
                 switch ($_notificationLevel) {
                     case self::NOTIFICATION_LEVEL_EVENT_RESCHEDULE:
                         $messageSubject = sprintf($translate->_('Event "%1$s" at %2$s has been rescheduled'), $_event->summary, $startDateString);
                         $method = Calendar_Model_iMIP::METHOD_REQUEST;
                         break;
                     case self::NOTIFICATION_LEVEL_EVENT_UPDATE:
                         $messageSubject = sprintf($translate->_('Event "%1$s" at %2$s has been updated'), $_event->summary, $startDateString);
                         $method = Calendar_Model_iMIP::METHOD_REQUEST;
                         break;
                     case self::NOTIFICATION_LEVEL_ATTENDEE_STATUS_UPDATE:
                         if (!empty($_updates['attendee']) && !empty($_updates['attendee']['toUpdate']) && count($_updates['attendee']['toUpdate']) == 1) {
                             // single attendee status update
                             $attender = $_updates['attendee']['toUpdate'][0];
                             switch ($attender->status) {
                                 case Calendar_Model_Attender::STATUS_ACCEPTED:
                                     $messageSubject = sprintf($translate->_('%1$s accepted event "%2$s" at %3$s'), $attender->getName(), $_event->summary, $startDateString);
                                     break;
                                 case Calendar_Model_Attender::STATUS_DECLINED:
                                     $messageSubject = sprintf($translate->_('%1$s declined event "%2$s" at %3$s'), $attender->getName(), $_event->summary, $startDateString);
                                     break;
                                 case Calendar_Model_Attender::STATUS_TENTATIVE:
                                     $messageSubject = sprintf($translate->_('Tentative response from %1$s for event "%2$s" at %3$s'), $attender->getName(), $_event->summary, $startDateString);
                                     break;
                                 case Calendar_Model_Attender::STATUS_NEEDSACTION:
                                     $messageSubject = sprintf($translate->_('No response from %1$s for event "%2$s" at %3$s'), $attender->getName(), $_event->summary, $startDateString);
                                     break;
                             }
                         } else {
                             $messageSubject = sprintf($translate->_('Attendee changes for event "%1$s" at %2$s'), $_event->summary, $startDateString);
                         }
                         // we don't send iMIP parts to organizers with an account cause event is already up to date
                         if ($_event->organizer && !$_event->resolveOrganizer()->account_id) {
                             $method = Calendar_Model_iMIP::METHOD_REPLY;
                         }
                         break;
                 }
                 break;
             default:
                 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                     Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " unknown action '{$_action}'");
                 }
                 break;
         }
         $view = new Zend_View();
         $view->setScriptPath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'views');
         $view->translate = $translate;
         $view->timezone = $timezone;
         $view->event = $_event;
         $view->updater = $_updater;
         $view->updates = $_updates;
         $messageBody = $view->render('eventNotification.php');
         if (isset($method) && version_compare(PHP_VERSION, '5.3.0', '>=')) {
             $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
             $converter->setMethod($method);
             $vcalendar = $converter->fromTine20Model($_event);
             // in Tine 2.0 non organizers might be given the grant to update events
             // @see rfc6047 section 2.2.1 & rfc5545 section 3.2.18
             if ($method != Calendar_Model_iMIP::METHOD_REPLY && $_event->organizer !== $_updater->contact_id) {
                 foreach ($vcalendar->children() as $component) {
                     if ($component->name == 'VEVENT') {
                         if (isset($component->{'ORGANIZER'})) {
                             $component->{'ORGANIZER'}->add(new Sabre_VObject_Parameter('SEND-BY', 'mailto:' . $_updater->accountEmailAddress));
                         }
                     }
                 }
             }
             /* not yet supported
                // in Tine 2.0 status updater might not be updater
                if ($method == Calendar_Model_iMIP::METHOD_REPLY) {
                    
                }
                */
             $calendarPart = new Zend_Mime_Part($vcalendar->serialize());
             $calendarPart->charset = 'UTF-8';
             $calendarPart->type = 'text/calendar; method=' . $method;
             $calendarPart->encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE;
             $attachment = new Zend_Mime_Part($vcalendar->serialize());
             $attachment->type = 'application/ics';
             $attachment->encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE;
             $attachment->disposition = Zend_Mime::DISPOSITION_ATTACHMENT;
             $attachment->filename = 'event.ics';
             $attachments = array($attachment);
             if ($attachs) {
                 foreach ($attachs as $file) {
                     $stream = fopen($file['tempFile']['path'], 'r');
                     $part = new Zend_Mime_Part($stream);
                     $part->type = $file['tempFile']['type'];
                     $part->encoding = Zend_Mime::ENCODING_BASE64;
                     $part->disposition = Zend_Mime::DISPOSITION_ATTACHMENT;
                     $part->filename = $file['tempFile']['name'];
                     $attachments[] = $part;
                 }
             }
         } else {
             $calendarPart = null;
             $attachments = null;
         }
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " receiver: '{$_attender->getEmail()}'");
         }
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " subject: '{$messageSubject}'");
         }
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " body: {$messageBody}");
         }
         // NOTE: this is a contact as we only support users and groupmembers
         $contact = $_attender->getResolvedUser();
         $sender = $_action == 'alarm' ? $organizer : $_updater;
         Tinebase_Notification::getInstance()->send($sender, array($contact), $messageSubject, $messageBody, $calendarPart, $attachments);
     } catch (Exception $e) {
         Tinebase_Core::getLogger()->WARN(__METHOD__ . '::' . __LINE__ . " could not send notification :" . $e);
         return;
     }
 }
 /**
  * send notification to a single attender
  * 
  * @param Calendar_Model_Attender    $_attender
  * @param Calendar_Model_Event       $_event
  * @param Tinebase_Model_FullAccount $_updater
  * @param string                     $_action
  * @param string                     $_notificationLevel
  * @param array                      $_updates
  * @return void
  *
  * TODO this needs major refactoring
  */
 public function sendNotificationToAttender(Calendar_Model_Attender $_attender, $_event, $_updater, $_action, $_notificationLevel, $_updates = NULL)
 {
     try {
         $organizer = $_event->resolveOrganizer();
         $organizerAccountId = $organizer->account_id;
         $attendee = $_attender->getResolvedUser();
         if ($attendee instanceof Addressbook_Model_List) {
             // don't send notification to lists as we already resolved the list members for individual mails
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Skip notification for list " . $attendee->name);
             }
             return;
         }
         $attendeeAccountId = $_attender->getUserAccountId();
         $prefUserId = $attendeeAccountId ? $attendeeAccountId : ($organizerAccountId ? $organizerAccountId : $_event->created_by);
         try {
             $prefUser = Tinebase_User::getInstance()->getFullUserById($prefUserId);
         } catch (Exception $e) {
             $prefUser = Tinebase_Core::getUser();
             $prefUserId = $prefUser->getId();
         }
         // get prefered language, timezone and notification level
         $locale = Tinebase_Translation::getLocale(Tinebase_Core::getPreference()->getValueForUser(Tinebase_Preference::LOCALE, $prefUserId));
         $timezone = Tinebase_Core::getPreference()->getValueForUser(Tinebase_Preference::TIMEZONE, $prefUserId);
         $translate = Tinebase_Translation::getTranslation('Calendar', $locale);
         $sendLevel = Tinebase_Core::getPreference('Calendar')->getValueForUser(Calendar_Preference::NOTIFICATION_LEVEL, $prefUserId);
         $sendOnOwnActions = Tinebase_Core::getPreference('Calendar')->getValueForUser(Calendar_Preference::SEND_NOTIFICATION_OF_OWN_ACTIONS, $prefUserId);
         $sendAlarms = Tinebase_Core::getPreference('Calendar')->getValueForUser(Calendar_Preference::SEND_ALARM_NOTIFICATIONS, $prefUserId);
         // external (non account) notification
         if (!$attendeeAccountId) {
             // external organizer needs status updates
             $sendLevel = is_object($organizer) && $_attender->getEmail() == $organizer->getPreferedEmailAddress() ? 40 : 30;
             $sendOnOwnActions = false;
             $sendAlarms = false;
         }
         $recipients = array($attendee);
         $this->_handleResourceEditors($_attender, $_notificationLevel, $recipients, $_action, $sendLevel, $_updates);
         // check if user wants this notification NOTE: organizer gets mails unless she set notificationlevel to NONE
         // NOTE prefUser is organizer for external notifications
         if ($attendeeAccountId == $_updater->getId() && !$sendOnOwnActions || $sendLevel < $_notificationLevel && (is_object($organizer) && method_exists($attendee, 'getPreferedEmailAddress') && $attendee->getPreferedEmailAddress() != $organizer->getPreferedEmailAddress() || is_object($organizer) && !method_exists($attendee, 'getPreferedEmailAddress') && $attendee->email != $organizer->getPreferedEmailAddress() || $sendLevel == self::NOTIFICATION_LEVEL_NONE)) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Preferred notification level not reached -> skipping notification for {$_attender->getEmail()}");
             }
             return;
         }
         if ($_action == 'alarm' && !$sendAlarms) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " User does not want alarm mails -> skipping notification for {$_attender->getEmail()}");
             }
             return;
         }
         $method = NULL;
         // NOTE $method gets set in _getSubject as referenced param
         $messageSubject = $this->_getSubject($_event, $_notificationLevel, $_action, $_updates, $timezone, $locale, $translate, $method, $_attender);
         // we don't send iMIP parts to external attendee if config is active
         if (Calendar_Config::getInstance()->get(Calendar_Config::DISABLE_EXTERNAL_IMIP) && !$attendeeAccountId) {
             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
                 Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " External iMIP is disabled.");
             }
             $method = NULL;
         }
         $view = new Zend_View();
         $view->setScriptPath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'views');
         $view->translate = $translate;
         $view->timezone = $timezone;
         $view->event = $_event;
         $view->updater = $_updater;
         $view->updates = $_updates;
         $messageBody = $view->render('eventNotification.php');
         $calendarPart = null;
         $attachments = $this->_getAttachments($method, $_event, $_action, $_updater, $calendarPart);
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " receiver: '{$_attender->getEmail()}'");
         }
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " subject: '{$messageSubject}'");
         }
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " body: {$messageBody}");
         }
         $sender = $_action == 'alarm' ? $prefUser : $_updater;
         Tinebase_Notification::getInstance()->send($sender, $recipients, $messageSubject, $messageBody, $calendarPart, $attachments);
     } catch (Exception $e) {
         Tinebase_Exception::log($e);
         return;
     }
 }