Chinaunix首页 | 论坛 | 博客
  • 博客访问: 305403
  • 博文数量: 153
  • 博客积分: 3347
  • 博客等级: 中校
  • 技术积分: 1556
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-30 17:50
文章分类

全部博文(153)

文章存档

2013年(7)

2012年(21)

2011年(46)

2010年(16)

2009年(63)

我的朋友

分类:

2009-12-30 18:44:32


    function 
getChallenge($code){
        
// MSNP15
        // 
        // 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: ";
                        
$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 '
                                                       xmlns:xsd=""
                                   xmlns:soap="">
                    
                      .$this->user.'"
                            friendlyName="=?utf-8?B?'
.base64_encode($this->user).'?="
                            xml:lang="zh-TW"
                            proxy="MSNMSGR"
                            xmlns=""
                            msnpVer="MSNP15"
                            buildVer="8.1.0178"/>
                      .$to.'" xmlns=""/>
                      .htmlspecialchars($this->oim_ticket).'"
                              appid="'
.$this->prod_id.'"
                              lockkey="'
.$lockkey.'"
                              xmlns=""/>
                      
                        
                        1
                      
                    

                    
                      text
                      >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'');
            
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
            // 364763969
            
preg_match("#(.*)#"$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
            // MBI_SSL
            
preg_match("#(.*)#"$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) {
                
//q0:AuthenticationFailed
                
preg_match("#(.*)#"$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("#(.*)#"$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";
    }
}
阅读(885) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

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

顶下