Пример #1
0
 /**
  * Constructor.
  *
  * @param array $config  Configuration key-value pairs.
  */
 public function __construct($config = array())
 {
     global $prefs, $registry;
     parent::__construct($config);
     $blank = new Horde_Url();
     $this->addNewButton(_("_New Event"), $blank, array('id' => 'kronolithNewEvent'));
     $this->newExtra = $blank->link(array_merge(array('id' => 'kronolithQuickEvent'), Horde::getAccessKeyAndTitle(_("Quick _insert"), false, true)));
     $sidebar = $GLOBALS['injector']->createInstance('Horde_View');
     /* Minical. */
     $today = new Horde_Date($_SERVER['REQUEST_TIME']);
     $sidebar->today = $today->format('F Y');
     $sidebar->weekdays = array();
     for ($i = $prefs->getValue('week_start_monday'), $c = $i + 7; $i < $c; $i++) {
         $weekday = Horde_Nls::getLangInfo(constant('DAY_' . ($i % 7 + 1)));
         $sidebar->weekdays[$weekday] = Horde_String::substr($weekday, 0, 2);
     }
     /* Calendars. */
     $sidebar->newShares = $registry->getAuth() && !$prefs->isLocked('default_share');
     $sidebar->admin = $registry->isAdmin();
     $sidebar->resourceAdmin = $registry->isAdmin() || $GLOBALS['injector']->getInstance('Horde_Core_Perms')->hasAppPermission('resource_management');
     $sidebar->resources = $GLOBALS['conf']['resources']['enabled'];
     $sidebar->addRemote = !$prefs->isLocked('remote_cals');
     $remotes = unserialize($prefs->getValue('remote_cals'));
     $sidebar->showRemote = !($prefs->isLocked('remote_cals') && empty($remotes));
     $this->content = $sidebar->render('dynamic/sidebar');
 }
Пример #2
0
 /**
  * Output the necessary javascript code to allow display of the calendar
  * widget.
  *
  * @param array $params  Configuration parameters for the widget:
  * <pre>
  * 'click_month' - (boolean) If true, the month is clickable.
  *                 DEFAULT: false
  * 'click_week' - (boolean) If true, will display a clickable week.
  *                DEFAULT: false
  * 'click_year' - (boolean) If true, the year is clickable.
  *                DEFAULT: false
  * 'full_weekdays' - (boolean) Add full weekday localized list to
  *                   javascript object.
  *                   DEFAULT: false
  * 'short_weekdays' - (boolean) Display only the first letter of
  *                    weekdays?
  *                    DEFAULT: false
  * </pre>
  */
 public static function init(array $params = array())
 {
     if (self::$_initRun) {
         return;
     }
     self::$_initRun = true;
     $params = array_merge(array('click_month' => false, 'click_week' => false, 'click_year' => false, 'full_weekdays' => false, 'short_weekdays' => false), $params);
     $weekdays = self::weekdays();
     if ($params['short_weekdays']) {
         foreach ($weekdays as &$day) {
             $day = Horde_String::substr($day, 0, 1);
         }
     }
     $js = array('-Horde_Calendar.click_month' => intval($params['click_month']), '-Horde_Calendar.click_week' => intval($params['click_week']), '-Horde_Calendar.click_year' => intval($params['click_year']), '-Horde_Calendar.firstDayOfWeek' => intval($GLOBALS['prefs']->getValue('first_week_day')), 'Horde_Calendar.months' => self::months(), 'Horde_Calendar.weekdays' => $weekdays);
     if ($params['full_weekdays']) {
         $js['Horde_Calendar.fullweekdays'] = self::fullWeekdays();
     }
     $page_output = $GLOBALS['injector']->getInstance('Horde_PageOutput');
     $page_output->addScriptFile('calendar.js', 'horde');
     $page_output->addInlineJsVars($js);
 }
Пример #3
0
 /**
  * URL Parameters:
  *   a: (string) Action ID.
  *   allto: (boolean) View all To addresses?
  *   buid: (string) Browser UID.
  *   t: (string) Token.
  */
 protected function _init()
 {
     global $injector, $notification, $page_output, $prefs, $session;
     $imp_mailbox = $this->indices->mailbox->list_ob;
     $imp_mailbox->setIndex($this->indices);
     $mailbox_url = IMP_Minimal_Mailbox::url(array('mailbox' => $this->indices->mailbox));
     /* Make sure we have a valid index. */
     if (!$imp_mailbox->isValidIndex()) {
         $mailbox_url->add('a', 'm')->redirect();
     }
     $imp_ui = $injector->getInstance('IMP_Message_Ui');
     /* Run through action handlers */
     $msg_delete = false;
     switch ($this->vars->a) {
         // 'd' = delete message
         case 'd':
             $old_index = $imp_mailbox->getIndex();
             try {
                 $session->checkToken($this->vars->t);
                 $msg_delete = (bool) $injector->getInstance('IMP_Message')->delete($this->indices, array('mailboxob' => $imp_mailbox));
             } catch (Horde_Exception $e) {
                 $notification->push($e);
             }
             break;
             // 'u' = undelete message
         // 'u' = undelete message
         case 'u':
             $old_index = $imp_mailbox->getIndex();
             $injector->getInstance('IMP_Message')->undelete($this->indices);
             break;
             // 'rs' = report spam
             // 'ri' = report innocent
         // 'rs' = report spam
         // 'ri' = report innocent
         case 'rs':
         case 'ri':
             $old_index = $imp_mailbox->getIndex();
             $msg_delete = $injector->getInstance('IMP_Factory_Spam')->create($this->vars->a == 'rs' ? IMP_Spam::SPAM : IMP_Spam::INNOCENT)->report($this->indices, array('mailboxob' => $imp_mailbox)) === 1;
             break;
     }
     if ($msg_delete && $imp_ui->moveAfterAction($this->indices->mailbox)) {
         $imp_mailbox->setIndex(1);
     }
     /* We may have done processing that has taken us past the end of the
      * message array, so we will return to the mailbox. */
     if (!$imp_mailbox->isValidIndex() || $msg_delete && $prefs->getValue('mailbox_return')) {
         $mailbox_url->add('s', $old_index)->redirect();
     }
     /* Now that we are done processing, get the index and array index of
      * the current message. */
     $msg_index = $imp_mailbox[$imp_mailbox->getIndex()];
     $mailbox = $msg_index['m'];
     $uid = $msg_index['u'];
     $buid = $imp_mailbox->getBuid($mailbox, $uid);
     /* Get envelope/flag/header information. */
     try {
         $imp_imap = $mailbox->imp_imap;
         /* Need to fetch flags before HEADERTEXT, because SEEN flag might
          * be set before we can grab it. */
         $query = new Horde_Imap_Client_Fetch_Query();
         $query->flags();
         $flags_ret = $imp_imap->fetch($mailbox, $query, array('ids' => $imp_imap->getIdsOb($uid)));
         $query = new Horde_Imap_Client_Fetch_Query();
         $query->envelope();
         $fetch_ret = $imp_imap->fetch($mailbox, $query, array('ids' => $imp_imap->getIdsOb($uid)));
     } catch (IMP_Imap_Exception $e) {
         $mailbox_url->add('a', 'm')->redirect();
     }
     $envelope = $fetch_ret->first()->getEnvelope();
     $flags = $flags_ret->first()->getFlags();
     /* Parse the message. */
     try {
         $imp_contents = $injector->getInstance('IMP_Factory_Contents')->create(new IMP_Indices($imp_mailbox));
         $mime_headers = $imp_contents->getHeaderAndMarkAsSeen();
     } catch (IMP_Exception $e) {
         $mailbox_url->add('a', 'm')->redirect();
     }
     /* Get the starting index for the current message and the message
      * count. */
     $msgindex = $imp_mailbox->getIndex();
     $msgcount = count($imp_mailbox);
     /* Generate the mailbox link. */
     $mailbox_link = $mailbox_url->add('s', $msgindex);
     $self_link = self::url(array('buid' => $buid, 'mailbox' => $this->indices->mailbox));
     /* Create the Identity object. */
     $user_identity = $injector->getInstance('IMP_Identity');
     /* Develop the list of headers to display. */
     $basic_headers = $imp_ui->basicHeaders();
     $display_headers = $msgAddresses = array();
     if ($subject = $mime_headers->getValue('subject')) {
         /* Filter the subject text, if requested. */
         $subject = Horde_String::truncate(IMP::filterText($subject), 50);
     } else {
         $subject = _("[No Subject]");
     }
     $display_headers['subject'] = $subject;
     $format_date = $imp_ui->getLocalTime($envelope->date);
     if (!empty($format_date)) {
         $display_headers['date'] = $format_date;
     }
     /* Build From address links. */
     $display_headers['from'] = $imp_ui->buildAddressLinks($envelope->from, null, false);
     /* Build To/Cc/Bcc links. */
     foreach (array('to', 'cc', 'bcc') as $val) {
         $msgAddresses[] = $mime_headers->getValue($val);
         $addr_val = $imp_ui->buildAddressLinks($envelope->{$val}, null, false);
         if (!empty($addr_val)) {
             $display_headers[$val] = $addr_val;
         }
     }
     /* Check for the presence of mailing list information. */
     $list_info = $imp_ui->getListInformation($mime_headers);
     /* See if the priority has been set. */
     switch ($priority = $injector->getInstance('IMP_Mime_Headers')->getPriority($mime_headers)) {
         case 'high':
         case 'low':
             $basic_headers['priority'] = _("Priority");
             $display_headers['priority'] = Horde_String::ucfirst($priority);
             break;
     }
     /* Set the status information of the message. */
     $status = '';
     $match_identity = $identity = null;
     if (!empty($msgAddresses)) {
         $match_identity = $identity = $user_identity->getMatchingIdentity($msgAddresses);
         if (is_null($identity)) {
             $identity = $user_identity->getDefault();
         }
     }
     $flag_parse = $injector->getInstance('IMP_Flags')->parse(array('flags' => $flags, 'personal' => $match_identity));
     foreach ($flag_parse as $val) {
         if ($abbrev = $val->abbreviation) {
             $status .= $abbrev;
         } elseif ($val instanceof IMP_Flag_User) {
             $status .= ' *' . Horde_String::truncate($val->label, 8) . '*';
         }
     }
     /* Create the body of the message. */
     $inlineout = $imp_contents->getInlineOutput(array('display_mask' => IMP_Contents::RENDER_INLINE, 'no_inline_all' => true));
     $msg_text = $inlineout['msgtext'];
     $this->view->msg = nl2br($injector->getInstance('Horde_Core_Factory_TextFilter')->filter($msg_text, 'space2html'));
     $menu = array();
     if ($this->indices->mailbox->access_deletemsgs) {
         $menu[] = in_array(Horde_Imap_Client::FLAG_DELETED, $flags) ? array(_("Undelete"), $self_link->copy()->add('a', 'u')) : array(_("Delete"), $self_link->copy()->add(array('a' => 'd', 't' => $session->getToken())));
     }
     /* Add compose actions (Reply, Reply List, Reply All, Forward,
      * Redirect, Edit as New). */
     if (IMP_Compose::canCompose()) {
         $clink_ob = new IMP_Compose_Link();
         $clink_ob->args['buid'] = $buid;
         $clink_ob->args['mailbox'] = $this->indices->mailbox;
         $clink = $clink_ob->link()->add(array('identity' => $identity));
         $menu[] = array(_("Reply"), $clink->copy()->add(array('a' => 'r')));
         if ($list_info['reply_list']) {
             $menu[] = array(_("Reply to List"), $clink->copy()->add(array('a' => 'rl')));
         }
         $addr_ob = clone $envelope->to;
         $addr_ob->add($envelope->cc);
         $addr_ob->setIteratorFilter(0, $user_identity->getAllFromAddresses());
         if (count($addr_ob)) {
             $menu[] = array(_("Reply All"), $clink->copy()->add(array('a' => 'ra')));
         }
         $menu[] = array(_("Forward"), $clink->copy()->add(array('a' => 'f')));
         $menu[] = array(_("Redirect"), $clink->copy()->add(array('a' => 'rc')));
         $menu[] = array(_("Edit as New"), $clink->copy()->add(array('a' => 'en')));
     }
     /* Generate previous/next links. */
     if ($prev_msg = $imp_mailbox[$imp_mailbox->getIndex() - 1]) {
         $menu[] = array(_("Previous Message"), self::url(array('buid' => $imp_mailbox->getBuid($prev_msg['m'], $prev_msg['u']), 'mailbox' => $this->indices->mailbox)));
     }
     if ($next_msg = $imp_mailbox[$imp_mailbox->getIndex() + 1]) {
         $menu[] = array(_("Next Message"), self::url(array('buid' => $imp_mailbox->getBuid($next_msg['m'], $next_msg['u']), 'mailbox' => $this->indices->mailbox)));
     }
     $menu[] = array(sprintf(_("To %s"), $this->indices->mailbox->label), $mailbox_link);
     if ($mailbox->spam_show) {
         $menu[] = array(_("Report as Spam"), $self_link->copy()->add(array('a' => 'rs', 't' => $session->getToken())));
     }
     if ($mailbox->innocent_show) {
         $menu[] = array(_("Report as Innocent"), $self_link->copy()->add(array('a' => 'ri', 't' => $session->getToken())));
     }
     $this->view->menu = $this->getMenu('message', $menu);
     $hdrs = array();
     foreach ($display_headers as $head => $val) {
         $tmp = array('label' => $basic_headers[$head]);
         if (Horde_String::lower($head) == 'to' && !isset($this->vars->allto) && ($pos = strpos($val, ',')) !== false) {
             $val = Horde_String::substr($val, 0, $pos);
             $tmp['all_to'] = $self_link->copy()->add('allto', 1);
         }
         $tmp['val'] = $val;
         $hdrs[] = $tmp;
     }
     $this->view->hdrs = $hdrs;
     $atc = array();
     foreach ($inlineout['atc_parts'] as $key) {
         $summary = $imp_contents->getSummary($key, IMP_Contents::SUMMARY_BYTES | IMP_Contents::SUMMARY_SIZE | IMP_Contents::SUMMARY_DESCRIP | IMP_Contents::SUMMARY_DOWNLOAD);
         $tmp = array('descrip' => $summary['description_raw'], 'size' => $summary['size'], 'type' => $summary['type']);
         if (!empty($summary['download'])) {
             /* Preference: if set, only show download confirmation screen
              * if attachment over a certain size. */
             $tmp['download'] = IMP_Minimal_Messagepart::url(array('buid' => $buid, 'mailbox' => $this->indices->mailbox))->add('atc', $key);
         }
         if ($imp_contents->canDisplay($key, IMP_Contents::RENDER_INLINE)) {
             $tmp['view'] = IMP_Minimal_Messagepart::url(array('buid' => $buid, 'mailbox' => $this->indices->mailbox))->add('id', $key);
         }
         $atc[] = $tmp;
     }
     $this->view->atc = $atc;
     $this->title = $display_headers['subject'];
     $this->view->title = ($status ? $status . ' ' : '') . sprintf(_("(Message %d of %d)"), $msgindex, $msgcount);
     $page_output->noDnsPrefetch();
     $this->_pages[] = 'message';
     $this->_pages[] = 'menu';
 }
