private $passport_policy = '';\r
private $alias;\r
private $psm;\r
- private $use_ping;\r
private $retry_wait;\r
- private $backup_file;\r
private $update_pending;\r
private $PhotoStickerFile=false;\r
private $Emotions=false;\r
- private $MessageQueue=array();\r
- private $ChildProcess=array();\r
- private $MAXChildProcess=3;\r
private $ReqSBXFRTimeout=60;\r
private $LastPing;\r
private $ping_wait=50;\r
private $SBIdleTimeout=10;\r
private $SBStreamTimeout=2;\r
- private $NSStreamTimeout=2;\r
private $MsnObjArray=array();\r
private $MsnObjMap=array();\r
- private $SwitchBoardProcess=false; // false=>Main Process,1 => sb_control_process,2 => sb_ring_process\r
- private $SwitchBoardSessionUser=false;\r
- private $SwitchBoardMessageQueue=array();\r
private $ABAuthHeader;\r
private $ABService;\r
private $Contacts;\r
private $IgnoreList;\r
\r
- public $server = 'messenger.hotmail.com';\r
- public $port = 1863;\r
+ private $server = 'messenger.hotmail.com';\r
+ private $port = 1863;\r
\r
\r
public $clientid = '';\r
// for YIM: 518 bytes\r
public $max_msn_message_len = 1664;\r
public $max_yahoo_message_len = 518;\r
- \r
+\r
// Begin added for StatusNet\r
- \r
+\r
private $aContactList = array();\r
private $aADL = array();\r
- private $re_login;\r
private $switchBoardSessions = array();\r
private $switchBoardSockets = array();\r
private $waitingForXFR = array();\r
- \r
+\r
/**\r
* Event Handler Functions\r
*/\r
private $myEventHandlers = array();\r
- \r
+\r
// End added for StatusNet\r
- \r
+\r
+ /**\r
+ * Constructor method\r
+ *\r
+ * @param array $Configs Array of configuration options\r
+ * 'user' - Username\r
+ * 'password' - Password\r
+ * 'alias' - Bot nickname\r
+ * 'psm' - Bot personal status message\r
+ * 'retry_wait' - Time to wait before trying to reconnect\r
+ * 'update_pending' - Whether to update pending contacts\r
+ * 'PhotoSticker' - Photo file to use (?)\r
+ * 'debug' - Enable/Disable debugging mode\r
+ * @param integer $timeout Connection timeout\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
$this->user = $Configs['user'];\r
$this->password = $Configs['password'];\r
$this->alias = isset($Configs['alias']) ? $Configs['alias'] : '';\r
$this->psm = isset($Configs['psm']) ? $Configs['psm'] : '';\r
- $this->use_ping = isset($Configs['use_ping']) ? $Configs['use_ping'] : false;\r
$this->retry_wait = isset($Configs['retry_wait']) ? $Configs['retry_wait'] : 30;\r
- $this->backup_file = isset($Configs['backup_file']) ? $Configs['backup_file'] : true;\r
$this->update_pending = isset($Configs['update_pending']) ? $Configs['update_pending'] : true;\r
$this->PhotoStickerFile=isset($Configs['PhotoSticker']) ? $Configs['PhotoSticker'] : false;\r
- if($this->Emotions = isset($Configs['Emotions']) ? $Configs['Emotions']:false)\r
- {\r
+\r
+ if($this->Emotions = isset($Configs['Emotions']) ? $Configs['Emotions']:false) {\r
foreach($this->Emotions as $EmotionFilePath)\r
$this->MsnObj($EmotionFilePath,$Type=2);\r
- } \r
+ }\r
$this->debug = isset($Configs['debug']) ? $Configs['debug'] : false;\r
$this->timeout = $timeout;\r
- \r
- // check support\r
- if (!function_exists('curl_init')) throw new Exception("We need curl module!\n");\r
- if (!function_exists('preg_match')) throw new Exception("We need pcre module!\n");\r
- if (!function_exists('mhash')) throw new Exception("We need mhash module!\n");\r
\r
- if (!function_exists('mcrypt_cbc')) throw new Exception("We need mcrypt module!\n");\r
- if (!function_exists('bcmod')) throw new Exception("We need bcmath module for $protocol!\n");\r
+ // Check support\r
+ if (!function_exists('curl_init')) throw new Exception("curl module not found!\n");\r
+ if (!function_exists('preg_match')) throw new Exception("pcre module not found!\n");\r
+ if (!function_exists('mhash')) throw new Exception("mhash module not found!\n");\r
+ if (!function_exists('mcrypt_cbc')) throw new Exception("mcrypt module not found!\n");\r
+ if (!function_exists('bcmod')) throw new Exception("bcmath module not found!\n");\r
\r
/*\r
http://msnpiki.msnfanatic.com/index.php/Client_ID\r
if($ReturnSoapVarObj) return new SoapVar($ArrayString,XSD_ANYXML,$TypeName,$TypeNameSpace);\r
return $ArrayString;\r
}\r
- \r
+\r
+ /**\r
+ * Get Passport ticket\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
$user = $this->user;\r
'oim_ticket' => html_entity_decode($matches[9]),\r
'space_ticket' => html_entity_decode($matches[11]),\r
'storage_ticket' => html_entity_decode($matches[13])\r
- ); \r
+ );\r
$this->ticket=$aTickets;\r
$this->debug_message(var_export($aTickets, true));\r
$ABAuthHeaderArray=array(\r
$this->ABAuthHeader=new SoapHeader("http://www.msn.com/webservices/AddressBook","ABAuthHeader", $this->Array2SoapVar($ABAuthHeaderArray));\r
return $aTickets;\r
}\r
- \r
+\r
private function UpdateContacts()\r
{\r
$ABApplicationHeaderArray=array(\r
'PartnerScenario'=>'ContactSave'\r
)\r
);\r
- \r
+\r
$ABApplicationHeader=new SoapHeader("http://www.msn.com/webservices/AddressBook",'ABApplicationHeader', $this->Array2SoapVar($ABApplicationHeaderArray));\r
$ABFindAllArray=array(\r
'ABFindAll'=>array(\r
}\r
return true;\r
}\r
- \r
+\r
private function addContact($email, $network, $display = '', $sendADL = false)\r
{\r
if ($network != 1) return true;\r
return true;\r
}\r
\r
- function delMemberFromList($memberID, $email, $network, $list) {\r
+ function delMemberFromList($memberID, $email, $network, $list)\r
+ {\r
if ($network != 1 && $network != 32) return true;\r
if ($memberID === false) return true;\r
$user = $email;\r
if ($http_code != 200) {\r
preg_match('#<faultcode>(.*)</faultcode><faultstring>(.*)</faultstring>#', $data, $matches);\r
if (count($matches) == 0) {\r
- $this->log_message("*** can't delete member (network: $network) $email ($memberID) to $list");\r
+ $this->debug_message("*** can't delete member (network: $network) $email ($memberID) to $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->log_message("*** can't delete member (network: $network) $email ($memberID) to $list, error code: $faultcode, $faultstring");\r
+ $this->debug_message("*** can't delete member (network: $network) $email ($memberID) to $list, error code: $faultcode, $faultstring");\r
return false;\r
}\r
- $this->log_message("*** delete member (network: $network) $email ($memberID) from $list, not exist");\r
+ $this->debug_message("*** delete member (network: $network) $email ($memberID) from $list, not exist");\r
return true;\r
}\r
- $this->log_message("*** delete member (network: $network) $email ($memberID) from $list");\r
+ $this->debug_message("*** delete member (network: $network) $email ($memberID) from $list");\r
return true;\r
}\r
\r
- function addMemberToList($email, $network, $list) {\r
+ function addMemberToList($email, $network, $list)\r
+ {\r
if ($network != 1 && $network != 32) return true;\r
$ticket = htmlspecialchars($this->ticket['contact_ticket']);\r
$user = $email;\r
if ($http_code != 200) {\r
preg_match('#<faultcode>(.*)</faultcode><faultstring>(.*)</faultstring>#', $data, $matches);\r
if (count($matches) == 0) {\r
- $this->log_message("*** can't add member (network: $network) $email to $list");\r
+ $this->debug_message("*** can't add member (network: $network) $email to $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->log_message("*** can't add member (network: $network) $email to $list, error code: $faultcode, $faultstring");\r
+ $this->debug_message("*** can't add member (network: $network) $email to $list, error code: $faultcode, $faultstring");\r
return false;\r
}\r
- $this->log_message("*** add member (network: $network) $email to $list, already exist!");\r
+ $this->debug_message("*** add member (network: $network) $email to $list, already exist!");\r
return true;\r
}\r
- $this->log_message("*** add member (network: $network) $email to $list");\r
+ $this->debug_message("*** add member (network: $network) $email to $list");\r
return true;\r
}\r
\r
- function getMembershipList($returnData=false) {\r
+ function getMembershipList($returnData=false)\r
+ {\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
@list($u_name, $u_domain) = @explode('@', $email);\r
if ($u_domain == NULL) continue;\r
$aContactList[$u_domain][$u_name][$network][$sMemberRole] = $id;\r
- $this->log_message("*** add new contact (network: $network, status: $sMemberRole): $u_name@$u_domain ($id)");\r
+ $this->debug_message("*** add new contact (network: $network, status: $sMemberRole): $u_name@$u_domain ($id)");\r
}\r
}\r
}\r
\r
/**\r
* Connect to the NS server\r
- * @param $user Username\r
- * @param $password Password\r
- * @param $redirect_server Redirect server\r
- * @param $redirect_port Redirect port\r
+ * @param String $user Username\r
+ * @param String $password Password\r
+ * @param String $redirect_server Redirect server\r
+ * @param Integer $redirect_port Redirect port\r
+ * @return Boolean Returns true if successful\r
*/\r
private function connect($user, $password, $redirect_server = '', $redirect_port = 1863) {\r
$this->id = 1;\r
}\r
}\r
\r
- stream_set_timeout($this->NSfp, $this->NSStreamTimeout);\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 (!feof($this->NSfp))\r
+ while (!self::socketcheck($this->NSfp))\r
{\r
$data = $this->ns_readln();\r
// no data?\r
if ($data === false) {\r
- if ($this->timeout > 0) {\r
- $now_tm = time();\r
- $used_time = ($now_tm >= $start_tm) ? $now_tm - $start_tm : $now_tm;\r
- if ($used_time > $this->timeout) {\r
- // logout now\r
- // NS: >>> OUT\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
- continue;\r
+ // logout now\r
+ // NS: >>> OUT\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
$code = substr($data, 0, 3);\r
$start_tm = time();\r
\r
// logout now\r
// NS: >>> OUT\r
$this->ns_writeln("OUT");\r
- fclose($this->NSfp);\r
+ @fclose($this->NSfp);\r
$this->error = 'Passport authenticated fail!';\r
$this->debug_message("*** $this->error");\r
return false;\r
if($Type!='NS') break;\r
@list($ip, $port) = @explode(':', $server);\r
// this connection will close after XFR\r
- fclose($this->NSfp);\r
+ @fclose($this->NSfp);\r
\r
$this->NSfp = @fsockopen($ip, $port, $errno, $errstr, 5);\r
if (!$this->NSfp) {\r
return false;\r
}\r
\r
- stream_set_timeout($this->NSfp, $this->NSStreamTimeout);\r
+ stream_set_timeout($this->NSfp, $this->timeout);\r
// MSNP9\r
// NS: >> VER {id} MSNP9 CVR0\r
// MSNP15\r
// logout now\r
// NS: >>> OUT\r
$this->ns_writeln("OUT");\r
- fclose($this->NSfp);\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
/**\r
* Sign onto the NS server and retrieve the address book\r
+ *\r
+ * @return void\r
*/\r
public function signon() {\r
- $this->log_message("*** try to connect to MSN network");\r
- \r
+ $this->debug_message("*** try to connect to MSN network");\r
+\r
while(true) {\r
- while(!$this->connect($this->user, $this->password))\r
- {\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
continue;\r
}\r
$this->LastPing=time();\r
- $this->log_message("*** connected, wait for command");\r
$start_tm = time();\r
$ping_tm = time();\r
if(($this->aContactList = $this->getMembershipList()) === false) {\r
- $this->signonFailure('!!! Get Membership list failed');\r
+ $this->signonFailure('!!! Get membership list failed');\r
continue;\r
}\r
if ($this->update_pending) {\r
$len = strlen($str);\r
$this->ns_writeln("UUX $this->id $len");\r
$this->ns_writedata($str);\r
- break;\r
+ if(!socketcheck($this->NSfp)) {\r
+ $this->debug_message("*** connected, wait for command");\r
+ break;\r
+ } else {\r
+ $this->NSRetryWait($this->retry_wait);\r
+ }\r
}\r
}\r
- \r
+\r
/**\r
* Called if there is an error during signon\r
- * \r
- * @param $message Error message to log\r
+ *\r
+ * @param string $message Error message to log\r
*/\r
private function signonFailure($message) {\r
- $this->log_message($message);\r
- $this->callHandler('ConnectFailed', NULL);\r
+ $this->debug_message($message);\r
+ $this->callHandler('ConnectFailed');\r
$this->NSRetryWait($this->retry_wait);\r
}\r
- \r
+\r
function derive_key($key, $magic) {\r
$hash1 = mhash(MHASH_SHA1, $magic, $key);\r
$hash2 = mhash(MHASH_SHA1, $hash1.$magic, $key);\r
$header_array = array(\r
'SOAPAction: '.$this->oim_read_soap,\r
'Content-Type: text/xml; charset=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_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
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\r
- curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);\r
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);\r
- if ($this->debug) curl_setopt($curl, CURLOPT_HEADER, 1);\r
- curl_setopt($curl, CURLOPT_POST, 1);\r
- curl_setopt($curl, CURLOPT_POSTFIELDS, $XML);\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
-\r
- if ($http_code != 200) {\r
- $this->debug_message("*** Can't get OIM: $msgid, http code = $http_code");\r
- return false;\r
- }\r
-\r
- // why can't use preg_match('#<GetMessageResult>(.*)</GetMessageResult>#', $data, $matches)?\r
- // multi-lines?\r
- $start = strpos($data, '<GetMessageResult>');\r
- $end = strpos($data, '</GetMessageResult>');\r
- if ($start === false || $end === false || $start > $end) {\r
- $this->debug_message("*** Can't get OIM: $msgid");\r
- return false;\r
- }\r
- $lines = substr($data, $start + 18, $end - $start);\r
- $aLines = @explode("\n", $lines);\r
- $header = true;\r
- $ignore = false;\r
- $sOIM = '';\r
- foreach ($aLines as $line) {\r
- $line = rtrim($line);\r
- if ($header) {\r
- if ($line === '') {\r
- $header = false;\r
- continue;\r
- }\r
- continue;\r
- }\r
- // stop at empty lines\r
- if ($line === '') break;\r
- $sOIM .= $line;\r
- }\r
- $sMsg = base64_decode($sOIM);\r
- $this->debug_message("*** we get OIM ($msgid): $sMsg");\r
-\r
- // delete OIM\r
- $XML = '<?xml version="1.0" encoding="utf-8"?>\r
-<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"\r
- xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">\r
-<soap:Header>\r
- <PassportCookie xmlns="http://www.hotmail.msn.com/ws/2004/09/oim/rsi">\r
- <t>'.$t.'</t>\r
- <p>'.$p.'</p>\r
- </PassportCookie>\r
-</soap:Header>\r
-<soap:Body>\r
- <DeleteMessages xmlns="http://www.hotmail.msn.com/ws/2004/09/oim/rsi">\r
- <messageIds>\r
- <messageId>'.$msgid.'</messageId>\r
- </messageIds>\r
- </DeleteMessages>\r
-</soap:Body>\r
-</soap:Envelope>';\r
-\r
- $header_array = array(\r
- 'SOAPAction: '.$this->oim_del_soap,\r
- 'Content-Type: text/xml; charset=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
- $curl = curl_init();\r
- curl_setopt($curl, CURLOPT_URL, $this->oim_del_url);\r
- curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\r
- curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);\r
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);\r
- if ($this->debug) curl_setopt($curl, CURLOPT_HEADER, 1);\r
- curl_setopt($curl, CURLOPT_POST, 1);\r
- curl_setopt($curl, CURLOPT_POSTFIELDS, $XML);\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
-\r
- if ($http_code != 200)\r
- $this->debug_message("*** Can't delete OIM: $msgid, http code = $http_code");\r
- else\r
- $this->debug_message("*** OIM ($msgid) deleted");\r
- return $sMsg;\r
- }\r
- private function NSLogout() {\r
- if (is_resource($this->NSfp) && !feof($this->NSfp)) {\r
- // logout now\r
- // NS: >>> OUT\r
- $this->ns_writeln("OUT");\r
- fclose($this->NSfp);\r
- $this->NSfp = false;\r
- $this->log_message("*** logout now!");\r
- }\r
-\r
- }\r
- private function NSRetryWait($Wait) {\r
- $this->log_message("*** wait for $Wait seconds");\r
- for($i=0;$i<$Wait;$i++) {\r
- sleep(1);\r
- if($this->kill_me) return false;\r
- }\r
- return true;\r
- }\r
- public function ProcessSendMessageFileQueue() {\r
- $aFiles = glob(MSN_CLASS_SPOOL_DIR.DIRECTORY_SEPARATOR.'*.msn');\r
- if (!is_array($aFiles)) return true;\r
- clearstatcache();\r
- foreach ($aFiles as $filename) {\r
- $fp = fopen($filename, 'rt');\r
- if (!$fp) continue;\r
- $aTo = array();\r
- $sMessage = '';\r
- $buf = trim(fgets($fp));\r
- if (substr($buf, 0, 3) == 'TO:') {\r
- $aTo = @explode(',', str_replace(array("\r","\n","\t",' '),'',substr($buf, 3)));\r
- while (!feof($fp)) $sMessage.=rtrim(fgets($fp))."\n";\r
- }\r
- fclose($fp);\r
- if (!is_array($aTo) || count($aTo) == 0 || $sMessage == '')\r
- $this->log_message("!!! message format error? delete $filename");\r
- else\r
- {\r
- foreach($aTo as $To)\r
- {\r
- @list($user, $domain, $network) = @explode('@', $To);\r
- $MessageList[$network]["$user@$domain"]=$sMessage;\r
- }\r
- }\r
- if($this->backup_file)\r
- {\r
- $backup_dir = MSN_CLASS_SPOOL_DIR.'/backup';\r
- if (!file_exists($backup_dir)) @mkdir($backup_dir);\r
- $backup_name = $backup_dir.'/'.strftime('%Y%m%d%H%M%S').'_'.posix_getpid().'_'.basename($filename);\r
- if (@rename($filename, $backup_name))\r
- $this->log_message("*** move file to $backup_name");\r
- }\r
- else @unlink($filename);\r
- }\r
- foreach ($MessageList as $network => $Messages)\r
- {\r
- switch(trim($network))\r
- {\r
- case '':\r
- case 1: //MSN\r
- // okay, try to ask a switchboard (SB) for sending message\r
- // NS: >>> XFR {id} SB\r
- // $this->ns_writeln("XFR $this->id SB");\r
- foreach($Messages as $User => $Message)\r
- $this->MessageQueue[$User][]=$Message;\r
- break;\r
- case 'Offline': //MSN\r
- //Send OIM\r
- //FIXME: ä¿®æ£Send OIM\r
- foreach($Messages as $To => $Message)\r
- {\r
- $lockkey='';\r
- for ($i = 0; $i < $this->oim_try; $i++)\r
- {\r
- if(($oim_result = $this->sendOIM($To, $Message, $lockkey))===true) break;\r
- if (is_array($oim_result) && $oim_result['challenge'] !== false) {\r
- // need challenge lockkey\r
- $this->log_message("*** we need a new challenge code for ".$oim_result['challenge']);\r
- $lockkey = $this->getChallenge($oim_result['challenge']);\r
- continue;\r
- }\r
- if ($oim_result === false || $oim_result['auth_policy'] !== false)\r
- {\r
- if ($this->re_login)\r
- {\r
- $this->log_message("*** can't send OIM, but we already re-login again, so ignore this OIM");\r
- break;\r
- }\r
- $this->log_message("*** can't send OIM, maybe ticket expired, try to login again");\r
- // maybe we need to re-login again\r
- if(!$this->get_passport_ticket())\r
- {\r
- $this->log_message("*** can't re-login, something wrong here, ignore this OIM");\r
- break;\r
- }\r
- $this->log_message("**** get new ticket, try it again");\r
- continue;\r
- }\r
- }\r
- }\r
- break;\r
- default: //Other\r
- foreach($Messages as $To => $Message) {\r
- $Message=$this->getMessage($Message, $network);\r
- $len = strlen($Message);\r
- $this->ns_writeln("UUM $this->id $To $network 1 $len");\r
- $this->ns_writedata($Message);\r
- $this->log_message("*** sent to $To (network: $network):\n$Message");\r
- }\r
- }\r
- }\r
- if(isset($this->MessageQueue[$User])&&(!isset($this->MessageQueue[$User]['XFRSent'])))\r
- {\r
- $this->MessageQueue[$User]['XFRSent']=false;\r
- $this->MessageQueue[$User]['ReqTime']=false;\r
- }\r
- return true;\r
- }\r
- public function SignalFunction($signal)\r
- {\r
- switch($signal)\r
- {\r
- case SIGTRAP:\r
- case SIGTERM:\r
- case SIGHUP:\r
- $this->End();\r
- return;\r
- case SIGCHLD:\r
- $ChildPid=pcntl_wait($status,WUNTRACED);\r
- if($ChildPid>0)\r
- {\r
- $this->log_message("*** Child Process End for ".$this->ChildProcess[$ChildPid]);\r
- unset($this->ChildProcess[$ChildPid]);\r
- }\r
- return;\r
- }\r
- }\r
-\r
- public function Run()\r
- {\r
- $this->log_message("*** startup ***");\r
- if(!pcntl_signal(SIGCHLD,array($this,'SignalFunction'))) die("Signal SIGCHLD Error\n");\r
- if(!pcntl_signal(SIGTERM,array($this,'SignalFunction'))) die("Signal SIGTERM Error\n");\r
- if(!pcntl_signal(SIGTRAP,array($this,'SignalFunction'))) die("Signal SIGTRAP Error\n");\r
- $process_file = false;\r
- $sent = false;\r
- $aADL = array();\r
- $aContactList = array();\r
- while (true)\r
- {\r
- if($this->kill_me)\r
- {\r
- $this->log_message("*** Okay, kill me now!");\r
- return $this->NSLogout();\r
- }\r
- if (!is_resource($this->NSfp) || feof($this->NSfp))\r
- {\r
- $this->log_message("*** try to connect to MSN network");\r
- if (!$this->connect($this->user, $this->password))\r
- {\r
- $this->log_message("!!! Can't connect to server: $this->error");\r
- if(!$this->NSRetryWait($this->retry_wait)) continue;\r
- }\r
- $this->UpdateContacts();\r
- $this->LastPing=time();\r
- $this->log_message("*** connected, wait for command");\r
- $start_tm = time();\r
- $ping_tm = time();\r
- $aContactList = $this->getMembershipList();\r
- if ($this->update_pending) {\r
- if (is_array($aContactList)) {\r
- $pending = 'Pending';\r
- foreach ($aContactList as $u_domain => $aUserList) {\r
- foreach ($aUserList as $u_name => $aNetworks) {\r
- foreach ($aNetworks as $network => $aData) {\r
- if (isset($aData[$pending])) {\r
- // pending list\r
- $cnt = 0;\r
- foreach (array('Allow', 'Reverse') as $list) {\r
- if (isset($aData[$list]))\r
- $cnt++;\r
- else {\r
- if ($this->addMemberToList($u_name.'@'.$u_domain, $network, $list)) {\r
- $aContactList[$u_domain][$u_name][$network][$list] = false;\r
- $cnt++;\r
- }\r
- }\r
- }\r
- if ($cnt >= 2) {\r
- $id = $aData[$pending];\r
- // we can delete it from pending now\r
- if ($this->delMemberFromList($id, $u_name.'@'.$u_domain, $network, $pending))\r
- unset($aContactList[$u_domain][$u_name][$network][$pending]);\r
- }\r
- }\r
- else {\r
- // sync list\r
- foreach (array('Allow', 'Reverse') as $list) {\r
- if (!isset($aData[$list])) {\r
- if ($this->addMemberToList($u_name.'@'.$u_domain, $network, $list))\r
- $aContactList[$u_domain][$u_name][$network][$list] = false;\r
- }\r
- }\r
- }\r
- }\r
- }\r
- }\r
- }\r
- }\r
- $n = 0;\r
- $sList = '';\r
- $len = 0;\r
- if (is_array($aContactList)) {\r
- foreach ($aContactList as $u_domain => $aUserList) {\r
- $str = '<d n="'.$u_domain.'">';\r
- $len += strlen($str);\r
- if ($len > 7400) {\r
- $aADL[$n] = '<ml l="1">'.$sList.'</ml>';\r
- $n++;\r
- $sList = '';\r
- $len = strlen($str);\r
- }\r
- $sList .= $str;\r
- foreach ($aUserList as $u_name => $aNetworks) {\r
- foreach ($aNetworks as $network => $status) {\r
- $str = '<c n="'.$u_name.'" l="3" t="'.$network.'" />';\r
- $len += strlen($str);\r
- // max: 7500, but <ml l="1"></d></ml> is 19,\r
- // so we use 7475\r
- if ($len > 7475) {\r
- $sList .= '</d>';\r
- $aADL[$n] = '<ml l="1">'.$sList.'</ml>';\r
- $n++;\r
- $sList = '<d n="'.$u_domain.'">'.$str;\r
- $len = strlen($sList);\r
- }\r
- else\r
- $sList .= $str;\r
- }\r
- }\r
- $sList .= '</d>';\r
- }\r
- }\r
- $aADL[$n] = '<ml l="1">'.$sList.'</ml>';\r
- // NS: >>> BLP {id} BL\r
- $this->ns_writeln("BLP $this->id BL");\r
- foreach ($aADL as $str) {\r
- $len = strlen($str);\r
- // NS: >>> ADL {id} {size}\r
- $this->ns_writeln("ADL $this->id $len");\r
- $this->ns_writedata($str);\r
- }\r
- // NS: >>> PRP {id} MFN name\r
- if ($this->alias == '') $this->alias = $user;\r
- $aliasname = rawurlencode($this->alias);\r
- $this->ns_writeln("PRP $this->id MFN $aliasname");\r
- //è¨å®šå€‹äººå¤§é è²¼\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
- $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
- }\r
- $data = $this->ns_readln();\r
- if($data===false)\r
- {\r
- //If No NS Message Process SendMessageFileQueue\r
- if (time()-$this->LastPing > $this->ping_wait)\r
- {\r
- // NS: >>> PNG\r
- $this->ns_writeln("PNG");\r
- $this->LastPing = time();\r
- }\r
- if(count($this->ChildProcess)<$this->MAXChildProcess)\r
- {\r
- $Index=0;\r
- foreach($this->MessageQueue as $User => $Message)\r
- {\r
- if(!trim($User)) continue;\r
- if($Inxdex>=$this->MAXChildProcess-count($this->ChildProcess)) break;\r
- if((!$Message['XFRSent'])||($Message['XFRSent']&&(time()-$this->MessageQueue[$User]['ReqTime']>$this->ReqSBXFRTimeout)))\r
- {\r
- $this->MessageQueue[$User]['XFRSent']=true;\r
- $this->MessageQueue[$User]['ReqTime']=time();\r
- $this->log_message("*** Request SB for $User");\r
- $this->ns_writeln("XFR $this->id SB");\r
- $Index++;\r
- }\r
- }\r
- }\r
- if($this->ProcessSendMessageFileQueue()) continue;\r
- break;\r
- }\r
- switch (substr($data,0,3))\r
- {\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
- break;\r
-\r
- case 'RFS':\r
- // FIXME:\r
- // NS: <<< RFS ???\r
- // refresh ADL, so we re-send it again\r
- if (is_array($aADL)) {\r
- foreach ($aADL as $str) {\r
- $len = strlen($str);\r
- // NS: >>> ADL {id} {size}\r
- $this->ns_writeln("ADL $this->id $len");\r
- $this->ns_writedata($str);\r
- }\r
- }\r
- break;\r
-\r
- case 'LST':\r
- // NS: <<< LST {email} {alias} 11 0\r
- @list(/* LST */, $email, /* alias */, ) = @explode(' ', $data);\r
- @list($u_name, $u_domain) = @explode('@', $email);\r
- if (!isset($aContactList[$u_domain][$u_name][1])) {\r
- $aContactList[$u_domain][$u_name][1]['Allow'] = 'Allow';\r
- $this->log_message("*** add to our 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
- // NS: <<< ADL 0 {size}\r
- @list(/* ADL */, /* 0 */, $size,) = @explode(' ', $data);\r
- if (is_numeric($size) && $size > 0)\r
- {\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
- $u_domain = $matches[1];\r
- $u_name = $matches[2];\r
- $network = $matches[4];\r
- if (isset($aContactList[$u_domain][$u_name][$network]))\r
- $this->log_message("*** someone (network: $network) add us to their list (but already in our list): $u_name@$u_domain");\r
- else\r
- {\r
- $this->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
- if ($this->re_login) {\r
- $this->log_message("*** can't add $u_name@$u_domain (network: $network) to $list");\r
- continue;\r
- }\r
- $aTickets = $this->get_passport_ticket();\r
- if (!$aTickets || !is_array($aTickets)) {\r
- // failed to login? ignore it\r
- $this->log_message("*** can't re-login, something wrong here");\r
- $this->log_message("*** can't add $u_name@$u_domain (network: $network) to $list");\r
- continue;\r
- }\r
- $this->re_login = true;\r
- $this->ticket = $aTickets;\r
- $this->log_message("**** get new ticket, try it again");\r
- if (!$this->addMemberToList($u_name.'@'.$u_domain, $network, $list))\r
- {\r
- $this->log_message("*** can't add $u_name@$u_domain (network: $network) to $list");\r
- continue;\r
- }\r
- }\r
- $aContactList[$u_domain][$u_name][$network][$list] = false;\r
- $cnt++;\r
- }\r
- $this->log_message("*** someone (network: $network) add 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
- else\r
- $this->log_message("*** someone add us to their list: $data");\r
- $this->AddUsToMemberList($u_name.'@'.$u_domain, $network);\r
- }\r
- break;\r
-\r
- case 'RML':\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
- $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
- $u_domain = $matches[1];\r
- $u_name = $matches[2];\r
- $network = $matches[4];\r
- if (isset($aContactList[$u_domain][$u_name][$network]))\r
- {\r
- $aData = $aContactList[$u_domain][$u_name][$network];\r
- foreach ($aData as $list => $id)\r
- $this->delMemberFromList($id, $u_name.'@'.$u_domain, $network, $list);\r
- unset($aContactList[$u_domain][$u_name][$network]);\r
- $this->log_message("*** someone (network: $network) remove us from their list: $u_name@$u_domain");\r
- }\r
- else\r
- $this->log_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
- }\r
- else\r
- $this->log_message("*** someone remove us from their list: $data");\r
- }\r
- break;\r
-\r
- case 'MSG':\r
- // randomly, we get MSG notification from server\r
- // NS: <<< MSG Hotmail Hotmail {size}\r
- @list(/* MSG */, /* Hotmail */, /* Hotmail */, $size,) = @explode(' ', $data);\r
- if (is_numeric($size) && $size > 0) {\r
- $data = $this->ns_readdata($size);\r
- $aLines = @explode("\n", $data);\r
- $header = true;\r
- $ignore = false;\r
- $maildata = '';\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, 'Content-Type:', 13) == 0) {\r
- if (strpos($line, 'text/x-msmsgsinitialmdatanotification') === false &&\r
- strpos($line, 'text/x-msmsgsoimnotification') === false) {\r
- // we just need text/x-msmsgsinitialmdatanotification\r
- // or text/x-msmsgsoimnotification\r
- $ignore = true;\r
- break;\r
- }\r
- }\r
- continue;\r
- }\r
- if (strncasecmp($line, 'Mail-Data:', 10) == 0) {\r
- $maildata = trim(substr($line, 10));\r
- break;\r
- }\r
- }\r
- if ($ignore) {\r
- $this->log_message("*** ingnore MSG for: $line");\r
- break;\r
- }\r
- if ($maildata == '') {\r
- $this->log_message("*** ingnore MSG not for OIM");\r
- break;\r
- }\r
- $this->re_login = false;\r
- if (strcasecmp($maildata, 'too-large') == 0) {\r
- $this->log_message("*** large mail-data, need to get the data via SOAP");\r
- $maildata = $this->getOIM_maildata();\r
- if ($maildata === false) {\r
- $this->log_message("*** can't get mail-data via SOAP");\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->log_message("*** can't re-login, something wrong here, ignore this OIM");\r
- break;\r
- }\r
- $this->re_login = true;\r
- $this->ticket = $aTickets;\r
- $this->log_message("**** get new ticket, try it again");\r
- $maildata = $this->getOIM_maildata();\r
- if ($maildata === false) {\r
- $this->log_message("*** can't get mail-data via SOAP, and we already re-login again, so ignore this OIM");\r
- break;\r
- }\r
- }\r
- }\r
- // could be a lots of <M>...</M>, so we can't use preg_match here\r
- $p = $maildata;\r
- $aOIMs = array();\r
- while (1) {\r
- $start = strpos($p, '<M>');\r
- $end = strpos($p, '</M>');\r
- if ($start === false || $end === false || $start > $end) break;\r
- $end += 4;\r
- $sOIM = substr($p, $start, $end - $start);\r
- $aOIMs[] = $sOIM;\r
- $p = substr($p, $end);\r
- }\r
- if (count($aOIMs) == 0) {\r
- $this->log_message("*** ingnore empty OIM");\r
- break;\r
- }\r
- foreach ($aOIMs as $maildata) {\r
- // T: 11 for MSN, 13 for Yahoo\r
- // S: 6 for MSN, 7 for Yahoo\r
- // RT: the datetime received by server\r
- // RS: already read or not\r
- // SZ: size of message\r
- // E: sender\r
- // I: msgid\r
- // F: always 00000000-0000-0000-0000-000000000009\r
- // N: sender alias\r
- preg_match('#<T>(.*)</T>#', $maildata, $matches);\r
- if (count($matches) == 0) {\r
- $this->log_message("*** ingnore OIM maildata without <T>type</T>");\r
- continue;\r
- }\r
- $oim_type = $matches[1];\r
- if ($oim_type = 13)\r
- $network = 32;\r
- else\r
- $network = 1;\r
- preg_match('#<E>(.*)</E>#', $maildata, $matches);\r
- if (count($matches) == 0) {\r
- $this->log_message("*** ingnore 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->log_message("*** ingnore OIM maildata without <I>msgid</I>");\r
- continue;\r
- }\r
- $oim_msgid = $matches[1];\r
- preg_match('#<SZ>(.*)</SZ>#', $maildata, $matches);\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->log_message("*** You've OIM sent by $oim_sender, Time: $oim_time, MSGID: $oim_msgid, size: $oim_size");\r
- $sMsg = $this->getOIM_message($oim_msgid);\r
- if ($sMsg === false) {\r
- $this->log_message("*** can't get OIM, msgid = $oim_msgid");\r
- if ($this->re_login) {\r
- $this->log_message("*** can't get OIM via SOAP, and we already re-login again, so ignore 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->log_message("*** can't re-login, something wrong here, ignore this OIM");\r
- continue;\r
- }\r
- $this->re_login = true;\r
- $this->ticket = $aTickets;\r
- $this->log_message("**** get new ticket, try it again");\r
- $sMsg = $this->getOIM_message($oim_msgid);\r
- if ($sMsg === false) {\r
- $this->log_message("*** can't get OIM via SOAP, and we already re-login again, so ignore this OIM");\r
- continue;\r
- }\r
- }\r
- $this->log_message("*** MSG (Offline) from $oim_sender (network: $network): $sMsg");\r
-\r
- $this->ReceivedMessage($oim_sender,$sMsg,$network,true);\r
- }\r
- }\r
- break;\r
-\r
- case 'UBM':\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
- $data = $this->ns_readdata($size);\r
- $aLines = @explode("\n", $data);\r
- $header = true;\r
- $ignore = 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
- $ignore = true;\r
- break;\r
- }\r
- continue;\r
- }\r
- $aSubLines = @explode("\r", $line);\r
- foreach ($aSubLines as $str) {\r
- if ($sMsg !== '')\r
- $sMsg .= "\n";\r
- $sMsg .= $str;\r
- }\r
- }\r
- if($ignore)\r
- {\r
- $this->log_message("*** ingnore from $from_email: $line");\r
- break;\r
- }\r
- $this->log_message("*** MSG from $from_email (network: $network): $sMsg");\r
- $this->ReceivedMessage($from_email,$sMsg,$network,false);\r
- }\r
- break;\r
-\r
- case 'UBX':\r
- // randomly, we get UBX notification from server\r
- // NS: <<< UBX email {network} {size}\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
- break;\r
-\r
- case 'CHL':\r
- // randomly, we'll get challenge from server\r
- // NS: <<< CHL 0 {code}\r
- @list(/* CHL */, /* 0 */, $chl_code,) = @explode(' ', $data);\r
- $fingerprint = $this->getChallenge($chl_code);\r
- // NS: >>> QRY {id} {product_id} 32\r
- // NS: >>> fingerprint\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
- $this->ns_writeln("CHG $this->id NLN $this->clientid ".rawurlencode($this->MsnObj($this->PhotoStickerFile)));\r
- break;\r
- case 'CHG':\r
- // NS: <<< CHG {id} {status} {code}\r
- // ignore it\r
- // change our status to online first\r
- break;\r
-\r
- case 'XFR':\r
- // sometimes, NS will redirect to another NS\r
- // MSNP9\r
- // NS: <<< XFR {id} NS {server} 0 {server}\r
- // MSNP15\r
- // NS: <<< XFR {id} NS {server} U D\r
- // for normal switchboard XFR\r
- // NS: <<< XFR {id} SB {server} CKI {cki} U messenger.msn.com 0\r
- @list(/* XFR */, /* {id} */, $server_type, $server, /* CKI */, $cki_code, /* ... */) = @explode(' ', $data);\r
- @list($ip, $port) = @explode(':', $server);\r
- if ($server_type != 'SB') {\r
- // maybe exit?\r
- // this connection will close after XFR\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->log_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->log_message("*** Fork Error $User");\r
- break;\r
- }\r
- else\r
- {\r
- //Child Process\r
- $this->log_message("*** Child Process Start for $User");\r
- unset($Message['XFRSent']);\r
- unset($Message['ReqTime']);\r
- $bSBresult = $this->switchboard_control($ip, $port, $cki_code, $User, $Message);\r
- if ($bSBresult === false)\r
- {\r
- // error for switchboard\r
- $this->log_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
- // error for switchboard\r
- $this->log_message("!!! error for sending message to ".$aMSNUsers[$nCurrentUser]);\r
- $aOfflineUsers[] = $aMSNUsers[$nCurrentUser];\r
- }*/\r
- break;\r
- case 'QNG':\r
- // NS: <<< QNG {time}\r
- @list(/* QNG */, $this->ping_wait) = @explode(' ', $data);\r
- if ($this->ping_wait == 0) $this->ping_wait = 50;\r
- //if (is_int($use_ping) && $use_ping > 0) $ping_wait = $use_ping;\r
- //Mod by Ricky Set Online\r
- break;\r
+ 'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Messenger '.$this->buildver.')'\r
+ );\r
\r
- case 'RNG':\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
- // someone is trying to talk to us\r
- // NS: <<< RNG {session_id} {server} {auth_type} {ticket} {email} {alias} U {client} 0\r
- $this->log_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->log_message("*** Ignore RNG from $email");\r
- break;\r
- }\r
- $this->log_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->log_message("*** Fork Error $User");\r
- break;\r
- }\r
- else\r
- {\r
- //Child Process\r
- $this->log_message("*** Ring Child Process Start for $User");\r
- $this->switchboard_ring($sb_ip, $sb_port, $sid, $ticket,$email);\r
- die;\r
- }\r
- break;\r
- case 'OUT':\r
- // force logout from NS\r
- // NS: <<< OUT xxx\r
- fclose($this->NSfp);\r
- $this->log_message("*** LOGOUT from NS");\r
- break;\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
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\r
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);\r
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);\r
+ if ($this->debug) curl_setopt($curl, CURLOPT_HEADER, 1);\r
+ curl_setopt($curl, CURLOPT_POST, 1);\r
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $XML);\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
\r
- default:\r
- $code = substr($data,0,3);\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("*** NS: $this->error");\r
+ if ($http_code != 200) {\r
+ $this->debug_message("*** Can't get OIM: $msgid, http code = $http_code");\r
+ return false;\r
+ }\r
\r
- return $this->NsLogout();\r
- }\r
- break;\r
+ // why can't use preg_match('#<GetMessageResult>(.*)</GetMessageResult>#', $data, $matches)?\r
+ // multi-lines?\r
+ $start = strpos($data, '<GetMessageResult>');\r
+ $end = strpos($data, '</GetMessageResult>');\r
+ if ($start === false || $end === false || $start > $end) {\r
+ $this->debug_message("*** Can't get OIM: $msgid");\r
+ return false;\r
+ }\r
+ $lines = substr($data, $start + 18, $end - $start);\r
+ $aLines = @explode("\n", $lines);\r
+ $header = true;\r
+ $ignore = false;\r
+ $sOIM = '';\r
+ foreach ($aLines as $line) {\r
+ $line = rtrim($line);\r
+ if ($header) {\r
+ if ($line === '') {\r
+ $header = false;\r
+ continue;\r
+ }\r
+ continue;\r
}\r
+ // stop at empty lines\r
+ if ($line === '') break;\r
+ $sOIM .= $line;\r
+ }\r
+ $sMsg = base64_decode($sOIM);\r
+ $this->debug_message("*** we get OIM ($msgid): $sMsg");\r
+\r
+ // delete OIM\r
+ $XML = '<?xml version="1.0" encoding="utf-8"?>\r
+<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"\r
+ xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">\r
+<soap:Header>\r
+ <PassportCookie xmlns="http://www.hotmail.msn.com/ws/2004/09/oim/rsi">\r
+ <t>'.$t.'</t>\r
+ <p>'.$p.'</p>\r
+ </PassportCookie>\r
+</soap:Header>\r
+<soap:Body>\r
+ <DeleteMessages xmlns="http://www.hotmail.msn.com/ws/2004/09/oim/rsi">\r
+ <messageIds>\r
+ <messageId>'.$msgid.'</messageId>\r
+ </messageIds>\r
+ </DeleteMessages>\r
+</soap:Body>\r
+</soap:Envelope>';\r
+\r
+ $header_array = array(\r
+ 'SOAPAction: '.$this->oim_del_soap,\r
+ 'Content-Type: text/xml; charset=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
+ $curl = curl_init();\r
+ curl_setopt($curl, CURLOPT_URL, $this->oim_del_url);\r
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\r
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);\r
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);\r
+ if ($this->debug) curl_setopt($curl, CURLOPT_HEADER, 1);\r
+ curl_setopt($curl, CURLOPT_POST, 1);\r
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $XML);\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
+\r
+ if ($http_code != 200)\r
+ $this->debug_message("*** Can't delete OIM: $msgid, http code = $http_code");\r
+ else\r
+ $this->debug_message("*** OIM ($msgid) deleted");\r
+ return $sMsg;\r
+ }\r
+\r
+ private function NSLogout() {\r
+ if (is_resource($this->NSfp) && !feof($this->NSfp)) {\r
+ // logout now\r
+ // NS: >>> OUT\r
+ $this->ns_writeln("OUT");\r
+ fclose($this->NSfp);\r
+ $this->NSfp = false;\r
+ $this->debug_message("*** logout now!");\r
}\r
- return $this->NsLogout();\r
+\r
+ }\r
+\r
+ private function NSRetryWait($wait) {\r
+ $this->debug_message("*** wait for $Wait seconds");\r
+ sleep($wait);\r
}\r
\r
function getChallenge($code)\r
$data = $this->SB_readln();\r
if($this->kill_me)\r
{\r
- $this->log_message("*** SB Okay, kill me now!");\r
+ $this->debug_message("*** SB Okay, kill me now!");\r
break;\r
}\r
if($data === false)\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->log_message("*** $email join us");\r
+ $this->debug_message("*** $email join us");\r
$Joined=true;\r
break;\r
case 'BYE':\r
- $this->log_message("*** Quit for BYE");\r
+ $this->debug_message("*** Quit for BYE");\r
$SessionEnd=true;\r
break;\r
case 'USR':\r
}\r
if ($ignore)\r
{\r
- $this->log_message("*** ingnore from $from_email: $line");\r
+ $this->debug_message("*** ingnore 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->log_message("*** p2p message from $from_email, size $len");\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->log_message("*** p2p: size error, less than 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->log_message("*** p2p: header unpack error!");\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
$len = strlen($message);\r
$this->SB_writeln("MSG $this->id D $len");\r
$this->SB_writedata($message);\r
- $this->log_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: 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
$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
+\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
"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
+ "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
$hdr_TotalDataSizeLow=strlen($MessagePayload);\r
$hdr_TotalDataSizeHigh=0;\r
$new_id++;\r
- $hdr = pack("LLLLLLLLLLLL", \r
+ $hdr = pack("LLLLLLLLLLLL",\r
0,\r
$new_id,\r
0, 0,\r
$this->SB_writeln("MSG $id D $len");\r
$id++;\r
$this->SB_writedata($message);\r
- $this->log_message("*** p2p: send acknowledgement for $hdr_SessionID");\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->log_message("*** MSG from $from_email: $sMsg");\r
+ $this->debug_message("*** MSG from $from_email: $sMsg");\r
$this->ReceivedMessage($from_email,$sMsg,$network,false);\r
break;\r
case '217':\r
- $this->log_message("*** User $user is offline. Try OIM.");\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
return $buf;\r
}\r
\r
- // write log\r
- function log_message($str) {\r
- /*$fname = MSN_CLASS_LOG_DIR.DIRECTORY_SEPARATOR.'msn_'.strftime('%Y%m%d').'.log';\r
- $fp = fopen($fname, 'at');\r
- if ($fp) {\r
- fputs($fp, strftime('%m/%d/%y %H:%M:%S').' ['.posix_getpid().'] '.$str."\n");\r
- fclose($fp);\r
- }*/\r
- $this->debug_message($str);\r
- return;\r
- }\r
/**\r
*\r
* @param $FilePath 圖檔路徑\r
- * @param $Type 檔案類型 3=>大é è²¼,2表情圖案 \r
+ * @param $Type 檔案類型 3=>大é è²¼,2表情圖案\r
* @return array\r
*/\r
private function MsnObj($FilePath,$Type=3)\r
$this->debug_message("*** p2p: addMsnObj $FilePath::$MsnObj\n");\r
return $MsnObj;\r
}\r
- \r
+\r
private function linetoArray($lines) {\r
$lines=str_replace("\r",'',$lines);\r
$lines=explode("\n",$lines);\r
}\r
return $Data;\r
}\r
- \r
+\r
private function GetPictureFilePath($Context)\r
{\r
$MsnObj=base64_decode($Context);\r
return $this->MsnObjArray[$location];\r
return false;\r
}\r
- \r
+\r
private function GetMsnObjDefine($Message)\r
{\r
$DefineString='';\r
}\r
return $DefineString;\r
}\r
- \r
+\r
/**\r
* Read and handle incoming command from NS\r
*/\r
- public function nsReceive() {\r
+ private function nsReceive() {\r
// Sign in again if not signed in or socket failed\r
- if (!is_resource($this->NSfp) || feof($this->NSfp)) {\r
- $this->callHandler('Reconnect', NULL);\r
+ if (!is_resource($this->NSfp) || self::socketcheck($this->NSfp)) {\r
+ $this->callHandler('Reconnect');\r
+ $this->NSRetryWait($this->retry_wait);\r
$this->signon();\r
return;\r
}\r
- \r
+\r
$data = $this->ns_readln();\r
if($data === false) {\r
// There was no data / an error when reading from the socket so reconnect\r
- $this->callHandler('Reconnect', NULL);\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
// after 'USR {id} OK {user} {verify} 0' response, the server will send SBS and profile to us\r
// NS: <<< SBS 0 null\r
break;\r
- \r
+\r
case 'RFS':\r
// FIXME:\r
// NS: <<< RFS ???\r
}\r
}\r
break;\r
- \r
+\r
case 'LST':\r
// NS: <<< LST {email} {alias} 11 0\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->log_message("*** add to our contact list: $u_name@$u_domain");\r
+ $this->debug_message("*** add to our contact list: $u_name@$u_domain");\r
}\r
break;\r
- \r
+\r
case 'ADL':\r
// randomly, we get ADL command, someome add us to their contact list for MSNP15\r
// NS: <<< ADL 0 {size}\r
$u_name = $matches[2];\r
$network = $matches[4];\r
if (isset($this->aContactList[$u_domain][$u_name][$network]))\r
- $this->log_message("*** someone (network: $network) add us to their list (but already in our list): $u_name@$u_domain");\r
- else\r
- {\r
- $this->re_login = false;\r
+ $this->debug_message("*** someone (network: $network) add 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
- if ($this->re_login) {\r
- $this->log_message("*** can't add $u_name@$u_domain (network: $network) to $list");\r
+ if ($re_login) {\r
+ $this->debug_message("*** can't add $u_name@$u_domain (network: $network) to $list");\r
continue;\r
}\r
$aTickets = $this->get_passport_ticket();\r
if (!$aTickets || !is_array($aTickets)) {\r
// failed to login? ignore it\r
- $this->log_message("*** can't re-login, something wrong here");\r
- $this->log_message("*** can't add $u_name@$u_domain (network: $network) to $list");\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
continue;\r
}\r
- $this->re_login = true;\r
+ $re_login = true;\r
$this->ticket = $aTickets;\r
- $this->log_message("**** get new ticket, try it again");\r
+ $this->debug_message("**** get new ticket, try it again");\r
if (!$this->addMemberToList($u_name.'@'.$u_domain, $network, $list))\r
{\r
- $this->log_message("*** can't add $u_name@$u_domain (network: $network) to $list");\r
+ $this->debug_message("*** can't add $u_name@$u_domain (network: $network) to $list");\r
continue;\r
}\r
}\r
$this->aContactList[$u_domain][$u_name][$network][$list] = false;\r
$cnt++;\r
}\r
- $this->log_message("*** someone (network: $network) add us to their list: $u_name@$u_domain");\r
+ $this->debug_message("*** someone (network: $network) add 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
else\r
- $this->log_message("*** someone add us to their list: $data");\r
+ $this->debug_message("*** someone add us to their list: $data");\r
$this->AddUsToMemberList($u_name.'@'.$u_domain, $network);\r
}\r
break;\r
- \r
+\r
case 'RML':\r
// randomly, we get RML command, someome remove us to their contact list for MSNP15\r
// NS: <<< RML 0 {size}\r
foreach ($aData as $list => $id)\r
$this->delMemberFromList($id, $u_name.'@'.$u_domain, $network, $list);\r
unset($this->aContactList[$u_domain][$u_name][$network]);\r
- $this->log_message("*** someone (network: $network) remove us from their list: $u_name@$u_domain");\r
+ $this->debug_message("*** someone (network: $network) remove us from their list: $u_name@$u_domain");\r
}\r
else\r
- $this->log_message("*** someone (network: $network) remove us from their list (but not in our list): $u_name@$u_domain");\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
}\r
else\r
- $this->log_message("*** someone remove us from their list: $data");\r
+ $this->debug_message("*** someone remove us from their list: $data");\r
}\r
break;\r
- \r
+\r
case 'MSG':\r
// randomly, we get MSG notification from server\r
// NS: <<< MSG Hotmail Hotmail {size}\r
}\r
}\r
if ($ignore) {\r
- $this->log_message("*** ingnore MSG for: $line");\r
+ $this->debug_message("*** ingnore MSG for: $line");\r
break;\r
}\r
if ($maildata == '') {\r
- $this->log_message("*** ingnore MSG not for OIM");\r
+ $this->debug_message("*** ingnore MSG not for OIM");\r
break;\r
}\r
- $this->re_login = false;\r
+ $re_login = false;\r
if (strcasecmp($maildata, 'too-large') == 0) {\r
- $this->log_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->log_message("*** can't get mail-data via SOAP");\r
+ $this->debug_message("*** can't get mail-data via SOAP");\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->log_message("*** can't re-login, something wrong here, ignore this OIM");\r
+ $this->debug_message("*** can't re-login, something wrong here, ignore this OIM");\r
break;\r
}\r
- $this->re_login = true;\r
+ $re_login = true;\r
$this->ticket = $aTickets;\r
- $this->log_message("**** get new ticket, try it again");\r
+ $this->debug_message("*** get new ticket, try it again");\r
$maildata = $this->getOIM_maildata();\r
if ($maildata === false) {\r
- $this->log_message("*** can't get mail-data via SOAP, and we already re-login again, so ignore this OIM");\r
+ $this->debug_message("*** can't get mail-data via SOAP, and we already re-login again, so ignore this OIM");\r
break;\r
}\r
}\r
$p = substr($p, $end);\r
}\r
if (count($aOIMs) == 0) {\r
- $this->log_message("*** ingnore empty OIM");\r
+ $this->debug_message("*** ingnore 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->log_message("*** ingnore OIM maildata without <T>type</T>");\r
+ $this->debug_message("*** ingnore OIM maildata without <T>type</T>");\r
continue;\r
}\r
$oim_type = $matches[1];\r
$network = 1;\r
preg_match('#<E>(.*)</E>#', $maildata, $matches);\r
if (count($matches) == 0) {\r
- $this->log_message("*** ingnore OIM maildata without <E>sender</E>");\r
+ $this->debug_message("*** ingnore 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->log_message("*** ingnore OIM maildata without <I>msgid</I>");\r
+ $this->debug_message("*** ingnore 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->log_message("*** You've OIM sent by $oim_sender, Time: $oim_time, MSGID: $oim_msgid, size: $oim_size");\r
+ $this->debug_message("*** You've OIM sent by $oim_sender, Time: $oim_time, MSGID: $oim_msgid, size: $oim_size");\r
$sMsg = $this->getOIM_message($oim_msgid);\r
if ($sMsg === false) {\r
- $this->log_message("*** can't get OIM, msgid = $oim_msgid");\r
- if ($this->re_login) {\r
- $this->log_message("*** can't get OIM via SOAP, and we already re-login again, so ignore this OIM");\r
+ $this->debug_message("*** can't 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
continue;\r
}\r
$aTickets = $this->get_passport_ticket();\r
if (!$aTickets || !is_array($aTickets)) {\r
// failed to login? ignore it\r
- $this->log_message("*** can't re-login, something wrong here, ignore this OIM");\r
+ $this->debug_message("*** can't re-login, something wrong here, ignore this OIM");\r
continue;\r
}\r
- $this->re_login = true;\r
+ $re_login = true;\r
$this->ticket = $aTickets;\r
- $this->log_message("**** get new ticket, try it again");\r
+ $this->debug_message("*** get new ticket, try it again");\r
$sMsg = $this->getOIM_message($oim_msgid);\r
if ($sMsg === false) {\r
- $this->log_message("*** can't get OIM via SOAP, and we already re-login again, so ignore this OIM");\r
+ $this->debug_message("*** can't get OIM via SOAP, and we already re-login again, so ignore this OIM");\r
continue;\r
}\r
}\r
- $this->log_message("*** MSG (Offline) from $oim_sender (network: $network): $sMsg");\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
break;\r
- \r
+\r
case 'UBM':\r
// randomly, we get UBM, this is the message from other network, like Yahoo!\r
// NS: <<< UBM {email} $network $type {size}\r
}\r
if($ignore)\r
{\r
- $this->log_message("*** ingnore from $from_email: $line");\r
+ $this->debug_message("*** ingnore from $from_email: $line");\r
break;\r
}\r
- $this->log_message("*** MSG from $from_email (network: $network): $sMsg");\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
- \r
+\r
case 'UBX':\r
// randomly, we get UBX notification from server\r
// NS: <<< UBX email {network} {size}\r
if (is_numeric($size) && $size > 0)\r
$this->ns_readdata($size);\r
break;\r
- \r
+\r
case 'CHL':\r
// randomly, we'll get challenge from server\r
// NS: <<< CHL 0 {code}\r
// NS: >>> fingerprint\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
+ $this->ns_writeln("CHG $this->id NLN $this->clientid");\r
if($this->PhotoStickerFile!==false)\r
$this->ns_writeln("CHG $this->id NLN $this->clientid ".rawurlencode($this->MsnObj($this->PhotoStickerFile)));\r
break;\r
// ignore it\r
// change our status to online first\r
break;\r
- \r
+\r
case 'XFR':\r
// sometimes, NS will redirect to another NS\r
// MSNP9\r
foreach($this->MessageQueue as $User => $Message)\r
{\r
//$this->ChildProcess[$ChildPid]\r
- $this->log_message("*** XFR SB $User");\r
+ $this->debug_message("*** XFR SB $User");\r
$pid=pcntl_fork();\r
if($pid)\r
{\r
}\r
elseif($pid==-1)\r
{\r
- $this->log_message("*** Fork Error $User");\r
+ $this->debug_message("*** Fork Error $User");\r
break;\r
}\r
else\r
{\r
//Child Process\r
- $this->log_message("*** Child Process Start for $User");\r
+ $this->debug_message("*** Child Process Start for $User");\r
unset($Message['XFRSent']);\r
unset($Message['ReqTime']);\r
$bSBresult = $this->switchboard_control($ip, $port, $cki_code, $User, $Message);\r
if ($bSBresult === false)\r
{\r
// error for switchboard\r
- $this->log_message("!!! error for sending message to ".$User);\r
+ $this->debug_message("!!! error for sending message to ".$User);\r
}\r
die;\r
}\r
$bSBresult = $this->switchboard_control($ip, $port, $cki_code, $aMSNUsers[$nCurrentUser], $sMessage);\r
if ($bSBresult === false) {\r
// error for switchboard\r
- $this->log_message("!!! error for sending message to ".$aMSNUsers[$nCurrentUser]);\r
+ $this->debug_message("!!! error for sending message to ".$aMSNUsers[$nCurrentUser]);\r
$aOfflineUsers[] = $aMSNUsers[$nCurrentUser];\r
}*/\r
break;\r
case 'QNG':\r
// NS: <<< QNG {time}\r
@list(/* QNG */, $ping_wait) = @explode(' ', $data);\r
- //if ($this->ping_wait == 0) $this->ping_wait = 50;\r
- //if (is_int($use_ping) && $use_ping > 0) $ping_wait = $use_ping;\r
- //Mod by Ricky Set Online\r
- \r
$this->callHandler('Pong', $ping_wait);\r
break;\r
- \r
+\r
case 'RNG':\r
if($this->PhotoStickerFile!==false)\r
$this->ns_writeln("CHG $this->id NLN $this->clientid ".rawurlencode($this->MsnObj($this->PhotoStickerFile)));\r
$this->ns_writeln("CHG $this->id NLN $this->clientid");\r
// someone is trying to talk to us\r
// NS: <<< RNG {session_id} {server} {auth_type} {ticket} {email} {alias} U {client} 0\r
- $this->log_message("NS: <<< RNG $data");\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->log_message("*** Ignore RNG from $email");\r
+ $this->debug_message("*** Ignore RNG from $email");\r
break;\r
}\r
- $this->log_message("*** RING from $email, $sb_ip:$sb_port");\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
elseif($pid==-1)\r
{\r
- $this->log_message("*** Fork Error $User");\r
+ $this->debug_message("*** Fork Error $User");\r
break;\r
}\r
else\r
{\r
//Child Process\r
- $this->log_message("*** Ring Child Process Start for $User");\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
case 'OUT':\r
// force logout from NS\r
// NS: <<< OUT xxx\r
- $this->log_message("*** LOGOUT from NS");\r
+ $this->debug_message("*** LOGOUT from NS");\r
return $this->NsLogout();\r
- \r
+\r
default:\r
$code = substr($data,0,3);\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("*** NS: $this->error");\r
- \r
+\r
return $this->NsLogout();\r
}\r
break;\r
}\r
}\r
}\r
- \r
+\r
/**\r
* Read and handle incoming command/message from\r
* a switchboard session socket\r
*/\r
- public function sbReceive() {\r
- \r
+ private function sbReceive() {\r
+\r
+ }\r
+\r
+ /**\r
+ * Checks for new data and calls appropriate methods\r
+ *\r
+ * This method is usually called in an infinite loop to keep checking for new data\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
+ $ready = array();\r
+ $ready = $this->getSockets();\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
+\r
+ for($i = 0;$i<sizeof($ready);$i++) {\r
+ if ($ready[$i] == $this->NSfp) {\r
+ $this->nsReceive();\r
+ } else {\r
+ $this->sbReceive($socket);\r
+ }\r
+ }\r
}\r
\r
/**\r
* Send a request for a switchboard session\r
- * @param $to Target email for switchboard session\r
+ * @param String $to Target email for switchboard session\r
*/\r
private function reqSBSession($to) {\r
- $this->log_message("*** Request SB for $to");\r
+ $this->debug_message("*** Request SB for $to");\r
$this->ns_writeln("XFR $this->id SB");\r
- \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->waitingForXFR[] = &$this->switchBoardSessions[$to];\r
}\r
- \r
+\r
/**\r
* Following an XFR or RNG, connect to the switchboard session\r
- * @param $mode Mode, either 'Active' (in the case of XFR) or 'Passive' (in the case or RNG)\r
- * @param $ip IP of Switchboard\r
- * @param $port Port of Switchboard\r
- * @param $to User on other end of Switchboard\r
- * @param $param Array of parameters - 'cki', 'ticket', 'sid'\r
- * @return Whether successful\r
+ *\r
+ * @param string $mode Mode, either 'Active' (in the case of XFR) or 'Passive' (in the case or 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
+ * @param array $param Array of parameters - 'cki', 'ticket', 'sid'\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
- \r
+\r
$this->switchBoardSessions[$to]['socket'] = @fsockopen($ip, $port, $errno, $errstr, 5);\r
$socket = $this->switchBoardSessions[$to]['socket'];\r
if(!$socket) {\r
$this->debug_message("*** SB: Can't connect to $ip:$port, error => $errno, $errstr");\r
return false;\r
}\r
- $this->switchBoardSockets[$socket] = $socket;\r
- \r
+ $this->switchBoardSockets[(int) $socket] = $socket;\r
+\r
stream_set_timeout($socket, $this->SBStreamTimeout);\r
- \r
+\r
$id = &$this->switchBoardSessions[$to]['id'];\r
- \r
+\r
if($mode == 'Active') {\r
$cki_code = $param['cki'];\r
- \r
+\r
// SB: >>> USR {id} {user} {cki}\r
$this->sb_writeln($socket, $id, "USR $id $this->user $cki_code");\r
} else {\r
// Passive\r
$ticket = $param['ticket'];\r
$sid = $param['sid'];\r
- \r
+\r
// SB: >>> ANS {id} {user} {ticket} {session_id}\r
$this->sb_writeln($socket, $id, "ANS $id $this->user $ticket $sid");\r
}\r
- \r
+\r
$this->switchBoardSessions[$to]['lastActive'] = time();\r
}\r
- \r
+\r
/**\r
* Send a message via an existing SB session\r
- * @param $message Message\r
- * @param $to Recipient for message\r
- * @return Whether successful\r
+ *\r
+ * @param string $to Recipient for message\r
+ * @param string $message Message\r
+ * @return boolean true on success\r
*/\r
- private function sendMessageViaSB($message, $to) {\r
+ private function sendMessageViaSB($to, $message) {\r
if(socketcheck($this->switchBoardSessions[$to]['socket'])) {\r
$this->reqSBSession($to);\r
return false;\r
}\r
- \r
+\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
+\r
$id = &$this->switchBoardSessions[$to]['id'];\r
$socket = $this->switchBoardSessions[$to]['socket'];\r
- \r
+\r
$aMessage = $this->getMessage($Message);\r
//CheckEmotion...\r
$MsnObjDefine=$this->GetMsnObjDefine($aMessage);\r
// TODO handle failure during write to socket\r
$this->sb_writeln($socket, $id, "MSG $id N $len");\r
$this->sb_writedata($socket, $aMessage);\r
- \r
+\r
// Don't close the SB session, we might as well leave it open\r
- \r
+\r
return true;\r
}\r
- \r
+\r
/**\r
- * \r
- * @param $to\r
- * @param $sMessage\r
- * @param $lockkey\r
+ * Send offline message\r
+ * @param string $to Intended recipient\r
+ * @param string $sMessage Message\r
+ * @param string $lockkey Lock key\r
*/\r
private function sendOIM($to, $sMessage, $lockkey) {\r
$XML = '<?xml version="1.0" encoding="utf-8"?>\r
}\r
return array('challenge' => $challenge, 'auth_policy' => $auth_policy);\r
}\r
- \r
+\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
+ * @return void\r
*/\r
private function sendOtherNetworkMessage($message, $to, $network) {\r
- $message=$this->getMessage($nessage, $network);\r
+ $message = $this->getMessage($message, $network);\r
$len = strlen($message);\r
$this->ns_writeln("UUM $this->id $to $network 1 $len");\r
$this->ns_writedata($Message);\r
- $this->log_message("*** sent to $to (network: $network):\n$Message");\r
+ $this->debug_message("*** Sent to $to (network: $network):\n$Message");\r
}\r
- \r
+\r
/**\r
* Send a message\r
- * @param $message Message\r
- * @param $to To address in form user@host.com@network\r
- * where network is 1 for MSN, 32 for Yahoo\r
- * and 'Offline' for offline messages\r
+ *\r
+ * @param string $to To address in form user@host.com(@network)\r
+ * where network is 1 for MSN, 32 for Yahoo\r
+ * and 'Offline' for offline messages\r
+ * @param string $message Message\r
*/\r
- public function sendMessage($message, $to) {\r
+ public function sendMessage($to, $message) {\r
if($message != '') {\r
- list($name,$host,$network)=explode('@',$to);\r
- $network=$network==''?1:$network;\r
- \r
- if($network === 1 && $this->switchBoardSessions[$to]['socket'] != NULL && time()-$this->switchBoardSessions[$to]['lastActive'] < $this->SBIdleTimeout) {\r
+ list($name, $host, $network) = explode('@', $to);\r
+ $network = $network == '' ? 1 : $network;\r
+\r
+ if ($network === 1 && $this->switchBoardSessions[$to]['socket'] !== NULL) {\r
$recipient = $name . $host;\r
- $this->debug_message("*** Sending Message to $recipient using existing SB session");\r
- return $this->sendMessageViaSB($message, $recipient);\r
- } elseif($network == 'Offline') {\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
+ return false;\r
+ }\r
+ } elseif ($network == 'Offline') {\r
//Send OIM\r
//FIXME: ä¿®æ£Send OIM\r
- $lockkey='';\r
- for ($i = 0; $i < $this->oim_try; $i++)\r
- {\r
- if(($oim_result = $this->sendOIM($To, $Message, $lockkey))===true) break;\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 (is_array($oim_result) && $oim_result['challenge'] !== false) {\r
// need challenge lockkey\r
- $this->log_message("*** we need a new challenge code for ".$oim_result['challenge']);\r
+ $this->debug_message("*** Need challenge code for ".$oim_result['challenge']);\r
$lockkey = $this->getChallenge($oim_result['challenge']);\r
continue;\r
}\r
- if ($oim_result === false || $oim_result['auth_policy'] !== false)\r
- {\r
- if ($this->re_login)\r
- {\r
- $this->log_message("*** can't send OIM, but we already re-login again, so ignore this OIM");\r
- break;\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
}\r
- $this->log_message("*** can't send OIM, maybe ticket expired, try to login again");\r
- // maybe we need to re-login again\r
- if(!$this->get_passport_ticket())\r
- {\r
- $this->log_message("*** can't re-login, something wrong here, ignore this OIM");\r
- break;\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
+ return false;\r
}\r
- $this->log_message("**** get new ticket, try it again");\r
+ $this->debug_message("*** Getting new ticket and trying again");\r
continue;\r
}\r
}\r
}\r
return true;\r
}\r
- \r
+\r
//FIXME Not sure if this is needed?\r
private function endSBSession($socket) {\r
- if (feof($socket))\r
- {\r
+ if (feof($socket)) {\r
// lost connection? error? try OIM later\r
@fclose($socket);\r
return false;\r
@fclose($socket);\r
return true;\r
}\r
- \r
+\r
/**\r
* Sends a ping command\r
- * \r
+ *\r
* Should be called about every 50 seconds\r
+ *\r
+ * @return void\r
*/\r
public function sendPing() {\r
// NS: >>> PNG\r
$this->ns_writeln("PNG");\r
}\r
- \r
+\r
+ /**\r
+ * Methods to return sockets / check socket status\r
+ */\r
+\r
/**\r
* Get the NS socket\r
+ *\r
+ * @return resource NS socket\r
*/\r
public function getNSSocket() {\r
return $this->NSfp;\r
}\r
- \r
+\r
/**\r
* Get the Switchboard sockets currently in use\r
+ *\r
+ * @return array Array of Switchboard sockets\r
*/\r
public function getSBSockets() {\r
return $this->switchBoardSockets;\r
}\r
- \r
+\r
/**\r
* Get all the sockets currently in use\r
+ *\r
+ * @return array Array of socket resources\r
*/\r
public function getSockets() {\r
return array_merge($this->NSfp, $this->switchBoardSockets);\r
}\r
- \r
- /** \r
+\r
+ /**\r
* Checks socket for end of file\r
*\r
- * @access public\r
- * @param Resource $socket Socket to check\r
- * @return boolean true if end of file (socket) \r
+ * @param resource $socket Socket to check\r
+ * @return boolean true if end of file (socket)\r
*/\r
private static function socketcheck($socket){\r
$info = stream_get_meta_data($socket);\r
return $info['eof'];\r
}\r
- \r
+\r
+ /**\r
+ * Methods to add / call callbacks\r
+ */\r
+\r
/**\r
* Calls User Handler\r
*\r
* Calls registered handler for a specific event.\r
- * \r
- * @param String $event Command (event) name (Rvous etc)\r
- * @param String $data Raw message from server\r
+ *\r
+ * @param string $event Command (event) name (Rvous etc)\r
+ * @param array $data Data\r
* @see registerHandler\r
* @return void\r
*/\r
- private function callHandler($event, $data) {\r
+ private function callHandler($event, $data = NULL) {\r
if (isset($this->myEventHandlers[$event])) {\r
- call_user_func($this->myEventHandlers[$event], $data);\r
+ if ($data !== NULL) {\r
+ call_user_func($this->myEventHandlers[$event], $data);\r
+ } else {\r
+ call_user_func($this->myEventHandlers[$event]);\r
+ }\r
}\r
}\r
- \r
- /** \r
+\r
+ /**\r
* Registers a user handler\r
- * \r
+ *\r
* Handler List\r
* IMIn, Pong, ConnectFailed, Reconnect\r
*\r
- * @param String $event Event name\r
- * @param String $handler User function to call\r
+ * @param string $event Event name\r
+ * @param string $handler User function to call\r
* @see callHandler\r
- * @return boolean Returns true if successful\r
+ * @return boolean true if successful\r
*/\r
public function registerHandler($event, $handler) {\r
if (is_callable($handler)) {\r