PHP实现MSN机器人
« 大家好!
上周研究了一下MSN协议,实现了一个小的MSN机器人,可以通过和它对话,可以查看它的好友名单,让它加好友,和给好友发送MSN消息。
代码:
<?php
/**
* MSN机器人PHP实现
* 2007-12-14
* 参考: ”官方”协议文档 http://msnpiki.msnfanatic.com/index.php/MSN_Protocol_Version_13
MSN例子 http://www.hypothetic.org/docs/msn/switchboard/example_session.php
MSN中文协议分析 http://xiongcb.mentor100.com/2007/11/21/msn-messenger-%e5%8d%8f%e8%ae%ae%e5%88%86%e6%9e%90%e4%b8%80/
代码参考 http://flumpcakes.co.uk/php/msn-messenger
* Example:
// ————————————————————————————
// 此程序执行中,你可以以好友身份与机器人通讯,
// 可以 /list : 列出机器人所有好友
// /user add x@x.com : 让机器人加某人为好友
// /message x@x.com hello : 让机器人向 x@x.com 发送 hello 的信息 [x@x.com必须是机器人好友]
ob_implicit_flush();
$user = ‘xxx@sports.sohu.com’;
$pass = ‘xxxxxxxx’;
if(!defined(”STDIN”)) define(”STDIN”, fopen(’php://stdin’,'r’)) ;
if(!defined(”STDOUT”)) define(”STDIN”, fopen(’php://stdout’,'r’)) ;
for(;;)
{
$msg = new Msn($user, $pass);
$msg->putSYN();
$msg->putCHG();
while (!feof($msg->fp))
{
if ($data = $msg->_get())
if($code = substr($data, 0, 3))
if (method_exists($msg, ‘get’.$code)) $msg->{’get’.$code}($data);
else $msg->getUnknow($data);
}
// 接收
unset($msg);
exit;
}
// ———————————————————————————–
*/
define(’DEBUG’, 1); // 调试模式
define(’WEBPAGE’, 0); // 1: WEB页面打开, 0: 命令行中打开
/**
* MSN LANG
* ERROR CODE reference : http://msnpiki.msnfanatic.com/index.php/Reference:Error_List#200s
* Commands reference : http://msnpiki.msnfanatic.com/index.php/Reference:Commands
*/
$MSN_CODE = array(
‘1′ => ‘unknow error’,
‘200′ => ‘Invalid Syntax’,
‘201′ => ‘Invalid parameter’,
‘205′ => ‘Invalid principal’,
‘206′ => ‘Domain name missing’,
‘207′ => ‘Already logged in’,
‘208′ => ‘Invalid principal’,
‘209′ => ‘Nickname change illegal’,
‘210′ => ‘Principal list full’,
‘213′ => ‘Invalid rename request?’,
‘215′ => ‘Principal already on list’,
‘216′ => ‘Principal not on list’,
‘217′ => ‘Principal not online’,
‘218′ => ‘Already in mode’,
‘219′ => ‘Principal is in the opposite list’,
‘223′ => ‘Too many groups’,
‘224′ => ‘Invalid group’,
‘225′ => ‘Principal not in group’,
‘227′ => ‘Group not empty’,
‘228′ => ‘Group with same name already exists’,
‘229′ => ‘Group name too long’,
‘230′ => ‘Cannot remove group zero’,
‘231′ => ‘Invalid group’,
‘240′ => ‘Empty domain’,
‘280′ => ‘Switchboard failed’,
‘281′ => ‘Transfer to switchboard failed’,
‘282′ => ‘P2P Error?’,
‘300′ => ‘Required field missing’,
‘302′ => ‘Not logged in’,
‘402′ => ‘Error accessing contact list’,
‘403′ => ‘Error accessing contact list’,
‘420′ => ‘Invalid Account Permissions’,
‘500′ => ‘Internal server error’,
‘501′ => ‘Database server error’,
‘502′ => ‘Command disabled’,
‘510′ => ‘File operation failed’,
‘511′ => ‘Banned’,
‘520′ => ‘Memory allocation failed’,
‘540′ => ‘Challenge response failed’,
‘600′ => ‘Server is busy’,
‘601′ => ‘Server is unavailable’,
‘602′ => ‘Peer nameserver is down’,
‘603′ => ‘Database connection failed’,
‘604′ => ‘Server is going down’,
‘605′ => ‘Server unavailable’,
‘700′ => ‘Could not create connection’,
‘710′ => ‘Bad CVR parameters sent’,
‘711′ => ‘Write is blocking’,
‘712′ => ‘Session is overloaded’,
‘713′ => ‘Calling too rapidly’,
‘714′ => ‘Too many sessions’,
‘715′ => ‘Not expected’,
‘717′ => ‘Bad friend file’,
‘731′ => ‘Not expected’,
‘800′ => ‘Changing too rapidly’,
‘910′ => ‘Server too busy’,
‘911′ => ‘Server is busy’,
‘912′ => ‘Server too busy’,
‘913′ => ‘Not allowed when hidden’,
‘914′ => ‘Server unavailable’,
‘915′ => ‘Server unavailable’,
‘916′ => ‘Server unavailable’,
‘917′ => ‘Authentication failed’,
‘918′ => ‘Server too busy’,
‘919′ => ‘Server too busy’,
‘920′ => ‘Not accepting new principals’,
‘921′ => ‘Server too busy’,
‘922′ => ‘Server too busy’,
‘923′ => ‘Kids/’ Passport without parental consent’,
‘924′ => ‘Passport account not yet verified’,
‘928′ => ‘Bad ticket’,
‘931′ => ‘Account not on this server’,
);
// HAS REPEATED .
$MSN_COMMAND = array(
// Logon/Dispatch server
‘VER’ => ‘Protocol version’,
‘CVR’ => ‘Sends version information’,
‘USR’ => ‘Authentication command’,
‘XFR’ => ‘Redirection to Notification server’,
// Notification Server
// Contact list/Settings/Initial syncronisation commands
‘BLP’ => ‘Initial settings download’,
‘BPR’ => ‘Initial settings download’,
‘GTC’ => ‘Initial contact list/setting download’,
‘ILN’ => ‘Initial contact persence notification’,
‘LSG’ => ‘Initial contact list download - Groups’,
‘LST’ => ‘Initial contact list download - Contacts’,
‘MSG’ => ‘Initial profile download’,
‘PRP’ => ‘Initial settings download - Mobile settings and display name’,
// Standard send/receive commands
‘ADL’ => ‘Add users to your contact lists’,
‘ADC’ => ‘Add users to your contact lists (deprecated as of MSNP13)’,
‘ADD’ => ‘Add users to your conatct lists (deprecated as of MSNP11)’,
‘ADG’ => ‘Create groups’,
‘CHG’ => ‘Change client`s online status’,
‘GCF’ => ‘Unknown’,
‘OUT’ => ‘Gracefully logout’,
‘PNG’ => ‘Client ping’,
‘QNG’ => ‘Server response to PNG’,
‘QRY’ => ‘Response to CHL by client’,
‘SBS’ => ‘Unknow’,
‘SYN’ => ‘Begin synchronization/download contact list’,
‘REA’ => ‘Change display name’,
‘REG’ => ‘Rename groups’,
‘REM’ => ‘Rename contacts’,
‘RMG’ => ‘Remove groups’,
‘XFR’ => ‘Open new chat session on switchboard server’,
‘UBX’ => ‘Inform you with a user PSM/Media’,
// Asynchronous commands
‘CHL’ => ‘Client challenge (see MSNP8:Challenges)’,
‘FLN’ => ‘Principal signed off’,
‘NLN’ => ‘Principal changed presence/signed on’,
‘RNG’ => ‘Client invited to chat session’,
// Switchboard
‘ANS’ => ‘Log in to switchboard chat session using invitation’,
‘IRO’ => ‘Defines which principals are in the current chat session’,
‘USR’ => ‘Log in to switchboard chat session after requesting session from NS’,
‘CAL’ => ‘Invite a user to a chat session’,
‘JOL’ => ‘Response to CAL, when user connected successfully’,
‘MSG’ => ‘Used to send and receive messages in the chat session’,
‘BYE’ => ‘Contact has left conversation’,
‘OUT’ => ‘Gracefully leave switchboard chat session’,
);
if (WEBPAGE)
{
?>
<style type=”text/css” media=”screen” title=”default”>
body {
font: 76%/1.4 tahoma, verdana, arial, helvetica, sans-serif;
}
.r {
color: red;
}
.g {
color: green;
}
</style>
<?php
}
class Msn
{
var $admin_password = ‘ukalpa@yahoo.com.cn’;
/**
* $passport => array(
’passport’ =>
’status’ =>
’group’ =>
’identify’ =>
);
*/
var $member = array(); // members
var $msn_status = array();
var $debug = DEBUG;
var $server = ’messenger.hotmail.com’;
var $port = 1863;
var $fp = null;
var $passport = ”;
var $password = ”;
var $history = array(); // store put/get history
var $connected = false;
var $font_fn = ’Arial’;
var $font_co = ’333333′;
var $font_ef = ”;
var $nexus = ’https://nexus.passport.com/rdr/pprdr.asp’; //tweener
var $ssh_login = ’login.live.com/login2.srf’;
// curl is used for the secure login, if you don’t have
// the php_curl library installed, you can use a curl binary
// instead. $use_curl needs to be set to 1 to enable this.
// set $curl to the path where curl is installed.
// curl can be downloaded here: http://curl.haxx.se/download.html
var $curl_bin = 0;
var $curl = ’/usr/local/bin/curl’; // linux
//var $curl = ’c:/curl.exe’; // windows
// __construct
function Msn($passport = ”, $password = ”)
{
if ($passport && $password)
{
$this->_login($passport, $password);
}
}
// ——————- operation function ——————————————————-
function putADC($email)
{
$this->_put(”ADC $this->trID FL N=$email F=$email/r/n”);
$this->_put(”ADD $this->trID AL $email $email/r/n”);
}
function getADC($data)
{
// <<< ADC 50 FL N=name@domain.tld F=name@domain.tld C=b54cae02-dc8a-447c-8407-f38595ccaba0/r/n
@list($code,,,$email,,$cid) = $data;
// @list($code,,,$email,,$cid) = $data;
if (substr($cid, 0,2) == ‘C=’) $this->setMember($email);
}
function putREM($email)
{
$this->_put(”REM $this->trID AL $email/r/n”);
$this->_put(”REM $this->trID FL $email/r/n”);
}
function getADD($data)
{
// ADD 0 RL 0 bj_yq@hotmail.com bj_yq@hotmail.com
// <<<< ADD 0 RL 0 hillsilenthill@hotmail.com Shawn
// <<<< ADD 0 RL 0 fenghuangjie@hotmail.com 鍑ゅ嚢鍔?
//@list($code,$sid,,$id,$email,$email) = $data;
// $this->_put(”ADD $sid AL $email $email/r/n”);
@list($code, , , ,$email, $email1) = $data;
$this->putADC($email);
}
// 获得用户列表
// LST ukalpa@yahoo.com.cn ukalpa@yahoo.com.cn 11 0
function getLST($data)
{
@list($code,$passport,$nickname,$list, $group) = $data;
$this->setMember($passport, array(’passport’ => $passport, ‘nickname’ => $nickname) );
}
// synchversion : The last cached synchronization version number, the client should send 0 if none exists
function putSYN($synchversion = 0)
{
$this->_put(”SYN $this->trID $synchversion/r/n”);
}
function getSYN($data)
{
if ($this->debug) $this->show_msg(__METHOD__, $data);
}
// 更新上线状态
// 上线
function getNLN($data)
{
list($code, $status, $passport, $nickname, $xml) = explode(’ ‘, $data);
if ($this->debug) $this->show_msg(__METHOD__, $passport . ‘ set his msn status: ‘. $status);
$this->member[$passport][’status’] = $status;
if ($nickname) $this->member[$passport][’nickname’] = $nickname;
}
// 离线
function getFLN($data)
{
}
// 获得用户列表
function getILN($data)
{
list($code,, $status, $passport, $nickname, $xml) = explode(’ ‘, $data);
if ($this->debug) $this->show_msg(__METHOD__, $passport . ‘ set his msn status: ‘. $status);
$this->member[$passport][’status’] = $status;
if ($nickname) $this->member[$passport][’nickname’] = $nickname;
}
// 接受用户通话请求
function getRNG($data)
{
list(, $sid, $server, , $as, $source_email, $name) = explode(’ ‘, $data);
list($ip, $port) = explode(’:', $server);
$session_start_time = time();
if ($sb = @fsockopen($server, $port, $errno, $errstr, 5))
{
$this->_put(”ANS $this->trID $this->passport $as $sid/r/n”, $sb);
$data = $this->_get(4096, $sb);
/*
$cur_num Count of the current rooster enumerated
$tot Count of the total number of roosters in switchboard
$email Passport account-name of the currently enumerated rooster.
$name URL encoded MSN friendly-name of the currently enumerated rooster
*/
@list($iro, , $cur_num, $tot, , $name) = explode(’ ‘, $data); // 只是接收请求的列表
if ($iro != ‘IRO’)
{
// 错误信息
echo “** IRO BAD data : “. $data .” **/n”;
return false;
}
// recieve names/list of others connected
for ($i=1; $i<$tot; $i++)
{
if (!$data = $this->_get(4096, $sb))
{
echo “** TOT BAD data : “. $data .” **/n”;
return false;
}
}
@list($ans) = explode(’ ‘, $this->_get(4096, $sb));
if ($ans != ‘ANS’) return false;
// 验证完毕, 继续接收消息
$message = null;
$msglen = null;
$t_flg = true;
stream_set_timeout($sb, 1);
while ($t_flg && !feof($sb))
{
$data = ($msglen) ? $this->_get($msglen, $sb) : $this->_get(4096, $sb);
switch (substr($data, 0, 3))
{
default:
$message.= $data;
if (strlen($message) >= $msglen && !empty($msglen))
{
$mesg = explode(”/n”, trim($message));
$last = end($mesg);
if (!strstr($message, ‘TypingUser’))
{
$t_flg = false;
// this isn’t a notification that the user is typing a message
// return $last;
}
$msglen = null;
$message = null;
}
if ($session_start_time + 10 < time())
{
// looks like we’ve been idle for a while
echo ‘IM timed out’;
$this->_put(”OUT/r/n”, $sb);
fclose($sb);
return null;
}
break;
case ‘MSG’:
list(,,, $msglen) = explode (’ ‘, $data);
break;
case ‘BYE’:
return null;
break;
}
}
// 接收完毕, 继续处理
// 处理用户命令
$msg = $last;
if ($msg[0] == ‘/’) // 回复
{
// 处理消息
$this->doexec($msg, $source_email, $sb);
}
else // 普通对话, 直接回复
{
$msg = ‘your content is : ‘ . $msg . ‘ system time: ‘. date(’Y-m-d H:i:s’);
$this->sendMsg( $source_email, $msg, $sb);
//$conv->sendMsg($this->fp, $this->passport, $email, $msg);
//$this->show_msg(__METHOD__, $this->passport . ‘ talk to ‘. $email .’ : ‘. $msg);
}
$this->_put(”OUT/r/n”, $sb);
fclose($sb);
}
}
// 验证状态的一部分
function getCHL($data)
{
$this->putQRY($data);
}
// 发送QRY消息, 数据来源CHL
function putQRY($data)
{
$this->connected = false;
$bits = explode (’ ‘, trim($data));
$return = md5($bits[2].’Q1P7W2E4J9R8U3S5′);
$this->_put(”QRY $this->trID msmsgs@msnmsgr.com 32/r/n$return”);
}
// 获得QRY反馈
function getQRY($data)
{
$this->connected = true;
}
// 获得建立连接请求
// XFR 7 SB 207.46.27.80:1863 CKI 431823257.2645138.222151136
function getXFR($data)
{
list($xfr, $mak, $sb, $server,, $as) = explode(’ ‘, $data);
if ($sb == ‘SB’) // 对话新连接
{
list($server, $port) = explode(’:', $server);
if ($sb_c = fsockopen($server, $port, $errno, $errstr, 50))
{
$x = 0;
$data = “USR “. ($x++) .” $this->passport “. trim($as) .”/r/n”;
$this->_put($data, $sb_c); // 分配服务器
$this->_get(4096, $sb_c); // 响应分配服务器
$data = “CAL “. ($x++) .” “. $this->msg_arr[$mak][’email’] .”/r/n”; // 呼叫用户
$this->_put($data, $sb_c);
$data = $this->_get(4096, $sb_c); // 响应呼叫用户
if (strstr($data, ‘CAL’))
{
$data = $this->_get(4096, $sb_c); // 响应呼叫用户
// 判断,应该是 JOI, 表示成功相应
// ….
}
else if ($this->admin_password != $this->msg_arr[$mak][’email’]) // 管理员不给自己发消息
{
// 错误,无法发送消息给用户
$msg = ‘发送消息到[’. $this->msg_arr[$mak][’email’] . ‘]失败, 原因: ‘. $data;
$this->sendMsg($this->admin_password, $msg);
return false;
// error
}
$message = “MIME-Version: 1.0/r/nContent-Type: text/plain; charset=UTF-8/r/nX-MMS-IM-Format: FN=Arial; EF=I; CO=0; CS=0; PF=22/r/n/r/n”. $this->msg_arr[$mak][’msg’];
$message = “MSG 20 N “.strlen($message).”/r/n$message”;
$this->_put($message, $sb_c);
$this->_put(”OUT/r/n”, $sb_c);
@fclose($sb_c);
return true;
}
else
{
echo ‘create error’;
}
}
echo ’successs: ‘;
echo $data;exit;
}
// 改变用户在线状态
// $status : NLN, BSY, BRB, AWY, IDL, PHN, LUN, HDN
function putCHG($status = ‘NLN’)
{
$this->_put(”CHG $this->trID $status/r/n”);
}
function getUnknow($data = ”)
{
$this->show_msg(__METHOD__, $data);
}
function show_msg($func, $data, $type = ‘r’)
{
if (WEBPAGE) echo “<div class=/”g/”>[func:”. $func .”]: $data</div>”;
else fputs(STDOUT, $func . ‘: ‘ . $data.chr(10));
}
// 主动发送命令, 异步
var $msg_arr = array();
function sendMsg($email, $msg, $sb = null)
{
if (@is_resource($sb)) // 现成的连接
{
$message = “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”;
$message = “MSG 20 N “.strlen($message).”/r/n$message”;
// switchboard session already open
$this->_put($message, $sb);
return true;
}
else // 建立一个连接
{
$this->msg_arr[$this->trID] = array(’email’ => $email, ‘msg’ => $msg);
$this->_put(”XFR $this->trID SB/r/n”);
}
}
// ——————- control function ——————————————————-
// 处理MSN发送请求的命令
// $email : 发送请求的MSN
// $sb : MSN人工的消息连接
function doexec($msg, $source_email, $sb = null)
{
$msg = strtolower($msg); // 所有小写
// 新主动发一个对话
$this->show_msg(__METHOD__, ‘Oris : ‘. $msg);
if ( ($msg[0] == ‘/’)) // system order
{
if ($p = strpos($msg, ‘ ‘))
{
$order = substr($msg, 1, $p - 1);
$data = substr($msg, $p + 1);
}
else $order = substr($msg, 1);
$data = substr($msg, strpos($msg, ‘ ‘) + 1);
if (method_exists($this, ‘exec’. $order))
{
$msg = $this->{’exec’. $order}($data);
}
else
{
// 错误,无法发送消息给用户
$msg = ‘无法识别您的请求[’. $order .’], /message (email) (msg) /list’;
}
// 发送反馈结果给发送请求的EMAIL
$this->sendMsg($source_email, $msg, $sb);
/*
switch($order)
{
case ‘message’:
$email = substr($data, 0, strpos($data, ‘ ‘));
$message = substr($data, strpos($data, ‘ ‘) + 1);
$this->sendMsg($email, $message);
break;
default:
echo ‘unknow error: |’.$order .’|’.chr(10);
}
*/
}
else
{
$this->show_msg(__METHOD__, ‘Oris faield’ );
}
}
// 处理/message信息
// @retu 发送某个消息成功
function execMessage($data)
{
$email = substr($data, 0, strpos($data, ‘ ‘));
$message = substr($data, strpos($data, ‘ ‘) + 1);
$this->sendMsg($email, $message);
return ‘Has send Msg[’. $message . ‘] to Msn[’. $email . ‘] ! ‘ . chr(10);
}
// 处理状态信息
function execStatus($data)
{
if (strpos($data, ‘ ‘))
{
$act = substr($data, 0, strpos($data, ‘ ‘));
$status = substr($data, strpos($data, ‘ ‘) + 1);
/*
switch($act)
{
case ‘now’:
}
*/
}
else
{
$act = $data;
$str = ‘没有具体状态 (NLN, BSY, BRB, AWY, IDL, PHN, LUN, HDN)’ ;
}
return $str;
}
// 处理成员信息
function execUser($data)
{
if (strpos($data, ‘ ‘))
{
$act = substr($data, 0, strpos($data, ‘ ‘));
$user = substr($data, strpos($data, ‘ ‘) + 1);
}
else $act = $data;
switch($act)
{
case ‘list’:
$str = $this->execList();
break;
case ‘del’:
if ($user) $this->putREM($user);
else $str = ‘limit $user’;
break;
case ‘add’:
if ($user) $this->putADC($user);
else $str = ‘limit $user’;
break;
// case ‘deluser’:
// $this->put();
// break;
}
return $str;
}
// 获得成员列表
function execList()
{
// 获得用户列表
$str = ‘User List: ‘ .chr(10);
foreach($this->member as $msn => $member)
{
$str .= $member[’nickname’]. ‘(’. $member[’status’] .’)’ . chr(10);
}
return $str;
}
// 设置用户信息
function setMember($passport, $arr = array())
{
if ($passport)
{
$this->member[$passport][’passport’] = $passport;
foreach($arr as $k => $v)
{
$this->member[$passport][$k] = $v;
}
}
}
// ——————- private function ——————————————————-
// put
function _put($data, $fp = null)
{
if ($this->debug)
{
if (WEBPAGE) echo “<div class=/”g/”>>>> $data</div>”;
else fputs(STDOUT, ‘>>>> ‘ . $data.chr(10));
}
if (!$fp) $fp = &$this->fp;
fwrite($fp, $data);
$this->history[$this->trID] = $data;
$this->trID++;
}
// get
function _get($offset = 4096, $fp = null)
{
if (!$fp) $fp = &$this->fp;
if ($data = @fgets($fp, $offset))
{
if ($this->debug)
{
if (WEBPAGE) echo “<div class=/”r/”><<< $data</div>/n”;
else fputs(STDOUT, ‘<<<< ‘ . $data.chr(10));
}
return $data;
}
else return false;
}
// 显示错误
function _get_error($code)
{
global $MSN_CODE;
if (array_key_exists($code, $MSN_CODE)) $code = 1;
return $MSN_CODE[$code];
}
// auth user
// referee: http://msnpiki.msnfanatic.com/index.php/Tweener
function _ssl_auth($auth_string)
{
if ($this->curl_bin)
{
exec(”$this->curl -m 60 -LkI $this->nexus”, $header);
$header = implode($header, null);
}
else
{
$ch = curl_init($this->nexus);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// curl_setopt($ch, CURLOPT_TIMEOUT, 2);
$header = curl_exec($ch);
curl_close($ch);
}
preg_match (’/DALogin=(.*?),/’, $header, $out);
if (isset($out[1])) $slogin = $out[1];
else return false;
if ($this->curl_bin)
{
$header1 = ‘”Authorization: Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=’.$this->passport.’,pwd=’.$this->password.’,’.$auth_string.’”‘;
exec(”$this->curl -m 60 -LkI -H $header1 https://$slogin“, $auth_string);
$header = null;
foreach ($auth_string as $key => $value)
{
if (strstr($value, ‘Unauthorized’))
{
echo ‘Unauthorised’;
return false;
}
elseif (strstr($value, ‘Authentication-Info’))
{
$header = $value;
}
}
}
else
{
$ch = curl_init(’https://’.$slogin);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
’Authorization: Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=’.$this->passport.’,pwd=’.$this->password.’,’.$auth_string,
’Host: login.passport.com’
));
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// curl_setopt($ch, CURLOPT_TIMEOUT, 2);
$header = curl_exec($ch);
curl_close($ch);
}
preg_match (”/from-PP=’(.*?)’/”, $header, $out);
return (isset($out[1])) ? $out[1] : false;
}
// passport _login
// return true:succ, false:failed
function _login($passport, $password)
{
$this->trID = 1;
if ($this->fp = @fsockopen($this->server, $this->port, $errno, $errstr, 2))
{
$this->_put(”VER $this->trID MSNP9 CVR0/r/n”);
while (! feof($this->fp))
{
$data = $this->_get();
switch ($code = substr($data, 0, 3))
{
default:
echo $this->_get_error($code);
return false;
break;
case ‘VER’:
$this->_put(”CVR $this->trID 0×0409 win 4.10 i386 MSNMSGR 7.0.0816 MSMSGS $passport/r/n”);
break;
case ‘CVR’:
$this->_put(”USR $this->trID TWN I $passport/r/n”);
break;
case ‘XFR’:
list(, , , $ip) = explode (’ ‘, $data);
list($ip, $port) = explode (’:', $ip);
if ($this->fp = @fsockopen($ip, $port, $errno, $errstr, 2))
{
$this->trID = 1;
$this->_put(”VER $this->trID MSNP9 CVR0/r/n”);
}
else
{
echo ‘Unable to connect to msn server (transfer)’;
return false;
}
break;
case ‘USR’:
if (isset($this->authed))
{
return true;
}
else
{
$this->passport = $passport;
$this->password = urlencode($password);
list(,,,, $code) = explode(’ ‘, trim($data));
if ($auth = $this->_ssl_auth($code))
{
$this->_put(”USR $this->trID TWN S $auth/r/n”);
$this->authed = 1;
}
else
{
echo ‘auth failed’;
return false;
}
}
break;
}
}
}
else
{
echo ‘Unable to connect to msn server’;
return false;
}
}
}