Пример #4
0
 /**
  * Helper function for guessing name parts from a single name string.
  *
  * @param array $hash  The attributes array.
  */
 protected function _guessName(&$hash)
 {
     if (($pos = strpos($hash['name'], ',')) !== false) {
         // Assume Last, First
         $hash['lastname'] = Horde_String::substr($hash['name'], 0, $pos);
         $hash['firstname'] = trim(Horde_String::substr($hash['name'], $pos + 1));
     } elseif (($pos = Horde_String::rpos($hash['name'], ' ')) !== false) {
         // Assume everything after last space as lastname
         $hash['lastname'] = trim(Horde_String::substr($hash['name'], $pos + 1));
         $hash['firstname'] = Horde_String::substr($hash['name'], 0, $pos);
     } else {
         $hash['lastname'] = $hash['name'];
         $hash['firstname'] = '';
     }
 }
Пример #5
0
 /**
  * Wraps the text of a message.
  *
  * @since Horde 3.2
  *
  * @param string $string Horde_String containing the text to wrap.
  * @param integer $width Wrap the string at this number of
  *                               characters.
  * @param string $break Character(s) to use when breaking lines.
  * @param boolean $cut Whether to cut inside words if a line
  *                               can't be wrapped.
  * @param string $charset Character set to use when breaking lines.
  * @param boolean $line_folding Whether to apply line folding rules per
  *                               RFC 822 or similar. The correct break
  *                               characters including leading whitespace
  *                               have to be specified too.
  *
  * @return string  Horde_String containing the wrapped text.
  */
 public function wordwrap($string, $width = 75, $break = "\n", $cut = false, $charset = null, $line_folding = false)
 {
     /* Get the user's default character set if none passed in. */
     if (is_null($charset)) {
         $charset = self::$charset;
     }
     $charset = Horde_String::_mbstringCharset($charset);
     $string = Horde_String::convertCharset($string, $charset, 'utf-8');
     $wrapped = '';
     while (Horde_String::length($string, 'utf-8') > $width) {
         $line = Horde_String::substr($string, 0, $width, 'utf-8');
         $string = Horde_String::substr($string, Horde_String::length($line, 'utf-8'), null, 'utf-8');
         // Make sure didn't cut a word, unless we want hard breaks anyway.
         if (!$cut && preg_match('/^(.+?)(\\s|\\r?\\n)/u', $string, $match)) {
             $line .= $match[1];
             $string = Horde_String::substr($string, Horde_String::length($match[1], 'utf-8'), null, 'utf-8');
         }
         // Wrap at existing line breaks.
         if (preg_match('/^(.*?)(\\r?\\n)(.*)$/u', $line, $match)) {
             $wrapped .= $match[1] . $match[2];
             $string = $match[3] . $string;
             continue;
         }
         // Wrap at the last colon or semicolon followed by a whitespace if
         // doing line folding.
         if ($line_folding && preg_match('/^(.*?)(;|:)(\\s+.*)$/u', $line, $match)) {
             $wrapped .= $match[1] . $match[2] . $break;
             $string = $match[3] . $string;
             continue;
         }
         // Wrap at the last whitespace of $line.
         if ($line_folding) {
             $sub = '(.+[^\\s])';
         } else {
             $sub = '(.*)';
         }
         if (preg_match('/^' . $sub . '(\\s+)(.*)$/u', $line, $match)) {
             $wrapped .= $match[1] . $break;
             $string = ($line_folding ? $match[2] : '') . $match[3] . $string;
             continue;
         }
         // Hard wrap if necessary.
         if ($cut) {
             $wrapped .= Horde_String::substr($line, 0, $width, 'utf-8') . $break;
             $string = Horde_String::substr($line, $width, null, 'utf-8') . $string;
             continue;
         }
         $wrapped .= $line;
     }
     return Horde_String::convertCharset($wrapped . $string, 'utf-8', $charset);
 }
