private $update_pending;\r
private $PhotoStickerFile=false;\r
private $Emotions=false;\r
- private $ReqSBXFRTimeout=60;\r
+ private $XFRReqTimeout=60;\r
private $LastPing;\r
private $ping_wait=50;\r
private $SBIdleTimeout=10;\r
private $ABAuthHeader;\r
private $ABService;\r
private $Contacts;\r
- private $IgnoreList;\r
\r
private $server = 'messenger.hotmail.com';\r
private $port = 1863;\r
\r
public $oim_try = 3;\r
\r
- public $log_file = '';\r
-\r
- public $log_path = false;\r
-\r
public $font_fn = 'Arial';\r
public $font_co = '333333';\r
public $font_ef = '';\r
\r
private $aContactList = array();\r
private $aADL = array();\r
+\r
+ /**\r
+ * Holds session information indexed by screenname if\r
+ * session has no socket or socket if socket present\r
+ *\r
+ * @var array\r
+ */\r
private $switchBoardSessions = array();\r
- private $switchBoardSockets = array();\r
+\r
+ /**\r
+ * Holds sockets indexed by screenname\r
+ *\r
+ * @var array\r
+ */\r
+ private $switchBoardSessionLookup = array();\r
+\r
+ /**\r
+ * Holds references to sessions waiting for XFR\r
+ *\r
+ * @var array\r
+ */\r
private $waitingForXFR = array();\r
\r
/**\r
* @param integer $client_id Client id (hexadecimal)\r
* @return MSN\r
*/\r
- public function __construct ($Configs=array(), $timeout = 15, $client_id = 0x7000800C)\r
- {\r
+ public function __construct ($Configs=array(), $timeout = 15, $client_id = 0x7000800C) {\r
$this->user = $Configs['user'];\r
$this->password = $Configs['password'];\r
$this->alias = isset($Configs['alias']) ? $Configs['alias'] : '';\r
$this->update_pending = isset($Configs['update_pending']) ? $Configs['update_pending'] : true;\r
$this->PhotoStickerFile=isset($Configs['PhotoSticker']) ? $Configs['PhotoSticker'] : false;\r
\r
- if($this->Emotions = isset($Configs['Emotions']) ? $Configs['Emotions']:false) {\r
+ if ($this->Emotions = isset($Configs['Emotions']) ? $Configs['Emotions']:false) {\r
foreach($this->Emotions as $EmotionFilePath)\r
$this->MsnObj($EmotionFilePath,$Type=2);\r
}\r
$this->ABService=new SoapClient(realpath(dirname(__FILE__)).'/soap/msnab_sharingservice.wsdl',array('trace' => 1));\r
}\r
\r
- private function Array2SoapVar($Array,$ReturnSoapVarObj=true,$TypeName=null,$TypeNameSpace=null)\r
- {\r
- $ArrayString='';\r
- foreach($Array as $Key => $Val)\r
- {\r
- if($Key{0}==':') continue;\r
- $Attrib='';\r
- if(is_array($Val[':']))\r
- {\r
- foreach($Val[':'] as $AttribName => $AttribVal)\r
- $Attrib.=" $AttribName='$AttribVal'";\r
+ private function Array2SoapVar($Array, $ReturnSoapVarObj = true, $TypeName = null, $TypeNameSpace = null) {\r
+ $ArrayString = '';\r
+ foreach($Array as $Key => $Val) {\r
+ if ($Key{0} == ':') continue;\r
+ $Attrib = '';\r
+ if (is_array($Val[':'])) {\r
+ foreach ($Val[':'] as $AttribName => $AttribVal)\r
+ $Attrib .= " $AttribName='$AttribVal'";\r
}\r
- if($Key{0}=='!')\r
- {\r
+ if ($Key{0} == '!') {\r
//List Type Define\r
- $Key=substr($Key,1);\r
- foreach($Val as $ListKey => $ListVal)\r
- {\r
- if($ListKey{0}==':') continue;\r
- if(is_array($ListVal)) $ListVal=$this->Array2SoapVar($ListVal,false);\r
- elseif(is_bool($ListVal)) $ListVal=$ListVal?'true':'false';\r
- $ArrayString.="<$Key$Attrib>$ListVal</$Key>";\r
+ $Key = substr($Key,1);\r
+ foreach ($Val as $ListKey => $ListVal) {\r
+ if ($ListKey{0} == ':') continue;\r
+ if (is_array($ListVal)) $ListVal = $this->Array2SoapVar($ListVal, false);\r
+ elseif (is_bool($ListVal)) $ListVal = $ListVal ? 'true' : 'false';\r
+ $ArrayString .= "<$Key$Attrib>$ListVal</$Key>";\r
}\r
continue;\r
}\r
- if(is_array($Val)) $Val=$this->Array2SoapVar($Val,false);\r
- elseif(is_bool($Val)) $Val=$Val?'true':'false';\r
- $ArrayString.="<$Key$Attrib>$Val</$Key>";\r
+ if (is_array($Val)) $Val = $this->Array2SoapVar($Val, false);\r
+ elseif (is_bool($Val)) $Val = $Val ? 'true' : 'false';\r
+ $ArrayString .= "<$Key$Attrib>$Val</$Key>";\r
}\r
- if($ReturnSoapVarObj) return new SoapVar($ArrayString,XSD_ANYXML,$TypeName,$TypeNameSpace);\r
+ if ($ReturnSoapVarObj) return new SoapVar($ArrayString, XSD_ANYXML, $TypeName, $TypeNameSpace);\r
return $ArrayString;\r
}\r
\r
* @param string $url URL string (Optional)\r
* @return mixed Array of tickets or false on failure\r
*/\r
- private function get_passport_ticket($url = '')\r
- {\r
+ private function get_passport_ticket($url = '') {\r
$user = $this->user;\r
$password = htmlspecialchars($this->password);\r
\r
</Body>\r
</Envelope>';\r
\r
- $this->debug_message("*** URL: $passport_url");\r
- $this->debug_message("*** Sending SOAP:\n$XML");\r
+ //$this->debug_message("*** URL: $passport_url");\r
+ //$this->debug_message("*** Sending SOAP:\n$XML");\r
$curl = curl_init();\r
curl_setopt($curl, CURLOPT_URL, $passport_url);\r
if ($this->debug) curl_setopt($curl, CURLOPT_HEADER, 1);\r
$data = curl_exec($curl);\r
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);\r
curl_close($curl);\r
- $this->debug_message("*** Get Result:\n$data");\r
+ //$this->debug_message("*** Get Result:\n$data");\r
\r
if ($http_code != 200) {\r
- // sometimes, rediret to another URL\r
+ // sometimes, redirect to another URL\r
// MSNP15\r
//<faultcode>psf:Redirect</faultcode>\r
//<psf:redirectUrl>https://msnia.login.live.com/pp450/RST.srf</psf:redirectUrl>\r
//<faultstring>Authentication Failure</faultstring>\r
if (strpos($data, '<faultcode>psf:Redirect</faultcode>') === false) {\r
- $this->debug_message("*** Can't get passport ticket! http code = $http_code");\r
+ $this->debug_message("*** Could not get passport ticket! http code = $http_code");\r
return false;\r
}\r
preg_match("#<psf\:redirectUrl>(.*)</psf\:redirectUrl>#", $data, $matches);\r
if (count($matches) == 0) {\r
- $this->debug_message("*** redirect, but can't get redirect URL!");\r
+ $this->debug_message('*** Redirected, but could not get redirect URL!');\r
return false;\r
}\r
$redirect_url = $matches[1];\r
if ($redirect_url == $passport_url) {\r
- $this->debug_message("*** redirect, but redirect to same URL!");\r
+ $this->debug_message('*** Redirected, but to same URL!');\r
return false;\r
}\r
- $this->debug_message("*** redirect to $redirect_url");\r
+ $this->debug_message("*** Redirected to $redirect_url");\r
return $this->get_passport_ticket($redirect_url);\r
}\r
\r
- // sometimes, rediret to another URL, also return 200\r
+ // sometimes, redirect to another URL, also return 200\r
// MSNP15\r
//<faultcode>psf:Redirect</faultcode>\r
//<psf:redirectUrl>https://msnia.login.live.com/pp450/RST.srf</psf:redirectUrl>\r
if (count($matches) != 0) {\r
$redirect_url = $matches[1];\r
if ($redirect_url == $passport_url) {\r
- $this->debug_message("*** redirect, but redirect to same URL!");\r
+ $this->debug_message('*** Redirected, but to same URL!');\r
return false;\r
}\r
- $this->debug_message("*** redirect to $redirect_url");\r
+ $this->debug_message("*** Redirected to $redirect_url");\r
return $this->get_passport_ticket($redirect_url);\r
}\r
}\r
\r
// no ticket found!\r
if (count($matches) == 0) {\r
- $this->debug_message("*** Can't get passport ticket!");\r
+ $this->debug_message('*** Could not get passport ticket!');\r
return false;\r
}\r
\r
'space_ticket' => html_entity_decode($matches[11]),\r
'storage_ticket' => html_entity_decode($matches[13])\r
);\r
- $this->ticket=$aTickets;\r
- $this->debug_message(var_export($aTickets, true));\r
- $ABAuthHeaderArray=array(\r
- 'ABAuthHeader'=>array(\r
- ':'=>array('xmlns'=>'http://www.msn.com/webservices/AddressBook'),\r
- 'ManagedGroupRequest'=>false,\r
- 'TicketToken'=>htmlspecialchars($this->ticket['contact_ticket']),\r
+ $this->ticket = $aTickets;\r
+ //$this->debug_message(var_export($aTickets, true));\r
+ $ABAuthHeaderArray = array(\r
+ 'ABAuthHeader' => array(\r
+ ':' => array('xmlns' => 'http://www.msn.com/webservices/AddressBook'),\r
+ 'ManagedGroupRequest' => false,\r
+ 'TicketToken' => htmlspecialchars($this->ticket['contact_ticket']),\r
)\r
);\r
- $this->ABAuthHeader=new SoapHeader("http://www.msn.com/webservices/AddressBook","ABAuthHeader", $this->Array2SoapVar($ABAuthHeaderArray));\r
+ $this->ABAuthHeader = new SoapHeader('http://www.msn.com/webservices/AddressBook', 'ABAuthHeader', $this->Array2SoapVar($ABAuthHeaderArray));\r
return $aTickets;\r
}\r
\r
- private function UpdateContacts()\r
- {\r
- $ABApplicationHeaderArray=array(\r
- 'ABApplicationHeader'=>array(\r
- ':'=>array('xmlns'=>'http://www.msn.com/webservices/AddressBook'),\r
- 'ApplicationId'=>'CFE80F9D-180F-4399-82AB-413F33A1FA11',\r
- 'IsMigration'=>false,\r
- 'PartnerScenario'=>'ContactSave'\r
+ /**\r
+ * Fetch contact list\r
+ *\r
+ * @return boolean true on success\r
+ */\r
+ private function UpdateContacts() {\r
+ $ABApplicationHeaderArray = array(\r
+ 'ABApplicationHeader' => array(\r
+ ':' => array('xmlns' => 'http://www.msn.com/webservices/AddressBook'),\r
+ 'ApplicationId' => 'CFE80F9D-180F-4399-82AB-413F33A1FA11',\r
+ 'IsMigration' => false,\r
+ 'PartnerScenario' => 'ContactSave'\r
)\r
);\r
\r
- $ABApplicationHeader=new SoapHeader("http://www.msn.com/webservices/AddressBook",'ABApplicationHeader', $this->Array2SoapVar($ABApplicationHeaderArray));\r
- $ABFindAllArray=array(\r
- 'ABFindAll'=>array(\r
- ':'=>array('xmlns'=>'http://www.msn.com/webservices/AddressBook'),\r
- 'abId'=>'00000000-0000-0000-0000-000000000000',\r
- 'abView'=>'Full',\r
- 'lastChange'=>'0001-01-01T00:00:00.0000000-08:00',\r
+ $ABApplicationHeader = new SoapHeader('http://www.msn.com/webservices/AddressBook', 'ABApplicationHeader', $this->Array2SoapVar($ABApplicationHeaderArray));\r
+ $ABFindAllArray = array(\r
+ 'ABFindAll' => array(\r
+ ':' => array('xmlns'=>'http://www.msn.com/webservices/AddressBook'),\r
+ 'abId' => '00000000-0000-0000-0000-000000000000',\r
+ 'abView' => 'Full',\r
+ 'lastChange' => '0001-01-01T00:00:00.0000000-08:00',\r
)\r
);\r
- $ABFindAll=new SoapParam($this->Array2SoapVar($ABFindAllArray),'ABFindAll');\r
- $this->ABService->__setSoapHeaders(array($ABApplicationHeader,$this->ABAuthHeader));\r
- $this->Contacts=array();\r
- try\r
- {\r
- $this->debug_message("*** Update Contacts...");\r
- $Result=$this->ABService->ABFindAll($ABFindAll);\r
- $this->debug_message("*** Result:\n".print_r($Result,true)."\n".$this->ABService->__getLastResponse());\r
+ $ABFindAll = new SoapParam($this->Array2SoapVar($ABFindAllArray), 'ABFindAll');\r
+ $this->ABService->__setSoapHeaders(array($ABApplicationHeader, $this->ABAuthHeader));\r
+ $this->Contacts = array();\r
+ try {\r
+ $this->debug_message('*** Updating Contacts...');\r
+ $Result = $this->ABService->ABFindAll($ABFindAll);\r
+ $this->debug_message("*** Result:\n".print_r($Result, true)."\n".$this->ABService->__getLastResponse());\r
foreach($Result->ABFindAllResult->contacts->Contact as $Contact)\r
- $this->Contacts[$Contact->contactInfo->passportName]=$Contact;\r
- }\r
- catch(Exception $e)\r
- {\r
+ $this->Contacts[$Contact->contactInfo->passportName] = $Contact;\r
+ } catch(Exception $e) {\r
$this->debug_message("*** Update Contacts Error \nRequest:".$this->ABService->__getLastRequest()."\nError:".$e->getMessage());\r
return false;\r
}\r
return true;\r
}\r
\r
- private function addContact($email, $network, $display = '', $sendADL = false)\r
- {\r
+ /**\r
+ * Add contact\r
+ *\r
+ * @param string $email\r
+ * @param integer $network\r
+ * @param string $display\r
+ * @param boolean $sendADL\r
+ * @return boolean true on success\r
+ */\r
+ private function addContact($email, $network, $display = '', $sendADL = false) {\r
if ($network != 1) return true;\r
- if(isset($this->Contacts[$email])) return true;\r
-\r
- $ABContactAddArray=array(\r
- 'ABContactAdd'=>array(\r
- ':'=>array('xmlns'=>'http://www.msn.com/webservices/AddressBook'),\r
- 'abId'=>'00000000-0000-0000-0000-000000000000',\r
- 'contacts'=>array(\r
- 'Contact'=>array(\r
- ':'=>array('xmlns'=>'http://www.msn.com/webservices/AddressBook'),\r
- 'contactInfo'=>array(\r
- 'contactType'=>'LivePending',\r
- 'passportName'=>$email,\r
- 'isMessengerUser'=>true,\r
- 'MessengerMemberInfo'=>array(\r
- 'DisplayName'=>$email\r
+ if (isset($this->Contacts[$email])) return true;\r
+\r
+ $ABContactAddArray = array(\r
+ 'ABContactAdd' => array(\r
+ ':' => array('xmlns' => 'http://www.msn.com/webservices/AddressBook'),\r
+ 'abId' => '00000000-0000-0000-0000-000000000000',\r
+ 'contacts' => array(\r
+ 'Contact' => array(\r
+ ':' => array('xmlns' => 'http://www.msn.com/webservices/AddressBook'),\r
+ 'contactInfo' => array(\r
+ 'contactType' => 'LivePending',\r
+ 'passportName' => $email,\r
+ 'isMessengerUser' => true,\r
+ 'MessengerMemberInfo' => array(\r
+ 'DisplayName' => $email\r
)\r
)\r
)\r
),\r
- 'options'=>array(\r
- 'EnableAllowListManagement'=>true\r
+ 'options' => array(\r
+ 'EnableAllowListManagement' => true\r
)\r
)\r
);\r
- $ABContactAdd=new SoapParam($this->Array2SoapVar($ABContactAddArray),'ABContactAdd');\r
- try\r
- {\r
- $this->debug_message("*** Add Contacts $email...");\r
+ $ABContactAdd = new SoapParam($this->Array2SoapVar($ABContactAddArray), 'ABContactAdd');\r
+ try {\r
+ $this->debug_message("*** Adding Contact $email...");\r
$this->ABService->ABContactAdd($ABContactAdd);\r
- }\r
- catch(Exception $e)\r
- {\r
- $this->debug_message("*** Add Contacts Error \nRequest:".$this->ABService->__getLastRequest()."\nError:".$e->getMessage());\r
+ } catch(Exception $e) {\r
+ $this->debug_message("*** Add Contact Error \nRequest:".$this->ABService->__getLastRequest()."\nError:".$e->getMessage());\r
return false;\r
}\r
if ($sendADL && !feof($this->NSfp)) {\r
$str = '<ml l="1"><d n="'.$u_domain.'"><c n="'.$u_name.'" l="'.$l.'" t="'.$network.'" /></d></ml>';\r
$len = strlen($str);\r
// NS: >>> ADL {id} {size}\r
+ //TODO introduce error checking\r
$this->ns_writeln("ADL $this->id $len");\r
$this->ns_writedata($str);\r
}\r
return true;\r
}\r
\r
- function delMemberFromList($memberID, $email, $network, $list)\r
- {\r
+ /**\r
+ * Remove contact from list\r
+ *\r
+ * @param integer $memberID\r
+ * @param string $email\r
+ * @param integer $network\r
+ * @param string $list\r
+ */\r
+ function delMemberFromList($memberID, $email, $network, $list) {\r
if ($network != 1 && $network != 32) return true;\r
if ($memberID === false) return true;\r
$user = $email;\r
'User-Agent: MSN Explorer/9.0 (MSN 8.0; TmstmpExt)'\r
);\r
\r
- $this->debug_message("*** URL: $this->delmember_url");\r
- $this->debug_message("*** Sending SOAP:\n$XML");\r
+ //$this->debug_message("*** URL: $this->delmember_url");\r
+ //$this->debug_message("*** Sending SOAP:\n$XML");\r
$curl = curl_init();\r
curl_setopt($curl, CURLOPT_URL, $this->delmember_url);\r
curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
$data = curl_exec($curl);\r
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);\r
curl_close($curl);\r
- $this->debug_message("*** Get Result:\n$data");\r
+ //$this->debug_message("*** Get Result:\n$data");\r
\r
if ($http_code != 200) {\r
preg_match('#<faultcode>(.*)</faultcode><faultstring>(.*)</faultstring>#', $data, $matches);\r
if (count($matches) == 0) {\r
- $this->debug_message("*** can't delete member (network: $network) $email ($memberID) to $list");\r
+ $this->debug_message("*** Could not delete member (network: $network) $email ($memberID) from $list list");\r
return false;\r
}\r
$faultcode = trim($matches[1]);\r
$faultstring = trim($matches[2]);\r
if (strcasecmp($faultcode, 'soap:Client') || stripos($faultstring, 'Member does not exist') === false) {\r
- $this->debug_message("*** can't delete member (network: $network) $email ($memberID) to $list, error code: $faultcode, $faultstring");\r
+ $this->debug_message("*** Could not delete member (network: $network) $email ($memberID) from $list list, error code: $faultcode, $faultstring");\r
return false;\r
}\r
- $this->debug_message("*** delete member (network: $network) $email ($memberID) from $list, not exist");\r
+ $this->debug_message("*** Could not delete member (network: $network) $email ($memberID) from $list list, not present in list");\r
return true;\r
}\r
- $this->debug_message("*** delete member (network: $network) $email ($memberID) from $list");\r
+ $this->debug_message("*** Member successfully deleted (network: $network) $email ($memberID) from $list list");\r
return true;\r
}\r
\r
- function addMemberToList($email, $network, $list)\r
- {\r
+ /**\r
+ * Add contact to list\r
+ *\r
+ * @param string $email\r
+ * @param integer $network\r
+ * @param string $list\r
+ */\r
+ function addMemberToList($email, $network, $list) {\r
if ($network != 1 && $network != 32) return true;\r
$ticket = htmlspecialchars($this->ticket['contact_ticket']);\r
$user = $email;\r
'User-Agent: MSN Explorer/9.0 (MSN 8.0; TmstmpExt)'\r
);\r
\r
- $this->debug_message("*** URL: $this->addmember_url");\r
- $this->debug_message("*** Sending SOAP:\n$XML");\r
+ //$this->debug_message("*** URL: $this->addmember_url");\r
+ //$this->debug_message("*** Sending SOAP:\n$XML");\r
$curl = curl_init();\r
curl_setopt($curl, CURLOPT_URL, $this->addmember_url);\r
curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
$data = curl_exec($curl);\r
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);\r
curl_close($curl);\r
- $this->debug_message("*** Get Result:\n$data");\r
+ //$this->debug_message("*** Get Result:\n$data");\r
\r
if ($http_code != 200) {\r
preg_match('#<faultcode>(.*)</faultcode><faultstring>(.*)</faultstring>#', $data, $matches);\r
if (count($matches) == 0) {\r
- $this->debug_message("*** can't add member (network: $network) $email to $list");\r
+ $this->debug_message("*** Could not add member (network: $network) $email to $list list");\r
return false;\r
}\r
$faultcode = trim($matches[1]);\r
$faultstring = trim($matches[2]);\r
if (strcasecmp($faultcode, 'soap:Client') || stripos($faultstring, 'Member already exists') === false) {\r
- $this->debug_message("*** can't add member (network: $network) $email to $list, error code: $faultcode, $faultstring");\r
+ $this->debug_message("*** Could not add member (network: $network) $email to $list list, error code: $faultcode, $faultstring");\r
return false;\r
}\r
- $this->debug_message("*** add member (network: $network) $email to $list, already exist!");\r
+ $this->debug_message("*** Could not add member (network: $network) $email to $list list, already present");\r
return true;\r
}\r
- $this->debug_message("*** add member (network: $network) $email to $list");\r
+ $this->debug_message("*** Member successfully added (network: $network) $email to $list list");\r
return true;\r
}\r
\r
- function getMembershipList($returnData=false)\r
- {\r
+ /**\r
+ * Get membership lists\r
+ *\r
+ * @param mixed $returnData Membership list or false on failure\r
+ */\r
+ function getMembershipList($returnData = false) {\r
$ticket = htmlspecialchars($this->ticket['contact_ticket']);\r
$XML = '<?xml version="1.0" encoding="utf-8"?>\r
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"\r
'Content-Type: text/xml; charset=utf-8',\r
'User-Agent: MSN Explorer/9.0 (MSN 8.0; TmstmpExt)'\r
);\r
- $this->debug_message("*** URL: $this->membership_url");\r
- $this->debug_message("*** Sending SOAP:\n$XML");\r
+ //$this->debug_message("*** URL: $this->membership_url");\r
+ //$this->debug_message("*** Sending SOAP:\n$XML");\r
$curl = curl_init();\r
curl_setopt($curl, CURLOPT_URL, $this->membership_url);\r
curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
$data = curl_exec($curl);\r
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);\r
curl_close($curl);\r
- $this->debug_message("*** Get Result:\n$data");\r
- if($http_code != 200) return false;\r
+ //$this->debug_message("*** Get Result:\n$data");\r
+ if ($http_code != 200) return false;\r
$p = $data;\r
$aMemberships = array();\r
while (1) {\r
@list($u_name, $u_domain) = @explode('@', $email);\r
if ($u_domain == NULL) continue;\r
$aContactList[$u_domain][$u_name][$network][$sMemberRole] = $id;\r
- $this->debug_message("*** add new contact (network: $network, status: $sMemberRole): $u_name@$u_domain ($id)");\r
+ $this->debug_message("*** Adding new contact (network: $network, status: $sMemberRole): $u_name@$u_domain ($id)");\r
}\r
}\r
}\r
\r
/**\r
* Connect to the NS server\r
+ *\r
* @param String $user Username\r
* @param String $password Password\r
* @param String $redirect_server Redirect server\r
private function connect($user, $password, $redirect_server = '', $redirect_port = 1863) {\r
$this->id = 1;\r
if ($redirect_server === '') {\r
- $this->NSfp = @fsockopen($this->server, $this->port, $errno, $errstr, 5);\r
+ $this->NSfp = @fsockopen($this->server, $this->port, $errno, $errstr, $this->timeout);\r
if (!$this->NSfp) {\r
- $this->error = "Can't connect to $this->server:$this->port, error => $errno, $errstr";\r
+ $this->error = "!!! Could not connect to $this->server:$this->port, error => $errno, $errstr";\r
return false;\r
}\r
}\r
else {\r
- $this->NSfp = @fsockopen($redirect_server, $redirect_port, $errno, $errstr, 5);\r
+ $this->NSfp = @fsockopen($redirect_server, $redirect_port, $errno, $errstr, $this->timeout);\r
if (!$this->NSfp) {\r
- $this->error = "Can't connect to $redirect_server:$redirect_port, error => $errno, $errstr";\r
+ $this->error = "!!! Could not connect to $redirect_server:$redirect_port, error => $errno, $errstr";\r
return false;\r
}\r
}\r
-\r
- stream_set_timeout($this->NSfp, $this->timeout);\r
$this->authed = false;\r
// MSNP9\r
// NS: >> VER {id} MSNP9 CVR0\r
$this->ns_writeln("VER $this->id $this->protocol CVR0");\r
\r
$start_tm = time();\r
- while (!self::socketcheck($this->NSfp))\r
- {\r
+ while (!self::socketcheck($this->NSfp)) {\r
$data = $this->ns_readln();\r
// no data?\r
if ($data === false) {\r
$this->ns_writeln("OUT");\r
@fclose($this->NSfp);\r
$this->error = 'Timeout, maybe protocol changed!';\r
- $this->debug_message("*** $this->error");\r
return false;\r
}\r
\r
$this->ns_writeln("OUT");\r
@fclose($this->NSfp);\r
$this->error = 'Passport authenticated fail!';\r
- $this->debug_message("*** $this->error");\r
return false;\r
}\r
\r
// MSNP15\r
// NS: <<< XFR {id} NS {server} U D\r
@list(/* XFR */, /* id */, $Type, $server, /* ... */) = @explode(' ', $data);\r
- if($Type!='NS') break;\r
+ if ($Type!='NS') break;\r
@list($ip, $port) = @explode(':', $server);\r
// this connection will close after XFR\r
@fclose($this->NSfp);\r
\r
- $this->NSfp = @fsockopen($ip, $port, $errno, $errstr, 5);\r
+ $this->NSfp = @fsockopen($ip, $port, $errno, $errstr, $this->timeout);\r
if (!$this->NSfp) {\r
$this->error = "Can't connect to $ip:$port, error => $errno, $errstr";\r
- $this->debug_message("*** $this->error");\r
return false;\r
}\r
\r
- stream_set_timeout($this->NSfp, $this->timeout);\r
// MSNP9\r
// NS: >> VER {id} MSNP9 CVR0\r
// MSNP15\r
@list(/* GCF */, /* 0 */, $size,) = @explode(' ', $data);\r
// we don't need the data, just read it and drop\r
if (is_numeric($size) && $size > 0)\r
- $this->ns_readdata($size);\r
+ $this->ns_readdata($size);\r
break;\r
\r
default:\r
$this->ns_writeln("OUT");\r
@fclose($this->NSfp);\r
$this->error = "Error code: $code, please check the detail information from: http://msnpiki.msnfanatic.com/index.php/Reference:Error_List";\r
- $this->debug_message("*** $this->error");\r
return false;\r
}\r
// unknown response from server, just ignore it\r
* @return void\r
*/\r
public function signon() {\r
- $this->debug_message("*** try to connect to MSN network");\r
-\r
- while(true) {\r
- while(!$this->connect($this->user, $this->password)) {\r
- $this->signonFailure("!!! Can't connect to server: $this->error");\r
- }\r
- if($this->UpdateContacts() === false) {\r
- $this->signonFailure('!!! Update contacts failed');\r
+ /* FIXME Don't implement the signon as a loop or we could hang\r
+ * the queue handler! */\r
+ $this->debug_message('*** Trying to connect to MSN network');\r
+\r
+ while (true) {\r
+ // Connect\r
+ if (!$this->connect($this->user, $this->password)) {\r
+ $this->signonFailure("!!! Could not connect to server: $this->error");\r
continue;\r
}\r
- $this->LastPing=time();\r
- $start_tm = time();\r
- $ping_tm = time();\r
- if(($this->aContactList = $this->getMembershipList()) === false) {\r
+\r
+ // Update contacts\r
+ if ($this->UpdateContacts() === false) continue;\r
+\r
+ // Get membership lists\r
+ if (($this->aContactList = $this->getMembershipList()) === false) {\r
$this->signonFailure('!!! Get membership list failed');\r
continue;\r
}\r
+\r
if ($this->update_pending) {\r
if (is_array($this->aContactList)) {\r
$pending = 'Pending';\r
//$MsnObj=$this->PhotoStckObj();\r
// NS: >>> CHG {id} {status} {clientid} {msnobj}\r
$this->ns_writeln("CHG $this->id NLN $this->clientid");\r
- if($this->PhotoStickerFile!==false)\r
+ if ($this->PhotoStickerFile !== false)\r
$this->ns_writeln("CHG $this->id NLN $this->clientid ".rawurlencode($this->MsnObj($this->PhotoStickerFile)));\r
// NS: >>> UUX {id} length\r
$str = '<Data><PSM>'.htmlspecialchars($this->psm).'</PSM><CurrentMedia></CurrentMedia><MachineGuid></MachineGuid></Data>';\r
$len = strlen($str);\r
$this->ns_writeln("UUX $this->id $len");\r
$this->ns_writedata($str);\r
- if(!socketcheck($this->NSfp)) {\r
- $this->debug_message("*** connected, wait for command");\r
+ if (!self::socketcheck($this->NSfp)) {\r
+ $this->debug_message('*** Connected, waiting for commands');\r
break;\r
} else {\r
$this->NSRetryWait($this->retry_wait);\r
return base64_encode($blob);\r
}\r
\r
+ /**\r
+ * Get OIM mail data\r
+ *\r
+ * @return string mail data or false on failure\r
+ */\r
function getOIM_maildata() {\r
preg_match('#t=(.*)&p=(.*)#', $this->ticket['web_ticket'], $matches);\r
if (count($matches) == 0) {\r
- $this->debug_message('*** no web ticket?');\r
+ $this->debug_message('*** No web ticket?');\r
return false;\r
}\r
$t = htmlspecialchars($matches[1]);\r
'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Messenger '.$this->buildver.')'\r
);\r
\r
- $this->debug_message("*** URL: $this->oim_maildata_url");\r
- $this->debug_message("*** Sending SOAP:\n$XML");\r
+ //$this->debug_message("*** URL: $this->oim_maildata_url");\r
+ //$this->debug_message("*** Sending SOAP:\n$XML");\r
$curl = curl_init();\r
curl_setopt($curl, CURLOPT_URL, $this->oim_maildata_url);\r
curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
$data = curl_exec($curl);\r
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);\r
curl_close($curl);\r
- $this->debug_message("*** Get Result:\n$data");\r
+ //$this->debug_message("*** Get Result:\n$data");\r
\r
if ($http_code != 200) {\r
- $this->debug_message("*** Can't get OIM maildata! http code: $http_code");\r
+ $this->debug_message("*** Could not get OIM maildata! http code: $http_code");\r
return false;\r
}\r
\r
// <GetMetadataResponse xmlns="http://www.hotmail.msn.com/ws/2004/09/oim/rsi">See #XML_Data</GetMetadataResponse>\r
preg_match('#<GetMetadataResponse([^>]*)>(.*)</GetMetadataResponse>#', $data, $matches);\r
if (count($matches) == 0) {\r
- $this->debug_message("*** Can't get OIM maildata");\r
- return '';\r
+ $this->debug_message('*** Could not get OIM maildata');\r
+ return false;\r
}\r
return $matches[2];\r
}\r
\r
+ /**\r
+ * Fetch OIM message with given id\r
+ *\r
+ * @param string $msgid\r
+ * @return string Message or false on failure\r
+ */\r
function getOIM_message($msgid) {\r
preg_match('#t=(.*)&p=(.*)#', $this->ticket['web_ticket'], $matches);\r
if (count($matches) == 0) {\r
- $this->debug_message('*** no web ticket?');\r
+ $this->debug_message('*** No web ticket?');\r
return false;\r
}\r
$t = htmlspecialchars($matches[1]);\r
'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Messenger '.$this->buildver.')'\r
);\r
\r
- $this->debug_message("*** URL: $this->oim_read_url");\r
- $this->debug_message("*** Sending SOAP:\n$XML");\r
+ //$this->debug_message("*** URL: $this->oim_read_url");\r
+ //$this->debug_message("*** Sending SOAP:\n$XML");\r
$curl = curl_init();\r
curl_setopt($curl, CURLOPT_URL, $this->oim_read_url);\r
curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
$data = curl_exec($curl);\r
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);\r
curl_close($curl);\r
- $this->debug_message("*** Get Result:\n$data");\r
+ //$this->debug_message("*** Get Result:\n$data");\r
\r
if ($http_code != 200) {\r
$this->debug_message("*** Can't get OIM: $msgid, http code = $http_code");\r
$sOIM .= $line;\r
}\r
$sMsg = base64_decode($sOIM);\r
- $this->debug_message("*** we get OIM ($msgid): $sMsg");\r
+ //$this->debug_message("*** we get OIM ($msgid): $sMsg");\r
\r
// delete OIM\r
$XML = '<?xml version="1.0" encoding="utf-8"?>\r
'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Messenger '.$this->buildver.')'\r
);\r
\r
- $this->debug_message("*** URL: $this->oim_del_url");\r
- $this->debug_message("*** Sending SOAP:\n$XML");\r
+ //$this->debug_message("*** URL: $this->oim_del_url");\r
+ //$this->debug_message("*** Sending SOAP:\n$XML");\r
$curl = curl_init();\r
curl_setopt($curl, CURLOPT_URL, $this->oim_del_url);\r
curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
$data = curl_exec($curl);\r
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);\r
curl_close($curl);\r
- $this->debug_message("*** Get Result:\n$data");\r
+ //$this->debug_message("*** Get Result:\n$data");\r
\r
if ($http_code != 200)\r
- $this->debug_message("*** Can't delete OIM: $msgid, http code = $http_code");\r
+ $this->debug_message("*** Could not delete OIM: $msgid, http code = $http_code");\r
else\r
$this->debug_message("*** OIM ($msgid) deleted");\r
return $sMsg;\r
}\r
\r
+ /**\r
+ * Log out and close the NS connection\r
+ *\r
+ * @return void\r
+ */\r
private function NSLogout() {\r
if (is_resource($this->NSfp) && !feof($this->NSfp)) {\r
// logout now\r
$this->ns_writeln("OUT");\r
fclose($this->NSfp);\r
$this->NSfp = false;\r
- $this->debug_message("*** logout now!");\r
+ $this->debug_message("*** Logged out");\r
}\r
-\r
}\r
\r
+ /**\r
+ * Sleep for the given number of seconds\r
+ *\r
+ * @param integer $wait Number of seconds to sleep for\r
+ */\r
private function NSRetryWait($wait) {\r
- $this->debug_message("*** wait for $Wait seconds");\r
+ $this->debug_message("*** Sleeping for $wait seconds before retrying");\r
sleep($wait);\r
}\r
\r
- function getChallenge($code)\r
- {\r
+ /**\r
+ * Generate challenge response\r
+ *\r
+ * @param string $code\r
+ * @return string challenge response code\r
+ */\r
+ function getChallenge($code) {\r
// MSNP15\r
// http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges\r
// Step 1: The MD5 Hash\r
return $hash;\r
}\r
\r
- private function getMessage($sMessage, $network = 1)\r
- {\r
+ /**\r
+ * Generate the data to send a message\r
+ *\r
+ * @param string $sMessage Message\r
+ * @param integer $network Network\r
+ */\r
+ private function getMessage($sMessage, $network = 1) {\r
$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";\r
$msg_header_len = strlen($msg_header);\r
if ($network == 1)\r
$maxlen = $this->max_msn_message_len - $msg_header_len;\r
else\r
$maxlen = $this->max_yahoo_message_len - $msg_header_len;\r
- $sMessage=str_replace("\r", '', $sMessage);\r
- $msg=substr($sMessage,0,$maxlen);\r
+ $sMessage = str_replace("\r", '', $sMessage);\r
+ $msg = substr($sMessage, 0, $maxlen);\r
return $msg_header.$msg;\r
}\r
- /**\r
- *\r
- * @param $Action 連線模式 'Active' => 主動傳送訊息,'Passive' => 接收訊息\r
- * @param $Param\r
- * @return boolean\r
- */\r
- private function DoSwitchBoard($Action,$Param)\r
- {\r
- $SessionEnd=false;\r
- $Joined=false;\r
- $this->id=1;\r
- $LastActive=time();\r
- stream_set_timeout($this->SBfp, $this->SBStreamTimeout);\r
- switch($Action)\r
- {\r
- case 'Active':\r
- $cki_code=$Param['cki'];\r
- $user=$Param['user'];\r
- $this->SwitchBoardMessageQueue=$Param['Msg'];\r
- // SB: >>> USR {id} {user} {cki}\r
- $this->SB_writeln("USR $this->id $this->user $cki_code");\r
- $this->SwitchBoardSessionUser=$user;\r
- break;\r
- case 'Passive':\r
- $ticket=$Param['ticket'];\r
- $sid=$Param['sid'];\r
- $user=$Param['user'];\r
- // SB: >>> ANS {id} {user} {ticket} {session_id}\r
- $this->SB_writeln("ANS $this->id $this->user $ticket $sid");\r
- $this->SwitchBoardSessionUser=$user;\r
- break;\r
- default:\r
- return false;\r
- }\r
- while((!feof($this->SBfp))&&(!$SessionEnd))\r
- {\r
- $data = $this->SB_readln();\r
- if($this->kill_me)\r
- {\r
- $this->debug_message("*** SB Okay, kill me now!");\r
- break;\r
- }\r
- if($data === false)\r
- {\r
- if(time()-$LastActive > $this->SBIdleTimeout)\r
- {\r
- $this->debug_message("*** SB Idle Timeout!");\r
- break;\r
- }\r
- if(!$Joined) continue;\r
- foreach($this->SwitchBoardMessageQueue as $Message)\r
- {\r
- if($Message=='') continue;\r
- $aMessage = $this->getMessage($Message);\r
- //CheckEmotion...\r
- $MsnObjDefine=$this->GetMsnObjDefine($aMessage);\r
- if($MsnObjDefine!=='')\r
- {\r
- $SendString="MIME-Version: 1.0\r\nContent-Type: text/x-mms-emoticon\r\n\r\n$MsnObjDefine";\r
- $len = strlen($SendString);\r
- $this->SB_writeln("MSG $this->id N $len");\r
- $this->SB_writedata($SendString);\r
- $this->id++;\r
- }\r
- $len = strlen($aMessage);\r
- $this->SB_writeln("MSG $this->id N $len");\r
- $this->SB_writedata($aMessage);\r
- }\r
- $this->SwitchBoardMessageQueue=array();\r
- if(!$this->IsIgnoreMail($user)) $LastActive = time();\r
- continue;\r
- }\r
- $code = substr($data, 0, 3);\r
- switch($code)\r
- {\r
- case 'IRO':\r
- // SB: <<< IRO {id} {rooster} {roostercount} {email} {alias} {clientid}\r
- @list(/* IRO */, /* id */, $cur_num, $total, $email, $alias, $clientid) = @explode(' ', $data);\r
- $this->debug_message("*** $email join us");\r
- $Joined=true;\r
- break;\r
- case 'BYE':\r
- $this->debug_message("*** Quit for BYE");\r
- $SessionEnd=true;\r
- break;\r
- case 'USR':\r
- // SB: <<< USR {id} OK {user} {alias}\r
- // we don't need the data, just ignore it\r
- // request user to join this switchboard\r
- // SB: >>> CAL {id} {user}\r
- $this->SB_writeln("CAL $this->id $user");\r
- break;\r
- case 'CAL':\r
- // SB: <<< CAL {id} RINGING {?}\r
- // we don't need this, just ignore, and wait for other response\r
- $this->id++;\r
- break;\r
- case 'JOI':\r
- // SB: <<< JOI {user} {alias} {clientid?}\r
- // someone join us\r
- // we don't need the data, just ignore it\r
- // no more user here\r
- $Joined=true;\r
- break;\r
- case 'MSG':\r
- // SB: <<< MSG {email} {alias} {len}\r
- @list(/* MSG */, $from_email, /* alias */, $len, ) = @explode(' ', $data);\r
- $len = trim($len);\r
- $data = $this->SB_readdata($len);\r
- $aLines = @explode("\n", $data);\r
- $header = true;\r
- $ignore = false;\r
- $is_p2p = false;\r
- $sMsg = '';\r
- foreach ($aLines as $line)\r
- {\r
- $line = rtrim($line);\r
- if ($header) {\r
- if ($line === '') {\r
- $header = false;\r
- continue;\r
- }\r
- if (strncasecmp($line, 'TypingUser:', 11) == 0) {\r
- // typing notification, just ignore\r
- $ignore = true;\r
- break;\r
- }\r
- if (strncasecmp($line, 'Chunk:', 6) == 0) {\r
- // we don't handle any split message, just ignore\r
- $ignore = true;\r
- break;\r
- }\r
- if (strncasecmp($line, 'Content-Type: application/x-msnmsgrp2p', 38) == 0) {\r
- // p2p message, ignore it, but we need to send acknowledgement for it...\r
- $is_p2p = true;\r
- $p = strstr($data, "\n\n");\r
- $sMsg = '';\r
- if ($p === false) {\r
- $p = strstr($data, "\r\n\r\n");\r
- if ($p !== false)\r
- $sMsg = substr($p, 4);\r
- }\r
- else\r
- $sMsg = substr($p, 2);\r
- break;\r
- }\r
- if (strncasecmp($line, 'Content-Type: application/x-', 28) == 0) {\r
- // ignore all application/x-... message\r
- // for example:\r
- // application/x-ms-ink => ink message\r
- $ignore = true;\r
- break;\r
- }\r
- if (strncasecmp($line, 'Content-Type: text/x-', 21) == 0) {\r
- // ignore all text/x-... message\r
- // for example:\r
- // text/x-msnmsgr-datacast => nudge, voice clip....\r
- // text/x-mms-animemoticon => customized animemotion word\r
- $ignore = true;\r
- break;\r
- }\r
- continue;\r
- }\r
- if ($sMsg !== '')\r
- $sMsg .= "\n";\r
- $sMsg .= $line;\r
- }\r
- if ($ignore)\r
- {\r
- $this->debug_message("*** ingnore from $from_email: $line");\r
- break;\r
- }\r
- if ($is_p2p)\r
- {\r
- // we will ignore any p2p message after sending acknowledgement\r
- $ignore = true;\r
- $len = strlen($sMsg);\r
- $this->debug_message("*** p2p message from $from_email, size $len");\r
- // header = 48 bytes\r
- // content >= 0 bytes\r
- // footer = 4 bytes\r
- // so it need to >= 52 bytes\r
- /*if ($len < 52) {\r
- $this->debug_message("*** p2p: size error, less than 52!");\r
- break;\r
- }*/\r
- $aDwords = @unpack("V12dword", $sMsg);\r
- if (!is_array($aDwords)) {\r
- $this->debug_message("*** p2p: header unpack error!");\r
- break;\r
- }\r
- $this->debug_message("*** p2p: dump received message:\n".$this->dump_binary($sMsg));\r
- $hdr_SessionID = $aDwords['dword1'];\r
- $hdr_Identifier = $aDwords['dword2'];\r
- $hdr_DataOffsetLow = $aDwords['dword3'];\r
- $hdr_DataOffsetHigh = $aDwords['dword4'];\r
- $hdr_TotalDataSizeLow = $aDwords['dword5'];\r
- $hdr_TotalDataSizeHigh = $aDwords['dword6'];\r
- $hdr_MessageLength = $aDwords['dword7'];\r
- $hdr_Flag = $aDwords['dword8'];\r
- $hdr_AckID = $aDwords['dword9'];\r
- $hdr_AckUID = $aDwords['dword10'];\r
- $hdr_AckSizeLow = $aDwords['dword11'];\r
- $hdr_AckSizeHigh = $aDwords['dword12'];\r
- $this->debug_message("*** p2p: header SessionID = $hdr_SessionID");\r
- $this->debug_message("*** p2p: header Inentifier = $hdr_Identifier");\r
- $this->debug_message("*** p2p: header Data Offset Low = $hdr_DataOffsetLow");\r
- $this->debug_message("*** p2p: header Data Offset High = $hdr_DataOffsetHigh");\r
- $this->debug_message("*** p2p: header Total Data Size Low = $hdr_TotalDataSizeLow");\r
- $this->debug_message("*** p2p: header Total Data Size High = $hdr_TotalDataSizeHigh");\r
- $this->debug_message("*** p2p: header MessageLength = $hdr_MessageLength");\r
- $this->debug_message("*** p2p: header Flag = $hdr_Flag");\r
- $this->debug_message("*** p2p: header AckID = $hdr_AckID");\r
- $this->debug_message("*** p2p: header AckUID = $hdr_AckUID");\r
- $this->debug_message("*** p2p: header AckSize Low = $hdr_AckSizeLow");\r
- $this->debug_message("*** p2p: header AckSize High = $hdr_AckSizeHigh");\r
- if($hdr_Flag==2) {\r
- //This is an ACK from SB ignore....\r
- $this->debug_message("*** p2p: //This is an ACK from SB ignore....:\n");\r
- break;\r
- }\r
- $MsgBody=$this->linetoArray(substr($sMsg,48,-4));\r
- $this->debug_message("*** p2p: body".print_r($MsgBody,true));\r
- if(($MsgBody['EUF-GUID']=='{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}')&&($PictureFilePath=$this->GetPictureFilePath($MsgBody['Context'])))\r
- {\r
- while(true)\r
- {\r
- if($this->SB_readln()===false) break;\r
- }\r
- $this->debug_message("*** p2p: Inv hdr:\n".$this->dump_binary(substr($sMsg,0,48)));\r
- preg_match('/{([0-9A-F\-]*)}/i',$MsgBody['Via'],$Matches);\r
- $BranchGUID=$Matches[1];\r
- //it's an invite to send a display picture.\r
- $new_id = ~$hdr_Identifier;\r
- $hdr = pack("LLLLLLLLLLLL", $hdr_SessionID,\r
- $new_id,\r
- 0, 0,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
- 0,\r
- 2,\r
- $hdr_Identifier,\r
- $hdr_AckID,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh);\r
- $footer = pack("L", 0);\r
- $message = "MIME-Version: 1.0\r\nContent-Type: application/x-msnmsgrp2p\r\nP2P-Dest: $from_email\r\n\r\n$hdr$footer";\r
- $len = strlen($message);\r
- $this->SB_writeln("MSG $this->id D $len");\r
- $this->SB_writedata($message);\r
- $this->debug_message("*** p2p: send display picture acknowledgement for $hdr_SessionID");\r
- $this->debug_message("*** p2p: Invite ACK message:\n".$this->dump_binary($message));\r
- $this->SB_readln();//Read ACK;\r
- $this->debug_message("*** p2p: Invite ACK Hdr:\n".$this->dump_binary($hdr));\r
- $new_id-=3;\r
- //Send 200 OK message\r
- $MessageContent="SessionID: ".$MsgBody['SessionID']."\r\n\r\n".pack("C", 0);\r
- $MessagePayload=\r
- "MSNSLP/1.0 200 OK\r\n".\r
- "To: <msnmsgr:".$from_email.">\r\n".\r
- "From: <msnmsgr:".$this->user.">\r\n".\r
- "Via: ".$MsgBody['Via']."\r\n".\r
- "CSeq: ".($MsgBody['CSeq']+1)."\r\n".\r
- "Call-ID: ".$MsgBody['Call-ID']."\r\n".\r
- "Max-Forwards: 0\r\n".\r
- "Content-Type: application/x-msnmsgr-sessionreqbody\r\n".\r
- "Content-Length: ".strlen($MessageContent)."\r\n\r\n".\r
- $MessageContent;\r
- $hdr_TotalDataSizeLow=strlen($MessagePayload);\r
- $hdr_TotalDataSizeHigh=0;\r
- $hdr = pack("LLLLLLLLLLLL", $hdr_SessionID,\r
- $new_id,\r
- 0, 0,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
- strlen($MessagePayload),\r
- 0,\r
- rand(),\r
- 0,\r
- 0,0);\r
-\r
- $message =\r
- "MIME-Version: 1.0\r\n".\r
- "Content-Type: application/x-msnmsgrp2p\r\n".\r
- "P2P-Dest: $from_email\r\n\r\n$hdr$MessagePayload$footer";\r
- $this->SB_writeln("MSG $this->id D ".strlen($message));\r
- $this->SB_writedata($message);\r
- $this->debug_message("*** p2p: dump 200 ok message:\n".$this->dump_binary($message));\r
- $this->SB_readln();//Read ACK;\r
-\r
- $this->debug_message("*** p2p: 200 ok:\n".$this->dump_binary($hdr));\r
- //send Data preparation message\r
- //send 4 null bytes as data\r
- $hdr_TotalDataSizeLow=4;\r
- $hdr_TotalDataSizeHigh=0;\r
- $new_id++;\r
- $hdr = pack("LLLLLLLLLLLL",\r
- $MsgBody['SessionID'],\r
- $new_id,\r
- 0, 0,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
- $hdr_TotalDataSizeLow,\r
- 0,\r
- rand(),\r
- 0,\r
- 0,0);\r
- $message =\r
- "MIME-Version: 1.0\r\n".\r
- "Content-Type: application/x-msnmsgrp2p\r\n".\r
- "P2P-Dest: $from_email\r\n\r\n$hdr".pack('L',0)."$footer";\r
- $this->SB_writeln("MSG $this->id D ".strlen($message));\r
- $this->SB_writedata($message);\r
- $this->debug_message("*** p2p: dump send Data preparation message:\n".$this->dump_binary($message));\r
- $this->debug_message("*** p2p: Data Prepare Hdr:\n".$this->dump_binary($hdr));\r
- $this->SB_readln();//Read ACK;\r
-\r
- //send Data Content..\r
- $footer=pack('N',1);\r
- $new_id++;\r
- $FileSize=filesize($PictureFilePath);\r
- if($hTitle=fopen($PictureFilePath,'rb'))\r
- {\r
- $Offset=0;\r
- //$new_id++;\r
- while(!feof($hTitle))\r
- {\r
- $FileContent=fread($hTitle,1024);\r
- $FileContentSize=strlen($FileContent);\r
- $hdr = pack("LLLLLLLLLLLL",\r
- $MsgBody['SessionID'],\r
- $new_id,\r
- $Offset, 0,\r
- $FileSize,0,\r
- $FileContentSize,\r
- 0x20,\r
- rand(),\r
- 0,\r
- 0,0\r
- );\r
- $message =\r
- "MIME-Version: 1.0\r\n".\r
- "Content-Type: application/x-msnmsgrp2p\r\n".\r
- "P2P-Dest: $from_email\r\n\r\n$hdr$FileContent$footer";\r
- $this->SB_writeln("MSG $this->id D ".strlen($message));\r
- $this->SB_writedata($message);\r
- $this->debug_message("*** p2p: dump send Data Content message $Offset / $FileSize :\n".$this->dump_binary($message));\r
- $this->debug_message("*** p2p: Data Content Hdr:\n".$this->dump_binary($hdr));\r
- //$this->SB_readln();//Read ACK;\r
- $Offset+=$FileContentSize;\r
- }\r
- }\r
- //Send Bye\r
- /*\r
- $MessageContent="\r\n".pack("C", 0);\r
- $MessagePayload=\r
- "BYE MSNMSGR:MSNSLP/1.0\r\n".\r
- "To: <msnmsgr:$from_email>\r\n".\r
- "From: <msnmsgr:".$this->user.">\r\n".\r
- "Via: MSNSLP/1.0/TLP ;branch={".$BranchGUID."}\r\n".\r
- "CSeq: 0\r\n".\r
- "Call-ID: ".$MsgBody['Call-ID']."\r\n".\r
- "Max-Forwards: 0\r\n".\r
- "Content-Type: application/x-msnmsgr-sessionclosebody\r\n".\r
- "Content-Length: ".strlen($MessageContent)."\r\n\r\n".$MessageContent;\r
- $footer=pack('N',0);\r
- $hdr_TotalDataSizeLow=strlen($MessagePayload);\r
- $hdr_TotalDataSizeHigh=0;\r
- $new_id++;\r
- $hdr = pack("LLLLLLLLLLLL",\r
- 0,\r
- $new_id,\r
- 0, 0,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
- 0,\r
- 0,\r
- rand(),\r
- 0,\r
- 0,0);\r
- $message =\r
- "MIME-Version: 1.0\r\n".\r
- "Content-Type: application/x-msnmsgrp2p\r\n".\r
- "P2P-Dest: $from_email\r\n\r\n$hdr$MessagePayload$footer";\r
- $this->SB_writeln("MSG $id D ".strlen($message));\r
- $id++;\r
- $this->SB_writedata($message);\r
- $this->debug_message("*** p2p: dump send BYE message :\n".$this->dump_binary($message));\r
- */\r
- break;\r
- }\r
- //TODO:\r
- //if ($hdr_Flag == 2) {\r
- // just send ACK...\r
- // $this->SB_writeln("ACK $id");\r
- // break;\r
- //}\r
- if ($hdr_SessionID == 4) {\r
- // ignore?\r
- $this->debug_message("*** p2p: ignore flag 4");\r
- break;\r
- }\r
- $finished = false;\r
- if ($hdr_TotalDataSizeHigh == 0) {\r
- // only 32 bites size\r
- if (($hdr_MessageLength + $hdr_DataOffsetLow) == $hdr_TotalDataSizeLow)\r
- $finished = true;\r
- }\r
- else {\r
- // we won't accept any file transfer\r
- // so I think we won't get any message size need to use 64 bits\r
- // 64 bits size here, can't count directly...\r
- $totalsize = base_convert(sprintf("%X%08X", $hdr_TotalDataSizeHigh, $hdr_TotalDataSizeLow), 16, 10);\r
- $dataoffset = base_convert(sprintf("%X%08X", $hdr_DataOffsetHigh, $hdr_DataOffsetLow), 16, 10);\r
- $messagelength = base_convert(sprintf("%X", $hdr_MessageLength), 16, 10);\r
- $now_size = bcadd($dataoffset, $messagelength);\r
- if (bccomp($now_size, $totalsize) >= 0)\r
- $finished = true;\r
- }\r
- if (!$finished) {\r
- // ignore not finished split packet\r
- $this->debug_message("*** p2p: ignore split packet, not finished");\r
- break;\r
- }\r
- //$new_id = ~$hdr_Identifier;\r
- /*\r
- $new_id++;\r
- $hdr = pack("LLLLLLLLLLLL", $hdr_SessionID,\r
- $new_id,\r
- 0, 0,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
- 0,\r
- 2,\r
- $hdr_Identifier,\r
- $hdr_AckID,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh);\r
- $footer = pack("L", 0);\r
- $message = "MIME-Version: 1.0\r\nContent-Type: application/x-msnmsgrp2p\r\nP2P-Dest: $from_email\r\n\r\n$hdr$footer";\r
- $len = strlen($message);\r
- $this->SB_writeln("MSG $id D $len");\r
- $id++;\r
- $this->SB_writedata($message);\r
- $this->debug_message("*** p2p: send acknowledgement for $hdr_SessionID");\r
- $this->debug_message("*** p2p: dump sent message:\n".$this->dump_binary($hdr.$footer));\r
- */\r
- break;\r
- }\r
- $this->debug_message("*** MSG from $from_email: $sMsg");\r
- $this->ReceivedMessage($from_email,$sMsg,$network,false);\r
- break;\r
- case '217':\r
- $this->debug_message("*** User $user is offline. Try OIM.");\r
- foreach($this->SwitchBoardMessageQueue as $Message)\r
- $this->SendMessage($Message,"$user@Offline");\r
- $SessionEnd=true;\r
- break;\r
- default:\r
- if (is_numeric($code))\r
- {\r
- $this->error = "Error code: $code, please check the detail information from: http://msnpiki.msnfanatic.com/index.php/Reference:Error_List";\r
- $this->debug_message("*** SB: $this->error");\r
- $SessionEnd=true;\r
- }\r
- break;\r
- }\r
- if(!$this->IsIgnoreMail($user)) $LastActive = time();\r
- }\r
- if (feof($this->SBfp))\r
- {\r
- // lost connection? error? try OIM later\r
- @fclose($this->SBfp);\r
- return false;\r
- }\r
- $this->SB_writeln("OUT");\r
- @fclose($this->SBfp);\r
- return true;\r
- }\r
- /*private function switchboard_control($ip, $port, $cki_code, $user, $Messages)\r
- {\r
- $this->SwitchBoardProcess=1;\r
- $this->debug_message("*** SB: try to connect to switchboard server $ip:$port");\r
- $this->SBfp = @fsockopen($ip, $port, $errno, $errstr, 5);\r
- if (!$this->SBfp)\r
- {\r
- $this->debug_message("*** SB: Can't connect to $ip:$port, error => $errno, $errstr");\r
- return false;\r
- }\r
- return $this->DoSwitchBoard('Active',array('cki'=>$cki_code, 'user'=>$user,'Msg'=>$Messages));\r
- }\r
- private function switchboard_ring($ip, $port, $sid, $ticket,$user)\r
- {\r
- $this->SwitchBoardProcess=2;\r
- $this->debug_message("*** SB: try to connect to switchboard server $ip:$port");\r
- $this->SBfp = @fsockopen($ip, $port, $errno, $errstr, 5);\r
- if (!$this->SBfp)\r
- {\r
- $this->debug_message("*** SB: Can't connect to $ip:$port, error => $errno, $errstr");\r
- return false;\r
- }\r
- return $this->DoSwitchBoard('Passive',array('sid'=>$sid,'user'=>$user,'ticket'=>$ticket));\r
- }*/\r
\r
// read data for specified size\r
private function ns_readdata($size) {\r
private function sb_readdata($socket, $size) {\r
$data = '';\r
$count = 0;\r
- while (!feof($this->SBfp)) {\r
- $buf = @fread($this->SBfp, $size - $count);\r
+ while (!feof($socket)) {\r
+ $buf = @fread($socket, $size - $count);\r
$data .= $buf;\r
$count += strlen($buf);\r
if ($count >= $size) break;\r
// show debug information\r
function debug_message($str) {\r
if (!$this->debug) return;\r
- if($this->debug===STDOUT) echo $str."\n";\r
+ if ($this->debug===STDOUT) echo $str."\n";\r
/*$fname=MSN_CLASS_LOG_DIR.DIRECTORY_SEPARATOR.'msn_'.strftime('%Y%m%d').'.debug';\r
$fp = fopen($fname, 'at');\r
if ($fp) {\r
*/\r
private function MsnObj($FilePath,$Type=3)\r
{\r
- if(!($FileSize=filesize($FilePath))) return '';\r
- $Location=md5($FilePath);\r
- $Friendly=md5($FilePath.$Type);\r
- if(isset($this->MsnObjMap[$Location])) return $this->MsnObjMap[$Location];\r
- $sha1d=base64_encode(sha1(file_get_contents($FilePath),true));\r
- $sha1c=base64_encode(sha1("Creator".$this->user."Size$FileSize"."Type$Type"."Location$Location"."Friendly".$Friendly."SHA1D$sha1d",true));\r
- $this->MsnObjArray[$Location]=$FilePath;\r
- $MsnObj='<msnobj Creator="'.$this->user.'" Size="'.$FileSize.'" Type="'.$Type.'" Location="'.$Location.'" Friendly="'.$Friendly.'" SHA1D="'.$sha1d.'" SHA1C="'.$sha1c.'"/>';\r
- $this->MsnObjMap[$Location]=$MsnObj;\r
+ if (!($FileSize=filesize($FilePath))) return '';\r
+ $Location = md5($FilePath);\r
+ $Friendly = md5($FilePath.$Type);\r
+ if (isset($this->MsnObjMap[$Location])) return $this->MsnObjMap[$Location];\r
+ $sha1d = base64_encode(sha1(file_get_contents($FilePath), true));\r
+ $sha1c = base64_encode(sha1("Creator".$this->user."Size$FileSize"."Type$Type"."Location$Location"."Friendly".$Friendly."SHA1D$sha1d",true));\r
+ $this->MsnObjArray[$Location] = $FilePath;\r
+ $MsnObj = '<msnobj Creator="'.$this->user.'" Size="'.$FileSize.'" Type="'.$Type.'" Location="'.$Location.'" Friendly="'.$Friendly.'" SHA1D="'.$sha1d.'" SHA1C="'.$sha1c.'"/>';\r
+ $this->MsnObjMap[$Location] = $MsnObj;\r
$this->debug_message("*** p2p: addMsnObj $FilePath::$MsnObj\n");\r
return $MsnObj;\r
}\r
\r
private function linetoArray($lines) {\r
- $lines=str_replace("\r",'',$lines);\r
- $lines=explode("\n",$lines);\r
- foreach($lines as $line) {\r
- if(!isset($line{3})) continue;\r
- list($Key,$Val)=explode(':',$line);\r
- $Data[trim($Key)]=trim($Val);\r
+ $lines = str_replace("\r", '', $lines);\r
+ $lines = explode("\n", $lines);\r
+ foreach ($lines as $line) {\r
+ if (!isset($line{3})) continue;\r
+ list($Key,$Val) = explode(':', $line);\r
+ $Data[trim($Key)] = trim($Val);\r
}\r
return $Data;\r
}\r
\r
- private function GetPictureFilePath($Context)\r
- {\r
- $MsnObj=base64_decode($Context);\r
- if(preg_match('/location="(.*?)"/i',$MsnObj,$Match))\r
- $location=$Match[1];\r
+ private function GetPictureFilePath($Context) {\r
+ $MsnObj = base64_decode($Context);\r
+ if (preg_match('/location="(.*?)"/i', $MsnObj, $Match))\r
+ $location = $Match[1];\r
$this->debug_message("*** p2p: PictureFile[$location] ::All".print_r($this->MsnObjArray,true)."\n");\r
- if($location&&(isset($this->MsnObjArray[$location])))\r
- return $this->MsnObjArray[$location];\r
+ if ($location && isset($this->MsnObjArray[$location]))\r
+ return $this->MsnObjArray[$location];\r
return false;\r
}\r
\r
- private function GetMsnObjDefine($Message)\r
- {\r
- $DefineString='';\r
- if(is_array($this->Emotions))\r
- foreach($this->Emotions as $Pattern => $FilePath)\r
- {\r
- if(strpos($Message,$Pattern)!==false)\r
- $DefineString.="$Pattern\t".$this->MsnObj($FilePath,2)."\t";\r
- }\r
+ private function GetMsnObjDefine($Message) {\r
+ $DefineString = '';\r
+ if (is_array($this->Emotions))\r
+ foreach ($this->Emotions as $Pattern => $FilePath) {\r
+ if (strpos($Message, $Pattern)!==false)\r
+ $DefineString .= "$Pattern\t".$this->MsnObj($FilePath, 2)."\t";\r
+ }\r
return $DefineString;\r
}\r
\r
/**\r
* Read and handle incoming command from NS\r
+ *\r
+ * @return void\r
*/\r
private function nsReceive() {\r
// Sign in again if not signed in or socket failed\r
}\r
\r
$data = $this->ns_readln();\r
- if($data === false) {\r
+ if ($data === false) {\r
// There was no data / an error when reading from the socket so reconnect\r
$this->callHandler('Reconnect');\r
$this->NSRetryWait($this->retry_wait);\r
$this->signon();\r
return;\r
} else {\r
- switch (substr($data,0,3))\r
- {\r
+ switch (substr($data, 0, 3)) {\r
case 'SBS':\r
// after 'USR {id} OK {user} {verify} 0' response, the server will send SBS and profile to us\r
// NS: <<< SBS 0 null\r
\r
case 'LST':\r
// NS: <<< LST {email} {alias} 11 0\r
- @list(/* LST */, $email, /* alias */, ) = @explode(' ', $data);\r
+ @list(/* LST */, $email, /* alias */,) = @explode(' ', $data);\r
@list($u_name, $u_domain) = @explode('@', $email);\r
if (!isset($this->aContactList[$u_domain][$u_name][1])) {\r
$this->aContactList[$u_domain][$u_name][1]['Allow'] = 'Allow';\r
- $this->debug_message("*** add to our contact list: $u_name@$u_domain");\r
+ $this->debug_message("*** Added to contact list: $u_name@$u_domain");\r
}\r
break;\r
\r
case 'ADL':\r
- // randomly, we get ADL command, someome add us to their contact list for MSNP15\r
+ // randomly, we get ADL command, someone add us to their contact list for MSNP15\r
// NS: <<< ADL 0 {size}\r
@list(/* ADL */, /* 0 */, $size,) = @explode(' ', $data);\r
- if (is_numeric($size) && $size > 0)\r
- {\r
+ if (is_numeric($size) && $size > 0) {\r
$data = $this->ns_readdata($size);\r
preg_match('#<ml><d n="([^"]+)"><c n="([^"]+)"(.*) t="(\d*)"(.*) /></d></ml>#', $data, $matches);\r
- if (is_array($matches) && count($matches) > 0)\r
- {\r
+ if (is_array($matches) && count($matches) > 0) {\r
$u_domain = $matches[1];\r
$u_name = $matches[2];\r
$network = $matches[4];\r
if (isset($this->aContactList[$u_domain][$u_name][$network]))\r
- $this->debug_message("*** someone (network: $network) add us to their list (but already in our list): $u_name@$u_domain");\r
+ $this->debug_message("*** Someone (network: $network) added us to their list (but already in our list): $u_name@$u_domain");\r
else {\r
$re_login = false;\r
$cnt = 0;\r
- foreach (array('Allow', 'Reverse') as $list)\r
- {\r
- if (!$this->addMemberToList($u_name.'@'.$u_domain, $network, $list))\r
- {\r
+ foreach (array('Allow', 'Reverse') as $list) {\r
+ if (!$this->addMemberToList($u_name.'@'.$u_domain, $network, $list)) {\r
if ($re_login) {\r
- $this->debug_message("*** can't add $u_name@$u_domain (network: $network) to $list");\r
+ $this->debug_message("*** Could not add $u_name@$u_domain (network: $network) to $list list");\r
continue;\r
}\r
$aTickets = $this->get_passport_ticket();\r
if (!$aTickets || !is_array($aTickets)) {\r
// failed to login? ignore it\r
- $this->debug_message("*** can't re-login, something wrong here");\r
- $this->debug_message("*** can't add $u_name@$u_domain (network: $network) to $list");\r
+ $this->debug_message("*** Could not re-login, something wrong here");\r
+ $this->debug_message("*** Could not add $u_name@$u_domain (network: $network) to $list list");\r
continue;\r
}\r
$re_login = true;\r
$this->ticket = $aTickets;\r
- $this->debug_message("**** get new ticket, try it again");\r
- if (!$this->addMemberToList($u_name.'@'.$u_domain, $network, $list))\r
- {\r
- $this->debug_message("*** can't add $u_name@$u_domain (network: $network) to $list");\r
+ $this->debug_message("**** Got new ticket, trying again");\r
+ if (!$this->addMemberToList($u_name.'@'.$u_domain, $network, $list)) {\r
+ $this->debug_message("*** Could not add $u_name@$u_domain (network: $network) to $list list");\r
continue;\r
}\r
}\r
$this->aContactList[$u_domain][$u_name][$network][$list] = false;\r
$cnt++;\r
}\r
- $this->debug_message("*** someone (network: $network) add us to their list: $u_name@$u_domain");\r
+ $this->debug_message("*** Someone (network: $network) added us to their list: $u_name@$u_domain");\r
}\r
$str = '<ml l="1"><d n="'.$u_domain.'"><c n="'.$u_name.'" l="3" t="'.$network.'" /></d></ml>';\r
$len = strlen($str);\r
+\r
+ $this->callHandler('AddedToList', array('screenname' => $u_name.'@'.$u_domain, 'network' => $network));\r
}\r
else\r
- $this->debug_message("*** someone add us to their list: $data");\r
- $this->AddUsToMemberList($u_name.'@'.$u_domain, $network);\r
+ $this->debug_message("*** Someone added us to their list: $data");\r
}\r
break;\r
\r
// randomly, we get RML command, someome remove us to their contact list for MSNP15\r
// NS: <<< RML 0 {size}\r
@list(/* RML */, /* 0 */, $size,) = @explode(' ', $data);\r
- if (is_numeric($size) && $size > 0)\r
- {\r
+ if (is_numeric($size) && $size > 0) {\r
$data = $this->ns_readdata($size);\r
preg_match('#<ml><d n="([^"]+)"><c n="([^"]+)"(.*) t="(\d*)"(.*) /></d></ml>#', $data, $matches);\r
- if (is_array($matches) && count($matches) > 0)\r
- {\r
+ if (is_array($matches) && count($matches) > 0) {\r
$u_domain = $matches[1];\r
$u_name = $matches[2];\r
$network = $matches[4];\r
- if (isset($this->aContactList[$u_domain][$u_name][$network]))\r
- {\r
+ if (isset($this->aContactList[$u_domain][$u_name][$network])) {\r
$aData = $this->aContactList[$u_domain][$u_name][$network];\r
+\r
foreach ($aData as $list => $id)\r
- $this->delMemberFromList($id, $u_name.'@'.$u_domain, $network, $list);\r
+ $this->delMemberFromList($id, $u_name.'@'.$u_domain, $network, $list);\r
+\r
unset($this->aContactList[$u_domain][$u_name][$network]);\r
- $this->debug_message("*** someone (network: $network) remove us from their list: $u_name@$u_domain");\r
+ $this->debug_message("*** Someone (network: $network) removed us from their list: $u_name@$u_domain");\r
}\r
else\r
- $this->debug_message("*** someone (network: $network) remove us from their list (but not in our list): $u_name@$u_domain");\r
- $this->RemoveUsFromMemberList($u_name.'@'.$u_domain, $network);\r
+ $this->debug_message("*** Someone (network: $network) removed us from their list (but not in our list): $u_name@$u_domain");\r
+\r
+ $this->callHandler('RemovedFromList', array('screenname' => $u_name.'@'.$u_domain, 'network' => $network));\r
}\r
else\r
- $this->debug_message("*** someone remove us from their list: $data");\r
+ $this->debug_message("*** Someone removed us from their list: $data");\r
}\r
break;\r
\r
continue;\r
}\r
if (strncasecmp($line, 'Content-Type:', 13) == 0) {\r
- if (strpos($line, 'text/x-msmsgsinitialmdatanotification') === false &&\r
- strpos($line, 'text/x-msmsgsoimnotification') === false) {\r
+ if (strpos($line, 'text/x-msmsgsinitialmdatanotification') === false && strpos($line, 'text/x-msmsgsoimnotification') === false) {\r
// we just need text/x-msmsgsinitialmdatanotification\r
// or text/x-msmsgsoimnotification\r
$ignore = true;\r
}\r
}\r
if ($ignore) {\r
- $this->debug_message("*** ingnore MSG for: $line");\r
+ $this->debug_message("*** Ignoring MSG for: $line");\r
break;\r
}\r
if ($maildata == '') {\r
- $this->debug_message("*** ingnore MSG not for OIM");\r
+ $this->debug_message("*** Ignoring MSG not for OIM");\r
break;\r
}\r
$re_login = false;\r
if (strcasecmp($maildata, 'too-large') == 0) {\r
- $this->debug_message("*** large mail-data, need to get the data via SOAP");\r
+ $this->debug_message("*** Large mail-data, need to get the data via SOAP");\r
$maildata = $this->getOIM_maildata();\r
if ($maildata === false) {\r
- $this->debug_message("*** can't get mail-data via SOAP");\r
+ $this->debug_message("*** Could not get mail-data via SOAP");\r
+\r
// maybe we need to re-login again\r
$aTickets = $this->get_passport_ticket();\r
if (!$aTickets || !is_array($aTickets)) {\r
// failed to login? ignore it\r
- $this->debug_message("*** can't re-login, something wrong here, ignore this OIM");\r
+ $this->debug_message("*** Could not re-login, something wrong here, ignoring this OIM");\r
break;\r
}\r
$re_login = true;\r
$this->ticket = $aTickets;\r
- $this->debug_message("*** get new ticket, try it again");\r
+ $this->debug_message("*** Got new ticket, trying again");\r
$maildata = $this->getOIM_maildata();\r
if ($maildata === false) {\r
- $this->debug_message("*** can't get mail-data via SOAP, and we already re-login again, so ignore this OIM");\r
+ $this->debug_message("*** Could not get mail-data via SOAP, and re-login already attempted, ignoring this OIM");\r
break;\r
}\r
}\r
$p = substr($p, $end);\r
}\r
if (count($aOIMs) == 0) {\r
- $this->debug_message("*** ingnore empty OIM");\r
+ $this->debug_message("*** Ignoring empty OIM");\r
break;\r
}\r
foreach ($aOIMs as $maildata) {\r
// N: sender alias\r
preg_match('#<T>(.*)</T>#', $maildata, $matches);\r
if (count($matches) == 0) {\r
- $this->debug_message("*** ingnore OIM maildata without <T>type</T>");\r
+ $this->debug_message("*** Ignoring OIM maildata without <T>type</T>");\r
continue;\r
}\r
$oim_type = $matches[1];\r
if ($oim_type = 13)\r
- $network = 32;\r
+ $network = 32;\r
else\r
- $network = 1;\r
+ $network = 1;\r
preg_match('#<E>(.*)</E>#', $maildata, $matches);\r
if (count($matches) == 0) {\r
- $this->debug_message("*** ingnore OIM maildata without <E>sender</E>");\r
+ $this->debug_message("*** Ignoring OIM maildata without <E>sender</E>");\r
continue;\r
}\r
$oim_sender = $matches[1];\r
preg_match('#<I>(.*)</I>#', $maildata, $matches);\r
if (count($matches) == 0) {\r
- $this->debug_message("*** ingnore OIM maildata without <I>msgid</I>");\r
+ $this->debug_message("*** Ignoring OIM maildata without <I>msgid</I>");\r
continue;\r
}\r
$oim_msgid = $matches[1];\r
$oim_size = (count($matches) == 0) ? 0 : $matches[1];\r
preg_match('#<RT>(.*)</RT>#', $maildata, $matches);\r
$oim_time = (count($matches) == 0) ? 0 : $matches[1];\r
- $this->debug_message("*** You've OIM sent by $oim_sender, Time: $oim_time, MSGID: $oim_msgid, size: $oim_size");\r
+ $this->debug_message("*** OIM received from $oim_sender, Time: $oim_time, MSGID: $oim_msgid, size: $oim_size");\r
$sMsg = $this->getOIM_message($oim_msgid);\r
if ($sMsg === false) {\r
- $this->debug_message("*** can't get OIM, msgid = $oim_msgid");\r
+ $this->debug_message("*** Could not get OIM, msgid = $oim_msgid");\r
if ($re_login) {\r
- $this->debug_message("*** can't get OIM via SOAP, and we already re-login again, so ignore this OIM");\r
+ $this->debug_message("*** Could not get OIM via SOAP, and re-login already attempted, ignoring this OIM");\r
continue;\r
}\r
$aTickets = $this->get_passport_ticket();\r
if (!$aTickets || !is_array($aTickets)) {\r
// failed to login? ignore it\r
- $this->debug_message("*** can't re-login, something wrong here, ignore this OIM");\r
+ $this->debug_message("*** Could not re-login, something wrong here, ignoring this OIM");\r
continue;\r
}\r
$re_login = true;\r
$this->debug_message("*** get new ticket, try it again");\r
$sMsg = $this->getOIM_message($oim_msgid);\r
if ($sMsg === false) {\r
- $this->debug_message("*** can't get OIM via SOAP, and we already re-login again, so ignore this OIM");\r
+ $this->debug_message("*** Could not get OIM via SOAP, and re-login already attempted, ignoring this OIM");\r
continue;\r
}\r
}\r
$this->debug_message("*** MSG (Offline) from $oim_sender (network: $network): $sMsg");\r
-\r
- //$this->ReceivedMessage($oim_sender,$sMsg,$network,true);\r
$this->callHandler('IMin', array('sender' => $oim_sender, 'message' => $sMsg, 'network' => $network, 'offline' => true));\r
}\r
}\r
// randomly, we get UBM, this is the message from other network, like Yahoo!\r
// NS: <<< UBM {email} $network $type {size}\r
@list(/* UBM */, $from_email, $network, $type, $size,) = @explode(' ', $data);\r
- if (is_numeric($size) && $size > 0)\r
- {\r
+ if (is_numeric($size) && $size > 0) {\r
$data = $this->ns_readdata($size);\r
$aLines = @explode("\n", $data);\r
$header = true;\r
$sMsg .= $str;\r
}\r
}\r
- if($ignore)\r
- {\r
- $this->debug_message("*** ingnore from $from_email: $line");\r
+ if ($ignore) {\r
+ $this->debug_message("*** Ignoring message from $from_email: $line");\r
break;\r
}\r
$this->debug_message("*** MSG from $from_email (network: $network): $sMsg");\r
- //$this->ReceivedMessage($from_email,$sMsg,$network,false);\r
$this->callHandler('IMin', array('sender' => $from_email, 'message' => $sMsg, 'network' => $network, 'offline' => false));\r
}\r
break;\r
@list(/* UBX */, /* email */, /* network */, $size,) = @explode(' ', $data);\r
// we don't need the notification data, so just ignore it\r
if (is_numeric($size) && $size > 0)\r
- $this->ns_readdata($size);\r
+ $this->ns_readdata($size);\r
break;\r
\r
case 'CHL':\r
$this->ns_writeln("QRY $this->id $this->prod_id 32");\r
$this->ns_writedata($fingerprint);\r
$this->ns_writeln("CHG $this->id NLN $this->clientid");\r
- if($this->PhotoStickerFile!==false)\r
+ if ($this->PhotoStickerFile !== false)\r
$this->ns_writeln("CHG $this->id NLN $this->clientid ".rawurlencode($this->MsnObj($this->PhotoStickerFile)));\r
break;\r
case 'CHG':\r
$this->NSLogout();\r
continue;\r
}\r
- if(count($this->MessageQueue))\r
- {\r
- foreach($this->MessageQueue as $User => $Message)\r
- {\r
- //$this->ChildProcess[$ChildPid]\r
- $this->debug_message("*** XFR SB $User");\r
- $pid=pcntl_fork();\r
- if($pid)\r
- {\r
- //Parrent Process\r
- $this->ChildProcess[$pid]=$User;\r
- break;\r
- }\r
- elseif($pid==-1)\r
- {\r
- $this->debug_message("*** Fork Error $User");\r
- break;\r
- }\r
- else\r
- {\r
- //Child Process\r
- $this->debug_message("*** Child Process Start for $User");\r
- unset($Message['XFRSent']);\r
- unset($Message['ReqTime']);\r
+\r
+ $this->debug_message("NS: <<< XFR SB");\r
+ $user = array_shift($this->waitingForXFR);\r
$bSBresult = $this->switchboard_control($ip, $port, $cki_code, $User, $Message);\r
- if ($bSBresult === false)\r
- {\r
- // error for switchboard\r
- $this->debug_message("!!! error for sending message to ".$User);\r
- }\r
- die;\r
- }\r
- }\r
- unset($this->MessageQueue[$User]);\r
- }\r
/*\r
$bSBresult = $this->switchboard_control($ip, $port, $cki_code, $aMSNUsers[$nCurrentUser], $sMessage);\r
if ($bSBresult === false) {\r
break;\r
\r
case 'RNG':\r
- if($this->PhotoStickerFile!==false)\r
+ if ($this->PhotoStickerFile !== false)\r
$this->ns_writeln("CHG $this->id NLN $this->clientid ".rawurlencode($this->MsnObj($this->PhotoStickerFile)));\r
else\r
$this->ns_writeln("CHG $this->id NLN $this->clientid");\r
$this->debug_message("NS: <<< RNG $data");\r
@list(/* RNG */, $sid, $server, /* auth_type */, $ticket, $email, $name, ) = @explode(' ', $data);\r
@list($sb_ip, $sb_port) = @explode(':', $server);\r
- if($this->IsIgnoreMail($email))\r
- {\r
- $this->debug_message("*** Ignore RNG from $email");\r
- break;\r
- }\r
$this->debug_message("*** RING from $email, $sb_ip:$sb_port");\r
- $this->addContact($email,1,$email, true);\r
- $pid=pcntl_fork();\r
- if($pid)\r
- {\r
- //Parrent Process\r
- $this->ChildProcess[$pid]='RNG';\r
- break;\r
- }\r
- elseif($pid==-1)\r
- {\r
- $this->debug_message("*** Fork Error $User");\r
- break;\r
- }\r
- else\r
- {\r
- //Child Process\r
- $this->debug_message("*** Ring Child Process Start for $User");\r
- $this->switchboard_ring($sb_ip, $sb_port, $sid, $ticket,$email);\r
- die;\r
- }\r
+ $this->addContact($email, 1, $email, true);\r
+ $this->connectToSBSession('Passive', $sb_ip, $sb_port, $email, array('sid' => $sid, 'ticket' => $ticket));\r
break;\r
case 'OUT':\r
// force logout from NS\r
* Read and handle incoming command/message from\r
* a switchboard session socket\r
*/\r
- private function sbReceive() {\r
+ private function sbReceive($socket) {\r
+ $intsocket = (int) $socket;\r
+ $session = &$this->switchBoardSessions[$intsocket];\r
+\r
+ if (feof($socket)) {\r
+ // Unset session lookup value\r
+ unset($this->switchBoardSessionLookup[$session['to']]);\r
+\r
+ // Unset session itself\r
+ unset($this->switchBoardSessions[$intsocket]);\r
+ return;\r
+ }\r
+\r
+ $id = &$session['id'];\r
+\r
+ $data = $this->sb_readln($socket);\r
+ $code = substr($data, 0, 3);\r
+ switch($code) {\r
+ case 'IRO':\r
+ // SB: <<< IRO {id} {rooster} {roostercount} {email} {alias} {clientid}\r
+ @list(/* IRO */, /* id */, $cur_num, $total, $email, $alias, $clientid) = @explode(' ', $data);\r
+ $this->debug_message("*** $email joined session");\r
+ $session['joined'] = true;\r
+ break;\r
+ case 'BYE':\r
+ $this->debug_message("*** Quit for BYE");\r
+ $this->endSBSession();\r
+ break;\r
+ case 'USR':\r
+ // SB: <<< USR {id} OK {user} {alias}\r
+ // we don't need the data, just ignore it\r
+ // request user to join this switchboard\r
+ // SB: >>> CAL {id} {user}\r
+ $this->sb_writeln($socket, $id, "CAL $this->id $user");\r
+ break;\r
+ case 'CAL':\r
+ // SB: <<< CAL {id} RINGING {?}\r
+ // we don't need this, just ignore, and wait for other response\r
+ $session['id']++;\r
+ break;\r
+ case 'JOI':\r
+ // SB: <<< JOI {user} {alias} {clientid?}\r
+ // someone join us\r
+ // we don't need the data, just ignore it\r
+ // no more user here\r
+ $session['joined'] = true;\r
+ break;\r
+ case 'MSG':\r
+ // SB: <<< MSG {email} {alias} {len}\r
+ @list(/* MSG */, $from_email, /* alias */, $len, ) = @explode(' ', $data);\r
+ $len = trim($len);\r
+ $data = $this->sb_readdata($socket, $len);\r
+ $aLines = @explode("\n", $data);\r
+ $header = true;\r
+ $ignore = false;\r
+ $is_p2p = false;\r
+ $sMsg = '';\r
+ foreach ($aLines as $line) {\r
+ $line = rtrim($line);\r
+ if ($header) {\r
+ if ($line === '') {\r
+ $header = false;\r
+ continue;\r
+ }\r
+ if (strncasecmp($line, 'TypingUser:', 11) == 0) {\r
+ // typing notification, just ignore\r
+ $ignore = true;\r
+ break;\r
+ }\r
+ if (strncasecmp($line, 'Chunk:', 6) == 0) {\r
+ // we don't handle any split message, just ignore\r
+ $ignore = true;\r
+ break;\r
+ }\r
+ if (strncasecmp($line, 'Content-Type: application/x-msnmsgrp2p', 38) == 0) {\r
+ // p2p message, ignore it, but we need to send acknowledgement for it...\r
+ $is_p2p = true;\r
+ $p = strstr($data, "\n\n");\r
+ $sMsg = '';\r
+ if ($p === false) {\r
+ $p = strstr($data, "\r\n\r\n");\r
+ if ($p !== false)\r
+ $sMsg = substr($p, 4);\r
+ }\r
+ else\r
+ $sMsg = substr($p, 2);\r
+ break;\r
+ }\r
+ if (strncasecmp($line, 'Content-Type: application/x-', 28) == 0) {\r
+ // ignore all application/x-... message\r
+ // for example:\r
+ // application/x-ms-ink => ink message\r
+ $ignore = true;\r
+ break;\r
+ }\r
+ if (strncasecmp($line, 'Content-Type: text/x-', 21) == 0) {\r
+ // ignore all text/x-... message\r
+ // for example:\r
+ // text/x-msnmsgr-datacast => nudge, voice clip....\r
+ // text/x-mms-animemoticon => customized animemotion word\r
+ $ignore = true;\r
+ break;\r
+ }\r
+ continue;\r
+ }\r
+ if ($sMsg !== '')\r
+ $sMsg .= "\n";\r
+ $sMsg .= $line;\r
+ }\r
+ if ($ignore) {\r
+ $this->debug_message("*** Ignoring SB data from $from_email: $line");\r
+ break;\r
+ }\r
+ if ($is_p2p) {\r
+ // we will ignore any p2p message after sending acknowledgement\r
+ $ignore = true;\r
+ $len = strlen($sMsg);\r
+ $this->debug_message("*** p2p message from $from_email, size $len");\r
+ // header = 48 bytes\r
+ // content >= 0 bytes\r
+ // footer = 4 bytes\r
+ // so it need to >= 52 bytes\r
+ /*if ($len < 52) {\r
+ $this->debug_message("*** p2p: size error, less than 52!");\r
+ break;\r
+ }*/\r
+ $aDwords = @unpack("V12dword", $sMsg);\r
+ if (!is_array($aDwords)) {\r
+ $this->debug_message("*** p2p: header unpack error!");\r
+ break;\r
+ }\r
+ $this->debug_message("*** p2p: dump received message:\n".$this->dump_binary($sMsg));\r
+ $hdr_SessionID = $aDwords['dword1'];\r
+ $hdr_Identifier = $aDwords['dword2'];\r
+ $hdr_DataOffsetLow = $aDwords['dword3'];\r
+ $hdr_DataOffsetHigh = $aDwords['dword4'];\r
+ $hdr_TotalDataSizeLow = $aDwords['dword5'];\r
+ $hdr_TotalDataSizeHigh = $aDwords['dword6'];\r
+ $hdr_MessageLength = $aDwords['dword7'];\r
+ $hdr_Flag = $aDwords['dword8'];\r
+ $hdr_AckID = $aDwords['dword9'];\r
+ $hdr_AckUID = $aDwords['dword10'];\r
+ $hdr_AckSizeLow = $aDwords['dword11'];\r
+ $hdr_AckSizeHigh = $aDwords['dword12'];\r
+ $this->debug_message("*** p2p: header SessionID = $hdr_SessionID");\r
+ $this->debug_message("*** p2p: header Inentifier = $hdr_Identifier");\r
+ $this->debug_message("*** p2p: header Data Offset Low = $hdr_DataOffsetLow");\r
+ $this->debug_message("*** p2p: header Data Offset High = $hdr_DataOffsetHigh");\r
+ $this->debug_message("*** p2p: header Total Data Size Low = $hdr_TotalDataSizeLow");\r
+ $this->debug_message("*** p2p: header Total Data Size High = $hdr_TotalDataSizeHigh");\r
+ $this->debug_message("*** p2p: header MessageLength = $hdr_MessageLength");\r
+ $this->debug_message("*** p2p: header Flag = $hdr_Flag");\r
+ $this->debug_message("*** p2p: header AckID = $hdr_AckID");\r
+ $this->debug_message("*** p2p: header AckUID = $hdr_AckUID");\r
+ $this->debug_message("*** p2p: header AckSize Low = $hdr_AckSizeLow");\r
+ $this->debug_message("*** p2p: header AckSize High = $hdr_AckSizeHigh");\r
+ if ($hdr_Flag == 2) {\r
+ //This is an ACK from SB ignore....\r
+ $this->debug_message("*** p2p: //This is an ACK from SB ignore....:\n");\r
+ break;\r
+ }\r
+ $MsgBody = $this->linetoArray(substr($sMsg, 48, -4));\r
+ $this->debug_message("*** p2p: body".print_r($MsgBody, true));\r
+ if (($MsgBody['EUF-GUID']=='{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}')&&($PictureFilePath=$this->GetPictureFilePath($MsgBody['Context']))) {\r
+ while (true) {\r
+ if ($this->sb_readln($socket) === false) break;\r
+ }\r
+ $this->debug_message("*** p2p: Inv hdr:\n".$this->dump_binary(substr($sMsg, 0, 48)));\r
+ preg_match('/{([0-9A-F\-]*)}/i', $MsgBody['Via'], $Matches);\r
+ $BranchGUID = $Matches[1];\r
+ //it's an invite to send a display picture.\r
+ $new_id = ~$hdr_Identifier;\r
+ $hdr = pack(\r
+ "LLLLLLLLLLLL", $hdr_SessionID,\r
+ $new_id,\r
+ 0, 0,\r
+ $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
+ 0,\r
+ 2,\r
+ $hdr_Identifier,\r
+ $hdr_AckID,\r
+ $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh\r
+ );\r
+ $footer = pack("L", 0);\r
+ $message = "MIME-Version: 1.0\r\nContent-Type: application/x-msnmsgrp2p\r\nP2P-Dest: $from_email\r\n\r\n$hdr$footer";\r
+ $len = strlen($message);\r
+ $this->sb_writeln($socket, $id, "MSG $this->id D $len");\r
+ $this->sb_writedata($socket, $message);\r
+ $this->debug_message("*** p2p: send display picture acknowledgement for $hdr_SessionID");\r
+ $this->debug_message("*** p2p: Invite ACK message:\n".$this->dump_binary($message));\r
+ $this->sb_readln($socket); // Read ACK;\r
+ $this->debug_message("*** p2p: Invite ACK Hdr:\n".$this->dump_binary($hdr));\r
+ $new_id -= 3;\r
+ //Send 200 OK message\r
+ $MessageContent="SessionID: ".$MsgBody['SessionID']."\r\n\r\n".pack("C", 0);\r
+ $MessagePayload=\r
+ "MSNSLP/1.0 200 OK\r\n".\r
+ "To: <msnmsgr:".$from_email.">\r\n".\r
+ "From: <msnmsgr:".$this->user.">\r\n".\r
+ "Via: ".$MsgBody['Via']."\r\n".\r
+ "CSeq: ".($MsgBody['CSeq']+1)."\r\n".\r
+ "Call-ID: ".$MsgBody['Call-ID']."\r\n".\r
+ "Max-Forwards: 0\r\n".\r
+ "Content-Type: application/x-msnmsgr-sessionreqbody\r\n".\r
+ "Content-Length: ".strlen($MessageContent)."\r\n\r\n".\r
+ $MessageContent;\r
+ $hdr_TotalDataSizeLow=strlen($MessagePayload);\r
+ $hdr_TotalDataSizeHigh=0;\r
+ $hdr = pack(\r
+ "LLLLLLLLLLLL", $hdr_SessionID,\r
+ $new_id,\r
+ 0, 0,\r
+ $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
+ strlen($MessagePayload),\r
+ 0,\r
+ rand(),\r
+ 0,\r
+ 0, 0\r
+ );\r
+\r
+ $message =\r
+ "MIME-Version: 1.0\r\n".\r
+ "Content-Type: application/x-msnmsgrp2p\r\n".\r
+ "P2P-Dest: $from_email\r\n\r\n$hdr$MessagePayload$footer";\r
+ $this->sb_writeln($socket, $id, "MSG $this->id D ".strlen($message));\r
+ $this->sb_writedata($socket, $message);\r
+ $this->debug_message("*** p2p: dump 200 ok message:\n".$this->dump_binary($message));\r
+ $this->sb_readln($socket); // Read ACK;\r
+\r
+ $this->debug_message("*** p2p: 200 ok:\n".$this->dump_binary($hdr));\r
+ // send data preparation message\r
+ // send 4 null bytes as data\r
+ $hdr_TotalDataSizeLow = 4;\r
+ $hdr_TotalDataSizeHigh = 0 ;\r
+ $new_id++;\r
+ $hdr = pack(\r
+ "LLLLLLLLLLLL",\r
+ $MsgBody['SessionID'],\r
+ $new_id,\r
+ 0, 0,\r
+ $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
+ $hdr_TotalDataSizeLow,\r
+ 0,\r
+ rand(),\r
+ 0,\r
+ 0, 0\r
+ );\r
+ $message =\r
+ "MIME-Version: 1.0\r\n".\r
+ "Content-Type: application/x-msnmsgrp2p\r\n".\r
+ "P2P-Dest: $from_email\r\n\r\n$hdr".pack('L', 0)."$footer";\r
+ $this->sb_writeln($socket, $id, "MSG $this->id D ".strlen($message));\r
+ $this->sb_writedata($socket, $message);\r
+ $this->debug_message("*** p2p: dump send Data preparation message:\n".$this->dump_binary($message));\r
+ $this->debug_message("*** p2p: Data Prepare Hdr:\n".$this->dump_binary($hdr));\r
+ $this->sb_readln($socket); // Read ACK;\r
+\r
+ // send Data Content..\r
+ $footer=pack('N',1);\r
+ $new_id++;\r
+ $FileSize=filesize($PictureFilePath);\r
+ if ($hTitle=fopen($PictureFilePath,'rb')) {\r
+ $Offset = 0;\r
+ //$new_id++;\r
+ while (!feof($hTitle)) {\r
+ $FileContent = fread($hTitle, 1024);\r
+ $FileContentSize = strlen($FileContent);\r
+ $hdr = pack(\r
+ "LLLLLLLLLLLL",\r
+ $MsgBody['SessionID'],\r
+ $new_id,\r
+ $Offset, 0,\r
+ $FileSize, 0,\r
+ $FileContentSize,\r
+ 0x20,\r
+ rand(),\r
+ 0,\r
+ 0, 0\r
+ );\r
+ $message =\r
+ "MIME-Version: 1.0\r\n".\r
+ "Content-Type: application/x-msnmsgrp2p\r\n".\r
+ "P2P-Dest: $from_email\r\n\r\n$hdr$FileContent$footer";\r
+ $this->sb_writeln($socket, $id, "MSG $this->id D ".strlen($message));\r
+ $this->sb_writedata($socket, $message);\r
+ $this->debug_message("*** p2p: dump send Data Content message $Offset / $FileSize :\n".$this->dump_binary($message));\r
+ $this->debug_message("*** p2p: Data Content Hdr:\n".$this->dump_binary($hdr));\r
+ //$this->SB_readln($socket);//Read ACK;\r
+ $Offset += $FileContentSize;\r
+ }\r
+ }\r
+ //Send Bye\r
+ /*\r
+ $MessageContent="\r\n".pack("C", 0);\r
+ $MessagePayload=\r
+ "BYE MSNMSGR:MSNSLP/1.0\r\n".\r
+ "To: <msnmsgr:$from_email>\r\n".\r
+ "From: <msnmsgr:".$this->user.">\r\n".\r
+ "Via: MSNSLP/1.0/TLP ;branch={".$BranchGUID."}\r\n".\r
+ "CSeq: 0\r\n".\r
+ "Call-ID: ".$MsgBody['Call-ID']."\r\n".\r
+ "Max-Forwards: 0\r\n".\r
+ "Content-Type: application/x-msnmsgr-sessionclosebody\r\n".\r
+ "Content-Length: ".strlen($MessageContent)."\r\n\r\n".$MessageContent;\r
+ $footer=pack('N',0);\r
+ $hdr_TotalDataSizeLow=strlen($MessagePayload);\r
+ $hdr_TotalDataSizeHigh=0;\r
+ $new_id++;\r
+ $hdr = pack("LLLLLLLLLLLL",\r
+ 0,\r
+ $new_id,\r
+ 0, 0,\r
+ $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
+ 0,\r
+ 0,\r
+ rand(),\r
+ 0,\r
+ 0,0);\r
+ $message =\r
+ "MIME-Version: 1.0\r\n".\r
+ "Content-Type: application/x-msnmsgrp2p\r\n".\r
+ "P2P-Dest: $from_email\r\n\r\n$hdr$MessagePayload$footer";\r
+ $this->sb_writeln($socket, $id, "MSG $id D ".strlen($message));\r
+ $id++;\r
+ $this->sb_writedata($socket, $message);\r
+ $this->debug_message("*** p2p: dump send BYE message :\n".$this->dump_binary($message));\r
+ */\r
+ break;\r
+ }\r
+ //TODO:\r
+ //if ($hdr_Flag == 2) {\r
+ // just send ACK...\r
+ // $this->sb_writeln($socket, $id, "ACK $id");\r
+ // break;\r
+ //}\r
+ if ($hdr_SessionID == 4) {\r
+ // ignore?\r
+ $this->debug_message("*** p2p: ignore flag 4");\r
+ break;\r
+ }\r
+ $finished = false;\r
+ if ($hdr_TotalDataSizeHigh == 0) {\r
+ // only 32 bites size\r
+ if (($hdr_MessageLength + $hdr_DataOffsetLow) == $hdr_TotalDataSizeLow)\r
+ $finished = true;\r
+ }\r
+ else {\r
+ // we won't accept any file transfer\r
+ // so I think we won't get any message size need to use 64 bits\r
+ // 64 bits size here, can't count directly...\r
+ $totalsize = base_convert(sprintf("%X%08X", $hdr_TotalDataSizeHigh, $hdr_TotalDataSizeLow), 16, 10);\r
+ $dataoffset = base_convert(sprintf("%X%08X", $hdr_DataOffsetHigh, $hdr_DataOffsetLow), 16, 10);\r
+ $messagelength = base_convert(sprintf("%X", $hdr_MessageLength), 16, 10);\r
+ $now_size = bcadd($dataoffset, $messagelength);\r
+ if (bccomp($now_size, $totalsize) >= 0)\r
+ $finished = true;\r
+ }\r
+ if (!$finished) {\r
+ // ignore not finished split packet\r
+ $this->debug_message("*** p2p: ignore split packet, not finished");\r
+ break;\r
+ }\r
+ //$new_id = ~$hdr_Identifier;\r
+ /*\r
+ $new_id++;\r
+ $hdr = pack("LLLLLLLLLLLL", $hdr_SessionID,\r
+ $new_id,\r
+ 0, 0,\r
+ $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
+ 0,\r
+ 2,\r
+ $hdr_Identifier,\r
+ $hdr_AckID,\r
+ $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh);\r
+ $footer = pack("L", 0);\r
+ $message = "MIME-Version: 1.0\r\nContent-Type: application/x-msnmsgrp2p\r\nP2P-Dest: $from_email\r\n\r\n$hdr$footer";\r
+ $len = strlen($message);\r
+ $this->sb_writeln($socket, $id, "MSG $id D $len");\r
+ $id++;\r
+ $this->sb_writedata($socket, $message);\r
+ $this->debug_message("*** p2p: send acknowledgement for $hdr_SessionID");\r
+ $this->debug_message("*** p2p: dump sent message:\n".$this->dump_binary($hdr.$footer));\r
+ */\r
+ break;\r
+ }\r
+ $this->debug_message("*** MSG from $from_email: $sMsg");\r
+ $this->callHandler('IMin', array('sender' => $from_email, 'message' => $sMsg, 'network' => $network, 'offline' => false));\r
+ break;\r
+ case '217':\r
+ $this->debug_message("*** User $user is offline. Trying OIM.");\r
+ $session['offline'] = true;\r
+ break;\r
+ default:\r
+ if (is_numeric($code)) {\r
+ $this->error = "Error code: $code, please check the detail information from: http://msnpiki.msnfanatic.com/index.php/Reference:Error_List";\r
+ $this->debug_message("*** SB: $this->error");\r
+ $sessionEnd=true;\r
+ }\r
+ break;\r
+ }\r
+ }\r
\r
+ /**\r
+ * Called when we want to end a switchboard session\r
+ * or a switchboard session ends\r
+ *\r
+ * @param resource $socket Socket\r
+ * @param boolean $killsession Whether to delete the session\r
+ * @return void\r
+ */\r
+ private function endSBSession($socket, $killsession = false) {\r
+ if (!self::socketcheck($socket)) {\r
+ $this->sb_writeln($socket, $fake = 0, 'OUT');\r
+ }\r
+ @fclose($socket);\r
+\r
+ // Unset session lookup value\r
+ $intsocket = (int) $socket;\r
+ unset($this->switchBoardSessionLookup[$this->switchBoardSessions[$intsocket]['to']]);\r
+\r
+ // Unset session itself\r
+ unset($this->switchBoardSessions[$intsocket]);\r
}\r
\r
/**\r
* @return void\r
*/\r
public function receive() {\r
- //First, get an array of sockets that have data that is ready to be read\r
+ // First, get an array of sockets that have data that is ready to be read\r
$ready = array();\r
$ready = $this->getSockets();\r
- $numrdy = stream_select($ready, $w = NULL, $x = NULL,NULL);\r
+ $numrdy = stream_select($ready, $w = NULL, $x = NULL, NULL);\r
\r
- //Now that we've waited for something, go through the $ready\r
- //array and read appropriately\r
+ // Now that we've waited for something, go through the $ready\r
+ // array and read appropriately\r
\r
- for($i = 0;$i<sizeof($ready);$i++) {\r
- if ($ready[$i] == $this->NSfp) {\r
+ foreach ($ready as $socket) {\r
+ if ($socket == $this->NSfp) {\r
$this->nsReceive();\r
} else {\r
$this->sbReceive($socket);\r
\r
/**\r
* Send a request for a switchboard session\r
- * @param String $to Target email for switchboard session\r
+ *\r
+ * @param string $to Target email for switchboard session\r
*/\r
private function reqSBSession($to) {\r
$this->debug_message("*** Request SB for $to");\r
$this->ns_writeln("XFR $this->id SB");\r
\r
// Add to the queue of those waiting for a switchboard session reponse\r
- $this->switchBoardSessions[$to] = array('socket' => NULL, 'id' => 1, 'lastActive' => NULL, 'joined' => false, 'XFRReqTime' => time());\r
+ $this->switchBoardSessions[$to] = array(\r
+ 'to' => $to,\r
+ 'socket' => NULL,\r
+ 'id' => 1,\r
+ 'joined' => false,\r
+ 'offline' => false,\r
+ 'XFRReqTime' => time()\r
+ );\r
$this->waitingForXFR[] = &$this->switchBoardSessions[$to];\r
}\r
\r
/**\r
* Following an XFR or RNG, connect to the switchboard session\r
*\r
- * @param string $mode Mode, either 'Active' (in the case of XFR) or 'Passive' (in the case or RNG)\r
+ * @param string $mode Mode, either 'Active' (in the case of XFR) or 'Passive' (in the case of RNG)\r
* @param string $ip IP of Switchboard\r
* @param integer $port Port of Switchboard\r
* @param string $to User on other end of Switchboard\r
* @return boolean true if successful\r
*/\r
private function connectToSBSession($mode, $ip, $port, $to, $param) {\r
- $this->debug_message("*** SB: try to connect to switchboard server $ip:$port");\r
+ $this->debug_message("*** SB: Trying to connect to switchboard server $ip:$port");\r
\r
- $this->switchBoardSessions[$to]['socket'] = @fsockopen($ip, $port, $errno, $errstr, 5);\r
- $socket = $this->switchBoardSessions[$to]['socket'];\r
- if(!$socket) {\r
+ $socket = @fsockopen($ip, $port, $errno, $errstr, $this->timeout);\r
+ if (!$socket) {\r
$this->debug_message("*** SB: Can't connect to $ip:$port, error => $errno, $errstr");\r
return false;\r
}\r
- $this->switchBoardSockets[(int) $socket] = $socket;\r
\r
- stream_set_timeout($socket, $this->SBStreamTimeout);\r
+ // Store the socket in the lookup array\r
+ $this->switchBoardSessionLookup[$to] = $socket;\r
+\r
+ // Store the socket in the sessions array\r
+ $intsocket = (int) $socket;\r
+ $this->switchBoardSessions[$to] = array(\r
+ 'to' => $to,\r
+ 'socket' => $socket,\r
+ 'id' => 1,\r
+ 'joined' => false,\r
+ 'offline' => false,\r
+ 'XFRReqTime' => time()\r
+ );\r
+\r
+ // Change the index of the session to the socket\r
+ $this->switchBoardSessions[$intsocket] = $this->switchBoardSessions[$to];\r
+ unset($this->switchBoardSessions[$to]);\r
\r
- $id = &$this->switchBoardSessions[$to]['id'];\r
+ $id = &$this->switchBoardSessions[$intsocket]['id'];\r
\r
- if($mode == 'Active') {\r
+ if ($mode == 'Active') {\r
$cki_code = $param['cki'];\r
\r
// SB: >>> USR {id} {user} {cki}\r
// SB: >>> ANS {id} {user} {ticket} {session_id}\r
$this->sb_writeln($socket, $id, "ANS $id $this->user $ticket $sid");\r
}\r
-\r
- $this->switchBoardSessions[$to]['lastActive'] = time();\r
}\r
\r
/**\r
* @return boolean true on success\r
*/\r
private function sendMessageViaSB($to, $message) {\r
- if(socketcheck($this->switchBoardSessions[$to]['socket'])) {\r
- $this->reqSBSession($to);\r
+ $socket = $this->switchBoardSessionLookup[$to];\r
+ if (self::socketcheck($socket)) {\r
return false;\r
}\r
\r
- if(!$this->switchBoardSessions[$to]['joined']) {\r
+ if (!$this->switchBoardSessions[$to]['joined']) {\r
// If our participant has not joined the session yet we can't message them!\r
return false;\r
}\r
\r
- $id = &$this->switchBoardSessions[$to]['id'];\r
- $socket = $this->switchBoardSessions[$to]['socket'];\r
+ $intsocket = (int) $socket;\r
+ $id = &$this->switchBoardSessions[$intsocket]['id'];\r
\r
$aMessage = $this->getMessage($Message);\r
//CheckEmotion...\r
$MsnObjDefine=$this->GetMsnObjDefine($aMessage);\r
- if($MsnObjDefine !== '')\r
- {\r
+ if ($MsnObjDefine !== '') {\r
$SendString="MIME-Version: 1.0\r\nContent-Type: text/x-mms-emoticon\r\n\r\n$MsnObjDefine";\r
$len = strlen($SendString);\r
// TODO handle failure during write to socket\r
\r
/**\r
* Send offline message\r
+ *\r
* @param string $to Intended recipient\r
* @param string $sMessage Message\r
* @param string $lockkey Lock key\r
+ * @return mixed true on success or error data\r
*/\r
private function sendOIM($to, $sMessage, $lockkey) {\r
$XML = '<?xml version="1.0" encoding="utf-8"?>\r
/**\r
* Send a message to a user on another network\r
*\r
- * @param $message Message\r
- * @param $to Intended recipient\r
- * @param $network Network\r
+ * @param string $to Intended recipient\r
+ * @param string $message Message\r
+ * @param integer $network Network\r
* @return void\r
*/\r
- private function sendOtherNetworkMessage($message, $to, $network) {\r
+ private function sendOtherNetworkMessage($to, $message, $network) {\r
$message = $this->getMessage($message, $network);\r
$len = strlen($message);\r
+ // TODO Introduce error checking for message sending\r
$this->ns_writeln("UUM $this->id $to $network 1 $len");\r
$this->ns_writedata($Message);\r
$this->debug_message("*** Sent to $to (network: $network):\n$Message");\r
+ return true;\r
}\r
\r
/**\r
* @param string $message Message\r
*/\r
public function sendMessage($to, $message) {\r
- if($message != '') {\r
+ if ($message != '') {\r
list($name, $host, $network) = explode('@', $to);\r
$network = $network == '' ? 1 : $network;\r
+ $recipient = $name.$host;\r
\r
- if ($network === 1 && $this->switchBoardSessions[$to]['socket'] !== NULL) {\r
- $recipient = $name . $host;\r
- $this->debug_message("*** Attempting to send message to $recipient using existing SB session");\r
-\r
- if ($this->sendMessageViaSB($message, $recipient)) {\r
- $this->debug_message('*** Message sent successfully');\r
- return true;\r
- } else {\r
- $this->debug_message('*** Message sending failed, requesting new SB session');\r
- $this->reqSBSession($to);\r
+ if ($network === 1) {\r
+ if (!isset($this->switchBoardSessionLookup[$recipient]) && (!isset($this->switchBoardSessions[$recipient])\r
+ || time() - $this->switchBoardSessions[$recipient]['XFRReqTime'] > $this->XFRReqTimeout)) {\r
+ $this->debug_message("*** No existing SB session or request has timed out");\r
+ $this->reqSBSession($recipient);\r
return false;\r
+ } else {\r
+ $socket = $this->switchBoardSessionLookup[$to];\r
+ if ($this->switchBoardSessions[(int) $socket]['offline']) {\r
+ $this->debug_message("*** Contact ($recipient) offline, sending OIM");\r
+ $this->endSBSession($socket);\r
+ return $this->sendMessage($recipient.'@Offline', $message);\r
+ } else {\r
+ $this->debug_message("*** Attempting to send message to $recipient using existing SB session");\r
+\r
+ if ($this->sendMessageViaSB($recipient, $message)) {\r
+ $this->debug_message('*** Message sent successfully');\r
+ return true;\r
+ } else {\r
+ $this->debug_message('*** Message sending failed, requesting new SB session');\r
+ $this->reqSBSession($to);\r
+ return false;\r
+ }\r
+ }\r
}\r
} elseif ($network == 'Offline') {\r
//Send OIM\r
$lockkey = '';\r
$re_login = false;\r
for ($i = 0; $i < $this->oim_try; $i++) {\r
- if (($oim_result = $this->sendOIM($to, $message, $lockkey)) === true) break;\r
+ if (($oim_result = $this->sendOIM($recipient, $message, $lockkey)) === true) break;\r
if (is_array($oim_result) && $oim_result['challenge'] !== false) {\r
// need challenge lockkey\r
$this->debug_message("*** Need challenge code for ".$oim_result['challenge']);\r
}\r
if ($oim_result === false || $oim_result['auth_policy'] !== false) {\r
if ($re_login) {\r
- $this->debug_message("*** Can't send OIM, but we already re-logged-in again, so ignore this OIM");\r
- return true;\r
+ $this->debug_message("*** Can't send OIM, but we already re-logged-in again, so returning false");\r
+ return false;\r
}\r
$this->debug_message("*** Can't send OIM, maybe ticket expired, trying to login again");\r
\r
// Maybe we need to re-login again\r
if (!$this->get_passport_ticket()) {\r
- $this->debug_message("*** Can't re-login, something went wrong here, ignore this OIM");\r
+ $this->debug_message("*** Can't re-login, something went wrong here, returning false");\r
return false;\r
}\r
$this->debug_message("*** Getting new ticket and trying again");\r
}\r
}\r
} else {\r
- $this->debug_message("*** Not MSN network or no existing SB session");\r
- $this->reqSBSession($to);\r
- return false;\r
+ // Other network\r
+ return $this->sendOtherNetworkMessage($recipient, $message, $network);\r
}\r
}\r
return true;\r
}\r
\r
- //FIXME Not sure if this is needed?\r
- private function endSBSession($socket) {\r
- if (feof($socket)) {\r
- // lost connection? error? try OIM later\r
- @fclose($socket);\r
- return false;\r
- }\r
- $fake = 0;\r
- $this->sb_writeln($socket, $fake, "OUT");\r
- @fclose($socket);\r
- return true;\r
- }\r
-\r
/**\r
* Sends a ping command\r
*\r
* @return array Array of Switchboard sockets\r
*/\r
public function getSBSockets() {\r
- return $this->switchBoardSockets;\r
+ return $this->switchBoardSessionLookup;\r
}\r
\r
/**\r
* @return array Array of socket resources\r
*/\r
public function getSockets() {\r
- return array_merge($this->NSfp, $this->switchBoardSockets);\r
+ return array_merge(array($this->NSfp), $this->switchBoardSessionLookup);\r
}\r
\r
/**\r
* Registers a user handler\r
*\r
* Handler List\r
- * IMIn, Pong, ConnectFailed, Reconnect\r
+ * IMIn, Pong, ConnectFailed, Reconnect,\r
+ * AddedToList, RemovedFromList\r
*\r
* @param string $event Event name\r
* @param string $handler User function to call\r