/** * Returns a hash representing this calendar. * * @return array A simple hash. */ public function toHash() { global $calendar_manager, $conf, $injector, $registry; $owner = $registry->getAuth() && $this->_share->get('owner') == $registry->getAuth(); $hash = parent::toHash(); $hash['name'] = Kronolith::getLabel($this->_share); $hash['desc'] = (string) $this->_share->get('desc'); $hash['owner'] = $owner; $hash['users'] = Kronolith::listShareUsers($this->_share); $hash['fg'] = Kronolith::foregroundColor($this->_share); $hash['bg'] = Kronolith::backgroundColor($this->_share); $hash['show'] = in_array('tasks/' . $this->_share->getName(), $calendar_manager->get(Kronolith::DISPLAY_EXTERNAL_CALENDARS)); $hash['edit'] = $this->_share->hasPermission($registry->getAuth(), Horde_Perms::EDIT); $hash['caldav'] = $this->caldavUrl(); $hash['sub'] = Horde::url($registry->get('webroot', 'horde') . ($conf['urls']['pretty'] == 'rewrite' ? '/rpc/nag/' : '/rpc.php/nag/'), true, -1) . ($this->_share->get('owner') ? $registry->convertUsername($this->_share->get('owner'), false) : '-system-') . '/' . $this->_share->getName() . '.ics'; if ($owner) { $hash['perms'] = Kronolith::permissionToJson($this->_share->getPermission(), is_null($this->_share->get('owner'))); } return $hash; }
$owner = $GLOBALS['registry']->getAuth() && $calendar->owner() == $GLOBALS['registry']->getAuth(); if ($my && $owner || !$my && !$owner) { $code['conf']['calendars']['internal'][$id] = array('name' => ($owner || !$calendar->owner() ? '' : '[' . $GLOBALS['registry']->convertUsername($calendar->owner(), false) . '] ') . $calendar->name(), 'desc' => $calendar->description(), 'owner' => $owner, 'fg' => $calendar->foreground(), 'bg' => $calendar->background(), 'show' => in_array($id, $GLOBALS['calendar_manager']->get(Kronolith::DISPLAY_CALENDARS)), 'edit' => $calendar->hasPermission(Horde_Perms::EDIT), 'feed' => (string) Kronolith::feedUrl($id), 'embed' => Kronolith::embedCode($id)); if ($owner) { $code['conf']['calendars']['internal'][$id]['perms'] = Kronolith::permissionToJson($calendar->share()->getPermission()); } } } // Tasklists if (!$has_tasks) { continue; } foreach ($registry->tasks->listTasklists($my, Horde_Perms::SHOW) as $id => $tasklist) { $owner = $GLOBALS['registry']->getAuth() && $tasklist->get('owner') == $GLOBALS['registry']->getAuth(); if ($my && $owner || !$my && !$owner) { $code['conf']['calendars']['tasklists']['tasks/' . $id] = array('name' => Kronolith::getLabel($tasklist), 'desc' => $tasklist->get('desc'), 'owner' => $owner, 'fg' => Kronolith::foregroundColor($tasklist), 'bg' => Kronolith::backgroundColor($tasklist), 'show' => in_array('tasks/' . $id, $GLOBALS['calendar_manager']->get(Kronolith::DISPLAY_EXTERNAL_CALENDARS)), 'edit' => $tasklist->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::EDIT)); if ($owner) { $code['conf']['calendars']['tasklists']['tasks/' . $id]['perms'] = Kronolith::permissionToJson($tasklist->getPermission()); } } } } // Timeobjects foreach ($GLOBALS['calendar_manager']->get(Kronolith::ALL_EXTERNAL_CALENDARS) as $id => $calendar) { if ($calendar->api() == 'tasks') { continue; } if (!$calendar->display()) { continue; } $code['conf']['calendars']['external'][$id] = array('name' => $calendar->name(), 'fg' => $calendar->foreground(), 'bg' => $calendar->background(), 'api' => $registry->get('name', $registry->hasInterface($calendar->api())), 'show' => in_array($id, $GLOBALS['calendar_manager']->get(Kronolith::DISPLAY_EXTERNAL_CALENDARS)));
} if (!$haveDefault) { $sync[] = $default; $GLOBALS['prefs']->setValue('sync_calendars', serialize($sync)); } }); // Calendars use for synchronization $_prefs['sync_calendars'] = array('value' => 'a:0:{}', 'type' => 'multienum', 'enum' => array(), 'desc' => _("Select the calendars that, in addition to the default, should be used for synchronization with external devices:"), 'on_init' => function ($ui) { $enum = array(); $sync = @unserialize($GLOBALS['prefs']->getValue('sync_calendars')); if (empty($sync)) { $GLOBALS['prefs']->setValue('sync_calendars', serialize(array(Kronolith::getDefaultCalendar(Horde_Perms::EDIT)))); } foreach (Kronolith::listInternalCalendars(false, Horde_Perms::DELETE) as $key => $cal) { if ($cal->getName() != Kronolith::getDefaultCalendar(Horde_Perms::DELETE)) { $enum[$key] = Kronolith::getLabel($cal); } } $ui->prefs['sync_calendars']['enum'] = $enum; }, 'on_change' => function () { $sync = @unserialize($GLOBALS['prefs']->getValue('sync_calendars')); $haveDefault = false; $default = Kronolith::getDefaultCalendar(Horde_Perms::DELETE); foreach ($sync as $cid) { if ($cid == $default) { $haveDefault = true; break; } } if (!$haveDefault) { $sync[] = $default;
/** * Browse through Kronolith's object tree. * * @param string $path The level of the tree to browse. * @param array $properties The item properties to return. Defaults to 'name', * 'icon', and 'browseable'. * * @return array The contents of $path * @throws Kronolith_Exception */ public function browse($path = '', $properties = array()) { global $injector, $registry; // Default properties. if (!$properties) { $properties = array('name', 'icon', 'browseable'); } if (substr($path, 0, 9) == 'kronolith') { $path = substr($path, 9); } $path = trim($path, '/'); $parts = explode('/', $path); $currentUser = $registry->getAuth(); if (empty($path)) { // This request is for a list of all users who have calendars // visible to the requesting user. $calendars = Kronolith::listInternalCalendars(false, Horde_Perms::READ); $owners = array(); foreach ($calendars as $calendar) { $owners[$calendar->get('owner') ? $calendar->get('owner') : '-system-'] = true; } $results = array(); foreach (array_keys($owners) as $owner) { $path = 'kronolith/' . $registry->convertUsername($owner, false); if (in_array('name', $properties)) { $results[$path]['name'] = $injector->getInstance('Horde_Core_Factory_Identity')->create($owner)->getName(); } if (in_array('icon', $properties)) { $results[$path]['icon'] = Horde_Themes::img('user.png'); } if (in_array('browseable', $properties)) { $results[$path]['browseable'] = true; } if (in_array('read-only', $properties)) { $results[$path]['read-only'] = true; } } return $results; } elseif (count($parts) == 1) { // This request is for all calendars owned by the requested user $owner = $parts[0] == '-system-' ? '' : $registry->convertUsername($parts[0], true); $calendars = $injector->getInstance('Kronolith_Shares')->listShares($currentUser, array('perm' => Horde_Perms::SHOW, 'attributes' => $owner)); $results = array(); foreach ($calendars as $calendarId => $calendar) { if ($parts[0] == '-system-' && $calendar->get('owner')) { continue; } $retpath = 'kronolith/' . $parts[0] . '/' . $calendarId; if (in_array('name', $properties)) { $results[$retpath]['name'] = sprintf(_("Events from %s"), Kronolith::getLabel($calendar)); $results[$retpath . '.ics']['name'] = Kronolith::getLabel($calendar); } if (in_array('displayname', $properties)) { $results[$retpath]['displayname'] = Kronolith::getLabel($calendar); $results[$retpath . '.ics']['displayname'] = Kronolith::getLabel($calendar) . '.ics'; } if (in_array('owner', $properties)) { $results[$retpath]['owner'] = $results[$retpath . '.ics']['owner'] = $calendar->get('owner') ? $registry->convertUsername($calendar->get('owner'), false) : '-system-'; } if (in_array('icon', $properties)) { $results[$retpath]['icon'] = Horde_Themes::img('kronolith.png'); $results[$retpath . '.ics']['icon'] = Horde_Themes::img('mime/icalendar.png'); } if (in_array('browseable', $properties)) { $results[$retpath]['browseable'] = $calendar->hasPermission($currentUser, Horde_Perms::READ); $results[$retpath . '.ics']['browseable'] = false; } if (in_array('read-only', $properties)) { $results[$retpath]['read-only'] = $results[$retpath . '.ics']['read-only'] = !$calendar->hasPermission($currentUser, Horde_Perms::EDIT); } if (in_array('contenttype', $properties)) { $results[$retpath . '.ics']['contenttype'] = 'text/calendar'; } } return $results; } elseif (count($parts) == 2 && array_key_exists($parts[1], Kronolith::listInternalCalendars(false, Horde_Perms::READ))) { // This request is browsing into a specific calendar. Generate // the list of items and represent them as files within the // directory. try { $calendar = $injector->getInstance('Kronolith_Shares')->getShare($parts[1]); } catch (Horde_Exception_NotFound $e) { throw new Kronolith_Exception(_("Invalid calendar requested."), 404); } catch (Horde_Share_Exception $e) { throw new Kronolith_Exception($e->getMessage, 500); } $kronolith_driver = Kronolith::getDriver(null, $parts[1]); $events = $kronolith_driver->listEvents(); $icon = Horde_Themes::img('mime/icalendar.png'); $owner = $calendar->get('owner') ? $registry->convertUsername($calendar->get('owner'), false) : '-system-'; $dav = $injector->getInstance('Horde_Dav_Storage'); $results = array(); foreach ($events as $dayevents) { foreach ($dayevents as $event) { $id = $event->id; try { $id = $dav->getExternalObjectId($id, $parts[1]) ?: $id; } catch (Horde_Dav_Exception $e) { } $key = 'kronolith/' . $path . '/' . $id; if (in_array('modified', $properties) || in_array('etag', $properties)) { $modified = $this->modified($event->uid, $parts[1]); } if (in_array('name', $properties)) { $results[$key]['name'] = $event->getTitle(); } if (in_array('owner', $properties)) { $results[$key]['owner'] = $owner; } if (in_array('icon', $properties)) { $results[$key]['icon'] = $icon; } if (in_array('browseable', $properties)) { $results[$key]['browseable'] = false; } if (in_array('read-only', $properties)) { $results[$key]['read-only'] = !$calendar->hasPermission($currentUser, Horde_Perms::EDIT); } if (in_array('contenttype', $properties)) { $results[$key]['contenttype'] = 'text/calendar'; } if (in_array('modified', $properties)) { $results[$key]['modified'] = $modified; } if (in_array('created', $properties)) { $results[$key]['created'] = $this->getActionTimestamp($event->uid, 'add'); } if (in_array('etag', $properties)) { $results[$key]['etag'] = '"' . md5($event->id . '|' . $modified) . '"'; } } } return $results; } else { // The only valid request left is for either a specific event or // for the entire calendar. if (count($parts) == 3 && array_key_exists($parts[1], Kronolith::listInternalCalendars(false, Horde_Perms::READ))) { // This request is for a specific item within a given calendar. $dav = $injector->getInstance('Horde_Dav_Storage'); $object = $parts[2]; try { $object = $dav->getInternalObjectId($object, $parts[1]) ?: $object; } catch (Horde_Dav_Exception $e) { } $event = Kronolith::getDriver(null, $parts[1])->getEvent($object); $result = array('data' => $this->export($event->uid, 'text/calendar'), 'mimetype' => 'text/calendar'); $modified = $this->modified($event->uid, $parts[1]); if (!empty($modified)) { $result['mtime'] = $modified; } return $result; } elseif (count($parts) == 2 && substr($parts[1], -4, 4) == '.ics' && array_key_exists(substr($parts[1], 0, -4), Kronolith::listInternalCalendars(false, Horde_Perms::READ))) { // This request is for an entire calendar (calendar.ics). $ical_data = $this->exportCalendar(substr($parts[1], 0, -4), 'text/calendar'); return array('data' => $ical_data, 'mimetype' => 'text/calendar', 'contentlength' => strlen($ical_data), 'mtime' => $_SERVER['REQUEST_TIME']); } else { // All other requests are a 404: Not Found return false; } } }
$event->initialized = true; if (Horde_Util::getFormData('actionID') == 'search_calendar') { $event->readForm(); if (Horde_Util::getFormData('status') == Kronolith::STATUS_NONE) { $event->status = null; } $events = Kronolith::search($event, $search_calendar[1] == '__any' ? null : $search_calendar[0] . '|' . $search_calendar[1]); } $optgroup = $GLOBALS['browser']->hasFeature('optgroup'); $current_user = $GLOBALS['registry']->getAuth(); $calendars = array(); foreach (Kronolith::listInternalCalendars(false, Horde_Perms::READ) as $id => $cal) { if ($cal->get('owner') && $cal->get('owner') == $current_user) { $calendars[_("My Calendars:")]['|' . $id] = $cal->get('name'); } else { $calendars[_("Shared Calendars:")]['|' . $id] = Kronolith::getLabel($cal); } } foreach ($GLOBALS['calendar_manager']->get(Kronolith::ALL_EXTERNAL_CALENDARS) as $id => $cal) { $app = $GLOBALS['registry']->get('name', $GLOBALS['registry']->hasInterface($cal->api())); if (!$cal->display()) { continue; } $calendars[$app . ':']['Horde|external_' . $id] = $cal->name(); } foreach ($GLOBALS['calendar_manager']->get(Kronolith::ALL_REMOTE_CALENDARS) as $id => $cal) { $calendars[_("Remote Calendars:")]['Ical|' . $id] = $cal->name(); } foreach ($GLOBALS['calendar_manager']->get(Kronolith::ALL_HOLIDAYS) as $id => $holiday) { $calendars[_("Holidays:")]['Holidays|' . $id] = $holiday->name(); }
/** * Returns the name of this calendar. * * @return string This calendar's name. */ public function name() { return Kronolith::getLabel($this->_share); }
/** */ public function davGetCollections($user) { global $calendar_manager, $injector, $registry; $hordeUser = $user; try { $hordeUser = $injector->getInstance('Horde_Core_Hooks')->callHook('davusername', 'horde', array($hordeUser, true)); } catch (Horde_Exception_HookNotSet $e) { } $hordeUser = $registry->convertUsername($hordeUser, true); $shares = $injector->getInstance('Kronolith_Shares')->listShares($hordeUser); $dav = $injector->getInstance('Horde_Dav_Storage'); $calendars = array(); foreach ($shares as $id => $share) { if ($user == '-system-' && $share->get('owner')) { continue; } $calendar = $calendar_manager->getEntry(Kronolith::ALL_CALENDARS, $id)->toHash(); try { $id = $dav->getExternalCollectionId($id, 'calendar'); } catch (Horde_Dav_Exception $e) { } $calendars[] = array('id' => $id, 'uri' => $id, '{' . CalDAV\Plugin::NS_CALENDARSERVER . '}shared-url' => $calendar['caldav'], 'principaluri' => 'principals/' . $user, '{http://sabredav.org/ns}owner-principal' => 'principals/' . ($share->get('owner') ? $registry->convertUsername($share->get('owner'), false) : '-system-'), '{DAV:}displayname' => Kronolith::getLabel($share), '{' . CalDAV\Plugin::NS_CALDAV . '}calendar-description' => $share->get('desc'), '{http://apple.com/ns/ical/}calendar-color' => $share->get('color') . 'ff', '{' . CalDAV\Plugin::NS_CALDAV . '}supported-calendar-component-set' => new CalDAV\Property\SupportedCalendarComponentSet(array('VEVENT')), '{http://sabredav.org/ns}read-only' => !$share->hasPermission($hordeUser, Horde_Perms::EDIT)); } return $calendars; }
/** * Sends email notifications that a event has been added, edited, or * deleted to users that want such notifications. * * @param Kronolith_Event $event An event. * @param string $action The event action. One of "add", "edit", * or "delete". * * @throws Horde_Mime_Exception * @throws Kronolith_Exception */ public static function sendNotification($event, $action) { global $injector, $prefs, $registry; if (!in_array($action, array('add', 'edit', 'delete'))) { throw new Kronolith_Exception('Unknown event action: ' . $action); } // @TODO: Send notifications to the email addresses stored in the // resource object? if ($event->calendarType == 'resource') { return; } $groups = $injector->getInstance('Horde_Group'); $calendar = $event->calendar; $recipients = array(); try { $share = $injector->getInstance('Kronolith_Shares')->getShare($calendar); } catch (Horde_Share_Exception $e) { throw new Kronolith_Exception($e); } $owner = $share->get('owner'); if ($owner) { $recipients[$owner] = self::_notificationPref($owner, 'owner'); } $senderIdentity = $injector->getInstance('Horde_Core_Factory_Identity')->create($event->creator ?: $owner); foreach ($share->listUsers(Horde_Perms::READ) as $user) { if (empty($recipients[$user])) { $recipients[$user] = self::_notificationPref($user, 'read', $calendar); } } foreach ($share->listGroups(Horde_Perms::READ) as $group) { try { $group_users = $groups->listUsers($group); } catch (Horde_Group_Exception $e) { Horde::log($e, 'ERR'); continue; } foreach ($group_users as $user) { if (empty($recipients[$user])) { $recipients[$user] = self::_notificationPref($user, 'read', $calendar); } } } $addresses = array(); foreach ($recipients as $user => $vals) { if (!$vals) { continue; } $identity = $injector->getInstance('Horde_Core_Factory_Identity')->create($user); $email = $identity->getValue('from_addr'); if (strpos($email, '@') === false) { continue; } if (!isset($addresses[$vals['lang']][$vals['tf']][$vals['df']])) { $addresses[$vals['lang']][$vals['tf']][$vals['df']] = array(); } $tmp = new Horde_Mail_Rfc822_Address($email); $tmp->personal = $identity->getValue('fullname'); $addresses[$vals['lang']][$vals['tf']][$vals['df']][] = strval($tmp); } if (!$addresses) { return; } $image = self::getImagePart('big_new.png'); $view = new Horde_View(array('templatePath' => KRONOLITH_TEMPLATES . '/update')); $view->event = $event; $view->calendar = Kronolith::getLabel($share); $view->imageId = $image->getContentId(); if (!$prefs->isLocked('event_notification')) { $view->prefsUrl = Horde::url($registry->getServiceLink('prefs', 'kronolith'), true)->remove(session_name()); } new Horde_View_Helper_Text($view); foreach ($addresses as $lang => $twentyFour) { $registry->setLanguageEnvironment($lang); switch ($action) { case 'add': $subject = _("Event added:"); break; case 'edit': $subject = _("Event edited:"); break; case 'delete': $subject = _("Event deleted:"); break; } foreach ($twentyFour as $tf => $dateFormat) { foreach ($dateFormat as $df => $df_recipients) { $view->header = $subject . ' ' . $event->title; $mail = new Horde_Mime_Mail(array('Subject' => $view->header, 'To' => implode(',', $df_recipients), 'From' => $senderIdentity->getDefaultFromAddress(true), 'User-Agent' => 'Kronolith ' . $registry->getVersion())); $multipart = self::buildMimeMessage($view, 'notification', $image); $mail->setBasePart($multipart); Horde::log(sprintf('Sending event notifications for %s to %s', $event->title, implode(', ', $df_recipients)), 'DEBUG'); $mail->send($injector->getInstance('Horde_Mail')); } } } }
/** * Sends email notifications that a event has been added, edited, or * deleted to users that want such notifications. * * @param Kronolith_Event $event An event. * @param string $action The event action. One of "add", "edit", * or "delete". * * @throws Horde_Mime_Exception * @throws Kronolith_Exception */ public static function sendNotification($event, $action) { global $injector, $registry; if (!in_array($action, array('add', 'edit', 'delete'))) { throw new Kronolith_Exception('Unknown event action: ' . $action); } // @TODO: Send notifications to the email addresses stored in the // resource object? if ($event->calendarType == 'resource') { return; } $groups = $injector->getInstance('Horde_Group'); $calendar = $event->calendar; $recipients = array(); try { $share = $injector->getInstance('Kronolith_Shares')->getShare($calendar); } catch (Horde_Share_Exception $e) { throw new Kronolith_Exception($e); } $owner = $share->get('owner'); if ($owner) { $recipients[$owner] = self::_notificationPref($owner, 'owner'); } $senderIdentity = $injector->getInstance('Horde_Core_Factory_Identity')->create($event->creator ?: $owner); foreach ($share->listUsers(Horde_Perms::READ) as $user) { if (!isset($recipients[$user])) { $recipients[$user] = self::_notificationPref($user, 'read', $calendar); } } foreach ($share->listGroups(Horde_Perms::READ) as $group) { try { $group_users = $groups->listUsers($group); } catch (Horde_Group_Exception $e) { Horde::log($e, 'ERR'); continue; } foreach ($group_users as $user) { if (!isset($recipients[$user])) { $recipients[$user] = self::_notificationPref($user, 'read', $calendar); } } } $addresses = array(); foreach ($recipients as $user => $vals) { if (!$vals) { continue; } $identity = $injector->getInstance('Horde_Core_Factory_Identity')->create($user); $email = $identity->getValue('from_addr'); if (strpos($email, '@') === false) { continue; } if (!isset($addresses[$vals['lang']][$vals['tf']][$vals['df']])) { $addresses[$vals['lang']][$vals['tf']][$vals['df']] = array(); } $tmp = new Horde_Mail_Rfc822_Address($email); $tmp->personal = $identity->getValue('fullname'); $addresses[$vals['lang']][$vals['tf']][$vals['df']][] = strval($tmp); } if (!$addresses) { return; } foreach ($addresses as $lang => $twentyFour) { $registry->setLanguageEnvironment($lang); switch ($action) { case 'add': $subject = _("Event added:"); $notification_message = _("You requested to be notified when events are added to your calendars.") . "\n\n" . _("The event \"%s\" has been added to \"%s\" calendar, which is on %s at %s."); break; case 'edit': $subject = _("Event edited:"); $notification_message = _("You requested to be notified when events are edited in your calendars.") . "\n\n" . _("The event \"%s\" has been edited on \"%s\" calendar, which is on %s at %s."); break; case 'delete': $subject = _("Event deleted:"); $notification_message = _("You requested to be notified when events are deleted from your calendars.") . "\n\n" . _("The event \"%s\" has been deleted from \"%s\" calendar, which was on %s at %s."); break; } foreach ($twentyFour as $tf => $dateFormat) { foreach ($dateFormat as $df => $df_recipients) { $message = "\n" . sprintf($notification_message, $event->title, Kronolith::getLabel($share), $event->start->strftime($df), $event->start->strftime($tf ? '%R' : '%I:%M%p')) . "\n\n" . $event->description; $mime_mail = new Horde_Mime_Mail(array('Subject' => $subject . ' ' . $event->title, 'To' => implode(',', $df_recipients), 'From' => $senderIdentity->getDefaultFromAddress(true), 'User-Agent' => 'Kronolith ' . $registry->getVersion(), 'body' => $message)); Horde::log(sprintf('Sending event notifications for %s to %s', $event->title, implode(', ', $df_recipients)), 'DEBUG'); $mime_mail->send($injector->getInstance('Horde_Mail')); } } } }
public function html() { global $prefs; $sidebyside = $prefs->getValue('show_shared_side_by_side'); $twentyFour = $prefs->getValue('twentyFour'); $addLinks = Kronolith::getDefaultCalendar(Horde_Perms::EDIT) && ($GLOBALS['injector']->getInstance('Horde_Core_Perms')->hasAppPermission('max_events') === true || $GLOBALS['injector']->getInstance('Horde_Core_Perms')->hasAppPermission('max_events') > Kronolith::countEvents()); if ($sidebyside) { require KRONOLITH_TEMPLATES . '/month/head_side_by_side.inc'; } else { require KRONOLITH_TEMPLATES . '/month/head.inc'; } $html = ''; if (!$sidebyside && count($this->_currentCalendars)) { $html .= '<tr>'; } $showLocation = Kronolith::viewShowLocation(); $showTime = Kronolith::viewShowTime(); $day_url = Horde::url('day.php'); $this_link = $this->link(0, true); $new_url = Horde::url('new.php')->add('url', $this_link); $new_img = Horde::img('new_small.png', '+'); foreach ($this->_currentCalendars as $id => $cal) { if ($sidebyside) { $html .= '<tr>'; } $cell = 0; for ($day = $this->_startOfView; $day < $this->_startOfView + $this->_daysInView; ++$day) { $date = new Kronolith_Day($this->month, $day, $this->year); $date->hour = $twentyFour ? 12 : 6; $week = $date->weekOfYear(); if ($cell % 7 == 0) { $weeklink = Horde::url('week.php')->add('date', $date->dateString())->link(array('class' => 'kronolith-weeklink')) . ($sidebyside ? sprintf(_("Week %d"), $week) : $week) . '</a>'; if ($sidebyside) { $html .= sprintf('<td class="kronolith-first-col">%s<br />%s</td>', $weeklink, htmlspecialchars(Kronolith::getLabel($cal))); } else { if ($cell != 0) { $html .= "</tr>\n<tr>"; } $html .= '<td class="kronolith-first-col">' . $weeklink . '</td>'; } } if ($date->isToday()) { $style = ' class="kronolith-today"'; } elseif ($date->month != $this->month) { $style = ' class="kronolith-other-month"'; } elseif ($date->dayOfWeek() == 0 || $date->dayOfWeek() == 6) { $style = ' class="kronolith-weekend"'; } else { $style = ''; } $html .= '<td' . $style . '><div class="kronolith-day">'; $html .= $day_url->add('date', $date->dateString())->link() . $date->mday . '</a>'; if ($addLinks) { $new_url->add('date', $date->dateString()); if ($sidebyside) { $new_url->add('calendar', $id); } $html .= $new_url->link(array('title' => _("Create a New Event"), 'class' => 'newEvent')) . $new_img . '</a>'; } $html .= '</div>'; $date_stamp = $date->dateString(); if (!empty($this->_events[$date_stamp])) { foreach ($this->_events[$date_stamp] as $event) { if (!$sidebyside || $event->calendar == $id) { $html .= '<div class="kronolith-event"' . $event->getCSSColors() . '>'; if ($showTime && !$event->isAllDay()) { $html .= '<span class="kronolith-time">' . htmlspecialchars($event->getTimeRange()) . '</span>'; } $html .= $event->getLink($date, true, $this_link); if (!$event->isPrivate() && $showLocation) { $html .= '<span class="kronolith-location">' . htmlspecialchars($event->getLocation()) . '</span>'; } $html .= '</div>'; } } } $html .= "</td>\n"; ++$cell; } if ($sidebyside) { $html .= '</tr>'; } } if (!$sidebyside && count($this->_currentCalendars)) { $html .= '</tr>'; } echo $html . '</tbody></table>'; }
/** * Browse through Kronolith's object tree. * * @param string $path The level of the tree to browse. * @param array $properties The item properties to return. Defaults to 'name', * 'icon', and 'browseable'. * * @return array The contents of $path * @throws Kronolith_Exception */ public function browse($path = '', $properties = array()) { // Default properties. if (!$properties) { $properties = array('name', 'icon', 'browseable'); } if (substr($path, 0, 9) == 'kronolith') { $path = substr($path, 9); } $path = trim($path, '/'); $parts = explode('/', $path); if (empty($path)) { // This request is for a list of all users who have calendars // visible to the requesting user. $calendars = Kronolith::listInternalCalendars(false, Horde_Perms::READ); $owners = array(); foreach ($calendars as $calendar) { $owners[$calendar->get('owner') ? $calendar->get('owner') : '-system-'] = true; } $results = array(); foreach (array_keys($owners) as $owner) { $path = 'kronolith/' . $owner; if (in_array('name', $properties)) { $results[$path]['name'] = $owner; } if (in_array('icon', $properties)) { $results[$path]['icon'] = Horde_Themes::img('user.png'); } if (in_array('browseable', $properties)) { $results[$path]['browseable'] = true; } if (in_array('contenttype', $properties)) { $results[$path]['contenttype'] = 'httpd/unix-directory'; } if (in_array('contentlength', $properties)) { $results[$path]['contentlength'] = 0; } if (in_array('modified', $properties)) { $results[$path]['modified'] = $_SERVER['REQUEST_TIME']; } if (in_array('created', $properties)) { $results[$path]['created'] = 0; } // CalDAV Properties from RFC 4791 and // draft-desruisseaux-caldav-sched-03 $caldavns = 'urn:ietf:params:xml:ns:caldav'; $kronolith_rpc_base = $GLOBALS['registry']->get('webroot', 'horde') . '/rpc/kronolith/'; if (in_array($caldavns . ':calendar-home-set', $properties)) { $results[$path][$caldavns . ':calendar-home-set'] = Horde::url($kronolith_rpc_base . urlencode($owner), true); } if (in_array($caldavns . ':calendar-user-address-set', $properties)) { // FIXME: Add the calendar owner's email address from // their Horde Identity } } return $results; } elseif (count($parts) == 1) { // This request is for all calendars owned by the requested user $owner = $parts[0] == '-system-' ? '' : $parts[0]; $calendars = $GLOBALS['injector']->getInstance('Kronolith_Shares')->listShares($GLOBALS['registry']->getAuth(), array('perm' => Horde_Perms::SHOW, 'attributes' => $owner)); $results = array(); foreach ($calendars as $calendarId => $calendar) { if ($parts[0] == '-system-' && $calendar->get('owner')) { continue; } $retpath = 'kronolith/' . $parts[0] . '/' . $calendarId; if (in_array('name', $properties)) { $results[$retpath]['name'] = sprintf(_("Events from %s"), Kronolith::getLabel($calendar)); $results[$retpath . '.ics']['name'] = Kronolith::getLabel($calendar); } if (in_array('displayname', $properties)) { $results[$retpath]['displayname'] = rawurlencode(Kronolith::getLabel($calendar)); $results[$retpath . '.ics']['displayname'] = rawurlencode(Kronolith::getLabel($calendar)) . '.ics'; } if (in_array('icon', $properties)) { $results[$retpath]['icon'] = Horde_Themes::img('kronolith.png'); $results[$retpath . '.ics']['icon'] = Horde_Themes::img('mime/icalendar.png'); } if (in_array('browseable', $properties)) { $results[$retpath]['browseable'] = $calendar->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::READ); $results[$retpath . '.ics']['browseable'] = false; } if (in_array('contenttype', $properties)) { $results[$retpath]['contenttype'] = 'httpd/unix-directory'; $results[$retpath . '.ics']['contenttype'] = 'text/calendar'; } if (in_array('contentlength', $properties)) { $results[$retpath]['contentlength'] = 0; // FIXME: This is a hack. If the content length is longer // than the actual data then some WebDAV clients will // report an error when the file EOF is received. Ideally // we should determine the actual size of the .ics and // report it here, but the performance hit may be // prohibitive. This requires further investigation. $results[$retpath . '.ics']['contentlength'] = 1; } if (in_array('modified', $properties)) { $results[$retpath]['modified'] = $_SERVER['REQUEST_TIME']; $results[$retpath . '.ics']['modified'] = $_SERVER['REQUEST_TIME']; } if (in_array('created', $properties)) { $results[$retpath]['created'] = 0; $results[$retpath . '.ics']['created'] = 0; } } return $results; } elseif (count($parts) == 2 && array_key_exists($parts[1], Kronolith::listInternalCalendars(false, Horde_Perms::READ))) { // This request is browsing into a specific calendar. Generate // the list of items and represent them as files within the // directory. $kronolith_driver = Kronolith::getDriver(null, $parts[1]); $events = $kronolith_driver->listEvents(); $icon = Horde_Themes::img('mime/icalendar.png'); $results = array(); foreach ($events as $dayevents) { foreach ($dayevents as $event) { $key = 'kronolith/' . $path . '/' . $event->id; if (in_array('modified', $properties) || in_array('etag', $properties)) { $modified = $this->modified($event->uid); } if (in_array('name', $properties)) { $results[$key]['name'] = $event->getTitle(); } if (in_array('icon', $properties)) { $results[$key]['icon'] = $icon; } if (in_array('browseable', $properties)) { $results[$key]['browseable'] = false; } if (in_array('contenttype', $properties)) { $results[$key]['contenttype'] = 'text/calendar'; } if (in_array('contentlength', $properties)) { // FIXME: This is a hack. If the content length is // longer than the actual data then some WebDAV // clients will report an error when the file EOF is // received. Ideally we should determine the actual // size of the data and report it here, but the // performance hit may be prohibitive. This requires // further investigation. $results[$key]['contentlength'] = 1; } if (in_array('modified', $properties)) { $results[$key]['modified'] = $modified; } if (in_array('created', $properties)) { $results[$key]['created'] = $this->getActionTimestamp($event->uid, 'add'); } if (in_array('etag', $properties)) { $results[$key]['etag'] = '"' . md5($event->id . '|' . $modified) . '"'; } } } return $results; } else { // The only valid request left is for either a specific event or // for the entire calendar. if (count($parts) == 3 && array_key_exists($parts[1], Kronolith::listInternalCalendars(false, Horde_Perms::READ))) { // This request is for a specific item within a given calendar. $event = Kronolith::getDriver(null, $parts[1])->getEvent($parts[2]); $result = array('data' => $this->export($event->uid, 'text/calendar'), 'mimetype' => 'text/calendar'); $modified = $this->modified($event->uid); if (!empty($modified)) { $result['mtime'] = $modified; } return $result; } elseif (count($parts) == 2 && substr($parts[1], -4, 4) == '.ics' && array_key_exists(substr($parts[1], 0, -4), Kronolith::listInternalCalendars(false, Horde_Perms::READ))) { // This request is for an entire calendar (calendar.ics). $ical_data = $this->exportCalendar(substr($parts[1], 0, -4), 'text/calendar'); $result = array('data' => $ical_data, 'mimetype' => 'text/calendar', 'contentlength' => strlen($ical_data), 'mtime' => $_SERVER['REQUEST_TIME']); return $result; } else { // All other requests are a 404: Not Found return false; } } }