]> 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 af9a45e49deb35c3a48b54c74ee4da4ffdec081d..996c5571c20bd2c0a29458b7b1a00ef654f2e97b 100644 (file)
@@ -2,6 +2,7 @@
 /*\r
 \r
 phpmsnclass ver 2.0s\r
+Luke Fitzgerald <lw.fitzgerald@googlemail.com>\r
 \r
 Based on MSN class ver 2.0 by Tommy Wu, Ricky Su\r
 License: GPL\r
@@ -11,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
@@ -22,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
@@ -41,10 +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
     private $debug;\r
     private $timeout;\r
-    \r
+\r
     private $id;\r
     private $ticket;\r
     private $user = '';\r
@@ -69,7 +76,7 @@ class MSN {
     private $port = 1863;\r
 \r
     private $clientid = '';\r
-    \r
+\r
     private $error = '';\r
 \r
     private $authed = false;\r
@@ -80,13 +87,6 @@ class MSN {
     private $font_co = '333333';\r
     private $font_ef = '';\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
     // Begin added for StatusNet\r
 \r
     private $aContactList = array();\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
@@ -212,10 +211,10 @@ class MSN {
         // NS: >> VER {id} MSNP9 CVR0\r
         // MSNP15\r
         // NS: >>> VER {id} MSNP15 CVR0\r
-        $this->ns_writeln("VER $this->id ".PROTOCOL.' CVR0');\r
+        $this->ns_writeln("VER $this->id ".self::PROTOCOL.' CVR0');\r
 \r
         $start_tm = time();\r
-        while (!socketcheck($this->NSfp)) {\r
+        while (!self::socketcheck($this->NSfp)) {\r
             $data = $this->ns_readln();\r
             // no data?\r
             if ($data === false) {\r
@@ -238,7 +237,7 @@ class MSN {
                     // MSNP15\r
                     // NS: <<< VER {id} MSNP15 CVR0\r
                     // NS: >>> CVR {id} 0x0409 winnt 5.1 i386 MSMSGS 8.1.0178 msmsgs {user}\r
-                    $this->ns_writeln("CVR $this->id 0x0409 winnt 5.1 i386 MSMSGS ".BUILDVER." msmsgs $user");\r
+                    $this->ns_writeln("CVR $this->id 0x0409 winnt 5.1 i386 MSMSGS ".self::BUILDVER." msmsgs $user");\r
                     break;\r
 \r
                 case 'CVR':\r
@@ -248,7 +247,7 @@ class MSN {
                     // MSNP15\r
                     // NS: <<< CVR {id} {ver_list} {download_serve} ....\r
                     // NS: >>> USR {id} SSO I {user}\r
-                    $this->ns_writeln("USR $this->id ".LOGIN_METHOD." I $user");\r
+                    $this->ns_writeln("USR $this->id ".self::LOGIN_METHOD." I $user");\r
                     break;\r
 \r
                 case 'USR':\r
@@ -262,7 +261,7 @@ class MSN {
                     $this->user = $user;\r
                     $this->password = $password;\r
                     // NS: <<< USR {id} SSO S {policy} {nonce}\r
-                    @list(/* USR */, /* id */, /* SSO */, /* S */, $policy, $nonce,) = @explode(' ', $data);\r
+                    @list(/* USR */, /* id */, /* SSO */, /* S */, $policy, $nonce) = @explode(' ', $data);\r
 \r
                     $this->passport_policy = $policy;\r
                     $aTickets = $this->get_passport_ticket();\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
