]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Irc/IrcPlugin.php
75eaf687b265bc354b6f0298279aadee415bd6bc
[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     public $whiteList;
70     public $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
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      * @return boolean
145      */
146     public function onStartImDaemonIoManagers(&$classes) {
147         parent::onStartImDaemonIoManagers(&$classes);
148         $classes[] = new IrcManager($this); // handles sending/receiving
149         return true;
150     }
151
152     /**
153     * Get a microid URI for the given screenname
154     *
155     * @param string $screenname
156     * @return string microid URI
157     */
158     public function microiduri($screenname) {
159         return 'irc:' . $screenname;
160     }
161
162     /**
163      * Send a message to a given screenname
164      *
165      * @param string $screenname Screenname to send to
166      * @param string $body Text to send
167      * @return boolean success value
168      */
169     public function send_message($screenname, $body) {
170         $lines = explode("\n", $body);
171         foreach ($lines as $line) {
172             $this->fake_irc->doPrivmsg($screenname, $line);
173             $this->enqueue_outgoing_raw(array('type' => 'message', 'data' => $this->fake_irc->would_be_sent));
174         }
175         return true;
176     }
177
178     /**
179      * Accept a queued input message.
180      *
181      * @return true if processing completed, false if message should be reprocessed
182      */
183     public function receive_raw_message($data) {
184         if (strpos($data['source'], '#') === 0) {
185             $message = $data['message'];
186             $parts = explode(' ', $message, 2);
187             $command = $parts[0];
188             if (in_array($command, $this->whiteList)) {
189                 $this->handle_channel_incoming($data['sender'], $data['source'], $message);
190             } else {
191                 $this->handle_incoming($data['sender'], $message);
192             }
193         } else {
194             $this->handle_incoming($data['sender'], $data['message']);
195         }
196         return true;
197     }
198
199     protected function handle_channel_incoming($nick, $channel, $notice_text) {
200         $user = $this->get_user($nick);
201         // For common_current_user to work
202         global $_cur;
203         $_cur = $user;
204
205         if (!$user) {
206             $this->send_from_site($nick, 'Unknown user; go to ' .
207                              common_local_url('imsettings') .
208                              ' to add your address to your account');
209             common_log(LOG_WARNING, 'Message from unknown user ' . $nick);
210             return;
211         }
212         if ($this->handle_channel_command($user, $channel, $notice_text)) {
213             common_log(LOG_INFO, "Command message by $nick handled.");
214             return;
215         } else if ($this->is_autoreply($notice_text)) {
216             common_log(LOG_INFO, 'Ignoring auto reply from ' . $nick);
217             return;
218         } else if ($this->is_otr($notice_text)) {
219             common_log(LOG_INFO, 'Ignoring OTR from ' . $nick);
220             return;
221         } else {
222             common_log(LOG_INFO, 'Posting a notice from ' . $user->nickname);
223             $this->add_notice($nick, $user, $notice_text);
224         }
225
226         $user->free();
227         unset($user);
228         unset($_cur);
229         unset($message);
230     }
231
232     /**
233      * Attempt to handle a message from a channel as a command
234      *
235      * @param User $user user the message is from
236      * @param string $channel Channel the message originated from
237      * @param string $body message text
238      * @return boolean true if the message was a command and was executed, false if it was not a command
239      */
240     protected function handle_channel_command($user, $channel, $body) {
241         $inter = new CommandInterpreter();
242         $cmd = $inter->handle_command($user, $body);
243         if ($cmd) {
244             $chan = new ChannelResponseChannel($this, $channel);
245             $cmd->execute($chan);
246             return true;
247         } else {
248             return false;
249         }
250     }
251
252     /**
253      * Send a confirmation code to a user
254      *
255      * @param string $screenname screenname sending to
256      * @param string $code the confirmation code
257      * @param User $user user sending to
258      * @return boolean success value
259      */
260     public function send_confirmation_code($screenname, $code, $user, $checked = false) {
261         $body = sprintf(_('User "%s" on %s has said that your %s screenname belongs to them. ' .
262           'If that\'s true, you can confirm by clicking on this URL: ' .
263           '%s' .
264           ' . (If you cannot click it, copy-and-paste it into the ' .
265           'address bar of your browser). If that user isn\'t you, ' .
266           'or if you didn\'t request this confirmation, just ignore this message.'),
267           $user->nickname, common_config('site', 'name'), $this->getDisplayName(), common_local_url('confirmaddress', array('code' => $code)));
268
269         if ($this->regcheck && !$checked) {
270             return $this->checked_send_confirmation_code($screenname, $code, $user);
271         } else {
272             return $this->send_message($screenname, $body);
273         }
274     }
275
276     /**
277     * Only sends the confirmation message if the nick is
278     * registered
279     *
280     * @param string $screenname screenname sending to
281     * @param string $code the confirmation code
282     * @param User $user user sending to
283     * @return boolean success value
284     */
285     public function checked_send_confirmation_code($screenname, $code, $user) {
286         $this->fake_irc->doPrivmsg('NickServ', 'INFO '.$screenname);
287         $this->enqueue_outgoing_raw(
288             array(
289                 'type' => 'nickcheck',
290                 'data' => $this->fake_irc->would_be_sent,
291                 'nickdata' =>
292                     array(
293                         'screenname' => $screenname,
294                         'code' => $code,
295                         'user' => $user
296                     )
297             )
298         );
299         return true;
300     }
301
302     /**
303     * Initialize plugin
304     *
305     * @return boolean
306     */
307     public function initialize() {
308         if (!isset($this->host)) {
309             throw new Exception('must specify a host');
310         }
311         if (!isset($this->username)) {
312             throw new Exception('must specify a username');
313         }
314         if (!isset($this->realname)) {
315             throw new Exception('must specify a "real name"');
316         }
317         if (!isset($this->nick)) {
318             throw new Exception('must specify a nickname');
319         }
320
321         if (!isset($this->port)) {
322             $this->port = 6667;
323         }
324         if (!isset($this->transporttype)) {
325             $this->transporttype = 'tcp';
326         }
327         if (!isset($this->encoding)) {
328             $this->encoding = 'UTF-8';
329         }
330
331         if (!isset($this->regcheck)) {
332             $this->regcheck = true;
333         }
334
335         $this->fake_irc = new Fake_Irc;
336
337         /*
338          * Commands allowed to return output to a channel
339          */
340         $this->whiteList = array('stats', 'last', 'get');
341
342         return true;
343     }
344
345     /**
346      * Get plugin information
347      *
348      * @param array $versions array to insert information into
349      * @return void
350      */
351     public function onPluginVersion(&$versions) {
352         $versions[] = array('name' => 'IRC',
353                             'version' => STATUSNET_VERSION,
354                             'author' => 'Luke Fitzgerald',
355                             'homepage' => 'http://status.net/wiki/Plugin:IRC',
356                             'rawdescription' =>
357                             _m('The IRC plugin allows users to send and receive notices over an IRC network.'));
358         return true;
359     }
360 }