Пример #6
0
 /**
  * Export this event as a MS ActiveSync Message
  *
  * @param array $options  Options:
  *   - protocolversion: (float)  The EAS version to support
  *                      DEFAULT: 2.5
  *   - bodyprefs: (array)  A BODYPREFERENCE array.
  *                DEFAULT: none (No body prefs enforced).
  *   - truncation: (integer)  Truncate event body to this length
  *                 DEFAULT: none (No truncation).
  *
  * @return Horde_ActiveSync_Message_Appointment
  */
 public function toASAppointment(array $options = array())
 {
     global $prefs, $registry;
     $message = new Horde_ActiveSync_Message_Appointment(array('logger' => $GLOBALS['injector']->getInstance('Horde_Log_Logger'), 'protocolversion' => $options['protocolversion']));
     if (!$this->isPrivate()) {
         // Handle body/truncation
         if (!empty($options['bodyprefs'])) {
             if (Horde_String::length($this->description) > 0) {
                 $bp = $options['bodyprefs'];
                 $note = new Horde_ActiveSync_Message_AirSyncBaseBody();
                 // No HTML supported. Always use plaintext.
                 $note->type = Horde_ActiveSync::BODYPREF_TYPE_PLAIN;
                 if (isset($bp[Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'])) {
                     $truncation = $bp[Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'];
                 } elseif (isset($bp[Horde_ActiveSync::BODYPREF_TYPE_HTML])) {
                     $truncation = $bp[Horde_ActiveSync::BODYPREF_TYPE_HTML]['truncationsize'];
                     $this->description = Horde_Text_Filter::filter($this->description, 'Text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
                 } else {
                     $truncation = false;
                 }
                 if ($truncation && Horde_String::length($this->description) > $truncation) {
                     $note->data = Horde_String::substr($this->desciption, 0, $truncation);
                     $note->truncated = 1;
                 } else {
                     $note->data = $this->description;
                 }
                 $note->estimateddatasize = Horde_String::length($this->description);
                 $message->airsyncbasebody = $note;
             }
         } else {
             $message->setBody($this->description);
         }
         $message->setLocation($this->location);
     }
     $message->setSubject($this->getTitle());
     $message->setDatetime(array('start' => $this->start, 'end' => $this->end, 'allday' => $this->isAllDay()));
     $message->setTimezone($this->start);
     // Organizer
     if (count($this->attendees)) {
         if ($this->creator == $registry->getAuth()) {
             $as_ident = $prefs->getValue('activesync_identity') == 'horde' ? $prefs->getValue('default_identity') : $prefs->getValue('activesync_identity');
             $name = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($this->creator)->getValue('fullname', $as_ident);
             $email = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($this->creator)->getValue('from_addr', $as_ident);
         } else {
             $name = Kronolith::getUserName($this->creator);
             $email = Kronolith::getUserEmail($this->creator);
         }
         $message->setOrganizer(array('name' => $name, 'email' => $email));
     }
     // Privacy
     $message->setSensitivity($this->private ? Horde_ActiveSync_Message_Appointment::SENSITIVITY_PRIVATE : Horde_ActiveSync_Message_Appointment::SENSITIVITY_NORMAL);
     // Busy Status
     switch ($this->status) {
         case Kronolith::STATUS_CANCELLED:
             $status = Horde_ActiveSync_Message_Appointment::BUSYSTATUS_FREE;
             break;
         case Kronolith::STATUS_CONFIRMED:
             $status = Horde_ActiveSync_Message_Appointment::BUSYSTATUS_BUSY;
             break;
         case Kronolith::STATUS_TENTATIVE:
             $status = Horde_ActiveSync_Message_Appointment::BUSYSTATUS_TENTATIVE;
         case Kronolith::STATUS_FREE:
         case Kronolith::STATUS_NONE:
             $status = Horde_ActiveSync_Message_Appointment::BUSYSTATUS_FREE;
     }
     $message->setBusyStatus($status);
     // DTStamp
     $message->setDTStamp($_SERVER['REQUEST_TIME']);
     // Recurrence
     if ($this->recurs()) {
         $message->setRecurrence($this->recurrence, $GLOBALS['prefs']->getValue('week_start_monday'));
         /* Exceptions are tricky. Exceptions, even those that represent
          * deleted instances of a recurring event, must be added. To do this
          * we query the storage for all the events that represent exceptions
          * (those with the baseid == $this->uid) and then remove the
          * exceptionoriginaldate from the list of exceptions we know about.
          * Any dates left in this list when we are done, must represent
          * deleted instances of this recurring event.*/
         if (!empty($this->recurrence) && ($exceptions = $this->recurrence->getExceptions())) {
             $results = $this->boundExceptions();
             foreach ($results as $exception) {
                 $e = new Horde_ActiveSync_Message_Exception(array('protocolversion' => $options['protocolversion']));
                 $e->setDateTime(array('start' => $exception->start, 'end' => $exception->end, 'allday' => $exception->isAllDay()));
                 // The start time of the *original* recurring event
                 $e->setExceptionStartTime($exception->exceptionoriginaldate);
                 $originaldate = $exception->exceptionoriginaldate->format('Ymd');
                 $key = array_search($originaldate, $exceptions);
                 if ($key !== false) {
                     unset($exceptions[$key]);
                 }
                 // Remaining properties that could be different
                 $e->setSubject($exception->getTitle());
                 if (!$exception->isPrivate()) {
                     $e->setLocation($exception->location);
                     $e->setBody($exception->description);
                 }
                 $e->setSensitivity($exception->private ? Horde_ActiveSync_Message_Appointment::SENSITIVITY_PRIVATE : Horde_ActiveSync_Message_Appointment::SENSITIVITY_NORMAL);
                 $e->setReminder($exception->alarm);
                 $e->setDTStamp($_SERVER['REQUEST_TIME']);
                 if ($options['protocolversion'] > Horde_ActiveSync::VERSION_TWELVEONE) {
                     switch ($exception->status) {
                         case Kronolith::STATUS_TENTATIVE:
                             $e->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_TENTATIVE;
                             break;
                         case Kronolith::STATUS_NONE:
                             $e->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_NORESPONSE;
                             break;
                         case Kronolith::STATUS_CONFIRMED:
                             $e->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_ACCEPTED;
                             break;
                         default:
                             $e->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_NONE;
                     }
                 }
                 // Tags/Categories
                 if (!$exception->isPrivate()) {
                     foreach ($exception->tags as $tag) {
                         $e->addCategory($tag);
                     }
                 }
                 $message->addexception($e);
             }
             // Any dates left in $exceptions must be deleted exceptions
             foreach ($exceptions as $deleted) {
                 $e = new Horde_ActiveSync_Message_Exception(array('protocolversion' => $options['protocolversion']));
                 // Kronolith stores the date only, but some AS clients need
                 // the datetime.
                 list($year, $month, $mday) = sscanf($deleted, '%04d%02d%02d');
                 $st = clone $this->start;
                 $st->year = $year;
                 $st->month = $month;
                 $st->mday = $mday;
                 $e->setExceptionStartTime($st);
                 $e->deleted = true;
                 $message->addException($e);
             }
         }
     }
     // Attendees
     if (!$this->isPrivate() && count($this->attendees)) {
         $message->setMeetingStatus(Horde_ActiveSync_Message_Appointment::MEETING_IS_MEETING);
         foreach ($this->attendees as $email => $properties) {
             $attendee = new Horde_ActiveSync_Message_Attendee(array('protocolversion' => $options['protocolversion']));
             $adr_obj = new Horde_Mail_Rfc822_Address($email);
             $attendee->name = $adr_obj->label;
             $attendee->email = $adr_obj->bare_address;
             // AS only has required or optional, and only EAS Version > 2.5
             if ($options['protocolversion'] > Horde_ActiveSync::VERSION_TWOFIVE) {
                 $attendee->type = $properties['attendance'] !== Kronolith::PART_REQUIRED ? Horde_ActiveSync_Message_Attendee::TYPE_OPTIONAL : Horde_ActiveSync_Message_Attendee::TYPE_REQUIRED;
                 switch ($properties['response']) {
                     case Kronolith::RESPONSE_NONE:
                         $attendee->status = Horde_ActiveSync_Message_Attendee::STATUS_NORESPONSE;
                         break;
                     case Kronolith::RESPONSE_ACCEPTED:
                         $attendee->status = Horde_ActiveSync_Message_Attendee::STATUS_ACCEPT;
                         break;
                     case Kronolith::RESPONSE_DECLINED:
                         $attendee->status = Horde_ActiveSync_Message_Attendee::STATUS_DECLINE;
                         break;
                     case Kronolith::RESPONSE_TENTATIVE:
                         $attendee->status = Horde_ActiveSync_Message_Attendee::STATUS_TENTATIVE;
                         break;
                     default:
                         $attendee->status = Horde_ActiveSync_Message_Attendee::STATUS_UNKNOWN;
                 }
             }
             $message->addAttendee($attendee);
         }
     } else {
         $message->setMeetingStatus(Horde_ActiveSync_Message_Appointment::MEETING_NOT_MEETING);
     }
     // Resources
     if ($options['protocolversion'] > Horde_ActiveSync::VERSION_TWOFIVE) {
         $r = $this->getResources();
         foreach ($r as $id => $data) {
             $resource = Kronolith::getDriver('Resource')->getResource($id);
             // EAS *REQUIRES* an email field for Resources. If it is missing
             // a number of clients will fail, losing push.
             if ($resource->get('email')) {
                 $attendee = new Horde_ActiveSync_Message_Attendee(array('protocolversion' => $options['protocolversion']));
                 $attendee->email = $resource->get('email');
                 $attendee->type = Horde_ActiveSync_Message_Attendee::TYPE_RESOURCE;
                 $attendee->name = $data['name'];
                 $attendee->status = $data['response'];
                 $message->addAttendee($attendee);
             }
         }
     }
     // Reminder
     if ($this->alarm) {
         $message->setReminder($this->alarm);
     }
     // Categories (tags)
     if (!$this->isPrivate()) {
         foreach ($this->tags as $tag) {
             $message->addCategory($tag);
         }
     }
     // EAS 14
     if ($options['protocolversion'] > Horde_ActiveSync::VERSION_TWELVEONE) {
         // We don't track the actual responses we sent to other's invitations.
         // Set this based on the status flag.
         switch ($this->status) {
             case Kronolith::STATUS_TENTATIVE:
                 $message->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_TENTATIVE;
                 break;
             case Kronolith::STATUS_NONE:
                 $message->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_NORESPONSE;
                 break;
             case Kronolith::STATUS_CONFIRMED:
                 $message->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_ACCEPTED;
                 break;
             default:
                 $message->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_NONE;
         }
     }
     // 14.1
     if ($options['protocolversion'] >= Horde_ActiveSync::VERSION_FOURTEENONE) {
         $message->onlinemeetingexternallink = $this->url;
     }
     return $message;
 }
Пример #7
0
 /**
  * Create an AS memo from this task
  *
  * @param array $memo  A memo array.
  * @param array $options
  *
  * @return Horde_ActiveSync_Message_Note
  */
 public function toASNote($memo, $options = array())
 {
     $message = new Horde_ActiveSync_Message_Note(array('protocolversion' => $options['protocolversion']));
     $message->subject = $memo['desc'];
     $bp = $options['bodyprefs'];
     $body = new Horde_ActiveSync_Message_AirSyncBaseBody();
     // When the note is encrypted, we won't have the passphrase so the
     // body will be a Mnemo_Exception.
     if ($memo['body'] instanceof Mnemo_Exception) {
         $memo['body'] = $memo['body']->getMessage();
     }
     if (isset($bp[Horde_ActiveSync::BODYPREF_TYPE_HTML])) {
         $body->type = Horde_ActiveSync::BODYPREF_TYPE_HTML;
         $memo['body'] = Horde_Text_Filter::filter($memo['body'], 'Text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
         if (isset($bp[Horde_ActiveSync::BODYPREF_TYPE_HTML]['truncationsize']) && Horde_String::length($memo['body']) > $bp[Horde_ActiveSync::BODYPREF_TYPE_HTML]['truncationsize']) {
             $body->data = Horde_String::substr($memo['body'], $bp[Horde_ActiveSync::BODYPREF_TYPE_HTML]['truncationsize']);
             $body->truncated = 1;
         } else {
             $body->data = $memo['body'];
         }
     } else {
         $body->type = Horde_ActiveSync::BODYPREF_TYPE_PLAIN;
         if (isset($bp[Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize']) && Horde_String::length($memo['body']) > $bp[Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize']) {
             $body->data = Horde_String::substr($memo['body'], 0, $bp[Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize']);
             $body->truncated = 1;
         } else {
             $body->data = $memo['body'];
         }
     }
     $body->estimateddatasize = Horde_String::length($memo['body']);
     $message->body = $body;
     if (!empty($memo['tags'])) {
         $message->categories = $memo['tags'];
     }
     $history = $GLOBALS['injector']->getInstance('Horde_History');
     $last = $history->getActionTimeStamp('mnemo:' . $memo['memolist_id'] . ':' . $memo['uid'], 'modify');
     if (empty($last)) {
         $last = $history->getActionTimeStamp('mnemo:' . $memo['memolist_id'] . ':' . $memo['uid'], 'add');
     }
     $message->lastmodified = new Horde_Date($last);
     return $message;
 }
Пример #8
0
 /**
  * Returns a best guess at the lastname in a string.
  *
  * @param string $name  String contain the full name.
  *
  * @return string  String containing the last name.
  */
 public static function guessLastname($name)
 {
     $name = trim(preg_replace('|\\s|', ' ', $name));
     if (!empty($name)) {
         /* Assume that last names are always before any commas. */
         if (is_int(strpos($name, ','))) {
             $name = Horde_String::substr($name, 0, strpos($name, ','));
         }
         /* Take out anything in parentheses. */
         $name = trim(preg_replace('|\\(.*\\)|', '', $name));
         $namelist = explode(' ', $name);
         $name = $namelist[$nameindex = count($namelist) - 1];
         while (!empty($name) && ($nlength = Horde_String::length($name)) < 5 && strspn($name[$nlength - 1], '.:-') && !empty($namelist[$nameindex - 1])) {
             $name = $namelist[--$nameindex];
         }
     }
     return strlen($name) ? $name : null;
 }
Пример #9
0
 /**
  * This function verifies whether a given directory is below the root.
  *
  * @param string $dir  The directory to check.
  *
  * @return boolean  True if the directory is below the root.
  */
 public static function verifyDir($dir)
 {
     return Horde_String::substr(Horde_Util::realPath($dir), 0, Horde_String::length(self::$backend['root'])) == self::$backend['root'];
 }
Пример #10
0
 /**
  * Regenerates body text for use in the compose screen from IMAP data.
  *
  * @param IMP_Contents $contents  An IMP_Contents object.
  * @param array $options          Additional options:
  * <ul>
  *  <li>html: (boolean) Return text/html part, if available.</li>
  *  <li>imp_msg: (integer) If non-empty, the message data was created by
  *               IMP. Either:
  *   <ul>
  *    <li>self::COMPOSE</li>
  *    <li>self::FORWARD</li>
  *    <li>self::REPLY</li>
  *   </ul>
  *  </li>
  *  <li>replylimit: (boolean) Enforce length limits?</li>
  *  <li>toflowed: (boolean) Do flowed conversion?</li>
  * </ul>
  *
  * @return mixed  Null if bodypart not found, or array with the following
  *                keys:
  *   - charset: (string) The guessed charset to use.
  *   - flowed: (Horde_Text_Flowed) A flowed object, if the text is flowed.
  *             Otherwise, null.
  *   - id: (string) The MIME ID of the bodypart.
  *   - mode: (string) Either 'text' or 'html'.
  *   - text: (string) The body text.
  */
 protected function _getMessageText($contents, array $options = array())
 {
     global $conf, $injector, $notification, $prefs;
     $body_id = null;
     $mode = 'text';
     $options = array_merge(array('imp_msg' => self::COMPOSE), $options);
     if (!empty($options['html']) && self::canHtmlCompose() && ($body_id = $contents->findBody('html')) !== null) {
         $mime_message = $contents->getMIMEMessage();
         switch ($mime_message->getPrimaryType()) {
             case 'multipart':
                 if ($body_id != '1' && $mime_message->getSubType() == 'mixed' && ($id_ob = new Horde_Mime_Id('1')) && !$id_ob->isChild($body_id)) {
                     $body_id = null;
                 } else {
                     $mode = 'html';
                 }
                 break;
             default:
                 if (strval($body_id) != '1') {
                     $body_id = null;
                 } else {
                     $mode = 'html';
                 }
                 break;
         }
     }
     if (is_null($body_id)) {
         $body_id = $contents->findBody();
         if (is_null($body_id)) {
             return null;
         }
     }
     if (!($part = $contents->getMimePart($body_id))) {
         return null;
     }
     $type = $part->getType();
     $part_charset = $part->getCharset();
     $msg = Horde_String::convertCharset($part->getContents(), $part_charset, 'UTF-8');
     /* Enforce reply limits. */
     if (!empty($options['replylimit']) && !empty($conf['compose']['reply_limit'])) {
         $limit = $conf['compose']['reply_limit'];
         if (Horde_String::length($msg) > $limit) {
             $msg = Horde_String::substr($msg, 0, $limit) . "\n" . _("[Truncated Text]");
         }
     }
     if ($mode == 'html') {
         $dom = $injector->getInstance('Horde_Core_Factory_TextFilter')->filter($msg, 'Xss', array('charset' => $this->charset, 'return_dom' => true, 'strip_style_attributes' => false));
         /* If we are replying to a related part, and this part refers
          * to local message parts, we need to move those parts into this
          * message (since the original message may disappear during the
          * compose process). */
         if ($related_part = $contents->findMimeType($body_id, 'multipart/related')) {
             $this->_setMetadata('related_contents', $contents);
             $related_ob = new Horde_Mime_Related($related_part);
             $related_ob->cidReplace($dom, array($this, '_getMessageTextCallback'), $part_charset);
             $this->_setMetadata('related_contents', null);
         }
         /* Convert any Data URLs to attachments. */
         $xpath = new DOMXPath($dom->dom);
         foreach ($xpath->query('//*[@src]') as $val) {
             $data_url = new Horde_Url_Data($val->getAttribute('src'));
             if (strlen($data_url->data)) {
                 $data_part = new Horde_Mime_Part();
                 $data_part->setContents($data_url->data);
                 $data_part->setType($data_url->type);
                 try {
                     $atc = $this->addAttachmentFromPart($data_part);
                     $val->setAttribute('src', $atc->viewUrl());
                     $this->addRelatedAttachment($atc, $val, 'src');
                 } catch (IMP_Compose_Exception $e) {
                     $notification->push($e, 'horde.warning');
                 }
             }
         }
         $msg = $dom->returnBody();
     } elseif ($type == 'text/html') {
         $msg = $injector->getInstance('Horde_Core_Factory_TextFilter')->filter($msg, 'Html2text');
         $type = 'text/plain';
     }
     /* Always remove leading/trailing whitespace. The data in the
      * message body is not intended to be the exact representation of the
      * original message (use forward as message/rfc822 part for that). */
     $msg = trim($msg);
     if ($type == 'text/plain') {
         if ($prefs->getValue('reply_strip_sig') && ($pos = strrpos($msg, "\n-- ")) !== false) {
             $msg = rtrim(substr($msg, 0, $pos));
         }
         /* Remove PGP armored text. */
         $pgp = $injector->getInstance('Horde_Crypt_Pgp_Parse')->parseToPart($msg);
         if (!is_null($pgp)) {
             $msg = '';
             $pgp->buildMimeIds();
             foreach ($pgp->partIterator() as $val) {
                 if ($val->getPrimaryType() === 'text') {
                     $msg .= $val->getContents();
                 }
             }
         }
         if ($part->getContentTypeParameter('format') == 'flowed') {
             $flowed = new Horde_Text_Flowed($msg, 'UTF-8');
             if (Horde_String::lower($part->getContentTypeParameter('delsp')) == 'yes') {
                 $flowed->setDelSp(true);
             }
             $flowed->setMaxLength(0);
             $msg = $flowed->toFixed(false);
         } else {
             /* If the input is *not* in flowed format, make sure there is
              * no padding at the end of lines. */
             $msg = preg_replace("/\\s*\n/U", "\n", $msg);
         }
         if (isset($options['toflowed'])) {
             $flowed = new Horde_Text_Flowed($msg, 'UTF-8');
             $msg = $options['toflowed'] ? $flowed->toFlowed(true) : $flowed->toFlowed(false, array('nowrap' => true));
         }
     }
     if (strcasecmp($part->getCharset(), 'windows-1252') === 0) {
         $part_charset = 'ISO-8859-1';
     }
     return array('charset' => $part_charset, 'flowed' => isset($flowed) ? $flowed : null, 'id' => $body_id, 'mode' => $mode, 'text' => $msg);
 }
Пример #11
0
 /**
  * Limits a string to a given maximum length in a smarter way than just
  * using substr().
  *
  * Namely, cut from the MIDDLE instead of from the end so that if we're
  * doing this on (for instance) a bunch of binder names that start off with
  * the same verbose description, and then are different only at the very
  * end, they'll still be different from one another after truncating.
  *
  * <code>
  * $str = 'The quick brown fox jumps over the lazy dog tomorrow morning.';
  * $shortStr = $this->truncateMiddle($str, 40);
  * // $shortStr == 'The quick brown fox... tomorrow morning.'
  * </code>
  *
  * @param string $str         A text to truncate.
  * @param integer $maxLength  The maximum length of the text
  * @param string $joiner      Replacement string for the truncated text.
  *
  * @return string  The truncated text.
  */
 public function truncateMiddle($str, $maxLength = 80, $joiner = '...')
 {
     if (Horde_String::length($str) <= $maxLength) {
         return $str;
     }
     $maxLength = $maxLength - Horde_String::length($joiner);
     if ($maxLength <= 0) {
         return $str;
     }
     $startPieceLength = (int) ceil($maxLength / 2);
     $endPieceLength = (int) floor($maxLength / 2);
     $trimmedString = rtrim(Horde_String::substr($str, 0, $startPieceLength)) . $joiner;
     if ($endPieceLength > 0) {
         $trimmedString .= ltrim(Horde_String::substr($str, -1 * $endPieceLength));
     }
     return $trimmedString;
 }
Пример #12
0
 /**
  * Returns an external link passed through the dereferrer to strip session
  * IDs from the referrer.
  *
  * @param string $url   The external URL to link to.
  * @param boolean $tag  If true, a complete <a> tag is returned, only the
  *                      url otherwise.
  *
  * @return string  The link to the dereferrer script.
  */
 public static function externalUrl($url, $tag = false)
 {
     if (!isset($_GET[session_name()]) || Horde_String::substr($url, 0, 1) == '#' || Horde_String::substr($url, 0, 7) == 'mailto:') {
         $ext = $url;
     } else {
         $ext = self::signQueryString($GLOBALS['registry']->getServiceLink('go', 'horde')->add('url', $url));
     }
     if ($tag) {
         $ext = self::link($ext, $url, '', '_blank');
     }
     return $ext;
 }
Пример #13
0
 /**
  * Returns the widget necessary to configure this block.
  *
  * @param $app TODO
  * @param $block TODO
  * @param $param_id TODO
  * @param $val TODO
  *
  * @return TODO
  */
 public function getOptionsWidget($app, $block, $param_id, $val = null)
 {
     $widget = '';
     /* getParams() loads $_blocks */
     $this->getParams($app, $block);
     $param = $this->_blocks[$app][$block]['params'][$param_id];
     if (!isset($param['default'])) {
         $param['default'] = '';
     }
     switch ($param['type']) {
         case 'boolean':
         case 'checkbox':
             $checked = !empty($val[$param_id]) ? ' checked="checked"' : '';
             $widget = sprintf('<input type="checkbox" name="params[%s]"%s />', $param_id, $checked);
             break;
         case 'enum':
             $widget = sprintf('<select name="params[%s]">', $param_id);
             foreach ($param['values'] as $key => $name) {
                 if (Horde_String::length($name) > 30) {
                     $name = substr($name, 0, 27) . '...';
                 }
                 $widget .= sprintf("<option value=\"%s\"%s>%s</option>\n", htmlspecialchars($key), isset($val[$param_id]) && $val[$param_id] == $key ? ' selected="selected"' : '', htmlspecialchars($name));
             }
             $widget .= '</select>';
             break;
         case 'multienum':
             $widget = sprintf('<select multiple="multiple" name="params[%s][]">', $param_id);
             foreach ($param['values'] as $key => $name) {
                 if (Horde_String::length($name) > 30) {
                     $name = substr($name, 0, 27) . '...';
                 }
                 $widget .= sprintf("<option value=\"%s\"%s>%s</option>\n", htmlspecialchars($key), isset($val[$param_id]) && in_array($key, $val[$param_id]) ? ' selected="selected"' : '', htmlspecialchars($name));
             }
             $widget .= '</select>';
             break;
         case 'mlenum':
             // Multi-level enum.
             if (is_array($val) && isset($val['__' . $param_id])) {
                 $firstval = $val['__' . $param_id];
             } else {
                 $tmp = array_keys($param['values']);
                 $firstval = current($tmp);
             }
             $blockvalues = $param['values'][$firstval];
             asort($blockvalues);
             $widget = sprintf('<select name="params[__%s]" onchange="document.blockform.action.value=\'save-resume\';document.blockform.submit()">', $param_id) . "\n";
             foreach (array_keys($param['values']) as $key) {
                 $name = Horde_String::length($key) > 30 ? Horde_String::substr($key, 0, 27) . '...' : $key;
                 $widget .= sprintf("<option value=\"%s\"%s>%s</option>\n", htmlspecialchars($key), $key == $firstval ? ' selected="selected"' : '', htmlspecialchars($name));
             }
             $widget .= "</select><br />\n";
             $widget .= sprintf("<select name=\"params[%s]\">\n", $param_id);
             foreach ($blockvalues as $key => $name) {
                 $name = Horde_String::length($name) > 30 ? Horde_String::substr($name, 0, 27) . '...' : $name;
                 $widget .= sprintf("<option value=\"%s\"%s>%s</option>\n", htmlspecialchars($key), $val[$param_id] == $key ? ' selected="selected"' : '', htmlspecialchars($name));
             }
             $widget .= "</select><br />\n";
             break;
         case 'int':
         case 'text':
             $widget = sprintf('<input type="text" name="params[%s]" value="%s" />', $param_id, !isset($val[$param_id]) ? $param['default'] : $val[$param_id]);
             break;
         case 'password':
             $widget = sprintf('<input type="password" name="params[%s]" value="%s" />', $param_id, !isset($val[$param_id]) ? $param['default'] : $val[$param_id]);
             break;
         case 'error':
             $widget = '<span class="form-error">' . $param['default'] . '</span>';
             break;
     }
     return $widget;
 }
Пример #14
0
 /**
  * Returns the main text body of the message suitable for sending over
  * EAS response.
  *
  * @param array $options  An options array containgin:
  *  - bodyprefs: (array)  Bodypref settings
  *               DEFAULT: none (No bodyprefs used).
  *  - mimesupport: (integer)  Indicates if MIME is supported or not.
  *                  Possible values: 0 - Not supported 1 - Only S/MIME or
  *                  2 - All MIME.
  *                  DEFAULT: 0 (No MIME support)
  *  - protocolversion: (float)  The EAS protocol we are supporting.
  *                     DEFAULT 2.5
  *
  * @return array  An array of one or both of 'plain' and 'html' content.
  *
  * @throws Horde_ActiveSync_Exception, Horde_Exception_NotFound
  */
 public function getMessageBodyData(array $options = array())
 {
     $version = empty($options['protocolversion']) ? Horde_ActiveSync::VERSION_TWOFIVE : $options['protocolversion'];
     // Look for the parts we need. We try to detect and fetch only the parts
     // we need, while ensuring we have something to return. So, e.g., if we
     // don't have BODYPREF_TYPE_HTML, we only request plain text, but if we
     // can't find plain text but we have a html body, fetch that anyway.
     $text_id = $this->_message->findBody('plain');
     $html_id = $this->_message->findBody('html');
     // Deduce which part(s) we need to request.
     $want_html_text = $version >= Horde_ActiveSync::VERSION_TWELVE && (!empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML]) || !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_MIME]));
     $want_plain_text = $version == Horde_ActiveSync::VERSION_TWOFIVE || empty($options['bodyprefs']) || !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]) || !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_RTF]) || !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_MIME]) || $want_html_text && empty($html_id);
     $want_html_as_plain = false;
     if (!empty($text_id) && $want_plain_text) {
         $text_body_part = $this->_message->getPart($text_id);
         $charset = $text_body_part->getCharset();
     } elseif ($want_plain_text && !empty($html_id) && empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_MIME])) {
         $want_html_text = true;
         $want_html_as_plain = true;
     }
     if (!empty($html_id) && $want_html_text) {
         $html_body_part = $this->_message->getPart($html_id);
         $html_charset = $html_body_part->getCharset();
     }
     // Sanity check the truncation stuff
     if (empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]) && !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML]) && $want_plain_text && $want_html_text) {
         // We only have HTML truncation data, requested HTML body but only
         // have plaintext.
         $options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN] = $options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML];
     }
     $query = new Horde_Imap_Client_Fetch_Query();
     $query_opts = array('decode' => true, 'peek' => true);
     // Get body information
     if ($version >= Horde_ActiveSync::VERSION_TWELVE) {
         if (!empty($html_id)) {
             $query->bodyPartSize($html_id);
             $query->bodyPart($html_id, $query_opts);
         }
         if (!empty($text_id)) {
             $query->bodyPart($text_id, $query_opts);
             $query->bodyPartSize($text_id);
         }
     } else {
         // EAS 2.5 Plaintext body
         $query->bodyPart($text_id, $query_opts);
         $query->bodyPartSize($text_id);
     }
     try {
         $fetch_ret = $this->_imap->fetch($this->_mbox, $query, array('ids' => new Horde_Imap_Client_Ids(array($this->_uid))));
     } catch (Horde_Imap_Client_Exception $e) {
         throw new Horde_ActiveSync_Exception($e);
     }
     if (!($data = $fetch_ret->first())) {
         throw new Horde_Exception_NotFound(sprintf('Could not load message %s from server.', $this->_uid));
     }
     $return = array();
     if (!empty($text_id) && $want_plain_text) {
         $text = $data->getBodyPart($text_id);
         if (!$data->getBodyPartDecode($text_id)) {
             $text_body_part->setContents($text);
             $text = $text_body_part->getContents();
         }
         $text_size = !is_null($data->getBodyPartSize($text_id)) ? $data->getBodyPartSize($text_id) : Horde_String::length($text);
         if (!empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'])) {
             // EAS >= 12.0 truncation
             $text = Horde_String::substr($text, 0, $options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'], $charset);
         }
         $truncated = $text_size > Horde_String::length($text);
         if ($version >= Horde_ActiveSync::VERSION_TWELVE && $truncated && !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['allornone'])) {
             $text = '';
         }
         $return['plain'] = array('charset' => $charset, 'body' => $text, 'truncated' => $truncated, 'size' => $text_size);
     }
     if (!empty($html_id) && $want_html_text) {
         $html = $data->getBodyPart($html_id);
         if (!$data->getBodyPartDecode($html_id)) {
             $html_body_part->setContents($html);
             $html = $html_body_part->getContents();
         }
         // Size of the original HTML part.
         $html_size = !is_null($data->getBodyPartSize($html_id)) ? $data->getBodyPartSize($html_id) : Horde_String::length($html);
         if (!empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML]['truncationsize'])) {
             $html = Horde_String::substr($html, 0, $options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML]['truncationsize'], $html_charset);
         } elseif ($want_html_as_plain) {
             $html = Horde_Text_Filter::filter($html, 'Html2text', array('charset' => $html_charset));
             // Get the new size, since it probably changed.
             $html_size = Horde_String::length($html);
             if (!empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'])) {
                 // EAS >= 12.0 truncation
                 $html = Horde_String::substr($html, 0, $options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'], $html_charset);
             }
         }
         // Was the part truncated?
         $truncated = $html_size > Horde_String::length($html);
         if ($want_html_as_plain) {
             $return['plain'] = array('charset' => $html_charset, 'body' => $html, 'truncated' => $truncated, 'size' => $html_size);
         }
         if ($version >= Horde_ActiveSync::VERSION_TWELVE && !($truncated && !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML]['allornone']))) {
             $return['html'] = array('charset' => $html_charset, 'body' => $html, 'estimated_size' => $html_size, 'truncated' => $truncated);
         }
     }
     return $return;
 }
