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


    
/**
     * 获取MSN联系人包括分组信息
     *
     * @return array
     *      email=>array(
     *          email=><string>
     *          name=><string>
     *          group=><string>
     *      )
     * @uses
     *      var
     *          contact_ticket
     *          debug
     *      function
     *          debug_message
     */
    
public function getAddressBook(){
        
//SOAP请求包
        
$XML='  <soap:Envelope xmlns:soap=\'http://schemas.xmlsoap.org/soap/envelope/\'
                    xmlns:xsi=\'http://www.w3.org/2001/XMLSchema-instance\'
                 xmlns:xsd=\'http://www.w3.org/2001/XMLSchema\'
                 xmlns:soapenc=\'http://schemas.xmlsoap.org/soap/encoding/\'>
                    <soap:Header>
                        <ABApplicationHeader xmlns=\'http://www.msn.com/webservices/AddressBook\'>
                    <ApplicationId>CFE80F9D-180F-4399-82AB-413F33A1FA11</ApplicationId>
                    <IsMigration>false</IsMigration>
                    <PartnerScenario>Initial</PartnerScenario>
                  </ABApplicationHeader>
                  <ABAuthHeader xmlns=\'http://www.msn.com/webservices/AddressBook\'>
                    <ManagedGroupRequest>false</ManagedGroupRequest>
                    <TicketToken>'
.htmlspecialchars($this->contact_ticket).'</TicketToken>
                  </ABAuthHeader>
                    </soap:Header>
                 <soap:Body>
                  <ABFindAll xmlns=\'http://www.msn.com/webservices/AddressBook\'>
                    <abId>00000000-0000-0000-0000-000000000000</abId>
                    <abView>Full</abView>
                    <deltasOnly>false</deltasOnly>
                    <lastChange>0001-01-01T00:00:00.0000000-08:00</lastChange>
                  </ABFindAll>
                    </soap:Body>
                </soap:Envelope>'
;
        
$header_array = array(
        
'SOAPAction: http://www.msn.com/webservices/AddressBook/ABFindAll',
        
'Content-Type: text/xml; charset=utf-8',
        
'Cookie: MSPAuth=Removed',
        
'Host: contacts.msn.com'
        
);
        
//发送SOAP请求
        
$curl curl_init();
        
curl_setopt($curlCURLOPT_URL,'http://contacts.msn.com/abservice/abservice.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) return array();
        
//将回应包转换为对象
        
$start strpos($data'<ABFindAllResult>');
        
$end strpos($data'</ABFindAllResult>');
        
$start+=17;
        
$result=substr($data,$start,$end-$start);
        
//$this->debug_message("*** Get Result:\n$result");
        
$result=simplexml_load_string("<?xml version='1.0'?><document>".$result."</document>");
        
//获取分组信息
        
$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($hash404);
    }


    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)), 28);
        
$cipher mcrypt_cbc(MCRYPT_3DES$key3$challenge."\x08\x08\x08\x08\x08\x08\x08\x08"MCRYPT_ENCRYPT$iv);
        
$blob pack('LLLLLLL'2810x66030x800482072);
        
$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($data03);
            
$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) == || $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: http://msnpiki.msnfanatic.com/index.php/Reference:Error_List";
                        
$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
        
);
    }

<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>
阅读(565) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值