51 * The function called when a private message is received. |
51 * The function called when a private message is received. |
52 * @var string |
52 * @var string |
53 */ |
53 */ |
54 |
54 |
55 private $privmsg_handler = false; |
55 private $privmsg_handler = false; |
|
56 |
|
57 /** |
|
58 * The function called when a timeout is suspected. |
|
59 * @var string |
|
60 */ |
|
61 |
|
62 private $timeout_warning_handler = false; |
|
63 |
|
64 /** |
|
65 * The function called when a timeout is confirmed. |
|
66 * @var string |
|
67 */ |
|
68 |
|
69 private $timeout_error_handler = false; |
56 |
70 |
57 /** |
71 /** |
58 * Switch to track if quitted or not. Helps avoid quitting the connection twice thus causing write errors. |
72 * Switch to track if quitted or not. Helps avoid quitting the connection twice thus causing write errors. |
59 * @var bool |
73 * @var bool |
60 * @access private |
74 * @access private |
103 * @param string Real name |
117 * @param string Real name |
104 * @param string NickServ password |
118 * @param string NickServ password |
105 * @param int Flags, defaults to 0. |
119 * @param int Flags, defaults to 0. |
106 */ |
120 */ |
107 |
121 |
108 public function connect($nick, $username, $realname, $pass, $flags = 0) |
122 public function connect($nick, $username, $realname, $pass = false, $flags = 0) |
109 { |
123 { |
110 // Init connection |
124 // Init connection |
111 $this->sock = fsockopen($this->host, $this->port); |
125 $this->sock = fsockopen($this->host, $this->port); |
112 if ( !$this->sock ) |
126 if ( !$this->sock ) |
113 throw new Exception('Could not make socket connection to host.'); |
127 throw new Exception('Could not make socket connection to host.'); |
133 $this->put("PONG :{$match[1]}\r\n"); |
147 $this->put("PONG :{$match[1]}\r\n"); |
134 } |
148 } |
135 } |
149 } |
136 |
150 |
137 // identify to nickserv |
151 // identify to nickserv |
138 $this->privmsg('NickServ', "IDENTIFY $pass"); |
152 if ( $pass ) |
|
153 $this->privmsg('NickServ', "IDENTIFY $pass"); |
139 |
154 |
140 $this->nick = $nick; |
155 $this->nick = $nick; |
141 $this->user = $username; |
156 $this->user = $username; |
|
157 $this->quitted = false; |
142 } |
158 } |
143 |
159 |
144 /** |
160 /** |
145 * Writes some data to the socket, abstracted for debugging purposes. |
161 * Writes some data to the socket, abstracted for debugging purposes. |
146 * @param string Message to send, this should include a CRLF. |
162 * @param string Message to send, this should include a CRLF. |
162 /** |
178 /** |
163 * Reads from the socket... |
179 * Reads from the socket... |
164 * @return string |
180 * @return string |
165 */ |
181 */ |
166 |
182 |
167 public function get() |
183 public function get($timeout = 1) |
168 { |
184 { |
169 if ( !$this->sock ) |
185 if ( !$this->sock ) |
170 { |
186 { |
171 if ( defined('LIBIRC_DEBUG') ) |
187 if ( defined('LIBIRC_DEBUG') ) |
172 echo "<<< READ FAILED\n"; |
188 echo "<<< READ FAILED\n"; |
173 return false; |
189 return false; |
174 } |
190 } |
175 $out = fgets($this->sock, 4096); |
191 if ( ($c = stream_select($r = array($this->sock), $w = null, $e = null, $timeout)) !== false ) |
176 if ( defined('LIBIRC_DEBUG') ) |
192 { |
177 if ( !empty($out) ) |
193 if ( $c > 0 ) |
178 echo "<<< $out"; |
194 { |
179 return $out; |
195 $out = fgets($this->sock, 4096); |
|
196 if ( defined('LIBIRC_DEBUG') ) |
|
197 if ( !empty($out) ) |
|
198 echo "<<< $out"; |
|
199 return $out; |
|
200 } |
|
201 } |
|
202 return false; |
180 } |
203 } |
181 |
204 |
182 /** |
205 /** |
183 * Sends a message to a nick or channel. |
206 * Sends a message to a nick or channel. |
184 * @param string Nick or channel |
207 * @param string Nick or channel |
199 * The main event loop. |
222 * The main event loop. |
200 */ |
223 */ |
201 |
224 |
202 public function event_loop() |
225 public function event_loop() |
203 { |
226 { |
204 stream_set_timeout($this->sock, 0xFFFFFFFE); |
227 $timeout = 180; |
205 while ( $data = $this->get() ) |
228 $timeout_warn = false; |
206 { |
229 while ( true ) |
207 $data_trim = trim($data); |
230 { |
|
231 $data = $this->get($timeout); |
|
232 $data_trim = $data ? trim($data) : false; |
|
233 if ( empty($data_trim) ) |
|
234 { |
|
235 if ( $timeout_warn ) |
|
236 { |
|
237 // timeout confirmed :-/ |
|
238 if ( $this->timeout_error_handler ) |
|
239 { |
|
240 $result = @call_user_func($this->timeout_error_handler, $this); |
|
241 if ( $result == 'BREAK' ) |
|
242 break; |
|
243 } |
|
244 $timeout = 180; |
|
245 $timeout_warn = false; |
|
246 continue; |
|
247 } |
|
248 // timeout suspected |
|
249 if ( $this->timeout_warning_handler ) |
|
250 { |
|
251 $result = @call_user_func($this->timeout_warning_handler, $this); |
|
252 if ( $result == 'BREAK' ) |
|
253 break; |
|
254 } |
|
255 // ping the server |
|
256 $this->put("PING :{$this->nick}\r\n"); |
|
257 // set timeout lower to make reconnecting work as fast as possible |
|
258 $timeout = 10; |
|
259 $timeout_warn = true; |
|
260 continue; |
|
261 } |
208 $match = self::parse_message($data_trim); |
262 $match = self::parse_message($data_trim); |
209 if ( preg_match('/^PING :(.+?)$/', $data_trim, $pmatch) ) |
263 if ( preg_match('/^PING :(.+?)$/', $data_trim, $pmatch) ) |
210 { |
264 { |
211 $this->put("PONG :{$pmatch[1]}\r\n"); |
265 $this->put("PONG :{$pmatch[1]}\r\n"); |
212 eval(eb_fetch_hook('event_ping')); |
266 eval(eb_fetch_hook('event_ping')); |
|
267 } |
|
268 else if ( preg_match('/^:((?:[a-z0-9-]+\.)*[a-z0-9-]+) PONG \\1 :' . preg_quote($this->nick) .'/', $data_trim) ) |
|
269 { |
|
270 $timeout = 180; |
|
271 $timeout_warn = false; |
213 } |
272 } |
214 else if ( $match ) |
273 else if ( $match ) |
215 { |
274 { |
216 // Received PRIVMSG or other mainstream action |
275 // Received PRIVMSG or other mainstream action |
217 if ( $match['action'] == 'JOIN' || $match['action'] == 'PART' ) |
276 if ( $match['action'] == 'JOIN' || $match['action'] == 'PART' ) |
267 $this->privmsg_handler = $func; |
326 $this->privmsg_handler = $func; |
268 return true; |
327 return true; |
269 } |
328 } |
270 |
329 |
271 /** |
330 /** |
|
331 * Changes the functions called when IRC connection timeouts occur. |
|
332 * @param string Function to call when a warning (no traffic within 3 minutes) occurs. If false, nothing will be called. |
|
333 * @param string Function to call if a ping timeout occurs. If false, nothing will be called. |
|
334 */ |
|
335 |
|
336 function set_timeout_handlers($warn_func, $error_func) |
|
337 { |
|
338 $this->timeout_warning_handler = false; |
|
339 $this->timeout_error_handler = false; |
|
340 if ( function_exists($warn_func) ) |
|
341 { |
|
342 $this->timeout_warning_handler = $warn_func; |
|
343 } |
|
344 if ( function_exists($error_func) ) |
|
345 { |
|
346 $this->timeout_error_handler = $error_func; |
|
347 } |
|
348 return true; |
|
349 } |
|
350 |
|
351 /** |
272 * Parses a message line. |
352 * Parses a message line. |
273 * @param string Message text |
353 * @param string Message text |
274 * @return array Associative with keys: nick, user, host, action, target, message |
354 * @return array Associative with keys: nick, user, host, action, target, message |
275 */ |
355 */ |
276 |
356 |
307 $this->channels[strtolower($channel)] = $chan; |
387 $this->channels[strtolower($channel)] = $chan; |
308 return $chan; |
388 return $chan; |
309 } |
389 } |
310 |
390 |
311 /** |
391 /** |
|
392 * Changes the current nick. |
|
393 * @param string New nick. |
|
394 * @param string Password to authenticate to NickServ if needed. |
|
395 */ |
|
396 |
|
397 public function change_nick($nick, $pass = false) |
|
398 { |
|
399 $this->put("NICK $nick\r\n"); |
|
400 $this->nick = $nick; |
|
401 if ( $pass ) |
|
402 { |
|
403 while ( $data = $this->get(3) ) |
|
404 { |
|
405 if ( strstr($data, 'NickServ') ) |
|
406 { |
|
407 $this->privmsg('NickServ', "IDENTIFY $pass"); |
|
408 break; |
|
409 } |
|
410 } |
|
411 } |
|
412 } |
|
413 |
|
414 /** |
312 * Closes the connection and quits. |
415 * Closes the connection and quits. |
313 * @param string Optional part message |
416 * @param string Optional part message |
314 */ |
417 */ |
315 |
418 |
316 public function close($partmsg = false) |
419 public function close($partmsg = false) |