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

全部博文(153)

文章存档

2013年(7)

2012年(21)

2011年(46)

2010年(16)

2009年(63)

我的朋友

分类:

2009-12-30 18:43:56


    
/**
     * 获取MSN联系人包括分组信息
     *
     * @return array
     *      email=>array(
     *          email=>
     *          name=>
     *          group=>
     *      )
     * @uses
     *      var
     *          contact_ticket
     *          debug
     *      function
     *          debug_message
     */
    
public function getAddressBook(){
        
//SOAP请求包
        
$XML='                      xmlns:xsi=\'\'
                 xmlns:xsd=\'\'
                 xmlns:soapenc=\'\'>
                    
                        
                    CFE80F9D-180F-4399-82AB-413F33A1FA11
                    false
                    Initial
                  
                  
                    false
                    '
.htmlspecialchars($this->contact_ticket).'
                  
                    
                 
                  
                    00000000-0000-0000-0000-000000000000
                    Full
                    false
                    0001-01-01T00:00:00.0000000-08:00
                  
                    

                '
;
        
$header_array = array(
        
'SOAPAction: /ABFindAll',
        
'Content-Type: text/xml; charset=utf-8',
        
'Cookie: MSPAuth=Removed',
        
'Host: contacts.msn.com'
        
);
        
//发送SOAP请求
        
$curl = curl_init();
        
curl_setopt($curl, CURLOPT_URL,'');
        
curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);
        
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
        
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
        if (
$this->debug) curl_setopt($curl, CURLOPT_HEADER, 1);
        
curl_setopt($curl, CURLOPT_POST, 1);
        
curl_setopt($curl, CURLOPT_POSTFIELDS, $XML);
        
$data = curl_exec($curl);
        
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        
curl_close($curl);
        
//$this->debug_message("*** Get Result:\n$data");
        
if ($http_code != 200) return array();
        
//将回应包转换为对象
        
$start = strpos($data, '');
        
$end = strpos($data, '');
        
$start+=17;
        
$result=substr($data,$start,$end-$start);
        
//$this->debug_message("*** Get Result:\n$result");
        
$result=simplexml_load_string("".$result."");
        
//获取分组信息
        
$groups=array();
        foreach(
$result->groups->Group as $group){
            
$groups[(string)$group->groupId]=(string)$group->groupInfo->name;
        }
        
//获取联系人信息
        
$contacts=array();
        foreach(
$result->contacts->Contact as $contact){
            
$info=$contact->contactInfo;
            
//自己,不加入联系人中
            
if($info->contactType=='Me')continue;
            
//获取所属的组
            
$email=$name=$group='';
            if(isset(
$info->groupIds))if(isset($info->groupIds->guid)){
                
$group=$groups[(string)$info->groupIds->guid];
            }
            
//获取EMAIL地址
            
if(isset($info->passportName)){
                
$email=$info->passportName;
            }elseif(isset(
$info->emails)&&isset($info->emails->ContactEmail)){
                if(
is_array($info->emails->ContactEmail)){
                    
$email=$info->emails->ContactEmail[0]->email;
                }else{
                    
$email=$info->emails->ContactEmail->email;
                }
            }
            
//获取显示名
            
if(isset($info->annotations))if(isset($info->annotations->Annotation)){
                if(
is_array($info->annotations->Annotation)){
                    foreach(
$info->annotations->Annotation as $ann){
                        if(
$ann->Name=='AB.NickName'){
                            
$name=$ann->Value;
                            break;
                        }
                    }
                }elseif(
$info->annotations->Annotation->Name=='AB.NickName'){
                    
$name=$info->annotations->Annotation->Value;
                }
            }
            if(!
$name)if(isset($info->displayName))$name=$info->displayName;
            if(!
$name)if(isset($info->quickName))$name=$info->quickName;
            if(!
$name)$name=$email;
            
//加入联系人数组中
            
$contacts[(string)$email]=array('email'=>(string)$email,'name'=>(string)$name,'group'=>$group);
        }
        return 
