]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Irc/IrcPlugin.php
Added more commenting
[quix0rs-gnu-social.git] / plugins / Irc / IrcPlugin.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2010, StatusNet, Inc.
5  *
6  * Send and receive notices using an IRC network
7  *
8  * PHP version 5
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Affero General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Affero General Public License for more details.
19  *
20  * You should have received a copy of the GNU Affero General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * @category  IM
24  * @package   StatusNet
25  * @author    Luke Fitzgerald <lw.fitzgerald@googlemail.com>
26  * @copyright 2010 StatusNet, Inc.
27  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
28  * @link      http://status.net/
29  */
30
31 if (!defined('STATUSNET')) {
32     // This check helps protect against security problems;
33     // your code file can't be executed directly from the web.
34     exit(1);
35 }
36
37 // We bundle the Phergie library...
38 set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib/phergie');
39
40 /**
41  * Plugin for IRC
42  *
43  * @category  Plugin
44  * @package   StatusNet
45  * @author    Luke Fitzgerald <lw.fitzgerald@googlemail.com>
46  * @copyright 2010 StatusNet, Inc.
47  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
48  * @link      http://status.net/
49  */
50
51 class IrcPlugin extends ImPlugin {
52     public $host =  null;
53     public $port = null;
54     public $username = null;
55     public $realname = null;
56     public $nick = null;
57     public $password = null;
58     public $nickservidentifyregexp = null;
59     public $nickservpassword = null;
60     public $channels = null;
61     public $transporttype = null;
62     public $encoding = null;
63
64     public $regcheck = null;
65     public $unregregexp = null;
66     public $regregexp = null;
67
68     public $transport = 'irc';
69     protected $whiteList;
70     protected $fake_irc;
71
72     /**
73      * Get the internationalized/translated display name of this IM service
74      *
75      * @return string Name of service
76      */
77     public function getDisplayName() {
78         return _m('IRC');
79     }
80
81     /**
82      * Normalize a screenname for comparison
83      *
84      * @param string $screenname Screenname to normalize
85      * @return string An equivalent screenname in normalized form
86      */
87     public function normalize($screenname) {
88         $screenname = str_replace(" ","", $screenname);
89         return strtolower($screenname);
90     }
91
92     /**
93      * Get the screenname of the daemon that sends and receives messages
94      *
95      * @return string Screenname
96      */
97     public function daemon_screenname() {
98         return $this->nick;
99     }
100
101     /**
102      * Validate (ensure the validity of) a screenname
103      *
104      * @param string $screenname Screenname to validate
105      * @return boolean true if screenname is valid
106      */
107     public function validate($screenname) {
108         if (preg_match('/\A[a-z0-9\-_]{1,1000}\z/i', $screenname)) {
109             return true;
110         } else {
111             return false;
112         }
113     }
114
115     /**
116      * Load related modules when needed
117      *
118      * @param string $cls Name of the class to be loaded
119      * @return boolean hook value; true means continue processing, false means stop.
120      */
121     public function onAutoload($cls) {
122         $dir = dirname(__FILE__);
123
124         switch ($cls) {
125             case 'IrcManager':
126                 include_once $dir . '/'.strtolower($cls).'.php';
127                 return false;
128             case 'Fake_Irc':
129             case 'ChannelResponseChannel':
130                 include_once $dir . '/'. $cls .'.php';
131                 return false;
132             default:
133                 if (substr($cls, 0, 7) == 'Phergie') {
134                     include_once str_replace('_', DIRECTORY_SEPARATOR, $cls) . '.php';
135                     return false;
136                 }
137                 return true;
138         }
139     }
140
141     /*
142      * Start manager on daemon start
143      *
144      * @param array &$versions Array to insert manager into
145      * @return boolean
146      */
147     public function onStartImDaemonIoManagers(&$classes) {
148         parent::onStartImDaemonIoManagers(&$classes);
149         $classes[] = new IrcManager($this); // handles sending/receiving
150         return true;
151     }
152
153     /**
154     * Get a microid URI for the given screenname
155     *
156     * @param string $screenname Screenname
157     * @return string microid URI
158     */
159     public function microiduri($screenname) {
160         return 'irc:' . $screenname;
161     }
162
163     /**
164      * Send a message to a given screenname
165      *
166      * @param string $screenname Screenname to send to
167      * @param string $body Text to send
168      * @return boolean true on success
169      */
170     public function send_message($screenname, $body) {
171         $lines = explode("\n", $body);
172         foreach ($lines as $line) {
173             $this->fake_irc->doPrivmsg($screenname, $line);
174             $this->enqueue_outgoing_raw(array('type' => 'message', 'data' => $this->fake_irc->would_be_sent));
175         }
176         return true;
177     }
178
179     /**
180      * Accept a queued input message.
181      *
182      * @return boolean true if processing completed, false if message should be reprocessed
183      */
184     public function receive_raw_message($data) {
185         if (strpos($data['source'], '#') === 0) {
186             $message = $data['message'];
187             $parts = explode(' ', $message, 2);
188             $command = $parts[0];
189             if (in_array($command, $this->whiteList)) {
190                 $this->handle_channel_incoming($data['sender'], $data['source'], $message);
191             } else {
192                 $this->handle_incoming($data['sender'], $message);
193             }
194         } else {
195             $this->handle_incoming($data['sender'], $data['message']);
196         }
197         return true;
198     }
199
200     /**
201      * Helper for handling incoming messages from a channel requiring response
202      * to the channel instead of via PM
203      *
204      * @param string $nick Screenname the message was sent from
205      * @param string $channel Channel the message originated from
206      * @param string $message Message text
207      * @param boolean true on success
208      */
209     protected function handle_channel_incoming($nick, $channel, $notice_text) {
210         $user = $this->get_user($nick);
211         // For common_current_user to work
212         global $_cur;
213         $_cur = $user;
214
215         if (!$user) {
216             $this->send_from_site($nick, 'Unknown user; go to ' .
217                              common_local_url('imsettings') .
218                              ' to add your address to your account');
219             common_log(LOG_WARNING, 'Message from unknown user ' . $nick);
220             return;
221         }
222         if ($this->handle_channel_command($user, $channel, $notice_text)) {
223             common_log(LOG_INFO, "Command message by $nick handled.");
224             return;
225         } else if ($this->is_autoreply($notice_text)) {
226             common_log(LOG_INFO, 'Ignoring auto reply from ' . $nick);
227             return;
228         } else if ($this->is_otr($notice_text)) {
229             common_log(LOG_INFO, 'Ignoring OTR from ' . $nick);
230             return;
231         } else {
232             common_log(LOG_INFO, 'Posting a notice from ' . $user->nickname);
233             $this->add_notice($nick, $user, $notice_text);
234         }
235
236         $user->free();
237         unset($user);
238         unset($_cur);
239         unset($message);
240     }
241
242     /**
243      * Attempt to handle a message from a channel as a command
244      *
245      * @param User $user User the message is from
246      * @param string $channel Channel the message originated from
247      * @param string $body Message text
248      * @return boolean true if the message was a command and was executed, false if it was not a command
249      */
250     protected function handle_channel_command($user, $channel, $body) {
251         $inter = new CommandInterpreter();
252         $cmd = $inter->handle_command($user, $body);
253         if ($cmd) {
254             $chan = new ChannelResponseChannel($this, $channel);
255             $cmd->execute($chan);
256             return true;
257         } else {
258             return false;
259         }
260     }
261
262     /**
263      * Send a confirmation code to a user
264      *
265      * @param string $screenname screenname sending to
266      * @param string $code the confirmation code
267      * @param User $user user sending to
268      * @return boolean success value
269      */
270     public function send_confirmation_code($screenname, $code, $user, $checked = false) {
271         $body = sprintf(_('User "%s" on %s has said that your %s screenname belongs to them. ' .
272           'If that\'s true, you can confirm by clicking on this URL: ' .
273           '%s' .
274           ' . (If you cannot click it, copy-and-paste it into the ' .
275           'address bar of your browser). If that user isn\'t you, ' .
276           'or if you didn\'t request this confirmation, just ignore this message.'),
277           $user->nickname, common_config('site', 'name'), $this->getDisplayName(), common_local_url('confirmaddress', array('code' => $code)));
278
279         if ($this->regcheck && !$checked) {
280             return $this->checked_send_confirmation_code($screenname, $code, $user);
281         } else {
282             return $this->send_message($screenname, $body);
283         }
284     }
285
286     /**
287     * Only sends the confirmation message if the nick is
288     * registered
289     *
290     * @param string $screenname Screenname sending to
291     * @param string $code The confirmation code
292     * @param User $user User sending to
293     * @return boolean true on succes
294     */
295     public function checked_send_confirmation_code($screenname, $code, $user) {
296         $this->fake_irc->doPrivmsg('NickServ', 'INFO '.$screenname);
297         $this->enqueue_outgoing_raw(
298             array(
299                 'type' => 'nickcheck',
300                 'data' => $this->fake_irc->would_be_sent,
301                 'nickdata' =>
302                     array(
303                         'screenname' => $screenname,
304                         'code' => $code,
305                         'user' => $user
306                     )
307             )
308         );
309         return true;
310     }
311
312     /**
313     * Initialize plugin
314     *
315     * @return boolean
316     */
317     public function initialize() {
318         if (!isset($this->host)) {
319             throw new Exception('must specify a host');
320         }
321         if (!isset($this->username)) {
322             throw new Exception('must specify a username');
323         }
324         if (!isset($this->realname)) {
325             throw new Exception('must specify a "real name"');
326         }
327         if (!isset($this->nick)) {
328             throw new Exception('must specify a nickname');
329         }
330
331         if (!isset($this->port)) {
332             $this->port = 6667;
333         }
334         if (!isset($this->transporttype)) {
335             $this->transporttype = 'tcp';
336         }
337         if (!isset($this->encoding)) {
338             $this->encoding = 'UTF-8';
339         }
340
341         if (!isset($this->regcheck)) {
342             $this->regcheck = true;
343         }
344
345         $this->fake_irc = new Fake_Irc;
346
347         /*
348          * Commands allowed to return output to a channel
349          */
350         $this->whiteList = array('stats', 'last', 'get');
351
352         return true;
353     }
354
355     /**
356      * Get plugin information
357      *
358      * @param array $versions Array to insert information into
359      * @return void
360      */
361     public function onPluginVersion(&$versions) {
362         $versions[] = array('name' => 'IRC',
363                             'version' => STATUSNET_VERSION,
364                             'author' => 'Luke Fitzgerald',
365                             'homepage' => 'http://status.net/wiki/Plugin:IRC',
366                             'rawdescription' =>
367                             _m('The IRC plugin allows users to send and receive notices over an IRC network.'));
368         return true;
369     }
370 }