]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Irc/extlib/phergie/Phergie/Plugin/Remind.php
Merge branch '0.9.x' into 1.0.x
[quix0rs-gnu-social.git] / plugins / Irc / extlib / phergie / Phergie / Plugin / Remind.php
1 <?php
2 /**
3  * Phergie
4  *
5  * PHP version 5
6  *
7  * LICENSE
8  *
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
13  *
14  * @category  Phergie
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
20  */
21
22 /**
23  * Parses and logs messages that should be relayed to other users the next time
24  * the recipient is active on the same channel.
25  *
26  * @category Phergie
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
33  * @uses     extension PDO
34  * @uses     extension pdo_sqlite
35  */
36 class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
37 {
38     /**
39      * Number of reminders to show in public.
40      */
41     protected $publicReminders = 3;
42
43     /**
44      * PDO resource for a SQLite database containing the reminders.
45      *
46      * @var resource
47      */
48     protected $db;
49
50     /**
51      * Flag that indicates whether or not to use an in-memory reminder list.
52      *
53      * @var bool
54      */
55     protected $keepListInMemory = true;
56
57     /**
58      * In-memory store for pending reminders.
59      */
60     protected $msgStorage = array();
61
62     /**
63      * Check for dependencies.
64      *
65      * @return void
66      */
67     public function onLoad()
68     {
69         $plugins = $this->getPluginHandler();
70         $plugins->getPlugin('Command');
71         $plugins->getPlugin('Time');
72
73         if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) {
74             $this->fail('PDO and pdo_sqlite extensions must be installed');
75         }
76
77         $dir = dirname(__FILE__) . '/' . $this->getName();
78         $path = $dir . '/reminder.db';
79         if (!file_exists($dir)) {
80             mkdir($dir);
81         }
82
83         if (isset($this->config['remind.use_memory'])) {
84             $this->keepListInMemory = (bool) $this->config['remind.use_memory'];
85         }
86
87         if (isset($this->config['remind.public_reminders'])) {
88             $this->publicReminders = (int) $this->config['remind.public_reminders'];
89             $this->publicReminders = max($this->publicReminders, 0);
90         }
91
92         try {
93             $this->db = new PDO('sqlite:' . $path);
94             $this->createTables();
95         } catch (PDO_Exception $e) {
96             throw new Phergie_Plugin_Exception($e->getMessage());
97         }
98     }
99
100     /**
101      * Intercepts a message and processes any contained recognized commands.
102      *
103      * @return void
104      */
105     public function onPrivmsg()
106     {
107         $source = $this->getEvent()->getSource();
108         $nick = $this->getEvent()->getNick();
109
110         $this->deliverReminders($source, $nick);
111     }
112
113     /**
114      * Handle reminder requests
115      *
116      * @param string $recipient recipient of the message
117      * @param string $message   message to tell the recipient
118      *
119      * @return void
120      * @see handleRemind()
121      */
122     public function onCommandTell($recipient, $message)
123     {
124         $this->handleRemind($recipient, $message);
125     }
126
127     /**
128      * Handle reminder requests
129      *
130      * @param string $recipient recipient of the message
131      * @param string $message   message to tell the recipient
132      *
133      * @return void
134      * @see handleRemind()
135      */
136     public function onCommandAsk($recipient, $message)
137     {
138         $this->handleRemind($recipient, $message);
139     }
140
141     /**
142      * Handle reminder requests
143      *
144      * @param string $recipient recipient of the message
145      * @param string $message   message to tell the recipient
146      *
147      * @return void
148      * @see handleRemind()
149      */
150     public function onCommandRemind($recipient, $message)
151     {
152         $this->handleRemind($recipient, $message);
153     }
154
155     /**
156      * Handles the tell/remind command (stores the message)
157      *
158      * @param string $recipient name of the recipient
159      * @param string $message   message to store
160      *
161      * @return void
162      */
163     protected function handleRemind($recipient, $message)
164     {
165         $source = $this->getEvent()->getSource();
166         $nick = $this->getEvent()->getNick();
167
168         if (!$this->getEvent()->isInChannel()) {
169             $this->doPrivmsg($source, 'Reminders must be requested in-channel.');
170             return;
171         }
172
173         $q = $this->db->prepare(
174             'INSERT INTO remind
175                 (
176                     time,
177                     channel,
178                     recipient,
179                     sender,
180                     message
181                 )
182             VALUES
183                 (
184                     :time,
185                     :channel,
186                     :recipient,
187                     :sender,
188                     :message
189                )'
190         );
191         try {
192             $q->execute(
193                 array(
194                     'time' => date(DATE_RFC822),
195                     'channel' => $source,
196                     'recipient' => strtolower($recipient),
197                     'sender' => strtolower($nick),
198                     'message' => $message
199                 )
200             );
201         } catch (PDOException $e) {
202         }
203
204         if ($rowid = $this->db->lastInsertId()) {
205             $this->doPrivmsg($source, 'ok, ' . $nick . ', message stored');
206         } else {
207             $this->doPrivmsg(
208                 $source,
209                 $nick . ': bad things happened. Message not saved.'
210             );
211             return;
212         }
213
214         if ($this->keepListInMemory) {
215             $this->msgStorage[$source][strtolower($recipient)] = $rowid;
216         }
217     }
218
219     /**
220      * Determines if the user has pending reminders, and if so, delivers them.
221      *
222      * @param string $channel channel to check
223      * @param string $nick    nick to check
224      *
225      * @return void
226      */
227     protected function deliverReminders($channel, $nick)
228     {
229         if ($channel[0] != '#') {
230             // private message, not a channel, so don't check
231             return;
232         }
233
234         // short circuit if there's no message in memory (if allowed)
235         if ($this->keepListInMemory
236             && !isset($this->msgStorage[$channel][strtolower($nick)])
237         ) {
238             return;
239         }
240
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);
246         } else {
247             $msgs = $reminders;
248             $privmsgs = false;
249         }
250
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']
256             );
257             $this->doPrivmsg($channel, $formatted);
258             $this->deleteMessage($msg['rowid'], $channel, $nick);
259         }
260
261         if ($privmsgs) {
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']
267                 );
268                 $this->doPrivmsg($nick, $formatted);
269                 $this->deleteMessage($msg['rowid'], $channel, $nick);
270             }
271             $formatted = sprintf(
272                 '%s: (%d more messages sent in private.)',
273                 $nick, count($privmsgs)
274             );
275             $this->doPrivmsg($channel, $formatted);
276         }
277     }
278
279     /**
280      * Get pending messages (for a specific channel/recipient)
281      *
282      * @param string $channel   channel on which to check for pending messages
283      * @param string $recipient user for which to check pending messages
284      *
285      * @return array of records
286      */
287     protected function fetchMessages($channel = null, $recipient = null)
288     {
289         if ($channel) {
290             $qClause = 'WHERE channel = :channel AND recipient LIKE :recipient';
291             $params = compact('channel', 'recipient');
292         } else {
293             $qClause = '';
294             $params = array();
295         }
296         $q = $this->db->prepare(
297             'SELECT rowid, channel, sender, recipient, time, message
298             FROM remind ' . $qClause
299         );
300         $q->execute($params);
301         return $q->fetchAll();
302     }
303
304     /**
305      * Deletes a delivered message
306      *
307      * @param int    $rowid   ID of the message to delete
308      * @param string $channel message's channel
309      * @param string $nick    message's recipient
310      *
311      * @return void
312      */
313     protected function deleteMessage($rowid, $channel, $nick)
314     {
315         $nick = strtolower($nick);
316         $q = $this->db->prepare('DELETE FROM remind WHERE rowid = :rowid');
317         $q->execute(array('rowid' => $rowid));
318
319         if ($this->keepListInMemory) {
320             if (isset($this->msgStorage[$channel][$nick])
321                 && $this->msgStorage[$channel][$nick] == $rowid
322             ) {
323                 unset($this->msgStorage[$channel][$nick]);
324             }
325         }
326     }
327
328     /**
329      * Determines if a table exists
330      *
331      * @param string $name Table name
332      *
333      * @return bool
334      */
335     protected function haveTable($name)
336     {
337         $sql = 'SELECT COUNT(*) FROM sqlite_master WHERE name = '
338             . $this->db->quote($name);
339         return (bool) $this->db->query($sql)->fetchColumn();
340     }
341
342     /**
343      * Creates the database table(s) (if they don't exist)
344      *
345      * @return void
346      */
347     protected function createTables()
348     {
349         if (!$this->haveTable('remind')) {
350             $this->db->exec(
351                 'CREATE TABLE
352                     remind
353                     (
354                         time INTEGER,
355                         channel TEXT,
356                         recipient TEXT,
357                         sender TEXT,
358                         message TEXT
359                     )'
360             );
361         }
362     }
363
364     /**
365      * Populates the in-memory cache of pending reminders
366      *
367      * @return void
368      */
369     protected function populateMemory()
370     {
371         if (!$this->keepListInMemory) {
372             return;
373         }
374         foreach ($this->fetchMessages() as $msg) {
375             $this->msgStorage[$msg['channel']][$msg['recipient']] = $msg['rowid'];
376         }
377     }
378 }