Пример #15
0
?>
</a>
 </div>

 <div data-role="content" id="kronolith-minical" class="kronolith-minical">
  <table>
   <thead>
    <tr>
<?php 
for ($i = $GLOBALS['prefs']->getValue('week_start_monday'), $c = $i + 7; $i < $c; $i++) {
    ?>
     <th title="<?php 
    echo Horde_Nls::getLangInfo(constant('DAY_' . ($i % 7 + 1)));
    ?>
"><?php 
    echo Horde_String::substr(Horde_Nls::getLangInfo(constant('DAY_' . ($i % 7 + 1))), 0, 1);
    ?>
</th>
<?php 
}
?>
    </tr>
   </thead>
   <tbody><tr><td></td></tr></tbody>
  </table>
 </div>

 <div id="kronolithDayDetailHeader" data-role="header">
   <h3></h3>
 </div>
Пример #16
0
 /**
  * Helper method to build a view object for a tweet.
  *
  * @param  stdClass $tweet  The tweet object.
  *
  * @return Horde_View  The view object, populated with tweet data.
  */
 protected function _buildTweet($tweet)
 {
     global $injector, $registry;
     $view = new Horde_View(array('templatePath' => HORDE_TEMPLATES . '/block'));
     $view->addHelper('Tag');
     $view->ajax_uri = $registry->getServiceLink('ajax', $registry->getApp());
     $filter = $injector->getInstance('Horde_Core_Factory_TextFilter');
     $instance = $this->vars->i;
     // Links and media
     $map = $previews = array();
     foreach ($tweet->entities->urls as $link) {
         $replace = '<a target="_blank" href="' . $link->url . '" title="' . $link->expanded_url . '">' . htmlspecialchars($link->display_url) . '</a>';
         $map[$link->indices[0]] = array($link->indices[1], $replace);
     }
     if (!empty($tweet->entities->media)) {
         foreach ($tweet->entities->media as $picture) {
             $replace = '<a target="_blank" href="' . $picture->url . '" title="' . $picture->expanded_url . '">' . htmlentities($picture->display_url, ENT_COMPAT, 'UTF-8') . '</a>';
             $map[$picture->indices[0]] = array($picture->indices[1], $replace);
             $previews[] = ' <a href="#" onclick="return Horde[\'twitter' . $instance . '\'].showPreview(\'' . $picture->media_url . ':small\');"><img src="' . Horde_Themes::img('mime/image.png') . '" /></a>';
         }
     }
     if (!empty($tweet->entities->user_mentions)) {
         foreach ($tweet->entities->user_mentions as $user) {
             $replace = ' <a target="_blank" title="' . $user->name . '" href="http://twitter.com/' . $user->screen_name . '">@' . htmlentities($user->screen_name, ENT_COMPAT, 'UTF-8') . '</a>';
             $map[$user->indices[0]] = array($user->indices[1], $replace);
         }
     }
     if (!empty($tweet->entities->hashtags)) {
         foreach ($tweet->entities->hashtags as $hashtag) {
             $replace = ' <a target="_blank" href="http://twitter.com/search?q=#' . urlencode($hashtag->text) . '">#' . htmlentities($hashtag->text, ENT_COMPAT, 'UTF-8') . '</a>';
             $map[$hashtag->indices[0]] = array($hashtag->indices[1], $replace);
         }
     }
     $body = '';
     $pos = 0;
     while ($pos <= Horde_String::length($tweet->text) - 1) {
         if (!empty($map[$pos])) {
             $entity = $map[$pos];
             $body .= $entity[1];
             $pos = $entity[0];
         } else {
             $body .= Horde_String::substr($tweet->text, $pos, 1);
             ++$pos;
         }
     }
     foreach ($previews as $preview) {
         $body .= $preview;
     }
     $view->body = $body;
     /* If this is a retweet, use the original author's profile info */
     if (!empty($tweet->retweeted_status)) {
         $tweetObj = $tweet->retweeted_status;
     } else {
         $tweetObj = $tweet;
     }
     /* These are all referencing the *original* tweet */
     $view->profileLink = Horde::externalUrl('http://twitter.com/' . htmlspecialchars($tweetObj->user->screen_name), true);
     $view->profileImg = $GLOBALS['browser']->usingSSLConnection() ? $tweetObj->user->profile_image_url_https : $tweetObj->user->profile_image_url;
     $view->authorName = '@' . htmlspecialchars($tweetObj->user->screen_name);
     $view->authorFullname = htmlspecialchars($tweetObj->user->name);
     $view->createdAt = $tweetObj->created_at;
     $view->clientText = $filter->filter($tweet->source, 'xss');
     $view->tweet = $tweet;
     $view->instanceid = $instance;
     return $view;
 }
