1#!/usr/bin/env php
2<?php
3/**
4 * Copyright 2003-2017 Horde LLC (http://www.horde.org/)
5 *
6 * See the enclosed file COPYING for license information (GPL). If you
7 * did not receive this file, see http://www.horde.org/licenses/gpl.
8 *
9 * @author Chuck Hagenbuch <chuck@horde.org>
10 */
11
12if (file_exists(__DIR__ . '/../../kronolith/lib/Application.php')) {
13    $baseDir = __DIR__ . '/../';
14} else {
15    require_once 'PEAR/Config.php';
16    $baseDir = PEAR_Config::singleton()
17        ->get('horde_dir', null, 'pear.horde.org') . '/kronolith/';
18}
19require_once $baseDir . 'lib/Application.php';
20Horde_Registry::appInit('kronolith', array('cli' => true));
21
22send_agendas();
23
24/**
25 */
26function send_agendas()
27{
28    if (isset($_SERVER['REQUEST_TIME'])) {
29        $runtime = $_SERVER['REQUEST_TIME'];
30    } else {
31        $runtime = time();
32    }
33
34    $kronolith_shares = $GLOBALS['injector']->getInstance('Kronolith_Shares');
35    $calendars = $kronolith_shares->listAllShares();
36
37    // If there are no calendars to check, we're done.
38    if (!count($calendars)) {
39        return;
40    }
41
42    if (empty($GLOBALS['conf']['reminder']['server_name']) ||
43        empty($GLOBALS['conf']['reminder']['from_addr'])) {
44        die('You must configure the server_name and from_addr settings for reminders in the calendar configuration.');
45    }
46
47    $_SERVER['SERVER_NAME'] = $GLOBALS['conf']['server']['name'] = $GLOBALS['conf']['reminder']['server_name'];
48
49    // Retrieve a list of users associated with each calendar, and
50    // thus a list of users who have used kronolith and
51    // potentially have an agenda preference set.
52    $users = array();
53    foreach (array_keys($calendars) as $calendarId) {
54        try {
55            $calendar = $kronolith_shares->getShare($calendarId);
56        } catch (Exception $e) {
57            continue;
58        }
59        $users = array_merge($users, $calendar->listUsers(Horde_Perms::READ));
60    }
61
62    // Remove duplicates.
63    $users = array_unique($users);
64
65    // Generate image mime part first and only once, because we need
66    // the Content-ID.
67    $image = Kronolith::getImagePart('big_agenda.png');
68
69    $runtime = new Horde_Date($runtime);
70    $default_timezone = date_default_timezone_get();
71    $kronolith_driver = Kronolith::getDriver();
72    $view = new Horde_View(array('templatePath' => KRONOLITH_TEMPLATES . '/agenda', 'encoding' => 'UTF-8'));
73    new Horde_View_Helper_Text($view);
74    $view->imageId = $image->getContentId();
75    $view->date = $runtime;
76    if (!$GLOBALS['prefs']->isLocked('daily_agenda')) {
77        $view->prefsUrl = Horde::url($GLOBALS['registry']->getServiceLink('prefs', 'kronolith'), true)->remove(session_name());
78    }
79
80    // Loop through the users and generate an agenda for them
81    foreach ($users as $user) {
82        $prefs = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Prefs')->create('kronolith', array(
83            'user' => $user
84        ));
85        $agenda_calendars = $prefs->getValue('daily_agenda');
86
87        if (!$agenda_calendars) {
88            continue;
89        }
90
91        // Initialize the CalendarsManager for this user.
92        $GLOBALS['calendar_manager'] = new Kronolith_CalendarsManager($user);
93
94        // Try to find an email address for the user.
95        $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($user);
96        $email = $identity->getDefaultFromAddress(true);
97
98        // Check if user has a timezone pref, and set it. Otherwise, make
99        // sure to use the server's default timezone.
100        $tz = $prefs->getValue('timezone');
101        date_default_timezone_set(empty($tz) ? $default_timezone : $tz);
102
103        // If we found an email address, generate the agenda.
104        switch ($agenda_calendars) {
105        case 'owner':
106            $calendars = $kronolith_shares->listShares(
107                $user,
108                array('perm' => Horde_Perms::SHOW,
109                      'attributes' => $user));
110            $calendars = array_keys($calendars);
111            break;
112
113        case 'read':
114            $calendars = $kronolith_shares->listShares(
115                $user,
116                array('perm' => Horde_Perms::READ));
117            $calendars = array_keys($calendars);
118            break;
119
120        case 'show':
121        default:
122            $calendars = array();
123            $shown_calendars = unserialize($prefs->getValue('display_cals'));
124            $cals = $kronolith_shares->listShares(
125                $user,
126                array('perm' => Horde_Perms::SHOW));
127            foreach (array_keys($cals) as $calId) {
128                if (in_array($calId, $shown_calendars)) {
129                    $calendars[] = $calId;
130                }
131            }
132        }
133
134        // Get a list of events for today
135        $eventlist = array();
136        foreach ($calendars as $calId) {
137            $kronolith_driver->open($calId);
138            $events = $kronolith_driver->listEvents(
139                $runtime, $runtime, array('show_recurrence' => true));
140            foreach ($events as $dayevents) {
141                foreach ($dayevents as $event) {
142                    // The event list contains events starting at 12am.
143                    if ($event->start->compareDate($runtime) || $event->isPrivate($user)) {
144                        continue;
145                    }
146                    $eventlist[] = $event;
147                }
148            }
149        }
150
151        if (!count($eventlist)) {
152            continue;
153        }
154
155        // If there are any events, generate and send the email.
156        usort($eventlist, 'sort_events');
157        $GLOBALS['registry']->setLanguageEnvironment($prefs->getValue('language'));
158        $twentyFour = $prefs->getValue('twentyFour');
159
160        $view->pad = max(Horde_String::length(_("All day")) + 2, $twentyFour ? 6 : 8);
161        $view->dateFormat = $prefs->getValue('date_format');
162        $view->timeformat = $twentyFour  ? 'H:i' : 'h:ia';
163        $view->user = $user;
164        $view->events = $eventlist;
165
166        $mime_mail = new Horde_Mime_Mail(array(
167            'Subject' => sprintf(_("Your daily agenda for %s"), $runtime->strftime($view->dateFormat)),
168            'To' => $email,
169            'From' => $GLOBALS['conf']['reminder']['from_addr'],
170            'User-Agent' => 'Kronolith ' . $GLOBALS['registry']->getVersion(),
171            'Auto-Submitted' => 'auto-generated'));
172        try {
173            $mime_mail->addRecipients($email);
174        } catch (Horde_Mime_Exception $e) {}
175
176        $mime_mail->setBasePart(Kronolith::buildMimeMessage($view, 'notification', $image));
177
178        Horde::log(sprintf('Sending daily agenda to %s', $email), 'DEBUG');
179        try {
180            $mime_mail->send($GLOBALS['injector']->getInstance('Horde_Mail'));
181        } catch (Horde_Mime_Exception $e) {
182            Horde::log(sprintf('Error sending daily agenda to %s: %s', $email, $e->getMessage()), 'WARN');
183        }
184    }
185}
186
187function sort_events($a, $b)
188{
189    if ($a->allday && $b->allday) {
190        return 0;
191    }
192
193    if ($a->allday || $b->allday) {
194        return ($a->allday) ? -1 : 1;
195    }
196
197    if ($a->start == $b->start) {
198        return 0;
199    }
200
201    return ($a->start < $b->start) ? -1 : 1;
202}
203