PHP 获取MSN好友列表 组信息 发送离线消息 (三)


    function 
getChallenge($code){
        
// MSNP15
        // http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges
        // Step 1: The MD5 Hash
        
$md5Hash md5($code.$this->prod_key);
        
$aMD5 = @explode("\0"chunk_split($md5Hash8"\0"));
        for (
$i 0$i 4$i++) {
            
$aMD5[$i] = implode(''array_reverse(@explode("\0"chunk_split($aMD5[$i], 2"\0"))));
            
$aMD5[$i] = (base_convert($aMD5[$i], 1610)) & 0x7FFFFFFF;
        }
        
// Step 2: A new string
        
$chl_id $code.$this->prod_id;
        
$chl_id .= str_repeat('0'- (strlen($chl_id) % 8));
        
$aID = @explode("\0"substr(chunk_split($chl_id4"\0"), 0, -1));
        for (
$i 0$i count($aID); $i++) {
            
$aID[$i] = implode(''array_reverse(@explode("\0"chunk_split($aID[$i], 1"\0"))));
            
$aID[$i] = base_convert(bin2hex($aID[$i]), 1610);
        }
        
// Step 3: The 64 bit key
        
$magic_num 0x0E79A9C1;
        
$str7f 0x7FFFFFFF;
        
$high 0;
        
$low 0;
        for (
$i 0$i count($aID); $i += 2) {
            
$temp $aID[$i];
            
$temp bcmod(bcmul($magic_num$temp), $str7f);
            
$temp bcadd($temp$high);
            
$temp bcadd(bcmul($aMD5[0], $temp), $aMD5[1]);
            
$temp bcmod($temp$str7f);
            
$high $aID[$i+1];
            
$high bcmod(bcadd($high$temp), $str7f);
            
$high bcadd(bcmul($aMD5[2], $high), $aMD5[3]);
            
$high bcmod($high$str7f);
            
$low bcadd(bcadd($low$high), $temp);
        }
        
$high bcmod(bcadd($high$aMD5[1]), $str7f);
        
$low bcmod(bcadd($low$aMD5[3]), $str7f);
        
$new_high bcmul($high 0xFF0x1000000);
        
$new_high bcadd($new_highbcmul($high 0xFF000x100));
        
$new_high bcadd($new_highbcdiv($high 0xFF00000x100));
        
$new_high bcadd($new_highbcdiv($high 0xFF0000000x1000000));
        
// we need integer here
        
$high 0+$new_high;
        
$new_low bcmul($low 0xFF0x1000000);
        
$new_low bcadd($new_lowbcmul($low 0xFF000x100));
        
$new_low bcadd($new_lowbcdiv($low 0xFF00000x100));
        
$new_low bcadd($new_lowbcdiv($low 0xFF0000000x1000000));
        
// we need integer here
        
$low 0+$new_low;
        
// we just use 32 bits integer, don't need the key, just high/low
        // $key = bcadd(bcmul($high, 0x100000000), $low);
        // Step 4: Using the key
        
$md5Hash md5($code.$this->prod_key);
        
$aHash = @explode("\0"chunk_split($md5Hash8"\0"));
        
$hash '';
        
$hash .= sprintf("%08x", (base_convert($aHash[0], 1610)) ^ $high);
        
$hash .= sprintf("%08x", (base_convert($aHash[1], 1610)) ^ $low);
        
$hash .= sprintf("%08x", (base_convert($aHash[2], 1610)) ^ $high);
        
$hash .= sprintf("%08x", (base_convert($aHash[3], 1610)) ^ $low);
        return 
$hash;
    }
    private function 
