9 * This source file is subject to the new BSD license that is bundled
10 * with this package in the file LICENSE.
11 * It is also available through the world-wide-web at this URL:
12 * http://phergie.org/license
15 * @package Phergie_Plugin_Remind
16 * @author Phergie Development Team <team@phergie.org>
17 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
18 * @license http://phergie.org/license New BSD License
19 * @link http://pear.phergie.org/package/Phergie_Plugin_Remind
23 * Parses and logs messages that should be relayed to other users the next time
24 * the recipient is active on the same channel.
27 * @package Phergie_Plugin_Remind
28 * @author Phergie Development Team <team@phergie.org>
29 * @license http://phergie.org/license New BSD License
30 * @link http://pear.phergie.org/package/Phergie_Plugin_Remind
31 * @uses Phergie_Plugin_Command pear.phergie.org
32 * @uses Phergie_Plugin_Time pear.phergie.org
34 class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
37 * Number of reminders to show in public.
39 protected $publicReminders = 3;
42 * PDO resource for a SQLite database containing the reminders.
49 * Flag that indicates whether or not to use an in-memory reminder list.
53 protected $keepListInMemory = true;
56 * In-memory store for pending reminders.
58 protected $msgStorage = array();
61 * Check for dependencies.
65 public function onLoad()
67 $plugins = $this->getPluginHandler();
68 $plugins->getPlugin('Command');
69 $plugins->getPlugin('Time');
73 * Creates the database if it does not already exist.
77 public function onConnect()
79 $dir = dirname(__FILE__) . '/' . $this->getName();
80 $path = $dir . '/reminder.db';
81 if (!file_exists($dir)) {
85 if (isset($this->config['remind.use_memory'])) {
86 $this->keepListInMemory = (bool) $this->config['remind.use_memory'];
89 if (isset($this->config['remind.public_reminders'])) {
90 $this->publicReminders = (int) $this->config['remind.public_reminders'];
91 $this->publicReminders = max($this->publicReminders, 0);
95 $this->db = new PDO('sqlite:' . $path);
96 $this->createTables();
97 } catch (PDO_Exception $e) {
98 throw new Phergie_Plugin_Exception($e->getMessage());
103 * Intercepts a message and processes any contained recognized commands.
107 public function onPrivmsg()
109 $source = $this->getEvent()->getSource();
110 $nick = $this->getEvent()->getNick();
112 $this->deliverReminders($source, $nick);
116 * Handle reminder requests
118 * @param string $recipient recipient of the message
119 * @param string $message message to tell the recipient
122 * @see handleRemind()
124 public function onCommandTell($recipient, $message)
126 $this->handleRemind($recipient, $message);
130 * Handle reminder requests
132 * @param string $recipient recipient of the message
133 * @param string $message message to tell the recipient
136 * @see handleRemind()
138 public function onCommandAsk($recipient, $message)
140 $this->handleRemind($recipient, $message);
144 * Handle reminder requests
146 * @param string $recipient recipient of the message
147 * @param string $message message to tell the recipient
150 * @see handleRemind()
152 public function onCommandRemind($recipient, $message)
154 $this->handleRemind($recipient, $message);
158 * Handles the tell/remind command (stores the message)
160 * @param string $recipient name of the recipient
161 * @param string $message message to store
165 protected function handleRemind($recipient, $message)
167 $source = $this->getEvent()->getSource();
168 $nick = $this->getEvent()->getNick();
170 if (!$this->getEvent()->isInChannel()) {
171 $this->doPrivmsg($source, 'Reminders must be requested in-channel.');
175 $q = $this->db->prepare(
196 'time' => date(DATE_RFC822),
197 'channel' => $source,
198 'recipient' => strtolower($recipient),
199 'sender' => strtolower($nick),
200 'message' => $message
203 } catch (PDOException $e) {
206 if ($rowid = $this->db->lastInsertId()) {
207 $this->doPrivmsg($source, 'ok, ' . $nick . ', message stored');
211 $nick . ': bad things happened. Message not saved.'
216 if ($this->keepListInMemory) {
217 $this->msgStorage[$source][strtolower($recipient)] = $rowid;
222 * Determines if the user has pending reminders, and if so, delivers them.
224 * @param string $channel channel to check
225 * @param string $nick nick to check
229 protected function deliverReminders($channel, $nick)
231 if ($channel[0] != '#') {
232 // private message, not a channel, so don't check
236 // short circuit if there's no message in memory (if allowed)
237 if ($this->keepListInMemory
238 && !isset($this->msgStorage[$channel][strtolower($nick)])
243 // fetch and deliver messages
244 $reminders = $this->fetchMessages($channel, $nick);
245 if (count($reminders) > $this->publicReminders) {
246 $msgs = array_slice($reminders, 0, $this->publicReminders);
247 $privmsgs = array_slice($reminders, $this->publicReminders);
253 foreach ($msgs as $msg) {
254 $ts = $this->plugins->time->getCountdown($msg['time']);
255 $formatted = sprintf(
256 '%s: (from %s, %s ago) %s',
257 $nick, $msg['sender'], $ts, $msg['message']
259 $this->doPrivmsg($channel, $formatted);
260 $this->deleteMessage($msg['rowid'], $channel, $nick);
264 foreach ($privmsgs as $msg) {
265 $ts = $this->plugins->time->getCountdown($msg['time']);
266 $formatted = sprintf(
267 'from %s, %s ago: %s',
268 $msg['sender'], $ts, $msg['message']
270 $this->doPrivmsg($nick, $formatted);
271 $this->deleteMessage($msg['rowid'], $channel, $nick);
273 $formatted = sprintf(
274 '%s: (%d more messages sent in private.)',
275 $nick, count($privmsgs)
277 $this->doPrivmsg($channel, $formatted);
282 * Get pending messages (for a specific channel/recipient)
284 * @param string $channel channel on which to check for pending messages
285 * @param string $recipient user for which to check pending messages
287 * @return array of records
289 protected function fetchMessages($channel = null, $recipient = null)
292 $qClause = 'WHERE channel = :channel AND recipient LIKE :recipient';
293 $params = compact('channel', 'recipient');
298 $q = $this->db->prepare(
299 'SELECT rowid, channel, sender, recipient, time, message
300 FROM remind ' . $qClause
302 $q->execute($params);
303 return $q->fetchAll();
307 * Deletes a delivered message
309 * @param int $rowid ID of the message to delete
310 * @param string $channel message's channel
311 * @param string $nick message's recipient
315 protected function deleteMessage($rowid, $channel, $nick)
317 $nick = strtolower($nick);
318 $q = $this->db->prepare('DELETE FROM remind WHERE rowid = :rowid');
319 $q->execute(array('rowid' => $rowid));
321 if ($this->keepListInMemory) {
322 if (isset($this->msgStorage[$channel][$nick])
323 && $this->msgStorage[$channel][$nick] == $rowid
325 unset($this->msgStorage[$channel][$nick]);
331 * Determines if a table exists
333 * @param string $name Table name
337 protected function haveTable($name)
339 $sql = 'SELECT COUNT(*) FROM sqlite_master WHERE name = '
340 . $this->db->quote($name);
341 return (bool) $this->db->query($sql)->fetchColumn();
345 * Creates the database table(s) (if they don't exist)
349 protected function createTables()
351 if (!$this->haveTable('remind')) {
367 * Populates the in-memory cache of pending reminders
371 protected function populateMemory()
373 if (!$this->keepListInMemory) {
376 foreach ($this->fetchMessages() as $msg) {
377 $this->msgStorage[$msg['channel']][$msg['recipient']] = $msg['rowid'];