email = $email;
$this->password = $password;
//assign
if ($autoConnect) {
$this->_connected = $this->connect($email, $password, $this->server, $this->port);
//try to connect
}
}
/**
* check whether the login attempt was succesful
*
* @return bool
*/
public function loggedIn() {
return $this->_connected;
}
/**
* get the contact list
*
* @return Naneau_MSN_Messenger_ContactList
*/
public function getContactList() {
if (!$this->_connected) {
throw new Exception('Not connected, can\'t retrieve contact list');
}
if ($this->_contactList == null) {
$this->buildContactList();
}
return $this->_contactList;
//new contact list
}
/**
* set status
*
* @param int $status
* @return void
*/
public function setStatus($status) {
if ($this->_contactList == null) {
$this->getContactList();
}
//contact list must have been retrieved
$this->sendCommand('CHG', $status);
}
/**
* connect to the server
*
* @return bool
* @throws Exception if it can't open a connection
*/
private function connect() {
$this->getSock($this->server, $this->port);
//create connection
$this->sendCommand('VER', 'MSNP9 CVR0');
//start login
while ($response = $this->getResponse()) {
//login chain
switch (substr($response, 0, 3)) {
case 'USR':
//user related command
$data = explode(' ', trim($response));
//split the data
if ($data[2] == 'TWN') {
//challenge (not logged in yet)
if ($ticket = $this->passportLogin($data[4], $this->email, $this->password)) {
//try to do 'real' login with passport
$this->sendCommand('USR', 'TWN S ' . $ticket);
//replay with ticket
}
else {
//passport login failed
return false;
}
}
else {
//succesful login!
$this->fetchData();
//get data
return true;
}
break;
case 'VER':
//server returns version
$this->sendCommand('CVR', '0x0409 win 4.10 i386 MSNMSGR 7.0.0816 MSMSGS ' . $this->email);
//reply with our 'version' and email
break;
case 'CVR':
//protocol information
$this->sendCommand('USR', 'TWN I ' . $this->email);
//try to login
break;
case 'XFR':
//redirect
$server = explode(' ', $response);
$server = explode(':', $server[3]);
//split into server and port
$this->getSock($server[0], intval($server[1]));
//reconnect
$this->sendCommand('VER', 'MSNP9 CVR0');
//restart with the version
break;
default:
//unknown command
//we can't have those!
//really, we can't :x
return false;
break;
}
}
}
/**
* receive contact list info
*
*/
private function buildContactList() {
$contacts = array();
//the array of contacts
$this->sendCommand('SYN', 0);
//start synchronisation of contact list (pretend it's never happend)
while ($response = $this->getResponse()) {
if (substr($response, 0, 3) == 'LST') {
$data = explode(' ', $response);
$contacts[] = new Naneau_MSN_Messenger_Contact($data[1], urldecode($data[2]));
}
}
$this->_contactList = new Naneau_MSN_Messenger_ContactList($contacts);
}
/**
* fetch extra data after login
*
* @return void
*/
private function fetchData() {
while ($response = $this->getResponse()) {
$data = explode(':', $response);
if (isset($data[1])) {
$this->_data[$data[0]] = trim($data[1]);
//save data
}
}
}
/**
* create a socket
*
* @param string $server
* @param int $port
*/
private function getSock($server, $port) {
$this->_msgCount = 1;
//reset msgCount
if ($this->_con) {
fclose($this->_con);
}
//if connection, reset it
if (!($this->_con = @fsockopen($server, $port, $errno, $errstr, 2))) {
//can't connect
throw new Exception('Can\'t open connection socket: ' . $server . ':' . $port);
}
}
/**
* do the passport login
*
* @param string $server
* @param int $port
*/
private function passportLogin($challenge) {
$http = new Zend_Http_Client($this->passport);
$response = $http->request();
//do request to passport
$headers = $response->getHeaders();
//get response headers
preg_match ('/DALogin=(.*?),/', $headers['Passporturls'], $matches);
if (isset($matches[1])) {
//if the first parenthesized part (the real url) exists
$url = $matches[1];
//the login url
$http = new Zend_Http_Client('https://' . $matches[1]);
$http->setHeaders('Authorization', 'Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=' . $this->email . ',pwd=' . $this->password . ',' . $challenge . '"');
$response = $http->request();
$headers = $response->getHeaders();
//send login request to 'real' server we received in first request
preg_match ('/from-PP=\'(.*?)\'/', $headers['Authentication-info'], $matches);
//try to get a ticket out of the response headers
return isset($matches[1]) ? $matches[1] : false;
//must get a ticket, or it failed
}
else {
//something went wrong, no url in the response
return false;
}
}
/**
* get a response from the server, or false if there is none
*
* @return string|bool $response
*/
public function getResponse() {
if (!feof($this->_con) && $response = @fgets($this->_con)) {
//not end of file for connection, and there is a response
if ($this->_debug) {
echo '<<< ' . $response . '
';
}
return $response;
}
return false;
}
/**
* write a command the socket
*
* @param string $command
* @param string $options
* @return void
*/
public function sendCommand($command, $options) {
$dString = $command . ' ' . $this->_msgCount++ . ' ' . $options . "\r\n";
//the command
if ($this->_debug) {
echo '>>> ' . $dString . '
';
}
fwrite($this->_con, $dString);
//output it
}
}