getMessage($sMessage$network 1)    {
        
$msg_header "MIME-Version: 1.0\r\nContent-Type: text/plain; charset=UTF-8\r\nX-MMS-IM-Format: FN=$this->font_fn; EF=$this->font_ef; CO=$this->font_co; CS=0; PF=22\r\n\r\n";
        
$msg_header_len strlen($msg_header);
        if (
$network == 1)
        
$maxlen $this->max_msn_message_len $msg_header_len;
        else
        
$maxlen $this->max_yahoo_message_len $msg_header_len;
        
$aMessage = array();
        
$aStr = @explode("\n"$sMessage);
        
$cur_len 0;
        
$msg '';
        
$add_crlf false;
        foreach (
$aStr as $str) {
            
$str str_replace("\r"''$str);
            
$len strlen($str);
            while (
$len $maxlen) {
                if (
$cur_len 0) {
                    
// already has header/msg
                    
$aMessage[] = $msg_header.$msg;
                    
$cur_len 0;
                    
$msg '';
                    
$add_crlf false;
                }
                
$aMessage[] = $msg_header.substr($str0$maxlen);
                
$str substr($str$maxlen);
                
$len strlen($str);
            }
            if ((
$cur_len $len) > $maxlen) {
                
$aMessage[] = $msg_header.$msg;
                
$cur_len 0;
                
$msg '';
                
$add_crlf false;
            }
            if (
$msg !== '' || $add_crlf) {
                
$msg .= "\r\n";
                
$cur_len += 2;
            }
            
$add_crlf true;
            
$msg .= $str;
            
$cur_len += $len;
        }
        if (
$cur_len != 0)
        
$aMessage[] = $msg_header.$msg;
        return 
$aMessage;
    }
    private function 
switchboard_control($ip$port$cki_code$sTo$sMessage)
    {
        
$this->debug_message("*** SB: try to connect to switchboard server $ip:$port");
        
$this->sb = @fsockopen($ip$port$errno$errstr5);
        if (!
$this->sb) {
            
$this->error "SB: Can't connect to $ip:$port, error => $errno, $errstr";
            
$this->debug_message("*** $this->error");
            return 
false;
        }
        
$user $sTo;
        
stream_set_timeout($this->sb$this->stream_timeout);
        
// SB: >>> USR {id} {user} {cki}
        
$this->sb_writeln("USR $this->id $this->user $cki_code");
        
$sent false;
        
$start_tm time();
        
$got_error false;
        
$offline false;
        while (!
feof($this->sb)) {
            if (
$sent || $offline) break;
            
$data $this->sb_readln();
            if (
$data === false) {
                if (
$this->timeout 0) {
                    
$now_tm time();
                    
$used_time = ($now_tm >= $start_tm) ? $now_tm $start_tm $now_tm;
                    if (
$used_time $this->timeout) {
                        
$this->error 'Timeout, maybe protocol changed!';
                        
$this->debug_message("*** $this->error");
                        break;
                    }
                }
                continue;
            }
            
$code substr($data03);
            
$start_tm time();
            switch(
$code) {
                case 
'USR':
                    
$this->sb_writeln("CAL $this->id $user");
                    break;
                case 
'CAL':
                    break;
                case 
'217':
                    
$this->debug_message("*** SB: $user offline! skip to send message!");
                    
$offline true;
                    break;
                case 
'JOI':
                    
$aMessage $this->getMessage($sMessage);
                    foreach (
$aMessage as $message) {
                        
$len strlen($message);
                        
$this->sb_writeln("MSG 20 N $len");
                        
$this->sb_writedata($message);
                    }
                    
$sent true;
                    break;
                default:
                    if (
is_numeric($code)) {
                        
$this->error "Error code: $code, please check the detail information from: http://msnpiki.msnfanatic.com/index.php/Reference:Error_List";
                        
$this->debug_message("*** SB: $this->error");
                        
$got_error true;
                    }
                    break;
            }
        }
        if (
feof($this->sb)) {
            
// lost connection? error? try OIM later
            
@fclose($this->sb);
            return 
false;
        }
        
$this->sb_writeln("OUT");
        @
fclose($this->sb);
        if (
$offline || $got_error) return false;
        return 
true;
    }
    private function 