$contacts;
    }
    private function 
derive_key($key, $magic)
    {
        
$hash1 = mhash(MHASH_SHA1, $magic, $key);
        
$hash2 = mhash(MHASH_SHA1, $hash1.$magic, $key);
        
$hash3 = mhash(MHASH_SHA1, $hash1, $key);
        
$hash4 = mhash(MHASH_SHA1, $hash3.$magic, $key);
        return 
$hash2.substr($hash4, 0, 4);
    }


    private function 
generateLoginBLOB($key, $challenge)
    {
        
$key1 = base64_decode($key);
        
$key2 = $this->derive_key($key1, 'WS-SecureConversationSESSION KEY HASH');
        
$key3 = $this->derive_key($key1, 'WS-SecureConversationSESSION KEY ENCRYPTION');
        
// get hash of challenge using key2
        
$hash = mhash(MHASH_SHA1, $challenge, $key2);
        
// get 8 bytes random data
        
$iv = substr(base64_encode(rand(1000,9999).rand(1000,9999)), 2, 8);
        
$cipher = mcrypt_cbc(MCRYPT_3DES, $key3, $challenge."\x08\x08\x08\x08\x08\x08\x08\x08", MCRYPT_ENCRYPT, $iv);
        
$blob = pack('LLLLLLL', 28, 1, 0x6603, 0x8004, 8, 20, 72);
        
$blob .= $iv;
        
$blob .= $hash;
        
$blob .= $cipher;
        return 
base64_encode($blob);
    }

    public function 