@@ -281,7 +280,7 @@ class MSN {
                     $login_code = $this->generateLoginBLOB($secret, $nonce);\r
 \r
                     // NS: >>> USR {id} SSO S {ticket} {login_code}\r
-                    $this->ns_writeln("USR $this->id ".LOGIN_METHOD." S $ticket $login_code");\r
+                    $this->ns_writeln("USR $this->id ".self::LOGIN_METHOD." S $ticket $login_code");\r
                     $this->authed = true;\r
                     break;\r
 \r
@@ -291,7 +290,7 @@ class MSN {
                     // NS: <<< XFR {id} NS {server} 0 {server}\r
                     // MSNP15\r
                     // NS: <<< XFR {id} NS {server} U D\r
-                    @list(/* XFR */, /* id */, $Type, $server, /* ... */) = @explode(' ', $data);\r
+                    @list(/* XFR */, /* id */, $Type, $server) = @explode(' ', $data);\r
                     if ($Type!='NS') break;\r
                     @list($ip, $port) = @explode(':', $server);\r
                     // this connection will close after XFR\r
@@ -307,13 +306,13 @@ class MSN {
                     // NS: >> VER {id} MSNP9 CVR0\r
                     // MSNP15\r
                     // NS: >>> VER {id} MSNP15 CVR0\r
-                    $this->ns_writeln("VER $this->id ".PROTOCOL.' CVR0');\r
+                    $this->ns_writeln("VER $this->id ".self::PROTOCOL.' CVR0');\r
                     break;\r
 \r
                 case 'GCF':\r
                     // return some policy data after 'USR {id} SSO I {user}' command\r
                     // NS: <<< GCF 0 {size}\r
-                    @list(/* GCF */, /* 0 */, $size,) = @explode(' ', $data);\r
+                    @list(/* GCF */, /* 0 */, $size) = @explode(' ', $data);\r
                     // we don't need the data, just read it and drop\r
                     if (is_numeric($size) && $size > 0)\r
                         $this->ns_readdata($size);\r
@@ -346,6 +345,10 @@ class MSN {
         *        the queue handler! */\r
         $this->debug_message('*** Trying to connect to MSN network');\r
 \r
+        // Remove any remaining switchboard sessions\r
+        $this->switchBoardSessions = array();\r
+        $this->switchBoardSessionLookup = array();\r
+\r
         while (true) {\r
             // Connect\r
             if (!$this->connect($this->user, $this->password)) {\r
@@ -354,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
@@ -460,7 +466,7 @@ class MSN {
             $len = strlen($str);\r
             $this->ns_writeln("UUX $this->id $len");\r
             $this->ns_writedata($str);\r
-            if (!socketcheck($this->NSfp)) {\r
+            if (!self::socketcheck($this->NSfp)) {\r
                 $this->debug_message('*** Connected, waiting for commands');\r
                 break;\r
             } else {\r
@@ -476,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
@@ -500,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
@@ -508,7 +516,7 @@ class MSN {
      */\r
     private function nsReceive() {\r
         // Sign in again if not signed in or socket failed\r
-        if (!is_resource($this->NSfp) || socketcheck($this->NSfp)) {\r
+        if (!is_resource($this->NSfp) || self::socketcheck($this->NSfp)) {\r
             $this->callHandler('Reconnect');\r
             $this->NSRetryWait($this->retry_wait);\r
             $this->signon();\r
@@ -523,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
@@ -546,7 +554,7 @@ class MSN {
 \r
             case 'LST':\r
                 // NS: <<< LST {email} {alias} 11 0\r
-                @list(/* LST */, $email, /* alias */,) = @explode(' ', $data);\r
+                @list(/* LST */, $email) = @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
@@ -557,7 +565,7 @@ class MSN {
             case 'ADL':\r
                 // randomly, we get ADL command, someone add us to their contact list for MSNP15\r
                 // NS: <<< ADL 0 {size}\r
-                @list(/* ADL */, /* 0 */, $size,) = @explode(' ', $data);\r
+                @list(/* ADL */, /* 0 */, $size) = @explode(' ', $data);\r
                 if (is_numeric($size) && $size > 0) {\r
                     $data = $this->ns_readdata($size);\r
                     preg_match('#<ml><d n="([^"]+)"><c n="([^"]+)"(.*) t="(\d*)"(.*) /></d></ml>#', $data, $matches);\r
@@ -609,7 +617,7 @@ class MSN {
             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
+                @list(/* RML */, /* 0 */, $size) = @explode(' ', $data);\r
                 if (is_numeric($size) && $size > 0) {\r
                     $data = $this->ns_readdata($size);\r
                     preg_match('#<ml><d n="([^"]+)"><c n="([^"]+)"(.*) t="(\d*)"(.*) /></d></ml>#', $data, $matches);\r
@@ -639,7 +647,7 @@ class MSN {
             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
+                @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
@@ -784,7 +792,7 @@ class MSN {
             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
+                @list(/* UBM */, $from_email, $network, $type, $size) = @explode(' ', $data);\r
                 if (is_numeric($size) && $size > 0) {\r
                     $data = $this->ns_readdata($size);\r
                     $aLines = @explode("\n", $data);\r
@@ -823,7 +831,7 @@ class MSN {
             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
+                @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
@@ -832,11 +840,11 @@ class MSN {
             case 'CHL':\r
                 // randomly, we'll get challenge from server\r
                 // NS: <<< CHL 0 {code}\r
-                @list(/* CHL */, /* 0 */, $chl_code,) = @explode(' ', $data);\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 ".PROD_ID.' 32');\r
+                $this->ns_writeln("QRY $this->id ".self::PROD_ID.' 32');\r
                 $this->ns_writedata($fingerprint);\r
                 $this->ns_writeln("CHG $this->id NLN $this->clientid");\r
                 if ($this->PhotoStickerFile !== false)\r
@@ -856,7 +864,7 @@ class MSN {
                 // 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(/* 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
@@ -866,15 +874,8 @@ class MSN {
                 }\r
 \r
                 $this->debug_message("NS: <<< XFR SB");\r
-                $user = array_shift($this->waitingForXFR);\r
-                            $bSBresult = $this->switchboard_control($ip, $port, $cki_code, $User, $Message);\r
-                /*\r
-                 $bSBresult = $this->switchboard_control($ip, $port, $cki_code, $aMSNUsers[$nCurrentUser], $sMessage);\r
-                 if ($bSBresult === false) {\r
-                 // error for switchboard\r
-                 $this->debug_message("!!! error for sending message to ".$aMSNUsers[$nCurrentUser]);\r
-                 $aOfflineUsers[] = $aMSNUsers[$nCurrentUser];\r
-                 }*/\r
+                $session = array_shift($this->waitingForXFR);\r
+                $this->connectToSBSession('Active', $ip, $port, $session['to'], array('cki' => $cki_code));\r
                 break;\r
             case 'QNG':\r
                 // NS: <<< QNG {time}\r
@@ -890,12 +891,19 @@ class MSN {
                 // someone is trying to talk to us\r
                 // NS: <<< RNG {session_id} {server} {auth_type} {ticket} {email} {alias} U {client} 0\r
                 $this->debug_message("NS: <<< RNG $data");\r
-                @list(/* RNG */, $sid, $server, /* auth_type */, $ticket, $email, $name) = @explode(' ', $data);\r
+                @list(/* RNG */, $sid, $server, /* auth_type */, $ticket, $email, $name) = @explode(' ', $data);\r
                 @list($sb_ip, $sb_port) = @explode(':', $server);\r
                 $this->debug_message("*** RING from $email, $sb_ip:$sb_port");\r
                 $this->addContact($email, 1, $email, true);\r
                 $this->connectToSBSession('Passive', $sb_ip, $sb_port, $email, array('sid' => $sid, 'ticket' => $ticket));\r
                 break;\r
+\r
+            case 'NLN':\r
+                // NS: <<< NLN {status} {email} {networkid} {nickname} {clientid} {dpobj}\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
             case 'OUT':\r
                 // force logout from NS\r
                 // NS: <<< OUT xxx\r
@@ -940,18 +948,21 @@ 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
-                $this->endSBSession();\r
+                $this->endSBSession($socket);\r
                 break;\r
             case 'USR':\r
                 // SB: <<< USR {id} OK {user} {alias}\r
                 // we don't need the data, just ignore it\r
                 // request user to join this switchboard\r
                 // SB: >>> CAL {id} {user}\r
-                $this->sb_writeln($socket, $id, "CAL $this->id $user");\r
+                $this->sb_writeln($socket, $id, "CAL $id ".$session['to']);\r
                 break;\r
             case 'CAL':\r
                 // SB: <<< CAL {id} RINGING {?}\r
@@ -961,13 +972,15 @@ 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
-                @list(/* MSG */, $from_email, /* alias */, $len) = @explode(' ', $data);\r
+                @list(/* MSG */, $from_email, /* alias */, $len) = @explode(' ', $data);\r
                 $len = trim($len);\r
                 $data = $this->sb_readdata($socket, $len);\r
                 $aLines = @explode("\n", $data);\r
@@ -1104,7 +1117,7 @@ class MSN {
                         $footer = pack("L", 0);\r
                         $message = "MIME-Version: 1.0\r\nContent-Type: application/x-msnmsgrp2p\r\nP2P-Dest: $from_email\r\n\r\n$hdr$footer";\r
                         $len = strlen($message);\r
-                        $this->sb_writeln($socket, $id, "MSG $this->id D $len");\r
+                        $this->sb_writeln($socket, $id, "MSG $id D $len");\r
                         $this->sb_writedata($socket, $message);\r
                         $this->debug_message("*** p2p: send display picture acknowledgement for $hdr_SessionID");\r
                         $this->debug_message("*** p2p: Invite ACK message:\n".$this->dump_binary($message));\r
@@ -1142,7 +1155,7 @@ class MSN {
                             "MIME-Version: 1.0\r\n".\r
                             "Content-Type: application/x-msnmsgrp2p\r\n".\r
                             "P2P-Dest: $from_email\r\n\r\n$hdr$MessagePayload$footer";\r
-                        $this->sb_writeln($socket, $id, "MSG $this->id D ".strlen($message));\r
+                        $this->sb_writeln($socket, $id, "MSG $id D ".strlen($message));\r
                         $this->sb_writedata($socket, $message);\r
                         $this->debug_message("*** p2p: dump 200 ok message:\n".$this->dump_binary($message));\r
                         $this->sb_readln($socket); // Read ACK;\r
@@ -1169,7 +1182,7 @@ class MSN {
                             "MIME-Version: 1.0\r\n".\r
                             "Content-Type: application/x-msnmsgrp2p\r\n".\r
                             "P2P-Dest: $from_email\r\n\r\n$hdr".pack('L', 0)."$footer";\r
-                        $this->sb_writeln($socket, $id, "MSG $this->id D ".strlen($message));\r
+                        $this->sb_writeln($socket, $id, "MSG $id D ".strlen($message));\r
                         $this->sb_writedata($socket, $message);\r
                         $this->debug_message("*** p2p: dump send Data preparation message:\n".$this->dump_binary($message));\r
                         $this->debug_message("*** p2p: Data Prepare Hdr:\n".$this->dump_binary($hdr));\r
@@ -1201,7 +1214,7 @@ class MSN {
                                     "MIME-Version: 1.0\r\n".\r
                                     "Content-Type: application/x-msnmsgrp2p\r\n".\r
                                     "P2P-Dest: $from_email\r\n\r\n$hdr$FileContent$footer";\r
-                                $this->sb_writeln($socket, $id, "MSG $this->id D ".strlen($message));\r
+                                $this->sb_writeln($socket, $id, "MSG $id D ".strlen($message));\r
                                 $this->sb_writedata($socket, $message);\r
                                 $this->debug_message("*** p2p: dump send Data Content message  $Offset / $FileSize :\n".$this->dump_binary($message));\r
                                 $this->debug_message("*** p2p: Data Content Hdr:\n".$this->dump_binary($hdr));\r
@@ -1304,17 +1317,16 @@ class MSN {
                     break;\r
                 }\r
                 $this->debug_message("*** MSG from $from_email: $sMsg");\r
-                $this->callHandler('IMin', array('sender' => $from_email, 'message' => $sMsg, 'network' => $network, 'offline' => false));\r
+                $this->callHandler('IMin', array('sender' => $from_email, 'message' => $sMsg, 'network' => 1, 'offline' => false));\r
                 break;\r
             case '217':\r
-                $this->debug_message("*** User $user is offline. Trying OIM.");\r
+                $this->debug_message('*** User '.$session['to'].' is offline. Trying OIM.');\r
                 $session['offline'] = true;\r
                 break;\r
             default:\r
                 if (is_numeric($code)) {\r
                     $this->error = "Error code: $code, please check the detail information from: http://msnpiki.msnfanatic.com/index.php/Reference:Error_List";\r
                     $this->debug_message("*** SB: $this->error");\r
-                    $sessionEnd=true;\r
                 }\r
                 break;\r
         }\r
@@ -1348,7 +1360,7 @@ class MSN {
     /**\r
      * Switchboard related methods\r
      */\r
-    \r
+\r
     /**\r
      * Send a request for a switchboard session\r
      *\r
@@ -1367,7 +1379,7 @@ class MSN {
             'offline' => false,\r
             'XFRReqTime' => time()\r
         );\r
-        $this->waitingForXFR[] = &$this->switchBoardSessions[$to];\r
+        $this->waitingForXFR[$to] = &$this->switchBoardSessions[$to];\r
     }\r
 \r
     /**\r
@@ -1393,7 +1405,6 @@ class MSN {
         $this->switchBoardSessionLookup[$to] = $socket;\r
 \r
         // Store the socket in the sessions array\r
-        $intsocket = (int) $socket;\r
         $this->switchBoardSessions[$to] = array(\r
             'to' => $to,\r
             'socket' => $socket,\r
@@ -1404,6 +1415,7 @@ class MSN {
         );\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
@@ -1423,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
@@ -1432,8 +1444,8 @@ class MSN {
     * @param boolean $killsession Whether to delete the session\r
     * @return void\r
     */\r
-    private function endSBSession($socket, $killsession = false) {\r
-        if (!socketcheck($socket)) {\r
+    private function endSBSession($socket) {\r
+        if (!self::socketcheck($socket)) {\r
             $this->sb_writeln($socket, $fake = 0, 'OUT');\r
         }\r
         @fclose($socket);\r
@@ -1455,35 +1467,34 @@ class MSN {
      */\r
     private function sendMessageViaSB($to, $message) {\r
         $socket = $this->switchBoardSessionLookup[$to];\r
-        if (socketcheck($socket)) {\r
-            return false;\r
-        }\r
-\r
-        if (!$this->switchBoardSessions[$to]['joined']) {\r
-            // If our participant has not joined the session yet we can't message them!\r
+        if (self::socketcheck($socket)) {\r
             return false;\r
         }\r
 \r
-        $intsocket = (int) $socket;\r
-        $id = &$this->switchBoardSessions[$intsocket]['id'];\r
+        $id = &$this->switchBoardSessions[(int) $socket]['id'];\r
 \r
-        $aMessage = $this->getMessage($Message);\r
-        //CheckEmotion...\r
-        $MsnObjDefine=$this->GetMsnObjDefine($aMessage);\r
+        $aMessage = $this->getMessage($message);\r
+        // CheckEmotion...\r
+        $MsnObjDefine = $this->GetMsnObjDefine($aMessage);\r
         if ($MsnObjDefine !== '') {\r
-            $SendString="MIME-Version: 1.0\r\nContent-Type: text/x-mms-emoticon\r\n\r\n$MsnObjDefine";\r
+            $SendString = "MIME-Version: 1.0\r\nContent-Type: text/x-mms-emoticon\r\n\r\n$MsnObjDefine";\r
             $len = strlen($SendString);\r
-            // TODO handle failure during write to socket\r
-            $this->sb_writeln($socket, $id, "MSG $id N $len");\r
-            $this->sb_writedata($socket, $SendString);\r
+\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
         $len = strlen($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
-        // Don't close the SB session, we might as well leave it open\r
+        if ($this->sb_writeln($socket, $id, "MSG $id N $len") === false ||\r
+            $this->sb_writedata($socket, $aMessage) === 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
         return true;\r
     }\r
 \r
@@ -1498,9 +1509,10 @@ class MSN {
     private function sendOtherNetworkMessage($to, $message, $network) {\r
         $message = $this->getMessage($message, $network);\r
         $len = strlen($message);\r
-        // TODO Introduce error checking for message sending\r
-        $this->ns_writeln("UUM $this->id $to $network 1 $len");\r
-        $this->ns_writedata($Message);\r
+        if ($this->ns_writeln("UUM $this->id $to $network 1 $len") === false ||\r
+            $this->ns_writedata($Message) === false) {\r
+            return false;\r
+        }\r
         $this->debug_message("*** Sent to $to (network: $network):\n$Message");\r
         return true;\r
     }\r
@@ -1512,36 +1524,58 @@ 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
-            list($name, $host, $network) = explode('@', $to);\r
-            $network = $network == '' ? 1 : $network;\r
-            $recipient = $name.$host;\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]) && (!isset($this->switchBoardSessions[$recipient])\r
-                    || time() - $this->switchBoardSessions[$recipient]['XFRReqTime'] > $this->XFRReqTimeout)) {\r
-                    $this->debug_message("*** No existing SB session or request has timed out");\r
-                    $this->reqSBSession($recipient);\r
+                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
+\r
+                    $waitForSession = true;\r
                     return false;\r
                 } else {\r
-                    $socket = $this->switchBoardSessionLookup[$to];\r
-                    if ($this->switchBoardSessions[(int) $socket]['offline']) {\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
+                            $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
-                        } else {\r
-                            $this->debug_message('*** Message sending failed, requesting new SB session');\r
-                            $this->reqSBSession($to);\r
-                            return false;\r
                         }\r
+\r
+                        $waitForSession = false;\r
+                        return false;\r
                     }\r
                 }\r
             } elseif ($network == 'Offline') {\r
@@ -1573,6 +1607,7 @@ class MSN {
                         continue;\r
                     }\r
                 }\r
+                return true;\r
             } else {\r
                 // Other network\r
                 return $this->sendOtherNetworkMessage($recipient, $message, $network);\r
@@ -1584,7 +1619,7 @@ class MSN {
     /**\r
      * OIM methods\r
      */\r
-    \r
+\r
     /**\r
     * Get OIM mail data\r
     *\r
@@ -1614,15 +1649,15 @@ class MSN {
 </soap:Envelope>';\r
 \r
         $header_array = array(\r
-            'SOAPAction: '.OIM_MAILDATA_SOAP,\r
+            'SOAPAction: '.self::OIM_MAILDATA_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 '.BUILDVER.')'\r
+            'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Messenger '.self::BUILDVER.')'\r
         );\r
 \r
-        $this->debug_message('*** URL: '.OIM_MAILDATA_URL);\r
+        $this->debug_message('*** URL: '.self::OIM_MAILDATA_URL);\r
         $this->debug_message("*** Sending SOAP:\n$XML");\r
         $curl = curl_init();\r
-        curl_setopt($curl, CURLOPT_URL, OIM_MAILDATA_URL);\r
+        curl_setopt($curl, CURLOPT_URL, self::OIM_MAILDATA_URL);\r
         curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
         curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\r
         curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);\r
@@ -1684,15 +1719,15 @@ class MSN {
 </soap:Envelope>';\r
 \r
         $header_array = array(\r
-            'SOAPAction: '.OIM_READ_SOAP,\r
+            'SOAPAction: '.self::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 '.BUILDVER.')'\r
+            'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Messenger '.self::BUILDVER.')'\r
         );\r
 \r
-        $this->debug_message('*** URL: '.OIM_READ_URL);\r
+        $this->debug_message('*** URL: '.self::OIM_READ_URL);\r
         $this->debug_message("*** Sending SOAP:\n$XML");\r
         $curl = curl_init();\r
-        curl_setopt($curl, CURLOPT_URL, OIM_READ_URL);\r
+        curl_setopt($curl, CURLOPT_URL, self::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
@@ -1760,15 +1795,15 @@ class MSN {
 </soap:Envelope>';\r
 \r
         $header_array = array(\r
-            'SOAPAction: '.OIM_DEL_SOAP,\r
+            'SOAPAction: '.self::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 '.BUILDVER.')'\r
+            'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Messenger '.self::BUILDVER.')'\r
         );\r
 \r
-        $this->debug_message('*** URL: '.OIM_DEL_URL);\r
+        $this->debug_message('*** URL: '.self::OIM_DEL_URL);\r
         $this->debug_message("*** Sending SOAP:\n$XML");\r
         $curl = curl_init();\r
-        curl_setopt($curl, CURLOPT_URL, OIM_DEL_URL);\r
+        curl_setopt($curl, CURLOPT_URL, self::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
@@ -1787,7 +1822,7 @@ class MSN {
             $this->debug_message("*** OIM ($msgid) deleted");\r
         return $sMsg;\r
     }\r
-    \r
+\r
     /**\r
      * Send offline message\r
      *\r
@@ -1807,11 +1842,11 @@ class MSN {
         xml:lang="zh-TW"\r
         proxy="MSNMSGR"\r
         xmlns="http://messenger.msn.com/ws/2004/09/oim/"\r
-        msnpVer="'.PROTOCOL.'"\r
-        buildVer="'.BUILDVER.'"/>\r
+        msnpVer="'.self::PROTOCOL.'"\r
+        buildVer="'.self::BUILDVER.'"/>\r
   <To memberName="'.$to.'" xmlns="http://messenger.msn.com/ws/2004/09/oim/"/>\r
   <Ticket passport="'.htmlspecialchars($this->ticket['oim_ticket']).'"\r
-          appid="'.PROD_ID.'"\r
+          appid="'.self::PROD_ID.'"\r
           lockkey="'.$lockkey.'"\r
           xmlns="http://messenger.msn.com/ws/2004/09/oim/"/>\r
   <Sequence xmlns="http://schemas.xmlsoap.org/ws/2003/03/rm">\r
@@ -1834,15 +1869,15 @@ X-OIM-Sequence-Num: 1
 </soap:Envelope>';\r
 \r
         $header_array = array(\r
-            'SOAPAction: '.OIM_SEND_SOAP,\r
+            'SOAPAction: '.self::OIM_SEND_SOAP,\r
             'Content-Type: text/xml',\r
-            'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Messenger '.BUILDVER.')'\r
+            'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Messenger '.self::BUILDVER.')'\r
         );\r
 \r
-        $this->debug_message('*** URL: '.OIM_SEND_URL);\r
+        $this->debug_message('*** URL: '.self::OIM_SEND_URL);\r
         $this->debug_message("*** Sending SOAP:\n$XML");\r
         $curl = curl_init();\r
-        curl_setopt($curl, CURLOPT_URL, OIM_SEND_URL);\r
+        curl_setopt($curl, CURLOPT_URL, self::OIM_SEND_URL);\r
         curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
         curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\r
         curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);\r
@@ -1889,9 +1924,9 @@ X-OIM-Sequence-Num: 1
             //<faultstring>Exception of type 'System.Web.Services.Protocols.SoapException' was thrown.</faultstring>\r
             preg_match("#<faultstring>(.*)</faultstring>#", $data, $matches);\r
             if (count($matches) > 0)\r
-            $err_msg = $matches[1];\r
+                $err_msg = $matches[1];\r
             else\r
-            $err_msg = '';\r
+                $err_msg = '';\r
             $this->debug_message("*** OIM failed for $to");\r
             $this->debug_message("*** OIM Error code: $err_code");\r
             $this->debug_message("*** OIM Error Message: $err_msg");\r
@@ -1899,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
@@ -1993,7 +2028,6 @@ X-OIM-Sequence-Num: 1
                 $str = '<ml l="1"><d n="'.$u_domain.'"><c n="'.$u_name.'" l="'.$l.'" t="'.$network.'" /></d></ml>';\r
                 $len = strlen($str);\r
                 // NS: >>> ADL {id} {size}\r
-                //TODO introduce error checking\r
                 $this->ns_writeln("ADL $this->id $len");\r
                 $this->ns_writedata($str);\r
             }\r
@@ -2095,15 +2129,15 @@ X-OIM-Sequence-Num: 1
 </soap:Envelope>';\r
 \r
         $header_array = array(\r
-            'SOAPAction: '.DELMEMBER_SOAP,\r
+            'SOAPAction: '.self::DELMEMBER_SOAP,\r
             'Content-Type: text/xml; charset=utf-8',\r
             'User-Agent: MSN Explorer/9.0 (MSN 8.0; TmstmpExt)'\r
         );\r
 \r
-        $this->debug_message('*** URL: '.DELMEMBER_URL);\r
+        $this->debug_message('*** URL: '.self::DELMEMBER_URL);\r
         $this->debug_message("*** Sending SOAP:\n$XML");\r
         $curl = curl_init();\r
-        curl_setopt($curl, CURLOPT_URL, DELMEMBER_URL);\r
+        curl_setopt($curl, CURLOPT_URL, self::DELMEMBER_URL);\r
         curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
         curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\r
         curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);\r
@@ -2232,15 +2266,15 @@ X-OIM-Sequence-Num: 1
 </soap:Body>\r
 </soap:Envelope>';\r
         $header_array = array(\r
-            'SOAPAction: '.ADDMEMBER_SOAP,\r
+            'SOAPAction: '.self::ADDMEMBER_SOAP,\r
             'Content-Type: text/xml; charset=utf-8',\r
             'User-Agent: MSN Explorer/9.0 (MSN 8.0; TmstmpExt)'\r
         );\r
 \r
-        $this->debug_message('*** URL: '.ADDMEMBER_URL);\r
+        $this->debug_message('*** URL: '.self::ADDMEMBER_URL);\r
         $this->debug_message("*** Sending SOAP:\n$XML");\r
         $curl = curl_init();\r
-        curl_setopt($curl, CURLOPT_URL, ADDMEMBER_URL);\r
+        curl_setopt($curl, CURLOPT_URL, self::ADDMEMBER_URL);\r
         curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
         curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\r
         curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);\r
@@ -2310,14 +2344,14 @@ X-OIM-Sequence-Num: 1
 </soap:Body>\r
 </soap:Envelope>';\r
         $header_array = array(\r
-            'SOAPAction: '.MEMBERSHIP_SOAP,\r
+            'SOAPAction: '.self::MEMBERSHIP_SOAP,\r
             'Content-Type: text/xml; charset=utf-8',\r
             'User-Agent: MSN Explorer/9.0 (MSN 8.0; TmstmpExt)'\r
         );\r
-        $this->debug_message('*** URL: '.MEMBERSHIP_URL);\r
+        $this->debug_message('*** URL: '.self::MEMBERSHIP_URL);\r
         $this->debug_message("*** Sending SOAP:\n$XML");\r
         $curl = curl_init();\r
-        curl_setopt($curl, CURLOPT_URL, MEMBERSHIP_URL);\r
+        curl_setopt($curl, CURLOPT_URL, self::MEMBERSHIP_URL);\r
         curl_setopt($curl, CURLOPT_HTTPHEADER, $header_array);\r
         curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\r
         curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);\r
@@ -2329,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
@@ -2409,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
@@ -2453,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
@@ -2479,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
@@ -2493,32 +2527,38 @@ 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 void\r
+     * @return mixed Bytes written or false on failure\r
      */\r
     private function ns_writeln($data) {\r
-        @fwrite($this->NSfp, $data."\r\n");\r
-        $this->debug_message("NS: >>> $data");\r
-        $this->id++;\r
+        $result = @fwrite($this->NSfp, $data."\r\n");\r
+        if ($result !== false) {\r
+            $this->debug_message("NS: >>> $data");\r
+            $this->id++;\r
+        }\r
+        return $result;\r
     }\r
 \r
     /**\r
      * Write data to NS socket\r
-     * \r
+     *\r
      * @param string $data Data to write to socket\r
-     * @return void\r
+     * @return mixed Bytes written or false on failure\r
      */\r
     private function ns_writedata($data) {\r
-        @fwrite($this->NSfp, $data);\r
-        $this->debug_message("NS: >>> $data");\r
+        $result = @fwrite($this->NSfp, $data);\r
+        if ($result !== false) {\r
+            $this->debug_message("NS: >>> $data");\r
+        }\r
+        return $result;\r
     }\r
 \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
@@ -2538,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
@@ -2553,30 +2593,36 @@ 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
-     * @return void\r
+     * @return mixed Bytes written or false on error\r
      */\r
     private function sb_writeln($socket, &$id, $data) {\r
-        @fwrite($socket, $data."\r\n");\r
-        $this->debug_message("SB: >>> $data");\r
-        $id++;\r
+        $result = @fwrite($socket, $data."\r\n");\r
+        if ($result !== false) {\r
+            $this->debug_message("SB: >>> $data");\r
+            $id++;\r
+        }\r
+        return $result;\r
     }\r
 \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 void\r
+     * @return mixed Bytes written or false on error\r
      */\r
     private function sb_writedata($socket, $data) {\r
-        @fwrite($socket, $data);\r
-        $this->debug_message("SB: >>> $data");\r
+        $result = @fwrite($socket, $data);\r
+        if ($result !== false) {\r
+            $this->debug_message("SB: >>> $data");\r
+        }\r
+        return $result;\r
     }\r
 \r
     /**\r
@@ -2598,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
@@ -2617,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
@@ -2631,7 +2677,7 @@ X-OIM-Sequence-Num: 1
 \r
         return base64_encode($blob);\r
     }\r
-    \r
+\r
     /**\r
     * Generate challenge response\r
     *\r
@@ -2642,7 +2688,7 @@ X-OIM-Sequence-Num: 1
         // MSNP15\r
         // http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges\r
         // Step 1: The MD5 Hash\r
-        $md5Hash = md5($code.PROD_KEY);\r
+        $md5Hash = md5($code.self::PROD_KEY);\r
         $aMD5 = @explode("\0", chunk_split($md5Hash, 8, "\0"));\r
         for ($i = 0; $i < 4; $i++) {\r
             $aMD5[$i] = implode('', array_reverse(@explode("\0", chunk_split($aMD5[$i], 2, "\0"))));\r
@@ -2650,7 +2696,7 @@ X-OIM-Sequence-Num: 1
         }\r
 \r
         // Step 2: A new string\r
-        $chl_id = $code.PROD_ID;\r
+        $chl_id = $code.self::PROD_ID;\r
         $chl_id .= str_repeat('0', 8 - (strlen($chl_id) % 8));\r
 \r
         $aID = @explode("\0", substr(chunk_split($chl_id, 4, "\0"), 0, -1));\r
@@ -2700,7 +2746,7 @@ X-OIM-Sequence-Num: 1
         // $key = bcadd(bcmul($high, 0x100000000), $low);\r
 \r
         // Step 4: Using the key\r
-        $md5Hash = md5($code.PROD_KEY);\r
+        $md5Hash = md5($code.self::PROD_KEY);\r
         $aHash = @explode("\0", chunk_split($md5Hash, 8, "\0"));\r
 \r
         $hash = '';\r
@@ -2711,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
@@ -2723,7 +2769,7 @@ X-OIM-Sequence-Num: 1
             $Attrib = '';\r
             if (is_array($Val[':'])) {\r
                 foreach ($Val[':'] as $AttribName => $AttribVal)\r
-                $Attrib .= " $AttribName = '$AttribVal'";\r
+                    $Attrib .= " $AttribName = '$AttribVal'";\r
             }\r
             if ($Key{0} == '!') {\r
                 //List Type Define\r
@@ -2743,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
@@ -2754,7 +2800,7 @@ X-OIM-Sequence-Num: 1
         }\r
         return $Data;\r
     }\r
-    \r
+\r
     /**\r
     * Get Passport ticket\r
     *\r
@@ -2766,7 +2812,7 @@ X-OIM-Sequence-Num: 1
         $password = htmlspecialchars($this->password);\r
 \r
         if ($url === '')\r
-            $passport_url = PASSPORT_URL;\r
+            $passport_url = self::PASSPORT_URL;\r
         else\r
             $passport_url = $url;\r
 \r
@@ -3001,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
@@ -3013,14 +3059,14 @@ X-OIM-Sequence-Num: 1
         $msg_header = "MIME-Version: 1.0\r\nContent-Type: text/plain; charset=UTF-8\r\nX-MMS-IM-Format: FN=$this->font_fn; EF=$this->font_ef; CO=$this->font_co; CS=0; PF=22\r\n\r\n";\r
         $msg_header_len = strlen($msg_header);\r
         if ($network == 1)\r
-            $maxlen = $this->max_msn_message_len - $msg_header_len;\r
+            $maxlen = self::MAX_MSN_MESSAGE_LEN - $msg_header_len;\r
         else\r
-            $maxlen = $this->max_yahoo_message_len - $msg_header_len;\r
+            $maxlen = self::MAX_YAHOO_MESSAGE_LEN - $msg_header_len;\r
         $sMessage = str_replace("\r", '', $sMessage);\r
         $msg = substr($sMessage, 0, $maxlen);\r
         return $msg_header.$msg;\r
     }\r
-    \r
+\r
     /**\r
     * Sleep for the given number of seconds\r
     *\r
@@ -3030,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
@@ -3042,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
@@ -3071,8 +3117,8 @@ X-OIM-Sequence-Num: 1
      * Registers a user handler\r
      *\r
      * Handler List\r
-     * IMIn, Pong, ConnectFailed, Reconnect,\r
-     * AddedToList, RemovedFromList\r
+     * IMIn, SessionReady, Pong, ConnectFailed, Reconnect,\r
+     * AddedToList, RemovedFromList, StatusChange\r
      *\r
      * @param string $event Event name\r
      * @param string $handler User function to call\r
@@ -3087,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
@@ -3133,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