sendOIM($to$sMessage$lockkey) {
        
$XML '<?xml version="1.0" encoding="utf-8"?>
                    <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                                   xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
                    <soap:Header>
                      <From memberName="'
.$this->user.'"
                            friendlyName="=?utf-8?B?'
.base64_encode($this->user).'?="
                            xml:lang="zh-TW"
                            proxy="MSNMSGR"
                            xmlns="http://messenger.msn.com/ws/2004/09/oim/"
                            msnpVer="MSNP15"
                            buildVer="8.1.0178"/>
                      <To memberName="'
.$to.'" xmlns="http://messenger.msn.com/ws/2004/09/oim/"/>
                      <Ticket passport="'
.htmlspecialchars($this->oim_ticket).'"
                              appid="'
.$this->prod_id.'"
                              lockkey="'
.$lockkey.'"
                              xmlns="http://messenger.msn.com/ws/2004/09/oim/"/>
                      <Sequence xmlns="http://schemas.xmlsoap.org/ws/2003/03/rm">
                        <Identifier xmlns="http://messenger.msn.comhttp://schemas.xmlsoap.org/ws/2002/07/utility">http://messenger.msn.com</Identifier>
                        <MessageNumber>1</MessageNumber>
                      </Sequence>
                    </soap:Header>
                    <soap:Body>
                      <MessageType xmlns="texthttp://messenger.msn.com/ws/2004/09/oim/">text</MessageType>
                      <Content xmlns="MIME-Version'
>http://messenger.msn.com/ws/2004/09/oim/">MIME-Version: 1.0
        
Content-Typetext/plaincharset=UTF-8
        Content
-Transfer-Encodingbase64
        X
-OIM-Message-TypeOfflineMessage
        X
-OIM-Run-Id: {DAB68CFA-38C9-449B-945E-38AFA51E50A7}
        
X-OIM-Sequence-Num1
        
'.chunk_split(base64_encode($sMessage)).'
        
</Content>
        </
soap:Body>
        </
soap:Envelope>';
        $header_array = array(
            '
SOAPActionhttp://messenger.live.com/ws/2006/09/oim/Store2',
            
'Content-Type: text/xml',
            
'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Messenger 8.1.0178)'
            
);
            
//$this->debug_message("*** URL: $this->oim_send_url");
            //$this->debug_message("*** Sending SOAP:\n$XML");
            
$curl curl_init();
            
curl_setopt($curlCURLOPT_URL'https://ows.messenger.msn.com/OimWS/oim.asmx');
            
curl_setopt($curlCURLOPT_HTTPHEADER$header_array);
            
curl_setopt($curlCURLOPT_RETURNTRANSFER1);
            
curl_setopt($curlCURLOPT_FOLLOWLOCATION1);
            
curl_setopt($curlCURLOPT_SSL_VERIFYPEER0);
            if (
$this->debugcurl_setopt($curlCURLOPT_HEADER1);
            
curl_setopt($curlCURLOPT_POST1);
            
curl_setopt($curlCURLOPT_POSTFIELDS$XML);
            
$data curl_exec($curl);
            
$http_code curl_getinfo($curlCURLINFO_HTTP_CODE);
            
curl_close($curl);
            
//$this->debug_message("*** Get Result:\n$data");
            
if ($http_code == 200) {
                
//$this->debug_message("*** OIM sent for $to");
                
return true;
            }
            
$challenge false;
            
$auth_policy false;
            
// the lockkey is invalid, authenticated fail, we need challenge it again
            // <LockKeyChallenge xmlns="364763969http://messenger.msn.com/ws/2004/09/oim/">364763969</LockKeyChallenge>
            
preg_match("#<LockKeyChallenge (.*)>(.*)</LockKeyChallenge>#"$data$matches);
            if (
count($matches) != 0) {
                
// yes, we get new LockKeyChallenge
                
$challenge $matches[2];
                
$this->debug_message("*** OIM need new challenge ($challenge) for $to");
            }
            
// auth policy error
            // <RequiredAuthPolicy xmlns="MBI_SSLhttp://messenger.msn.com/ws/2004/09/oim/">MBI_SSL</RequiredAuthPolicy>
            
preg_match("#<RequiredAuthPolicy (.*)>(.*)</RequiredAuthPolicy>#"$data$matches);
            if (
count($matches) != 0) {
                
$auth_policy $matches[2];
                
$this->debug_message("*** OIM need new auth policy ($auth_policy) for $to");
            }
            if (
$auth_policy === false && $challenge === false) {
                
//<faultcode xmlns:q0="q0:AuthenticationFailedhttp://messenger.msn.com/ws/2004/09/oim/">q0:AuthenticationFailed</faultcode>
                
preg_match("#<faultcode (.*)>(.*)</faultcode>#"$data$matches);
                if (
count($matches) == 0) {
                    
// no error, we assume the OIM is sent
                    
$this->debug_message("*** OIM sent for $to");
                    return 
true;
                }
                
$err_code $matches[2];
                
preg_match("#<faultstring>(.*)</faultstring>#"$data$matches);
                if (
count($matches) > 0)
                
$err_msg $matches[1];
                else
                
$err_msg '';
                
$this->debug_message("*** OIM failed for $to");
                
$this->debug_message("*** OIM Error code: $err_code");
                
$this->debug_message("*** OIM Error Message: $err_msg");
                return 
false;
            }
            return array(
'challenge' => $challenge'auth_policy' => $auth_policy);
    }
    
// read data for specified size
    
private function readdata($size)
    {
        
$data '';
        
$count 0;
        while (!
feof($this->fp)) {
            
$buf = @fread($this->fp$size $count);
            
$data .= $buf;
            
$count += strlen($buf);
            if (
$count >= $size) break;
        }
        
//$this->debug_message("NS: data ($size/$count) <<<\n$data");
        
return $data;
    }
    
// read one line
    
private function readln()
    {
        
$data = @fgets($this->fp4096);
        if (
$data !== false) {
            
$data trim($data);
            
//$this->debug_message("NS: <<< $data");
        
}
        return 
$data;
    }
    
// write to server, append \r\n, also increase id
    
private function writeln($data)
    {
        @
fwrite($this->fp$data."\r\n");
        
//$this->debug_message("NS: >>> $data");
        
$this->id++;
        return;
    }
    
// write data to server
    
private function writedata($data)    {
        @
fwrite($this->fp$data);
        
//$this->debug_message("NS: >>> $data");
        
return;
    }
    
// read data for specified size for SB
    
private function sb_readdata($size)    {
        
$data '';
        
$count 0;
        while (!
feof($this->sb)) {
            
$buf = @fread($this->sb$size $count);
            
$data .= $buf;
            
$count += strlen($buf);
            if (
$count >= $size) break;
        }
        
//$this->debug_message("SB: data ($size/$count) <<<\n$data");
        
return $data;
    }
    
// read one line for SB
    
private function sb_readln()    {
        
$data = @fgets($this->sb4096);
        if (
$data !== false) {
            
$data trim($data);
            
//$this->debug_message("SB: <<< $data");
        
}
        return 
$data;
    }
    
// write to server for SB, append \r\n, also increase id
    // switchboard server only accept \r\n, it will lost connection if just \n only
    
private function sb_writeln($data)    {
        @
fwrite($this->sb$data."\r\n");
        
//$this->debug_message("SB: >>> $data");
        
$this->id++;
        return;
    }
    
// write data to server
    
private function sb_writedata($data)    {
        @
fwrite($this->sb$data);
        return;
    }
    
// show debug information
    
private function debug_message($str)    {
        if (
$this->debug)   echo $str."\n";
    }
}
<script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/buttonLite.js#style=-1&uuid=&pophcol=3&lang=zh"></script> <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/bshareC0.js"></script>
阅读(642) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-01-26 17:19:01

顶下

评论热议
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值