Пример #17
0
 /**
  * Create an AS message from this task
  *
  * @param array $options  Options:
  *   - protocolversion: (float)  The EAS version to support
  *                      DEFAULT: 2.5
  *   - bodyprefs: (array)  A BODYPREFERENCE array.
  *                DEFAULT: none (No body prefs enforced).
  *   - truncation: (integer)  Truncate event body to this length
  *                 DEFAULT: none (No truncation).
  *
  * @return Horde_ActiveSync_Message_Task
  */
 public function toASTask(array $options = array())
 {
     $message = new Horde_ActiveSync_Message_Task(array('protocolversion' => $options['protocolversion']));
     /* Notes and Title */
     if ($options['protocolversion'] >= Horde_ActiveSync::VERSION_TWELVE) {
         $bp = $options['bodyprefs'];
         $body = new Horde_ActiveSync_Message_AirSyncBaseBody();
         $body->type = Horde_ActiveSync::BODYPREF_TYPE_PLAIN;
         if (isset($bp[Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'])) {
             $truncation = $bp[Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'];
         } elseif (isset($bp[Horde_ActiveSync::BODYPREF_TYPE_HTML])) {
             $truncation = $bp[Horde_ActiveSync::BODYPREF_TYPE_HTML]['truncationsize'];
             $this->desc = Horde_Text_Filter::filter($this->desc, 'Text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
         } else {
             $truncation = false;
         }
         if ($truncation && Horde_String::length($this->desc) > $truncation) {
             $body->data = Horde_String::substr($this->desc, 0, $truncation);
             $body->truncated = 1;
         } else {
             $body->data = $this->desc;
         }
         $body->estimateddatasize = Horde_String::length($this->desc);
         $message->airsyncbasebody = $body;
     } else {
         $message->body = $this->desc;
     }
     $message->subject = $this->name;
     /* Completion */
     if ($this->completed) {
         $message->datecompleted = new Horde_Date($this->completed_date);
         $message->complete = Horde_ActiveSync_Message_Task::TASK_COMPLETE_TRUE;
     } else {
         $message->complete = Horde_ActiveSync_Message_Task::TASK_COMPLETE_FALSE;
     }
     /* Due Date */
     if (!empty($this->due)) {
         $message->utcduedate = new Horde_Date($this->due);
         $message->duedate = new Horde_Date($this->due, 'UTC');
     }
     /* Start Date */
     if (!empty($this->start)) {
         $message->utcstartdate = new Horde_Date($this->start);
         $message->startdate = new Horde_Date($this->start, 'UTC');
     }
     /* Priority */
     switch ($this->priority) {
         case 5:
             $priority = Horde_ActiveSync_Message_Task::IMPORTANCE_LOW;
             break;
         case 4:
         case 3:
         case 2:
             $priority = Horde_ActiveSync_Message_Task::IMPORTANCE_NORMAL;
             break;
         case 1:
             $priority = Horde_ActiveSync_Message_Task::IMPORTANCE_HIGH;
             break;
         default:
             $priority = Horde_ActiveSync_Message_Task::IMPORTANCE_NORMAL;
     }
     $message->setImportance($priority);
     /* Reminders */
     if ($this->due && $this->alarm) {
         $message->setReminder(new Horde_Date($this->due - $this->alarm * 60));
     }
     /* Recurrence */
     if ($this->recurs()) {
         $message->setRecurrence($this->recurrence);
     }
     /* Categories */
     $message->categories = $this->tags;
     return $message;
 }
Пример #18
0
 /**
  * Replace the memo identified by UID with the content represented in
  * the specified contentType.
  *
  * @param string $uid          Idenfity the memo to replace.
  * @param string $content      The content of the memo.
  * @param string $contentType  What format is the data in? Currently supports:
  *                             text/plain
  *                             text/x-vnote
  *                             activesync
  * @throws Mnemo_Exception
  * @throws Horde_Exception_PermissionDenied
  */
 public function replace($uid, $content, $contentType)
 {
     $storage = $GLOBALS['injector']->getInstance('Mnemo_Factory_Driver')->create();
     $memo = $storage->getByUID($uid);
     if (!array_key_exists($memo['memolist_id'], Mnemo::listNotepads(false, Horde_Perms::EDIT))) {
         throw new Horde_Exception_PermissionDenied();
     }
     switch ($contentType) {
         case 'text/plain':
             $storage->modify($memo['memo_id'], $storage->getMemoDescription($content), $content, null);
             break;
         case 'text/x-vnote':
             if (!$content instanceof Horde_Icalendar_Vnote) {
                 $iCal = new Horde_Icalendar();
                 if (!$iCal->parsevCalendar($content)) {
                     throw new Mnemo_Exception(_("There was an error importing the iCalendar data."));
                 }
                 $components = $iCal->getComponents();
                 switch (count($components)) {
                     case 0:
                         throw new Mnemo_Exception(_("No iCalendar data was found."));
                     case 1:
                         $content = $components[0];
                         break;
                     default:
                         throw new Mnemo_Exception(_("Multiple iCalendar components found; only one vNote is supported."));
                 }
             }
             $note = $storage->fromiCalendar($content);
             $storage->modify($memo['memo_id'], $note['desc'], $note['body'], !empty($note['tags']) ? $note['tags'] : '');
             break;
         case 'activesync':
             // We only support plaintext
             if ($content->body->type == Horde_ActiveSync::BODYPREF_TYPE_HTML) {
                 $body = Horde_Text_Filter::filter($content->body->data, 'Html2text');
             } else {
                 $body = $content->body->data;
             }
             $storage->modify($memo['memo_id'], Horde_String::substr($content->subject, 0, 255), $body, $content->categories);
             break;
         default:
             throw new Mnemo_Exception(sprintf(_("Unsupported Content-Type: %s"), $contentType));
     }
 }
Пример #19
0
 public function getCostObjectType($vars)
 {
     global $registry;
     $clients = $vars->get('clients');
     if (count($clients) == 0) {
         $clients = array('');
     }
     $costobjects = array();
     foreach ($clients as $client) {
         $criteria = array('user' => $GLOBALS['registry']->getAuth(), 'active' => true, 'client_id' => $client);
         foreach ($registry->listApps() as $app) {
             if ($registry->hasMethod('listCostObjects', $app)) {
                 try {
                     $res = $registry->callByPackage($app, 'listCostObjects', array($criteria));
                 } catch (Horde_Exception $e) {
                     $GLOBALS['notification']->push(sprintf(_("Error retrieving cost objects from \"%s\": %s"), $registry->get('name', $app), $res->getMessage()), 'horde.error');
                     continue;
                 }
                 foreach (array_keys($res) as $catkey) {
                     foreach (array_keys($res[$catkey]['objects']) as $okey) {
                         $res[$catkey]['objects'][$okey]['id'] = $app . ':' . $res[$catkey]['objects'][$okey]['id'];
                     }
                 }
                 $costobjects = array_merge($costobjects, $res);
             }
         }
     }
     $elts = array();
     $counter = 0;
     foreach ($costobjects as $category) {
         Horde_Array::arraySort($category['objects'], 'name');
         foreach ($category['objects'] as $object) {
             $name = $object['name'];
             if (Horde_String::length($name) > 80) {
                 $name = Horde_String::substr($name, 0, 76) . ' ...';
             }
             $elts[$object['id']] = $name;
         }
     }
     return $elts;
 }
Пример #20
0
 /**
  * Extract a set of encapsulated MAPI properties. Normally either embedded
  * in an attachment structure, or an idMessageProperty structure.
  *
  * @param string $data             The data string.
  * @param array &$attachment_data  TODO
  */
 protected function _extractMapiAttributes($data)
 {
     // Number of attributes.
     $number = $this->_geti($data, 32);
     $this->_logger->debug(sprintf('TNEF: Extracting %d MAPI attributes.', $number));
     while (strlen($data) > 0 && $number--) {
         $have_mval = false;
         $num_mval = 1;
         $value = null;
         $attr_type = $this->_geti($data, 16);
         $attr_name = $this->_geti($data, 16);
         $namespace = false;
         // Multivalue attributes.
         if (($attr_type & self::MAPI_MV_FLAG) != 0) {
             $have_mval = true;
             $attr_type = $attr_type & ~self::MAPI_MV_FLAG;
             $this->_logger->debug(sprintf('TNEF: Multivalue attribute of type: 0x%04X', $attr_type));
         }
         // Named attributes.
         if ($attr_name >= 0x8000 && $attr_name < 0xfffe) {
             $namespace = $this->_toNamespaceGUID($this->_getx($data, 16));
             // The type of named property, an ID or STRING.
             $named_type = $this->_geti($data, 32);
             switch ($named_type) {
                 case self::MAPI_NAMED_TYPE_ID:
                     $pid = $attr_name;
                     $attr_name = $this->_geti($data, 32);
                     $msg = sprintf('TNEF: pid: 0x%X type: 0x%X Named Id: %s 0x%04X', $pid, $attr_type, $namespace, $attr_name);
                     $this->_logger->debug($msg);
                     break;
                 case self::MAPI_NAMED_TYPE_STRING:
                     // @todo. We haven't needed data from any string named id
                     // yet, but might be able to just assign the name to
                     // $attr_name and pass it down to _currentObject for now.
                     // For H6, look at using some lightweight object to transport
                     // the name/value to the various objects.
                     $attr_name = 0x9999;
                     $id_len = $this->_geti($data, 32);
                     $data_len = $id_len + (4 - $id_len % 4) % 4;
                     $name = Horde_String::substr($this->_getx($data, $data_len), 0, $id_len);
                     $name = trim(Horde_String::convertCharset($name, 'UTF-16LE', 'UTF-8'));
                     $this->_logger->debug(sprintf('TNEF: Named String Id: %s', $name));
                     break;
                 case self::MAPI_NAMED_TYPE_NONE:
                     continue 2;
                     break;
                 default:
                     $msg = sprintf('TNEF: Unknown NAMED type: pid: 0x%X type: 0x%X Named TYPE: %s 0x%04X', $pid, $attr_type, $namespace, $named_type);
                     $this->_logger->notice($msg);
                     continue 2;
             }
         }
         if ($have_mval) {
             $num_mval = $this->_geti($data, 32);
             $this->_logger->debug(sprintf('TNEF: Number of multivalues: %s', $num_mval));
         }
         switch ($attr_type) {
             case self::MAPI_NULL:
             case self::MAPI_TYPE_UNSPECIFIED:
                 break;
             case self::MAPI_SHORT:
                 $value = $this->_geti($data, 16);
                 // Padding. See MS-OXTNEF 2.1.3.4
                 // Must always pad to a multiple of 4 bytes.
                 $this->_geti($data, 16);
                 break;
             case self::MAPI_INT:
             case self::MAPI_BOOLEAN:
                 for ($i = 0; $i < $num_mval; $i++) {
                     $value = $this->_geti($data, 32);
                 }
                 break;
             case self::MAPI_FLOAT:
             case self::MAPI_ERROR:
                 $value = $this->_getx($data, 4);
                 break;
             case self::MAPI_DOUBLE:
             case self::MAPI_APPTIME:
             case self::MAPI_CURRENCY:
             case self::MAPI_INT8BYTE:
             case self::MAPI_SYSTIME:
                 $value = $this->_getx($data, 8);
                 break;
             case self::MAPI_CLSID:
                 $this->_logger->debug('TNEF: CLSID??');
                 $this->_getx($data, 16);
                 break;
             case self::MAPI_STRING:
             case self::MAPI_UNICODE_STRING:
             case self::MAPI_BINARY:
             case self::MAPI_OBJECT:
                 $num_vals = $have_mval ? $num_mval : $this->_geti($data, 32);
                 for ($i = 0; $i < $num_vals; $i++) {
                     $length = $this->_geti($data, 32);
                     /* Pad to next 4 byte boundary. */
                     $datalen = $length + (4 - $length % 4) % 4;
                     /* Read and truncate to length. */
                     $value = substr($this->_getx($data, $datalen), 0, $length);
                 }
                 switch ($attr_type) {
                     case self::MAPI_UNICODE_STRING:
                         // MAPI Unicode is UTF-16LE; convert to UTF-8
                         $value = Horde_String::convertCharset($value, 'UTF-16LE', 'UTF-8');
                         break;
                 }
                 switch ($attr_type) {
                     case self::MAPI_STRING:
                     case self::MAPI_UNICODE_STRING:
                         // Strings are null-terminated.
                         $value = substr($value, 0, -1);
                         break;
                 }
                 break;
             default:
                 $msg = sprintf('TNEF: Unknown attribute type, "0x%X"', $attr_type);
                 throw new Horde_Compress_Exception($msg);
                 $this->_logger->notice($msg);
         }
         // @todo Utility method to make this log more readable.
         $this->_logger->debug(sprintf('TNEF: Attribute: 0x%X Type: 0x%X', $attr_name, $attr_type));
         switch ($attr_name) {
             case self::MAPI_TAG_RTF_COMPRESSED:
                 $this->_logger->debug('TNEF: Found compressed RTF text.');
                 $rtf = new Horde_Compress_Tnef_Rtf($this->_logger, $value);
                 $this->_files[] = $rtf;
                 // Give the currentObject a chance to do something with the RTF
                 // body. This is used, e.g., in meeting requests to populate
                 // the description field.
                 if ($this->_currentObject) {
                     try {
                         $this->_currentObject->setMapiAttribute($attr_type, $attr_name, $rtf->toPlain());
                     } catch (Horde_Compress_Exception $e) {
                         $this->_logger->err(sprintf('TNEF: Unable to set attribute: %s', $e->getMessage()));
                     }
                 }
                 break;
             case self::MAPI_ATTACH_DATA:
                 $this->_logger->debug('TNEF: Found nested MAPI object. Parsing.');
                 $this->_getx($value, 16);
                 $att = new Horde_Compress_Tnef($this->_logger);
                 $att->setCurrentObject($this->_currentObject);
                 $att->decompress($value);
                 $this->_attachments[] = $att;
                 $this->_logger->debug('TNEF: Completed nested attachment parsing.');
                 break;
             default:
                 try {
                     $this->_msgInfo->setMapiAttribute($attr_type, $attr_name, $value);
                     if ($this->_currentObject) {
                         $this->_currentObject->setMapiAttribute($attr_type, $attr_name, $value, $namespace);
                     }
                 } catch (Horde_Compress_Exception $e) {
                     $this->_logger->err(sprintf('TNEF: Unable to set attribute: %s', $e->getMessage()));
                 }
         }
     }
 }
Пример #21
0
 /**
  * Build the data needed for the BodyPart part.
  *
  * @param  Horde_Imap_Client_Data_Fetch $data  The FETCH results.
  * @param  Horde_Mime_Part $mime  The plaintext MIME part.
  * @param boolean $to_html        If true, $id is assumed to be a text/plain
  *                                part and is converted to html.
  *
  * @return array  The BodyPart data.
  *     - charset:  (string)   The charset of the text.
  *     - body: (string)       The body text.
  *     - truncated: (boolean) True if text was truncated.
  *     - size: (integer)      The original part size, in bytes.
  */
 protected function _getBodyPart(Horde_Imap_Client_Data_Fetch $data, Horde_Mime_Part $mime, $to_html)
 {
     $id = $mime->getMimeId();
     $text = $data->getBodyPart($id);
     if (!$data->getBodyPartDecode($id)) {
         $mime->setContents($text);
         $text = $mime->getContents();
     }
     if ($to_html) {
         $text = Horde_Text_Filter::filter($text, 'Text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO, 'charset' => $mime->getCharset()));
         $size = strlen($text);
     } else {
         $size = !is_null($data->getBodyPartSize($id)) ? $data->getBodyPartSize($id) : strlen($text);
     }
     if (!empty($this->_options['bodypartprefs']['truncationsize'])) {
         $text = Horde_String::substr($text, 0, $this->_options['bodypartprefs']['truncationsize'], $mime->getCharset());
     }
     return array('charset' => $mime->getCharset(), 'body' => $text, 'truncated' => $size > strlen($text), 'size' => $size);
 }
Пример #22
0
 /**
  * List code points for a given input.
  *
  * @param string $input
  *
  * @return array  Multi-dimension array with basic, non-basic and
  *                aggregated code points.
  */
 protected function _codePoints($input)
 {
     $codePoints = array('all' => array(), 'basic' => array(), 'nonBasic' => array());
     $len = Horde_String::length($input, 'UTF-8');
     for ($i = 0; $i < $len; ++$i) {
         $char = Horde_String::substr($input, $i, 1, 'UTF-8');
         $code = $this->_charToCodePoint($char);
         if ($code < 128) {
             $codePoints['all'][] = $codePoints['basic'][] = $code;
         } else {
             $codePoints['all'][] = $codePoints['nonBasic'][] = $code;
         }
     }
     return $codePoints;
 }
Пример #23
0
 /**
  * Returns a hash with all information necessary to reply to a message.
  *
  * @param mixed $message  The ID of the parent message to reply to, or arry of its data.
  *
  * @return array  A hash with all relevant information.
  * @throws Horde_Exception_NotFound
  * @throws Agora_Exception
  */
 public function replyMessage($message)
 {
     if (!is_array($message)) {
         $message = $this->getMessage($message);
     }
     /* Set up the form subject with the parent subject. */
     if (Horde_String::lower(Horde_String::substr($message['message_subject'], 0, 3)) != 're:') {
         $message['message_subject'] = 'Re: ' . $message['message_subject'];
     }
     /* Prepare the message quite body . */
     $message['body'] = sprintf(_("Posted by %s on %s"), htmlspecialchars($message['message_author']), strftime($GLOBALS['prefs']->getValue('date_format'), $message['message_timestamp'])) . "\n-------------------------------------------------------\n" . $message['body'];
     $message['body'] = "\n> " . Horde_String::wrap($message['body'], 60, "\n> ");
     return $message;
 }
Пример #24
0
 /**
  * Reformats the input string, where the string is 'format=flowed' plain
  * text as described in RFC 2646.
  *
  * @param boolean $toflowed  Convert to flowed?
  * @param boolean $quote     Add level of quoting to each line?
  * @param boolean $wrap      Wrap unquoted lines?
  */
 protected function _reformat($toflowed, $quote, $wrap = true)
 {
     $format_type = implode('|', array($toflowed, $quote));
     if ($format_type == $this->_formattype) {
         return;
     }
     $this->_output = array();
     $this->_formattype = $format_type;
     /* Set variables used in regexps. */
     $delsp = $toflowed && $this->_delsp ? 1 : 0;
     $opt = $this->_optlength - 1 - $delsp;
     /* Process message line by line. */
     $text = preg_split("/\r?\n/", $this->_text);
     $text_count = count($text) - 1;
     $skip = 0;
     reset($text);
     while (list($no, $line) = each($text)) {
         if ($skip) {
             --$skip;
             continue;
         }
         /* Per RFC 2646 [4.3], the 'Usenet Signature Convention' line
          * (DASH DASH SP) is not considered flowed.  Watch for this when
          * dealing with potentially flowed lines. */
         /* The next three steps come from RFC 2646 [4.2]. */
         /* STEP 1: Determine quote level for line. */
         if ($num_quotes = $this->_numquotes($line)) {
             $line = substr($line, $num_quotes);
         }
         /* Only combine lines if we are converting to flowed or if the
          * current line is quoted. */
         if (!$toflowed || $num_quotes) {
             /* STEP 2: Remove space stuffing from line. */
             $line = $this->_unstuff($line);
             /* STEP 3: Should we interpret this line as flowed?
              * While line is flowed (not empty and there is a space
              * at the end of the line), and there is a next line, and the
              * next line has the same quote depth, add to the current
              * line. A line is not flowed if it is a signature line. */
             if ($line != '-- ') {
                 while (!empty($line) && substr($line, -1) == ' ' && $text_count != $no && $this->_numquotes($text[$no + 1]) == $num_quotes) {
                     /* If DelSp is yes and this is flowed input, we need to
                      * remove the trailing space. */
                     if (!$toflowed && $this->_delsp) {
                         $line = substr($line, 0, -1);
                     }
                     $line .= $this->_unstuff(substr($text[++$no], $num_quotes));
                     ++$skip;
                 }
             }
         }
         /* Ensure line is fixed, since we already joined all flowed
          * lines. Remove all trailing ' ' from the line. */
         if ($line != '-- ') {
             $line = rtrim($line);
         }
         /* Increment quote depth if we're quoting. */
         if ($quote) {
             $num_quotes++;
         }
         /* The quote prefix for the line. */
         $quotestr = str_repeat('>', $num_quotes);
         if (empty($line)) {
             /* Line is empty. */
             $this->_output[] = array('text' => $quotestr, 'level' => $num_quotes);
         } elseif (!$wrap && !$num_quotes || empty($this->_maxlength) || Horde_String::length($line, $this->_charset) + $num_quotes <= $this->_maxlength) {
             /* Line does not require rewrapping. */
             $this->_output[] = array('text' => $quotestr . $this->_stuff($line, $num_quotes, $toflowed), 'level' => $num_quotes);
         } else {
             $min = $num_quotes + 1;
             /* Rewrap this paragraph. */
             while ($line) {
                 /* Stuff and re-quote the line. */
                 $line = $quotestr . $this->_stuff($line, $num_quotes, $toflowed);
                 $line_length = Horde_String::length($line, $this->_charset);
                 if ($line_length <= $this->_optlength) {
                     /* Remaining section of line is short enough. */
                     $this->_output[] = array('text' => $line, 'level' => $num_quotes);
                     break;
                 } else {
                     $regex = array();
                     if ($min <= $opt) {
                         $regex[] = '^(.{' . $min . ',' . $opt . '}) (.*)';
                     }
                     if ($min <= $this->_maxlength) {
                         $regex[] = '^(.{' . $min . ',' . $this->_maxlength . '}) (.*)';
                     }
                     $regex[] = '^(.{' . $min . ',})? (.*)';
                     if ($m = Horde_String::regexMatch($line, $regex, $this->_charset)) {
                         /* We need to wrap text at a certain number of
                          * *characters*, not a certain number of *bytes*;
                          * thus the need for a multibyte capable regex.
                          * If a multibyte regex isn't available, we are
                          * stuck with preg_match() (the function will
                          * still work - are just left with shorter rows
                          * than expected if multibyte characters exist in
                          * the row).
                          *
                          * 1. Try to find a string as long as _optlength.
                          * 2. Try to find a string as long as _maxlength.
                          * 3. Take the first word. */
                         if (empty($m[1])) {
                             $m[1] = $m[2];
                             $m[2] = '';
                         }
                         $this->_output[] = array('text' => $m[1] . ' ' . ($delsp ? ' ' : ''), 'level' => $num_quotes);
                         $line = $m[2];
                     } elseif ($line_length > 998) {
                         /* One excessively long word left on line.  Be
                          * absolutely sure it does not exceed 998
                          * characters in length or else we must
                          * truncate. */
                         $this->_output[] = array('text' => Horde_String::substr($line, 0, 998, $this->_charset), 'level' => $num_quotes);
                         $line = Horde_String::substr($line, 998, null, $this->_charset);
                     } else {
                         $this->_output[] = array('text' => $line, 'level' => $num_quotes);
                         break;
                     }
                 }
             }
         }
     }
 }
Пример #25
0
    }
    echo '</tbody>';
}
/* Display all of the files in this directory */
$readmes = array();
if ($fileList) {
    echo '<tbody>';
    foreach ($fileList as $currFile) {
        if ($conf['hide_restricted'] && Chora::isRestricted($currFile->getFileName())) {
            continue;
        }
        $lg = $currFile->getLastLog();
        $realname = $currFile->getFileName();
        $mimeType = Horde_Mime_Magic::filenameToMIME($realname);
        $currFile->mimeType = $mimeType;
        if (Horde_String::lower(Horde_String::substr($realname, 0, 6)) == 'readme') {
            $readmes[] = $currFile;
        }
        $icon = $injector->getInstance('Horde_Core_Factory_MimeViewer')->getIcon($mimeType);
        $author = Chora::showAuthorName($lg->getAuthor());
        $filerev = $lg->getRevision();
        $date = $lg->getDate();
        $log = $lg->getMessage();
        $attic = $currFile->isDeleted();
        $fileName = $where . ($attic ? '/' . 'Attic' : '') . '/' . $realname;
        $name = $injector->getInstance('Horde_Core_Factory_TextFilter')->filter($realname, 'space2html', array('encode' => true, 'encode_all' => true));
        $url = Chora::url('browsefile', $fileName, $branchArgs);
        $readableDate = Chora::readableTime($date);
        if ($log) {
            $shortLog = Horde_String::truncate(str_replace("\n", ' ', trim($log)), $conf['options']['shortLogLength']);
        }
Пример #26
0
 /**
  * Export this event as a MS ActiveSync Message
  *
  * @param array $options  Options:
  *   - protocolversion: (float)  The EAS version to support
  *                      DEFAULT: 2.5
  *   - bodyprefs: (array)  A BODYPREFERENCE array.
  *                DEFAULT: none (No body prefs enforced).
  *   - truncation: (integer)  Truncate event body to this length
  *                 DEFAULT: none (No truncation).
  *
  * @return Horde_ActiveSync_Message_Appointment
  */
 public function toASAppointment(array $options = array())
 {
     global $prefs, $registry;
     // @todo This should be a required option.
     if (empty($options['protocolversion'])) {
         $options['protocolversion'] = 2.5;
     }
     $message = new Horde_ActiveSync_Message_Appointment(array('logger' => $GLOBALS['injector']->getInstance('Horde_Log_Logger'), 'protocolversion' => $options['protocolversion']));
     if (!$this->isPrivate()) {
         // Handle body/truncation
         if (!empty($options['bodyprefs'])) {
             if (Horde_String::length($this->description) > 0) {
                 $bp = $options['bodyprefs'];
                 $note = new Horde_ActiveSync_Message_AirSyncBaseBody();
                 // No HTML supported. Always use plaintext.
                 $note->type = Horde_ActiveSync::BODYPREF_TYPE_PLAIN;
                 if (isset($bp[Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'])) {
                     $truncation = $bp[Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'];
                 } elseif (isset($bp[Horde_ActiveSync::BODYPREF_TYPE_HTML])) {
                     $truncation = $bp[Horde_ActiveSync::BODYPREF_TYPE_HTML]['truncationsize'];
                     $this->description = Horde_Text_Filter::filter($this->description, 'Text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
                 } else {
                     $truncation = false;
                 }
                 if ($truncation && Horde_String::length($this->description) > $truncation) {
                     $note->data = Horde_String::substr($this->description, 0, $truncation);
                     $note->truncated = 1;
                 } else {
                     $note->data = $this->description;
                 }
                 $note->estimateddatasize = Horde_String::length($this->description);
                 $message->airsyncbasebody = $note;
             }
         } else {
             $message->setBody($this->description);
         }
         if ($options['protocolversion'] >= Horde_ActiveSync::VERSION_SIXTEEN && !empty($this->location)) {
             $message->location = new Horde_ActiveSync_Message_AirSyncBaseLocation(array('logger' => $GLOBALS['injector']->getInstance('Horde_Log_Logger'), 'protocolversion' => $options['protocolversion']));
             // @todo - worth it to try to get full city/country etc...
             // from geotagging service if available??
             $message->location->displayname = $this->location;
         } else {
             $message->setLocation($this->location);
         }
     }
     $message->setSubject($this->getTitle());
     $message->alldayevent = $this->isAllDay();
     $st = clone $this->start;
     $et = clone $this->end;
     if ($this->isAllDay()) {
         // EAS requires all day to be from 12:00 to 12:00.
         if ($this->start->hour != 0 || $this->start->min != 0 || $this->start->sec != 0) {
             $st->hour = 0;
             $st->min = 0;
             $st->sec = 0;
         }
         // For end it's a bit trickier. If it's 11:59pm, bump it up to 12:00
         // am of the next day. Otherwise, if it's not 12:00am, make it 12:00
         // am of the same day. This *shouldn't* happen, but protect against
         // issues with EAS just in case.
         if ($this->end->hour != 0 || $this->end->min != 0 || $this->end->sec != 0) {
             if ($this->end->hour == 23 && $this->end->min == 59) {
                 $et->mday++;
             }
             $et->hour = 0;
             $et->min = 0;
             $et->sec = 0;
         }
     }
     $message->starttime = $st;
     $message->endtime = $et;
     $message->setTimezone($this->start);
     // Organizer
     $attendees = $this->attendees;
     $skipOrganizer = null;
     if ($this->organizer) {
         $message->setOrganizer(array('email' => $this->organizer));
     } elseif (count($attendees)) {
         if ($this->creator == $registry->getAuth()) {
             $as_ident = $prefs->getValue('activesync_identity') == 'horde' ? $prefs->getValue('default_identity') : $prefs->getValue('activesync_identity');
             $name = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($this->creator)->getValue('fullname', $as_ident);
             $email = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($this->creator)->getValue('from_addr', $as_ident);
         } else {
             $name = Kronolith::getUserName($this->creator);
             $email = Kronolith::getUserEmail($this->creator);
         }
         $message->setOrganizer(array('name' => $name, 'email' => $email));
         $skipOrganizer = $email;
     }
     // Privacy
     $message->setSensitivity($this->private ? Horde_ActiveSync_Message_Appointment::SENSITIVITY_PRIVATE : Horde_ActiveSync_Message_Appointment::SENSITIVITY_NORMAL);
     // Busy Status
     // This is the *busy* status of the time for this meeting. This is NOT
     // the Kronolith_Event::status or the attendance response for this
     // meeting. Kronolith does not (yet) support sepcifying the busy status
     // of the event time separate from the STATUS_FREE value of the
     // Kronolith_Event::status field, so for now we map these values the
     // best we can by assuming that STATUS_CONFIRMED meetings should always
     // show as BUSYSTATUS_BUSY etc...
     switch ($this->status) {
         case Kronolith::STATUS_CANCELLED:
         case Kronolith::STATUS_FREE:
         case Kronolith::STATUS_NONE:
             $status = Horde_ActiveSync_Message_Appointment::BUSYSTATUS_FREE;
             break;
         case Kronolith::STATUS_CONFIRMED:
             $status = Horde_ActiveSync_Message_Appointment::BUSYSTATUS_BUSY;
             break;
         case Kronolith::STATUS_TENTATIVE:
             $status = Horde_ActiveSync_Message_Appointment::BUSYSTATUS_TENTATIVE;
     }
     $message->setBusyStatus($status);
     // DTStamp
     $message->setDTStamp($_SERVER['REQUEST_TIME']);
     // Recurrence
     if ($this->recurs()) {
         $message->setRecurrence($this->recurrence, $GLOBALS['prefs']->getValue('week_start_monday'));
         /* Exceptions are tricky. Exceptions, even those that represent
          * deleted instances of a recurring event, must be added. To do this
          * we query the storage for all the events that represent exceptions
          * (those with the baseid == $this->uid) and then remove the
          * exceptionoriginaldate from the list of exceptions we know about.
          * Any dates left in this list when we are done, must represent
          * deleted instances of this recurring event.*/
         if (!empty($this->recurrence) && ($exceptions = $this->recurrence->getExceptions())) {
             $results = $this->boundExceptions();
             foreach ($results as $exception) {
                 $e = new Horde_ActiveSync_Message_Exception(array('protocolversion' => $options['protocolversion']));
                 $e->setDateTime(array('start' => $exception->start, 'end' => $exception->end, 'allday' => $exception->isAllDay()));
                 // The start time of the *original* recurring event.
                 // EAS < 16.0 uses 'exceptionstarttime'. Otherwise it's
                 // 'instanceid'.
                 if ($options['protocolversion'] < Horde_ActiveSync::VERSION_SIXTEEN) {
                     $e->setExceptionStartTime($exception->exceptionoriginaldate);
                 } else {
                     $e->instanceid = $exception->exceptionoriginaldate;
                 }
                 $originaldate = $exception->exceptionoriginaldate->format('Ymd');
                 $key = array_search($originaldate, $exceptions);
                 if ($key !== false) {
                     unset($exceptions[$key]);
                 }
                 // Remaining properties that could be different
                 $e->setSubject($exception->getTitle());
                 if (!$exception->isPrivate()) {
                     $e->setLocation($exception->location);
                     $e->setBody($exception->description);
                 }
                 $e->setSensitivity($exception->private ? Horde_ActiveSync_Message_Appointment::SENSITIVITY_PRIVATE : Horde_ActiveSync_Message_Appointment::SENSITIVITY_NORMAL);
                 $e->setReminder($exception->alarm);
                 $e->setDTStamp($_SERVER['REQUEST_TIME']);
                 if ($options['protocolversion'] > Horde_ActiveSync::VERSION_TWELVEONE) {
                     switch ($exception->status) {
                         case Kronolith::STATUS_TENTATIVE:
                             $e->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_TENTATIVE;
                             break;
                         case Kronolith::STATUS_NONE:
                             $e->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_NORESPONSE;
                             break;
                         case Kronolith::STATUS_CONFIRMED:
                             $e->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_ACCEPTED;
                             break;
                         default:
                             $e->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_NONE;
                     }
                 }
                 // Tags/Categories
                 if (!$exception->isPrivate()) {
                     foreach ($exception->tags as $tag) {
                         $e->addCategory($tag);
                     }
                 }
                 $message->addexception($e);
             }
             // Any dates left in $exceptions must be deleted exceptions
             foreach ($exceptions as $deleted) {
                 $e = new Horde_ActiveSync_Message_Exception(array('protocolversion' => $options['protocolversion']));
                 // Kronolith stores the date only, but some AS clients need
                 // the datetime.
                 list($year, $month, $mday) = sscanf($deleted, '%04d%02d%02d');
                 $st = clone $this->start;
                 $st->year = $year;
                 $st->month = $month;
                 $st->mday = $mday;
                 if ($options['protocolversion'] < Horde_ActiveSync::VERSION_SIXTEEN) {
                     $e->setExceptionStartTime($st);
                 } else {
                     $e->instanceid = $st;
                 }
                 $e->deleted = true;
                 $message->addException($e);
             }
         }
     }
     // Attendees
     if (!$this->isPrivate() && count($attendees)) {
         $message->setMeetingStatus($this->status == Kronolith::STATUS_CANCELLED ? Horde_ActiveSync_Message_Appointment::MEETING_CANCELLED : Horde_ActiveSync_Message_Appointment::MEETING_IS_MEETING);
         foreach ($attendees as $attendee) {
             if ($skipOrganizer && $attendee->email == $skipOrganizer) {
                 continue;
             }
             $attendeeAS = new Horde_ActiveSync_Message_Attendee(array('protocolversion' => $options['protocolversion']));
             $attendeeAS->name = $attendee->addressObject->label;
             $attendeeAS->email = $attendee->addressObject->bare_address;
             // AS only has required or optional, and only EAS Version > 2.5
             if ($options['protocolversion'] > Horde_ActiveSync::VERSION_TWOFIVE) {
                 $attendeeAS->type = $attendee->role !== Kronolith::PART_REQUIRED ? Horde_ActiveSync_Message_Attendee::TYPE_OPTIONAL : Horde_ActiveSync_Message_Attendee::TYPE_REQUIRED;
                 switch ($attendee->response) {
                     case Kronolith::RESPONSE_NONE:
                         $attendeeAS->status = Horde_ActiveSync_Message_Attendee::STATUS_NORESPONSE;
                         break;
                     case Kronolith::RESPONSE_ACCEPTED:
                         $attendeeAS->status = Horde_ActiveSync_Message_Attendee::STATUS_ACCEPT;
                         break;
                     case Kronolith::RESPONSE_DECLINED:
                         $attendeeAS->status = Horde_ActiveSync_Message_Attendee::STATUS_DECLINE;
                         break;
                     case Kronolith::RESPONSE_TENTATIVE:
                         $attendeeAS->status = Horde_ActiveSync_Message_Attendee::STATUS_TENTATIVE;
                         break;
                     default:
                         $attendeeAS->status = Horde_ActiveSync_Message_Attendee::STATUS_UNKNOWN;
                 }
             }
             $message->addAttendee($attendeeAS);
         }
     } elseif ($this->status == Kronolith::STATUS_CANCELLED) {
         $message->setMeetingStatus(Horde_ActiveSync_Message_Appointment::MEETING_CANCELLED);
     } else {
         $message->setMeetingStatus(Horde_ActiveSync_Message_Appointment::MEETING_NOT_MEETING);
     }
     // Resources
     if ($options['protocolversion'] > Horde_ActiveSync::VERSION_TWOFIVE) {
         $r = $this->getResources();
         foreach ($r as $id => $data) {
             $resource = Kronolith::getDriver('Resource')->getResource($id);
             // EAS *REQUIRES* an email field for Resources. If it is missing
             // a number of clients will fail, losing push.
             if ($resource->get('email')) {
                 $attendeeAS = new Horde_ActiveSync_Message_Attendee(array('protocolversion' => $options['protocolversion']));
                 $attendeeAS->email = $resource->get('email');
                 $attendeeAS->type = Horde_ActiveSync_Message_Attendee::TYPE_RESOURCE;
                 $attendeeAS->name = $data['name'];
                 $attendeeAS->status = $data['response'];
                 $message->addAttendee($attendeeAS);
             }
         }
     }
     // Reminder
     if ($this->alarm) {
         $message->setReminder($this->alarm);
     }
     // Categories (tags)
     if (!$this->isPrivate()) {
         foreach ($this->tags as $tag) {
             $message->addCategory($tag);
         }
     }
     // EAS 14, and only if it is a meeting.
     if ($options['protocolversion'] > Horde_ActiveSync::VERSION_TWELVEONE && $message->getMeetingStatus() == Horde_ActiveSync_Message_Appointment::MEETING_IS_MEETING) {
         // Are we the
         if (empty($this->organizer) && $this->creator == $registry->getAuth()) {
             $message->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_ORGANIZER;
         }
         // We don't track the actual responses we sent to other's invitations.
         // Set this based on the status flag.
         switch ($this->status) {
             case Kronolith::STATUS_TENTATIVE:
                 $message->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_TENTATIVE;
                 break;
             case Kronolith::STATUS_NONE:
                 $message->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_NORESPONSE;
                 break;
             case Kronolith::STATUS_CONFIRMED:
                 $message->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_ACCEPTED;
                 break;
             default:
                 $message->responsetype = Horde_ActiveSync_Message_Appointment::RESPONSE_NONE;
         }
     }
     // 14.1
     if ($options['protocolversion'] >= Horde_ActiveSync::VERSION_FOURTEENONE) {
         $message->onlinemeetingexternallink = $this->url;
     }
     // 16.0
     if ($options['protocolversion'] >= Horde_ActiveSync::VERSION_SIXTEEN) {
         $files = $this->listFiles();
         if (count($files)) {
             foreach ($files as $file) {
                 $atc = new Horde_ActiveSync_Message_AirSyncBaseAttachment(array('logger' => $GLOBALS['injector']->getInstance('Horde_Log_Logger'), 'protocolversion' => $options['protocolversion']));
                 $atc->displayname = $file['name'];
                 $atc->attname = $this->_getEASFileReference($file['name']);
                 $atc->attmethod = Horde_ActiveSync_Message_AirSyncBaseAttachment::ATT_TYPE_NORMAL;
                 $atc->attsize = $file['size'];
                 $message->addAttachment($atc);
             }
         }
     }
     return $message;
 }