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 * @uses extension pdo_sqlite
36 class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
39 * Number of reminders to show in public.
41 protected $publicReminders = 3;
44 * PDO resource for a SQLite database containing the reminders.
51 * Flag that indicates whether or not to use an in-memory reminder list.
55 protected $keepListInMemory = true;
58 * In-memory store for pending reminders.
60 protected $msgStorage = array();
63 * Check for dependencies.
67 public function onLoad()
69 $plugins = $this->getPluginHandler();
70 $plugins->getPlugin('Command');
71 $plugins->getPlugin('Time');
73 if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) {
74 $this->fail('PDO and pdo_sqlite extensions must be installed');
77 $dir = dirname(__FILE__) . '/' . $this->getName();
78 $path = $dir . '/reminder.db';
79 if (!file_exists($dir)) {
83 if (isset($this->config['remind.use_memory'])) {
84 $this->keepListInMemory = (bool) $this->config['remind.use_memory'];
87 if (isset($this->config['remind.public_reminders'])) {
88 $this->publicReminders = (int) $this->config['remind.public_reminders'];
89 $this->publicReminders = max($this->publicReminders, 0);
93 $this->db = new PDO('sqlite:' . $path);
94 $this->createTables();
95 } catch (PDO_Exception $e) {
96 throw new Phergie_Plugin_Exception($e->getMessage());
101 * Intercepts a message and processes any contained recognized commands.
105 public function onPrivmsg()
107 $source = $this->getEvent()->getSource();
108 $nick = $this->getEvent()->getNick();
110 $this->deliverReminders($source, $nick);
114 * Handle reminder requests
116 * @param string $recipient recipient of the message
117 * @param string $message message to tell the recipient
120 * @see handleRemind()
122 public function onCommandTell($recipient, $message)
124 $this->handleRemind($recipient, $message);
128 * Handle reminder requests
130 * @param string $recipient recipient of the message
131 * @param string $message message to tell the recipient
134 * @see handleRemind()
136 public function onCommandAsk($recipient, $message)
138 $this->handleRemind($recipient, $message);
142 * Handle reminder requests
144 * @param string $recipient recipient of the message
145 * @param string $message message to tell the recipient
148 * @see handleRemind()
150 public function onCommandRemind($recipient, $message)
152 $this->handleRemind($recipient, $message);
156 * Handles the tell/remind command (stores the message)
158 * @param string $recipient name of the recipient
159 * @param string $message message to store
163 protected function handleRemind($recipient, $message)
165 $source = $this->getEvent()->getSource();
166 $nick = $this->getEvent()->getNick();
168 if (!$this->getEvent()->isInChannel()) {
169 $this->doPrivmsg($source, 'Reminders must be requested in-channel.');
173 $q = $this->db->prepare(
194 'time' => date(DATE_RFC822),
195 'channel' => $source,
196 'recipient' => strtolower($recipient),
197 'sender' => strtolower($nick),
198 'message' => $message
201 } catch (PDOException $e) {
204 if ($rowid = $this->db->lastInsertId()) {
205 $this->doPrivmsg($source, 'ok, ' . $nick . ', message stored');
209 $nick . ': bad things happened. Message not saved.'
214 if ($this->keepListInMemory) {
215 $this->msgStorage[$source][strtolower($recipient)] = $rowid;
220 * Determines if the user has pending reminders, and if so, delivers them.
222 * @param string $channel channel to check
223 * @param string $nick nick to check
227 protected function deliverReminders($channel, $nick)
229 if ($channel[0] != '#') {
230 // private message, not a channel, so don't check
234 // short circuit if there's no message in memory (if allowed)
235 if ($this->keepListInMemory
236 && !isset($this->msgStorage[$channel][strtolower($nick)])
241 // fetch and deliver messages
242 $reminders = $this->fetchMessages($channel, $nick);
243 if (count($reminders) > $this->publicReminders) {
244 $msgs = array_slice($reminders, 0, $this->publicReminders);
245 $privmsgs = array_slice($reminders, $this->publicReminders);
251 foreach ($msgs as $msg) {
252 $ts = $this->plugins->time->getCountdown($msg['time']);
253 $formatted = sprintf(
254 '%s: (from %s, %s ago) %s',
255 $nick, $msg['sender'], $ts, $msg['message']
257 $this->doPrivmsg($channel, $formatted);
258 $this->deleteMessage($msg['rowid'], $channel, $nick);
262 foreach ($privmsgs as $msg) {
263 $ts = $this->plugins->time->getCountdown($msg['time']);
264 $formatted = sprintf(
265 'from %s, %s ago: %s',
266 $msg['sender'], $ts, $msg['message']
268 $this->doPrivmsg($nick, $formatted);
269 $this->deleteMessage($msg['rowid'], $channel, $nick);
271 $formatted = sprintf(
272 '%s: (%d more messages sent in private.)',
273 $nick, count($privmsgs)
275 $this->doPrivmsg($channel, $formatted);
280 * Get pending messages (for a specific channel/recipient)
282 * @param string $channel channel on which to check for pending messages
283 * @param string $recipient user for which to check pending messages
285 * @return array of records
287 protected function fetchMessages($channel = null, $recipient = null)
290 $qClause = 'WHERE channel = :channel AND recipient LIKE :recipient';
291 $params = compact('channel', 'recipient');
296 $q = $this->db->prepare(
297 'SELECT rowid, channel, sender, recipient, time, message
298 FROM remind ' . $qClause
300 $q->execute($params);
301 return $q->fetchAll();
305 * Deletes a delivered message
307 * @param int $rowid ID of the message to delete
308 * @param string $channel message's channel
309 * @param string $nick message's recipient
313 protected function deleteMessage($rowid, $channel, $nick)
315 $nick = strtolower($nick);
316 $q = $this->db->prepare('DELETE FROM remind WHERE rowid = :rowid');
317 $q->execute(array('rowid' => $rowid));
319 if ($this->keepListInMemory) {
320 if (isset($this->msgStorage[$channel][$nick])
321 && $this->msgStorage[$channel][$nick] == $rowid
323 unset($this->msgStorage[$channel][$nick]);
329 * Determines if a table exists
331 * @param string $name Table name
335 protected function haveTable($name)
337 $sql = 'SELECT COUNT(*) FROM sqlite_master WHERE name = '
338 . $this->db->quote($name);
339 return (bool) $this->db->query($sql)->fetchColumn();
343 * Creates the database table(s) (if they don't exist)
347 protected function createTables()
349 if (!$this->haveTable('remind')) {
365 * Populates the in-memory cache of pending reminders
369 protected function populateMemory()
371 if (!$this->keepListInMemory) {
374 foreach ($this->fetchMessages() as $msg) {
375 $this->msgStorage[$msg['channel']][$msg['recipient']] = $msg['rowid'];