5 function __construct($host = null, $port = null, $blocking = true) {
13 $host = substr($host, 1);
15 $this->stream
= @stream_socket_client
("{$scheme}://$host:$port", $errno, $errstr, 4);
18 debug("Error creating socket: $host $errstr\n");
21 // socket_set_timeout($this->stream, 30);
22 stream_set_blocking($this->stream
, $blocking);
28 fclose($this->stream
);
32 function SetBlocking($blocking = true)
36 stream_set_blocking($this->stream
, $blocking);
38 function SetTimeout($timeout, $ms=0)
42 stream_set_timeout($this->stream
, $timeout, $ms);
48 $x = stream_get_meta_data($this->stream
);
49 if($x['eof'] && $x['unread_bytes']==0 && feof($this->stream
))
53 function Read($length = 512, $type = PHP_BINARY_READ
)
55 if(!$this->stream
) return false;
56 if($type == PHP_NORMAL_READ
){
57 $ret = fgets($this->stream
, $length);
58 } elseif($type == PHP_BINARY_READ
) {
59 $ret = fread($this->stream
, $length);
61 //file_put_contents('/home/wok/public_html/kiwi/rawlog', '> '.$ret, FILE_APPEND);
67 if(!$this->stream
) return false;
69 //file_put_contents('/home/wok/public_html/kiwi/rawlog', '< '.$data, FILE_APPEND);
70 $x = @fwrite
($this->stream
, $data);
77 return array('local'=>stream_socket_get_name($this->stream
,false),'remote'=>stream_socket_get_name($this->stream
, true));
80 class SocketStreamSSL
extends SocketStream
82 function __construct($host = null, $port = null, $blocking = true)
86 $this->stream
= @stream_socket_client
("ssl://$host:$port", $errno, $errstr, 4);
89 debug("Error creating socket: $host $errstr\n");
92 // socket_set_timeout($this->stream, 30);
93 stream_set_blocking($this->stream
, $blocking);
101 protected $msgqueue = array();
102 protected $dccs = array();
103 private $reconnect=0;
108 function __construct($url, $kiwi=null, $opts=array()){
110 $urlinfo = parse_url($url);
111 $this->urlinfo
= $urlinfo;
112 if(!ereg("^ircs?$", $urlinfo['scheme']))
114 $ssl = ($urlinfo['scheme']=='ircs');
115 $host = $urlinfo['host'];
116 $port = isset($urlinfo['port'])?
$urlinfo['port']:6667;
117 $this->nick
= $nick = isset($urlinfo['user'])?
$urlinfo['user']:'kiwi_user|'.(string)rand(0,9999);
118 //$ident = isset($urlinfo['pass'])?$urlinfo['pass']:$nick;
119 $ident = (isset($opts['ident'])) ?
"{$opts['ident']}_kiwi" : "{$nick}_kiwi";
121 if(isset($urlinfo['path'])){
122 $path = trim($urlinfo['path'], "/");
123 $chans = explode(",", $path); //"#".str_replace(array(":", ","), array(" ", ",#"), $path);
125 $this->connected
= false;
127 $this->stream
= new SocketStreamSSL($host, $port, false);
129 $this->stream
= new SocketStream($host, $port, false);
130 if(!$this->stream ||
!$this->stream
->stream
){
134 // Send the login data
135 if($kiwi != null) $this->stream
->Write($kiwi."\r\n");
136 if(isset($urlinfo['fragment'])) $this->stream
->Write("PASS {$urlinfo['fragment']}\r\n");
138 $this->stream
->Write("NICK $nick\r\n");
139 $this->stream
->Write("USER $ident 0 0 :$nick\r\n");
141 // foreach($chans as $chan)
142 // $this->stream->Write("JOIN ".str_replace(":", " ", $chan)."\r\n");
146 $this->chans
= $chans;
147 $this->connected
= true;
150 function __destruct(){
152 $this->stream
->Write("QUIT :kiwi\r\n");
156 if((!$this->stream ||
!$this->stream
->stream
)){
157 if(time() > $this->reconnect
) {
158 $this->__construct($this->url
);
159 $this->reconnect
= time() +
10;
164 if($this->stream
->Eof()){
165 $this->stream
= null;
168 $r=array($this->stream
->stream
);
170 if(($num=@stream_select
($r, $w,$e,0,50000))===false){
173 $data=$this->stream
->Read(512, PHP_NORMAL_READ
);
175 if(preg_match("/^(?::(?:([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)|([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)!([a-z0-9~\.\-_|]+)@([a-z0-9\.\-:]+)) )?([a-z0-9]+)(?:(?: ([^:]+))?(?: :(.+))?)$/i", $data, $regs))
177 unset($prefix, $nick, $ident, $hostname, $command, $params, $trailing, $flarp);
181 $hostname = $regs[4];
183 $params = isset($regs[6]) ?
$regs[6] : '';
184 $trailing = trim(isset($regs[7]) ?
$regs[7] : '');
185 $flarp = compact('prefix', 'nick', 'ident', 'hostname', 'command', 'params', 'trailing');
186 $this->ProcessMessage($flarp);
191 if(sizeof($this->msgqueue
) && (microtime(true)>($this->lastqueuewrite+
0.1)) && ($msg=array_shift($this->msgqueue
)))
192 { $this->lastqueuewrite
= microtime(true); $this->stream
->Write($msg); }
193 foreach($this->dccs
as $k=>&$dcc)
198 $this->SendNotice($dcc->errorinfo
['nick'], $dcc->errorinfo
['text']);
199 unset($this->dccs
[$k]);
202 if(($now=microtime(1))>$this->nextping
)
204 $this->stream
->Write("PONG x\r\n");
205 $this->nextping
= $now +
150;
209 function ProcessMessage($message)
211 //echo $message['command']."\n";
212 switch($message['command'])
215 $this->stream
->Write("PONG {$message['trailing']}\r\n");
218 $this->ProcessPrivMsg($message);
222 foreach($this->chans
as $chan)
223 $this->stream
->Write("JOIN ".str_replace(":", " ", $chan)."\r\n");
226 $newnick = 'kiwi_user|'.rand(0,99999);
227 $this->SendCmd("NICK ".$newnick);
228 $this->nick
= $newnick;
231 $this->OnMODE($message);
234 $this->On353($message);
237 $chan = $message['params'];
238 foreach($this->chanlist
as &$chan){
239 if(isset($chan['userlist'][$message['nick']]))
240 unset($chan['userlist'][$message['nick']]);
244 $chan = $message['params'];
245 //debug("Parting {$message['nick']} from $chan");
246 if(isset($this->chanlist
[ltrim($chan, "#")])){
247 unset($this->chanlist
[ltrim($chan, "#")]['userlist'][$message['nick']]);
251 $chan = $message['trailing'];
252 $nick = array($message['nick'] => '');
253 $nicklist = is_array($this->chanlist
[ltrim($chan, "#")]['userlist']) ?
$this->chanlist
[ltrim($chan, "#")]['userlist'] :
256 $this->chanlist
[ltrim($chan, "#")]['userlist'] = array_merge($nicklist, $nick);
259 if($message['nick'] == $this->nick
){
260 $this->nick
= $message['trailing'];
262 foreach($this->chanlist
as $chan_name => $chan){
263 foreach($chan['userlist'] as $nick => $status){
264 if($nick == $message['nick']){
265 $this->chanlist
[$chan_name]['userlist'][$message['trailing']] = $this->chanlist
[$chan_name]['userlist'][$message['nick']];
266 unset($this->chanlist
[$chan_name]['userlist'][$message['nick']]);
274 function OnMODE($message){
275 if($message['params'] == $this->nick
) {
276 $modes = $message['trailing'];
277 $size = strlen($modes);
279 for($i=0;$i<$size;$i++
){
280 if($modes{$i} == '+'){
283 } elseif($modes{$i} == '-'){
287 if($add && strpos($this->modes
, $modes{$i}) === false)
288 $this->modes
.=$modes{$i};
289 if(!$add && strpos($this->modes
, $modes{$i}))
290 $this->modes
= str_replace($modes{$i}, "", $this->modes
);
293 $params = $message['params'];
294 $chan = trim(strtok($params, ' '));
295 if(in_array(trim($chan,'#'), $this->chans
)){
296 $modes = strtok(' ');
297 $therest = explode(" ", trim(strtok('')));
298 $size = strlen($modes);
301 for($i=0;$i<$size;$i++
){
302 if($modes{$i} == '+'){
306 } elseif($modes{$i} == '-'){
313 $user = $therest[$i+
$offset];
316 if(stripos($this->chanlist
[trim($chan,'#')]['userlist'][$user], '+')===false)
317 $this->chanlist
[trim($chan,'#')]['userlist'][$user] .= '+';
320 $this->chanlist
[trim($chan,'#')]['userlist'][$user] = str_replace('+','',$this->chanlist
[trim($chan,'#')]['userlist'][$user]);
325 $user = $therest[$i+
$offset];
328 if(stripos($this->chanlist
[trim($chan,'#')]['userlist'][$user], '@')===false)
329 $this->chanlist
[trim($chan,'#')]['userlist'][$user] .= '@';
332 $this->chanlist
[trim($chan,'#')]['userlist'][$user] = str_replace('@','',$this->chanlist
[trim($chan,'#')]['userlist'][$user]);
337 $user = $therest[$i+
$offset];
340 if(stripos($this->chanlist
[trim($chan,'#')]['userlist'][$user], '%')===false)
341 $this->chanlist
[trim($chan,'#')]['userlist'][$user] .= '%';
344 $this->chanlist
[trim($chan,'#')]['userlist'][$user] = str_replace('%','',$this->chanlist
[trim($chan,'#')]['userlist'][$user]);
349 $user = $therest[$i+
$offset];
352 if(stripos($this->chanlist
[trim($chan,'#')]['userlist'][$user], '~')===false)
353 $this->chanlist
[trim($chan,'#')]['userlist'][$user] .= '~';
356 $this->chanlist
[trim($chan,'#')]['userlist'][$user] = str_replace('~','',$this->chanlist
[trim($chan,'#')]['userlist'][$user]);
363 function On353($message){
364 // Response to NAMES command
365 list($nick,,$chan) = explode(" ", $message['params']);
366 $nicks = explode(" ", $message['trailing']);
367 $prefixes = array('~', '&', '@','%','+');
369 foreach($nicks as $nick){
370 if(in_array($nick{0}, $prefixes)){
372 $nick = substr($nick,1);
376 $nicklist[$nick] = $prefix;
378 if(sizeof($nicklist)){
379 // If we havn't got a list of nicks for this channel yet, create it
380 if(!isset($this->chanlist
[ltrim($chan, "#")]['userlist'])){
381 $this->chanlist
[ltrim($chan, "#")]['userlist'] = array();
383 $this->chanlist
[ltrim($chan, "#")]['userlist'] = array_merge($this->chanlist
[ltrim($chan, "#")]['userlist'], $nicklist);
386 function ProcessPrivMsg($message){
387 //$cmd = strtok($message['trailing'], ' ');
391 function SendMessage($dest, $text){
394 $this->stream
->Write("PRIVMSG $dest :$text\r\n");
396 function Join($chan){
397 $this->stream
->Write("JOIN ".str_replace(":", " ", $chan)."\r\n");
399 function SendNotice($dest, $text)
401 $this->stream
->Write("NOTICE $dest :$text\r\n");
403 function QueueMessage($dest, $text)
405 $this->msgqueue
[] = "PRIVMSG $dest :$text\r\n";
407 function QueueNotice($dest, $text)
409 $this->msgqueue
[] = "NOTICE $dest :$text\r\n";
411 function GetMainChan()
413 return '#'.$this->chans
[0];