sendMessage($sMessage, $aTo) {
        if (!
is_array($aTo)) {
            if (
$aTo === '')
            
$aTo = array();
            else
            
$aTo = array($aTo);
        }
        
stream_set_timeout($this->fp, $this->stream_timeout);
        
$quit = false;
        
$online_cnt = 0;
        
$offline_cnt = 0;
        
$other_cnt = 0;
        
$start_tm = time();
        while (!
feof($this->fp)) {
            if (
$quit) break;
            
$data = $this->readln();
            
// no data ?
            
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($data, 0, 3);
            
$start_tm = time();
            switch (
$code) {
                case 
'SBS':
                    
$this->writeln("CHG $this->id NLN");
                    break;
                case 
'MSG':
                    @list(
/* MSG */, /* Hotmail */, /* Hotmail */, $size,) = @explode(' ', $data);
                    
// we don't need the notification data, so just ignore it
                    
if (is_numeric($size) && $size > 0)
                    
$this->readdata($size);
                    break;
                case 
'CHL':
                    @list(
/* CHL */, /* 0 */, $chl_code,) = @explode(' ', $data);
                    
$fingerprint = $this->getChallenge($chl_code);
                    
// NS: >>> QRY {id} {product_id} 32
                    // NS: >>> fingerprint
                    
$this->writeln("QRY $this->id $this->prod_id 32");
                    
$this->writedata($fingerprint);
                    break;
                case 
'SYN':
                    break;
                case 
'CHG':
                    if (
count($aTo) == 0 || $sMessage === '') {
                        
$quit = true;
                        break;
                    }
                    
$aMSNUsers = array();
                    
$aOfflineUsers = array();
                    
$aOtherUsers = array();
                    
$nMSNUsers = 0;
                    foreach (
$aTo as $sUser) {
                        @list(
$u_user, $u_domain, $u_network) = @explode([email='@']'@'[/email], $sUser);
                        if (
$u_network === '' || $u_network == NULL)
                        
$u_network = 1;
                        
$to_email = trim([email=$u_user.'@'.$u_domain]$u_user.'@'.$u_domain[/email]);
                        if (
$u_network == 1)
                        
$aMSNUsers[$nMSNUsers++] = $to_email;
                        else
                        
$aOtherUsers[$u_network][] = $to_email;
                    }
                    if (
$nMSNUsers == 0) {
                        
// no MSN account, only others
                        // process other network first
                        
foreach ($aOtherUsers as $network => $aNetUsers) {
                            
$other_cnt++;
                            
$aMessage = $this->getMessage($sMessage, $network);
                            foreach (
$aNetUsers as $to) {
                                foreach (
$aMessage as $message) {
                                    
$len = strlen($message);
                                    
$this->writeln("UUM $this->id $to $network 1 $len");
                                    
$this->writedata($message);
                                }
                                
$this->debug_message("*** sent to $to (network: $network):\n$sMessage");
                            }
                        }
                        
$quit = true;
                        break;
                    }
                    
$nCurrentUser = 0;
                    
// okay, try to ask a switchboard (SB) for sending message
                    // NS: >>> XFR {id} SB
                    
$this->writeln("XFR $this->id SB");
                    break;
                case 
'XFR':
                    
// NS: <<< XFR {id} SB {server} CKI {cki} U messenger.msn.com 0
                    
@list(/* XFR */, /* {id} */, /* SB */, $server, /* CKI */, $cki_code, /* ... */) = @explode(' ', $data);
                    @list(
$ip, $port) = @explode(':', $server);
                    
$bSBresult = $this->switchboard_control($ip, $port, $cki_code, $aMSNUsers[$nCurrentUser], $sMessage);
                    if (
$bSBresult === false) {
                        
// error for switchboard
                        
$this->debug_message("!!! error for sending message to ".$aMSNUsers[$nCurrentUser]);
                        
$aOfflineUsers[] = $aMSNUsers[$nCurrentUser];
                    }
                    else
                    
$online_cnt++;
                    
$nCurrentUser++;
                    if (
$nCurrentUser < $nMSNUsers) {
                        
// for next user
                        // okay, try to ask a switchboard (SB) for sending message
                        // NS: >>> XFR {id} SB
                        
$this->writeln("XFR $this->id SB");
                        continue;
                    }
                    
// okay, process offline user
                    
$lockkey = '';
                    
$re_login = false;
                    foreach (
$aOfflineUsers as $to) {
                        
$offline_cnt++;
                        for (
$i = 0; $i < $this->oim_try; $i++) {
                            
$oim_result = $this->sendOIM($to, $sMessage, $lockkey);
                            if (
$oim_result === true) {
                                
// finished
                                
break;
                            }
                            if (
is_array($oim_result) && $oim_result['challenge'] !== false) {
                                
// need challenge lockkey
                                
$lockkey = $this->getChallenge($oim_result['challenge']);
                            }
                            if (
$oim_result === false || $oim_result['auth_policy'] !== false) {
                                if (
$re_login) {
                                    
$this->debug_message("*** can't send OIM, but we already re-login again, so ignore this OIM");
                                    break;
                                }
                                
$this->debug_message("*** can't send OIM, maybe ticket expired, try to login again");
                                
// maybe we need to re-login again
                                
$aTickets = $this->get_passport_ticket();
                                if (!
$aTickets || !is_array($aTickets)) {
                                    
// failed to login? ignore it
                                    
$this->debug_message("*** can't re-login, something wrong here, ignore this OIM");
                                    break;
                                }
                                
$re_login = true;
                                
$this->oim_ticket = $aTickets['oim_ticket'];
                                
$this->contact_ticket = $aTickets['contact_ticket'];
                                
$this->debug_message("**** get new ticket, try it again");
                            }
                        }
                    }
                    
$quit = true;
                    break;
                case 
'LST':
                    
// NS: <<< LST {email} {alias} 11 0
                    
@list(/* LST */, $email, $alias, ) = @explode(' ', $data);
                    
$this->friends[$email]=$alias;
                    break;
                default:
                    if (
is_numeric($code)) {
                        
$this->error = "Error code: $code, please check the detail information from: ";
                        
$this->debug_message("*** NS: $this->error");
                    }
                    break;
            }
        }
        
// logout now
        // NS: >>> OUT
        
$this->writeln("OUT");
        
fclose($this->fp);
        return array(
        
'online' => $online_cnt,
        
'offline' => $offline_cnt,
        
'others' => $other_cnt
        
);
    }

阅读(866) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~