]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - plugins/Msn/extlib/phpmsnclass/msn.class.php
Fix mising require_once (now required here because of rearranging)
[quix0rs-gnu-social.git] / plugins / Msn / extlib / phpmsnclass / msn.class.php
index 6d7b95b72b92b8d76a1deb4a1da2ecfd387ac330..996c5571c20bd2c0a29458b7b1a00ef654f2e97b 100644 (file)
@@ -12,7 +12,7 @@ Documentation on the MSN protocol can be found at: http://msnpiki.msnfanatic.com
 This class uses MSNP15.\r
 \r
 In addition to PHP5, the additional php modules required are:\r
-curl pcre mhash mcrypt bcmath\r
+curl pcre mcrypt bcmath\r
 \r
 */\r
 \r
@@ -23,10 +23,10 @@ class MSN {
     const PROD_KEY = 'PK}_A_0N_K%O?A9S';\r
     const PROD_ID = 'PROD0114ES4Z%Q5W';\r
     const LOGIN_METHOD = 'SSO';\r
-    \r
+\r
     const OIM_SEND_URL = 'https://ows.messenger.msn.com/OimWS/oim.asmx';\r
     const OIM_SEND_SOAP = 'http://messenger.live.com/ws/2006/09/oim/Store2';\r
-    \r
+\r
     const OIM_MAILDATA_URL = 'https://rsi.hotmail.com/rsi/rsi.asmx';\r
     const OIM_MAILDATA_SOAP = 'http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMetadata';\r
     const OIM_READ_URL = 'https://rsi.hotmail.com/rsi/rsi.asmx';\r
@@ -42,16 +42,16 @@ class MSN {
 \r
     const DELMEMBER_URL = 'https://contacts.msn.com/abservice/SharingService.asmx';\r
     const DELMEMBER_SOAP = 'http://www.msn.com/webservices/AddressBook/DeleteMember';\r
-    \r
+\r
     // the message length (include header) is limited (maybe since WLM 8.5 released)\r
     // for WLM: 1664 bytes\r
     // for YIM: 518 bytes\r
     const MAX_MSN_MESSAGE_LEN = 1664;\r
     const MAX_YAHOO_MESSAGE_LEN = 518;\r
-    \r
+\r
     private $debug;\r
     private $timeout;\r
-    \r
+\r
     private $id;\r
     private $ticket;\r
     private $user = '';\r
@@ -76,7 +76,7 @@ class MSN {
     private $port = 1863;\r
 \r
     private $clientid = '';\r
-    \r
+\r
     private $error = '';\r
 \r
     private $authed = false;\r
@@ -156,7 +156,6 @@ class MSN {
         // 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
@@ -181,7 +180,7 @@ class MSN {
     /**\r
      * Signon methods\r
      */\r
-    \r
+\r
     /**\r
      * Connect to the NS server\r
      *\r
@@ -271,7 +270,7 @@ class MSN {
                         // NS: >>> OUT\r
                         $this->ns_writeln("OUT");\r
                         @fclose($this->NSfp);\r
-                        $this->error = 'Passport authenticated fail!';\r
+                        $this->error = 'Passport authentication failed!';\r
                         return false;\r
                     }\r
 \r
@@ -345,7 +344,7 @@ class MSN {
         /* 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
+\r
         // Remove any remaining switchboard sessions\r
         $this->switchBoardSessions = array();\r
         $this->switchBoardSessionLookup = array();\r
@@ -358,7 +357,10 @@ class MSN {
             }\r
 \r
             // Update contacts\r
-            if ($this->UpdateContacts() === false) continue;\r
+            if ($this->UpdateContacts() === false) {\r
+                $this->signonFailure('');\r
+                continue;\r
+            }\r
 \r
             // Get membership lists\r
             if (($this->aContactList = $this->getMembershipList()) === false) {\r
@@ -480,8 +482,10 @@ class MSN {
     * @return void\r
     */\r
     private function signonFailure($message) {\r
-        $this->debug_message($message);\r
-        $this->callHandler('ConnectFailed');\r
+        if(!empty($message)) {\r
+            $this->debug_message($message);\r
+        }\r
+        $this->callHandler('ConnectFailed', $message);\r
         $this->NSRetryWait($this->retry_wait);\r
     }\r
 \r
@@ -504,7 +508,7 @@ class MSN {
     /**\r
      * NS and SB command handling methods\r
      */\r
-    \r
+\r
     /**\r
      * Read and handle incoming command from NS\r
      *\r
@@ -527,7 +531,7 @@ class MSN {
             $this->signon();\r
             return;\r
         }\r
-        \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
@@ -893,14 +897,13 @@ class MSN {
                 $this->addContact($email, 1, $email, true);\r
                 $this->connectToSBSession('Passive', $sb_ip, $sb_port, $email, array('sid' => $sid, 'ticket' => $ticket));\r
                 break;\r
-            \r
+\r
             case 'NLN':\r
                 // NS: <<< NLN {status} {email} {networkid} {nickname} {clientid} {dpobj}\r
-                // NS: <<< NLN NLN darkip@inflatablegoldfish.com 1 Luke 2685403136 0\r
                 @list(/* NLN */, $status, $email, $network, $nickname) = @explode(' ', $data);\r
                 $this->callHandler('StatusChange', array('screenname' => $email, 'status' => $status, 'network' => $network, 'nickname' => $nickname));\r
                 break;\r
-            \r
+\r
             case 'OUT':\r
                 // force logout from NS\r
                 // NS: <<< OUT xxx\r
@@ -945,7 +948,10 @@ class MSN {
                 // 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
+                if ($email == $session['to']) {\r
+                    $session['joined'] = true;\r
+                    $this->callHandler('SessionReady', array('to' => $email));\r
+                }\r
                 break;\r
             case 'BYE':\r
                 $this->debug_message("*** Quit for BYE");\r
@@ -966,9 +972,11 @@ class MSN {
             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
+                @list(/* JOI */, $email) = @explode(' ', $data);\r
+                if ($email == $session['to']) {\r
+                    $session['joined'] = true;\r
+                    $this->callHandler('SessionReady', array('to' => $email));\r
+                }\r
                 break;\r
             case 'MSG':\r
                 // SB: <<< MSG {email} {alias} {len}\r
@@ -1352,7 +1360,7 @@ class MSN {
     /**\r
      * Switchboard related methods\r
      */\r
-    \r
+\r
     /**\r
      * Send a request for a switchboard session\r
      *\r
@@ -1405,12 +1413,12 @@ class MSN {
             'offline' => false,\r
             'XFRReqTime' => time()\r
         );\r
-        \r
+\r
         // Change the index of the session to the socket\r
         $intsocket = (int) $socket;\r
         $this->switchBoardSessions[$intsocket] = $this->switchBoardSessions[$to];\r
         unset($this->switchBoardSessions[$to]);\r
-        \r
+\r
         $id = &$this->switchBoardSessions[$intsocket]['id'];\r
 \r
         if ($mode == 'Active') {\r
@@ -1427,7 +1435,7 @@ class MSN {
             $this->sb_writeln($socket, $id, "ANS $id $this->user $ticket $sid");\r
         }\r
     }\r
-    \r
+\r
     /**\r
     * Called when we want to end a switchboard session\r
     * or a switchboard session ends\r
@@ -1474,6 +1482,7 @@ class MSN {
 \r
             if ($this->sb_writeln($socket, $id, "MSG $id N $len") === false ||\r
                 $this->sb_writedata($socket, $SendString) === false) {\r
+                    $this->endSBSession($socket);\r
                     return false;\r
                 }\r
         }\r
@@ -1481,7 +1490,8 @@ class MSN {
 \r
         if ($this->sb_writeln($socket, $id, "MSG $id N $len") === false ||\r
             $this->sb_writedata($socket, $aMessage) === false) {\r
-               return false;\r
+                $this->endSBSession($socket);\r
+                return false;\r
             }\r
 \r
         // Don't close the SB session, we might as well leave it open\r
@@ -1514,46 +1524,57 @@ class MSN {
      *                   where network is 1 for MSN, 32 for Yahoo\r
      *                   and 'Offline' for offline messages\r
      * @param string $message Message\r
+     * @param boolean &$waitForSession Boolean passed by reference,\r
+     *                                 if set to true on return, message\r
+     *                                 did not fail to send but is\r
+     *                                 waiting for a valid session\r
+     *\r
+     * @return boolean true on success\r
      */\r
-    public function sendMessage($to, $message) {\r
+    public function sendMessage($to, $message, &$waitForSession) {\r
         if ($message != '') {\r
-               $toParts = explode('@', $to);\r
-               if(count($toParts) < 3) {\r
-                       list($name, $host) = $toParts;\r
-                       $network = 1;\r
-               } else {\r
-                       list($name, $host, $network) = $toParts;\r
-               }\r
-               \r
+            $toParts = explode('@', $to);\r
+            if(count($toParts) < 3) {\r
+                list($name, $host) = $toParts;\r
+                $network = 1;\r
+            } else {\r
+                list($name, $host, $network) = $toParts;\r
+            }\r
+\r
             $recipient = $name.'@'.$host;\r
 \r
             if ($network === 1) {\r
                 if (!isset($this->switchBoardSessionLookup[$recipient])) {\r
-                       if (!isset($this->switchBoardSessions[$recipient]) || 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
-                       }\r
-                       return false;\r
+                    if (!isset($this->switchBoardSessions[$recipient]) || 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
+                    }\r
+\r
+                    $waitForSession = true;\r
+                    return false;\r
                 } else {\r
                     $socket = $this->switchBoardSessionLookup[$recipient];\r
                     $intsocket = (int) $socket;\r
                     if ($this->switchBoardSessions[$intsocket]['offline']) {\r
                         $this->debug_message("*** Contact ($recipient) offline, sending OIM");\r
                         $this->endSBSession($socket);\r
+                        $waitForSession = false;\r
                         return $this->sendMessage($recipient.'@Offline', $message);\r
                     } else {\r
-                       if ($this->switchBoardSessions[$intsocket]['joined'] !== true) {\r
-                               $this->debug_message("*** Recipient has not joined session, returning false");\r
-                               return false;\r
-                       }\r
-                       \r
+                        if ($this->switchBoardSessions[$intsocket]['joined'] !== true) {\r
+                            $this->debug_message("*** Recipient has not joined session, returning false");\r
+                            $waitForSession = true;\r
+                            return false;\r
+                        }\r
+\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
                         }\r
-                        \r
+\r
+                        $waitForSession = false;\r
                         return false;\r
                     }\r
                 }\r
@@ -1598,7 +1619,7 @@ class MSN {
     /**\r
      * OIM methods\r
      */\r
-    \r
+\r
     /**\r
     * Get OIM mail data\r
     *\r
@@ -1801,7 +1822,7 @@ class MSN {
             $this->debug_message("*** OIM ($msgid) deleted");\r
         return $sMsg;\r
     }\r
-    \r
+\r
     /**\r
      * Send offline message\r
      *\r
@@ -1913,11 +1934,11 @@ X-OIM-Sequence-Num: 1
         }\r
         return array('challenge' => $challenge, 'auth_policy' => $auth_policy);\r
     }\r
-    \r
+\r
     /**\r
      * Contact / Membership list methods\r
      */\r
-    \r
+\r
     /**\r
     * Fetch contact list\r
     *\r
@@ -2342,7 +2363,7 @@ X-OIM-Sequence-Num: 1
         $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);\r
         curl_close($curl);\r
         $this->debug_message("*** Get Result:\n$data");\r
-        \r
+\r
         if ($http_code != 200) return false;\r
         $p = $data;\r
         $aMemberships = array();\r
@@ -2422,11 +2443,11 @@ X-OIM-Sequence-Num: 1
         }\r
         return $aContactList;\r
     }\r
-    \r
+\r
     /**\r
      * MsnObj related methods\r
      */\r
-    \r
+\r
     /**\r
      *\r
      * @param $FilePath 圖檔路徑\r
@@ -2466,14 +2487,14 @@ X-OIM-Sequence-Num: 1
             }\r
         return $DefineString;\r
     }\r
-    \r
+\r
     /**\r
      * Socket methods\r
      */\r
-    \r
+\r
     /**\r
      * Read data of specified size from NS socket\r
-     * \r
+     *\r
      * @param integer $size Size to read\r
      * @return string Data read\r
      */\r
@@ -2492,7 +2513,7 @@ X-OIM-Sequence-Num: 1
 \r
     /**\r
      * Read line from the NS socket\r
-     * \r
+     *\r
      * @return string Data read\r
      */\r
     private function ns_readln() {\r
@@ -2506,9 +2527,9 @@ X-OIM-Sequence-Num: 1
 \r
     /**\r
      * Write line to NS socket\r
-     * \r
+     *\r
      * Also increments id\r
-     * \r
+     *\r
      * @param string $data Line to write to socket\r
      * @return mixed Bytes written or false on failure\r
      */\r
@@ -2523,7 +2544,7 @@ X-OIM-Sequence-Num: 1
 \r
     /**\r
      * Write data to NS socket\r
-     * \r
+     *\r
      * @param string $data Data to write to socket\r
      * @return mixed Bytes written or false on failure\r
      */\r
@@ -2537,7 +2558,7 @@ X-OIM-Sequence-Num: 1
 \r
     /**\r
      * Read data of specified size from given SB socket\r
-     * \r
+     *\r
      * @param resource $socket SB socket\r
      * @param integer $size Size to read\r
      * @return string Data read\r
@@ -2557,7 +2578,7 @@ X-OIM-Sequence-Num: 1
 \r
     /**\r
      * Read line from given SB socket\r
-     * \r
+     *\r
      * @param resource $socket SB Socket\r
      * @return string Line read\r
      */\r
@@ -2572,9 +2593,9 @@ X-OIM-Sequence-Num: 1
 \r
     /**\r
      * Write line to given SB socket\r
-     * \r
+     *\r
      * Also increments id\r
-     * \r
+     *\r
      * @param resource $socket SB socket\r
      * @param integer $id Reference to SB id\r
      * @param string $data Line to write\r
@@ -2591,7 +2612,7 @@ X-OIM-Sequence-Num: 1
 \r
     /**\r
      * Write data to given SB socket\r
-     * \r
+     *\r
      * @param resource $socket SB socket\r
      * @param $data Data to write to socket\r
      * @return mixed Bytes written or false on error\r
@@ -2623,16 +2644,16 @@ X-OIM-Sequence-Num: 1
         $info = stream_get_meta_data($socket);\r
         return $info['eof'];\r
     }\r
-    \r
+\r
     /**\r
      * Key generation methods\r
      */\r
-    \r
+\r
     private function derive_key($key, $magic) {\r
-        $hash1 = mhash(MHASH_SHA1, $magic, $key);\r
-        $hash2 = mhash(MHASH_SHA1, $hash1.$magic, $key);\r
-        $hash3 = mhash(MHASH_SHA1, $hash1, $key);\r
-        $hash4 = mhash(MHASH_SHA1, $hash3.$magic, $key);\r
+        $hash1 = $this->mhash_sha1($magic, $key);\r
+        $hash2 = $this->mhash_sha1($hash1.$magic, $key);\r
+        $hash3 = $this->mhash_sha1($hash1, $key);\r
+        $hash4 = $this->mhash_sha1($hash3.$magic, $key);\r
         return $hash2.substr($hash4, 0, 4);\r
     }\r
 \r
@@ -2642,7 +2663,7 @@ X-OIM-Sequence-Num: 1
         $key3 = $this->derive_key($key1, 'WS-SecureConversationSESSION KEY ENCRYPTION');\r
 \r
         // get hash of challenge using key2\r
-        $hash = mhash(MHASH_SHA1, $challenge, $key2);\r
+        $hash = $this->mhash_sha1($challenge, $key2);\r
 \r
         // get 8 bytes random data\r
         $iv = substr(base64_encode(rand(1000,9999).rand(1000,9999)), 2, 8);\r
@@ -2656,7 +2677,7 @@ X-OIM-Sequence-Num: 1
 \r
         return base64_encode($blob);\r
     }\r
-    \r
+\r
     /**\r
     * Generate challenge response\r
     *\r
@@ -2736,11 +2757,11 @@ X-OIM-Sequence-Num: 1
 \r
         return $hash;\r
     }\r
-    \r
+\r
     /**\r
      * Utility methods\r
      */\r
-    \r
+\r
     private function Array2SoapVar($Array, $ReturnSoapVarObj = true, $TypeName = null, $TypeNameSpace = null) {\r
         $ArrayString = '';\r
         foreach($Array as $Key => $Val) {\r
@@ -2768,7 +2789,7 @@ X-OIM-Sequence-Num: 1
         if ($ReturnSoapVarObj) return new SoapVar($ArrayString, XSD_ANYXML, $TypeName, $TypeNameSpace);\r
         return $ArrayString;\r
     }\r
-    \r
+\r
     private function linetoArray($lines) {\r
         $lines = str_replace("\r", '', $lines);\r
         $lines = explode("\n", $lines);\r
@@ -2779,7 +2800,7 @@ X-OIM-Sequence-Num: 1
         }\r
         return $Data;\r
     }\r
-    \r
+\r
     /**\r
     * Get Passport ticket\r
     *\r
@@ -3026,7 +3047,7 @@ X-OIM-Sequence-Num: 1
         $this->ABAuthHeader = new SoapHeader('http://www.msn.com/webservices/AddressBook', 'ABAuthHeader', $this->Array2SoapVar($ABAuthHeaderArray));\r
         return $aTickets;\r
     }\r
-    \r
+\r
     /**\r
     * Generate the data to send a message\r
     *\r
@@ -3045,7 +3066,7 @@ X-OIM-Sequence-Num: 1
         $msg = substr($sMessage, 0, $maxlen);\r
         return $msg_header.$msg;\r
     }\r
-    \r
+\r
     /**\r
     * Sleep for the given number of seconds\r
     *\r
@@ -3055,7 +3076,7 @@ X-OIM-Sequence-Num: 1
         $this->debug_message("*** Sleeping for $wait seconds before retrying");\r
         sleep($wait);\r
     }\r
-    \r
+\r
     /**\r
      * Sends a ping command\r
      *\r
@@ -3067,7 +3088,7 @@ X-OIM-Sequence-Num: 1
         // NS: >>> PNG\r
         $this->ns_writeln("PNG");\r
     }\r
-    \r
+\r
     /**\r
     * Methods to add / call callbacks\r
     */\r
@@ -3096,7 +3117,7 @@ X-OIM-Sequence-Num: 1
      * Registers a user handler\r
      *\r
      * Handler List\r
-     * IMIn, Pong, ConnectFailed, Reconnect,\r
+     * IMIn, SessionReady, Pong, ConnectFailed, Reconnect,\r
      * AddedToList, RemovedFromList, StatusChange\r
      *\r
      * @param string $event Event name\r
@@ -3112,24 +3133,24 @@ X-OIM-Sequence-Num: 1
             return false;\r
         }\r
     }\r
-    \r
+\r
     /**\r
      * Debugging methods\r
      */\r
-    \r
+\r
     /**\r
      * Print message if debugging is enabled\r
-     * \r
+     *\r
      * @param string $str Message to print\r
      */\r
     private function debug_message($str) {\r
         if (!$this->debug) return;\r
         echo $str."\n";\r
     }\r
-    \r
+\r
     /**\r
      * Dump binary data\r
-     * \r
+     *\r
      * @param string $str Data string\r
      * @return Binary data\r
      */\r
@@ -3158,4 +3179,32 @@ X-OIM-Sequence-Num: 1
         $buf .= "$h_str $a_str\n";\r
         return $buf;\r
     }\r
+\r
+    function mhash_sha1($data, $key)\r
+    {\r
+        if (extension_loaded("mhash"))\r
+            return mhash(MHASH_SHA1, $data, $key);\r
+\r
+        if (function_exists("hash_hmac"))\r
+            return hash_hmac('sha1', $data, $key, true);\r
+\r
+        // RFC 2104 HMAC implementation for php. Hacked by Lance Rushing\r
+        $b = 64;\r
+        if (strlen($key) > $b)\r
+            $key = pack("H*", sha1($key));\r
+        $key = str_pad($key, $b, chr(0x00));\r
+        $ipad = str_pad("", $b, chr(0x36));\r
+        $opad = str_pad("", $b, chr(0x5c));\r
+        $k_ipad = $key ^ $ipad ;\r
+        $k_opad = $key ^ $opad;\r
+\r
+        $sha1_value = sha1($k_opad . pack("H*", sha1($k_ipad . $data)));\r
+\r
+        $hash_data = '';\r
+        $str = join('',explode('\x', $sha1_value));\r
+        $len = strlen($str);\r
+        for ($i = 0; $i < $len; $i += 2)\r
+            $hash_data .= chr(hexdec(substr($str, $i, 2)));\r
+        return $hash_data;\r
+    }\r
 }\r