- private function DoSwitchBoard($Action,$Param)\r
- {\r
- $SessionEnd=false;\r
- $Joined=false;\r
- $id=1;\r
- $LastActive=time();\r
- stream_set_timeout($this->SBFp, $this->SBTimeout);\r
- switch($Action)\r
- {\r
- case 'Active':\r
- $cki_code=$Param['cki'];\r
- $user=$Param['user'];\r
- $this->SwitchBoardMessageQueue=$Param['Msg'];\r
- // SB: >>> USR {id} {user} {cki}\r
- $this->SB_writeln("USR $id $this->user $cki_code");\r
- $id++;\r
- $this->SwitchBoardSessionUser=$user;\r
- break;\r
- case 'Passive':\r
- $ticket=$Param['ticket'];\r
- $sid=$Param['sid'];\r
- $user=$Param['user'];\r
- // SB: >>> ANS {id} {user} {ticket} {session_id}\r
- $this->SB_writeln("ANS $id $this->user $ticket $sid");\r
- $id++;\r
- $this->SwitchBoardSessionUser=$user;\r
- break;\r
- default:\r
- return false;\r
- }\r
- while((!feof($this->SBFp))&&(!$SessionEnd))\r
- {\r
- $data = $this->SB_readln();\r
- if($this->kill_me)\r
- {\r
- $this->log_message("*** SB Okay, kill me now!");\r
- break;\r
- }\r
- if($data === false)\r
- {\r
- if(time()-$LastActive > $this->SBIdleTimeout)\r
- {\r
- $this->debug_message("*** SB Idle Timeout!");\r
- break;\r
- }\r
- if(!$Joined) continue;\r
- foreach($this->SwitchBoardMessageQueue as $Message)\r
- {\r
- if($Message=='') continue;\r
- $aMessage = $this->getMessage($Message);\r
- //CheckEmotion...\r
- $MsnObjDefine=$this->GetMsnObjDefine($aMessage);\r
- if($MsnObjDefine!=='')\r
- {\r
- $SendString="MIME-Version: 1.0\r\nContent-Type: text/x-mms-emoticon\r\n\r\n$MsnObjDefine";\r
- $len = strlen($SendString);\r
- $this->SB_writeln("MSG $id N $len");\r
- $id++;\r
- $this->SB_writedata($SendString);\r
- $this->id++;\r
- }\r
- $len = strlen($aMessage);\r
- $this->SB_writeln("MSG $id N $len");\r
- $id++;\r
- $this->SB_writedata($aMessage);\r
- }\r
- $this->SwitchBoardMessageQueue=array();\r
- $LastActive=time();\r
- continue;\r
- }\r
- $code = substr($data, 0, 3);\r
- switch($code)\r
- {\r
- case 'IRO':\r
- // SB: <<< IRO {id} {rooster} {roostercount} {email} {alias} {clientid}\r
- @list(/* IRO */, /* id */, $cur_num, $total, $email, $alias, $clientid) = @explode(' ', $data);\r
- $this->log_message("*** $email join us");\r
- $Joined=true;\r
- break;\r
- case 'BYE':\r
- $this->log_message("*** Quit for BYE");\r
- $SessionEnd=true;\r
- break;\r
- case 'USR':\r
- // SB: <<< USR {id} OK {user} {alias}\r
- // we don't need the data, just ignore it\r
- // request user to join this switchboard\r
- // SB: >>> CAL {id} {user}\r
- $this->SB_writeln("CAL $id $user");\r
- $id++;\r
- break;\r
- case 'CAL':\r
- // SB: <<< CAL {id} RINGING {?}\r
- // we don't need this, just ignore, and wait for other response\r
- $this->id++;\r
- break;\r
- case 'JOI':\r
- // SB: <<< JOI {user} {alias} {clientid?}\r
- // someone join us\r
- // we don't need the data, just ignore it\r
- // no more user here\r
- $Joined=true;\r
- break;\r
- case 'MSG':\r
- // SB: <<< MSG {email} {alias} {len}\r
- @list(/* MSG */, $from_email, /* alias */, $len, ) = @explode(' ', $data);\r
- $len = trim($len);\r
- $data = $this->SB_readdata($len);\r
- $aLines = @explode("\n", $data);\r
- $header = true;\r
- $ignore = false;\r
- $is_p2p = false;\r
- $sMsg = '';\r
- foreach ($aLines as $line)\r
- {\r
- $line = rtrim($line);\r
- if ($header) {\r
- if ($line === '') {\r
- $header = false;\r
- continue;\r
- }\r
- if (strncasecmp($line, 'TypingUser:', 11) == 0) {\r
- // typing notification, just ignore\r
- $ignore = true;\r
- break;\r
- }\r
- if (strncasecmp($line, 'Chunk:', 6) == 0) {\r
- // we don't handle any split message, just ignore\r
- $ignore = true;\r
- break;\r
- }\r
- if (strncasecmp($line, 'Content-Type: application/x-msnmsgrp2p', 38) == 0) {\r
- // p2p message, ignore it, but we need to send acknowledgement for it...\r
- $is_p2p = true;\r
- $p = strstr($data, "\n\n");\r
- $sMsg = '';\r
- if ($p === false) {\r
- $p = strstr($data, "\r\n\r\n");\r
- if ($p !== false)\r
- $sMsg = substr($p, 4);\r
- }\r
- else\r
- $sMsg = substr($p, 2);\r
- break;\r
- }\r
- if (strncasecmp($line, 'Content-Type: application/x-', 28) == 0) {\r
- // ignore all application/x-... message\r
- // for example:\r
- // application/x-ms-ink => ink message\r
- $ignore = true;\r
- break;\r
- }\r
- if (strncasecmp($line, 'Content-Type: text/x-', 21) == 0) {\r
- // ignore all text/x-... message\r
- // for example:\r
- // text/x-msnmsgr-datacast => nudge, voice clip....\r
- // text/x-mms-animemoticon => customized animemotion word\r
- $ignore = true;\r
- break;\r
- }\r
- continue;\r
- }\r
- if ($sMsg !== '')\r
- $sMsg .= "\n";\r
- $sMsg .= $line;\r
- }\r
- if ($ignore)\r
- {\r
- $this->log_message("*** ingnore from $from_email: $line");\r
- break;\r
- }\r
- if ($is_p2p)\r
- {\r
- // we will ignore any p2p message after sending acknowledgement\r
- $ignore = true;\r
- $len = strlen($sMsg);\r
- $this->log_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
- break;\r
- }*/\r
- $aDwords = @unpack("V12dword", $sMsg);\r
- if (!is_array($aDwords)) {\r
- $this->log_message("*** p2p: header unpack error!");\r
- break;\r
- }\r
- $this->debug_message("*** p2p: dump received message:\n".$this->dump_binary($sMsg));\r
- $hdr_SessionID = $aDwords['dword1'];\r
- $hdr_Identifier = $aDwords['dword2'];\r
- $hdr_DataOffsetLow = $aDwords['dword3'];\r
- $hdr_DataOffsetHigh = $aDwords['dword4'];\r
- $hdr_TotalDataSizeLow = $aDwords['dword5'];\r
- $hdr_TotalDataSizeHigh = $aDwords['dword6'];\r
- $hdr_MessageLength = $aDwords['dword7'];\r
- $hdr_Flag = $aDwords['dword8'];\r
- $hdr_AckID = $aDwords['dword9'];\r
- $hdr_AckUID = $aDwords['dword10'];\r
- $hdr_AckSizeLow = $aDwords['dword11'];\r
- $hdr_AckSizeHigh = $aDwords['dword12'];\r
- $this->debug_message("*** p2p: header SessionID = $hdr_SessionID");\r
- $this->debug_message("*** p2p: header Inentifier = $hdr_Identifier");\r
- $this->debug_message("*** p2p: header Data Offset Low = $hdr_DataOffsetLow");\r
- $this->debug_message("*** p2p: header Data Offset High = $hdr_DataOffsetHigh");\r
- $this->debug_message("*** p2p: header Total Data Size Low = $hdr_TotalDataSizeLow");\r
- $this->debug_message("*** p2p: header Total Data Size High = $hdr_TotalDataSizeHigh");\r
- $this->debug_message("*** p2p: header MessageLength = $hdr_MessageLength");\r
- $this->debug_message("*** p2p: header Flag = $hdr_Flag");\r
- $this->debug_message("*** p2p: header AckID = $hdr_AckID");\r
- $this->debug_message("*** p2p: header AckUID = $hdr_AckUID");\r
- $this->debug_message("*** p2p: header AckSize Low = $hdr_AckSizeLow");\r
- $this->debug_message("*** p2p: header AckSize High = $hdr_AckSizeHigh");\r
- if($hdr_Flag==2) {\r
- //This is an ACK from SB ignore....\r
- $this->debug_message("*** p2p: //This is an ACK from SB ignore....:\n");\r
- break;\r
- }\r
- $MsgBody=$this->linetoArray(substr($sMsg,48,-4));\r
- $this->debug_message("*** p2p: body".print_r($MsgBody,true));\r
- if(($MsgBody['EUF-GUID']=='{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}')&&($PictureFilePath=$this->GetPictureFilePath($MsgBody['Context'])))\r
- {\r
- while(true)\r
- {\r
- if($this->SB_readln()===false) break;\r
- }\r
- $this->debug_message("*** p2p: Inv hdr:\n".$this->dump_binary(substr($sMsg,0,48)));\r
- preg_match('/{([0-9A-F\-]*)}/i',$MsgBody['Via'],$Matches);\r
- $BranchGUID=$Matches[1];\r
- //it's an invite to send a display picture.\r
- $new_id = ~$hdr_Identifier;\r
- $hdr = pack("LLLLLLLLLLLL", $hdr_SessionID,\r
- $new_id,\r
- 0, 0,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
- 0,\r
- 2,\r
- $hdr_Identifier,\r
- $hdr_AckID,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh);\r
- $footer = pack("L", 0);\r
- $message = "MIME-Version: 1.0\r\nContent-Type: application/x-msnmsgrp2p\r\nP2P-Dest: $from_email\r\n\r\n$hdr$footer";\r
- $len = strlen($message);\r
- $this->SB_writeln("MSG $id D $len");\r
- $id++;\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: Invite ACK Hdr:\n".$this->dump_binary($hdr));\r
- $new_id-=3;\r
- //Send 200 OK message\r
- $MessageContent="SessionID: ".$MsgBody['SessionID']."\r\n\r\n".pack("C", 0);\r
- $MessagePayload=\r
- "MSNSLP/1.0 200 OK\r\n".\r
- "To: <msnmsgr:".$from_email.">\r\n".\r
- "From: <msnmsgr:".$this->user.">\r\n".\r
- "Via: ".$MsgBody['Via']."\r\n".\r
- "CSeq: ".($MsgBody['CSeq']+1)."\r\n".\r
- "Call-ID: ".$MsgBody['Call-ID']."\r\n".\r
- "Max-Forwards: 0\r\n".\r
- "Content-Type: application/x-msnmsgr-sessionreqbody\r\n".\r
- "Content-Length: ".strlen($MessageContent)."\r\n\r\n".\r
- $MessageContent;\r
- $hdr_TotalDataSizeLow=strlen($MessagePayload);\r
- $hdr_TotalDataSizeHigh=0;\r
- $hdr = pack("LLLLLLLLLLLL", $hdr_SessionID,\r
- $new_id,\r
- 0, 0,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
- strlen($MessagePayload),\r
- 0,\r
- rand(),\r
- 0,\r
- 0,0);\r
-\r
- $message =\r
- "MIME-Version: 1.0\r\n".\r
- "Content-Type: application/x-msnmsgrp2p\r\n".\r
- "P2P-Dest: $from_email\r\n\r\n$hdr$MessagePayload$footer";\r
- $this->SB_writeln("MSG $id D ".strlen($message));\r
- $id++;\r
- $this->SB_writedata($message);\r
- $this->debug_message("*** p2p: dump 200 ok message:\n".$this->dump_binary($message));\r
- $this->SB_readln();//Read ACK;\r
- \r
- $this->debug_message("*** p2p: 200 ok:\n".$this->dump_binary($hdr));\r
- //send Data preparation message\r
- //send 4 null bytes as data\r
- $hdr_TotalDataSizeLow=4;\r
- $hdr_TotalDataSizeHigh=0;\r
- $new_id++;\r
- $hdr = pack("LLLLLLLLLLLL",\r
- $MsgBody['SessionID'],\r
- $new_id,\r
- 0, 0,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
- $hdr_TotalDataSizeLow,\r
- 0,\r
- rand(),\r
- 0,\r
- 0,0);\r
- $message =\r
- "MIME-Version: 1.0\r\n".\r
- "Content-Type: application/x-msnmsgrp2p\r\n".\r
- "P2P-Dest: $from_email\r\n\r\n$hdr".pack('L',0)."$footer";\r
- $this->SB_writeln("MSG $id D ".strlen($message));\r
- $id++;\r
- $this->SB_writedata($message);\r
- $this->debug_message("*** p2p: dump send Data preparation message:\n".$this->dump_binary($message));\r
- $this->debug_message("*** p2p: Data Prepare Hdr:\n".$this->dump_binary($hdr));\r
- $this->SB_readln();//Read ACK;\r
-\r
- //send Data Content..\r
- $footer=pack('N',1);\r
- $new_id++;\r
- $FileSize=filesize($PictureFilePath);\r
- if($hTitle=fopen($PictureFilePath,'rb'))\r
- {\r
- $Offset=0;\r
- //$new_id++;\r
- while(!feof($hTitle))\r
- {\r
- $FileContent=fread($hTitle,1024);\r
- $FileContentSize=strlen($FileContent);\r
- $hdr = pack("LLLLLLLLLLLL",\r
- $MsgBody['SessionID'],\r
- $new_id,\r
- $Offset, 0,\r
- $FileSize,0,\r
- $FileContentSize,\r
- 0x20,\r
- rand(),\r
- 0,\r
- 0,0\r
- );\r
- $message =\r
- "MIME-Version: 1.0\r\n".\r
- "Content-Type: application/x-msnmsgrp2p\r\n".\r
- "P2P-Dest: $from_email\r\n\r\n$hdr$FileContent$footer";\r
- $this->SB_writeln("MSG $id D ".strlen($message));\r
- $id++;\r
- $this->SB_writedata($message);\r
- $this->debug_message("*** p2p: dump send Data Content message $Offset / $FileSize :\n".$this->dump_binary($message));\r
- $this->debug_message("*** p2p: Data Content Hdr:\n".$this->dump_binary($hdr));\r
- //$this->SB_readln();//Read ACK;\r
- $Offset+=$FileContentSize;\r
- }\r
- }\r
- //Send Bye\r
- /*\r
- $MessageContent="\r\n".pack("C", 0);\r
- $MessagePayload=\r
- "BYE MSNMSGR:MSNSLP/1.0\r\n".\r
- "To: <msnmsgr:$from_email>\r\n".\r
- "From: <msnmsgr:".$this->user.">\r\n".\r
- "Via: MSNSLP/1.0/TLP ;branch={".$BranchGUID."}\r\n". \r
- "CSeq: 0\r\n".\r
- "Call-ID: ".$MsgBody['Call-ID']."\r\n".\r
- "Max-Forwards: 0\r\n".\r
- "Content-Type: application/x-msnmsgr-sessionclosebody\r\n".\r
- "Content-Length: ".strlen($MessageContent)."\r\n\r\n".$MessageContent;\r
- $footer=pack('N',0);\r
- $hdr_TotalDataSizeLow=strlen($MessagePayload);\r
- $hdr_TotalDataSizeHigh=0;\r
- $new_id++;\r
- $hdr = pack("LLLLLLLLLLLL", \r
- 0,\r
- $new_id,\r
- 0, 0,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
- 0,\r
- 0,\r
- rand(),\r
- 0,\r
- 0,0);\r
- $message =\r
- "MIME-Version: 1.0\r\n".\r
- "Content-Type: application/x-msnmsgrp2p\r\n".\r
- "P2P-Dest: $from_email\r\n\r\n$hdr$MessagePayload$footer";\r
- $this->SB_writeln("MSG $id D ".strlen($message));\r
- $id++;\r
- $this->SB_writedata($message);\r
- $this->debug_message("*** p2p: dump send BYE message :\n".$this->dump_binary($message));\r
- */\r
- break;\r
- }\r
- //TODO:\r
- //if ($hdr_Flag == 2) {\r
- // just send ACK...\r
- // $this->SB_writeln("ACK $id");\r
- // break;\r
- //}\r
- if ($hdr_SessionID == 4) {\r
- // ignore?\r
- $this->debug_message("*** p2p: ignore flag 4");\r
- break;\r
- }\r
- $finished = false;\r
- if ($hdr_TotalDataSizeHigh == 0) {\r
- // only 32 bites size\r
- if (($hdr_MessageLength + $hdr_DataOffsetLow) == $hdr_TotalDataSizeLow)\r
- $finished = true;\r
- }\r
- else {\r
- // we won't accept any file transfer\r
- // so I think we won't get any message size need to use 64 bits\r
- // 64 bits size here, can't count directly...\r
- $totalsize = base_convert(sprintf("%X%08X", $hdr_TotalDataSizeHigh, $hdr_TotalDataSizeLow), 16, 10);\r
- $dataoffset = base_convert(sprintf("%X%08X", $hdr_DataOffsetHigh, $hdr_DataOffsetLow), 16, 10);\r
- $messagelength = base_convert(sprintf("%X", $hdr_MessageLength), 16, 10);\r
- $now_size = bcadd($dataoffset, $messagelength);\r
- if (bccomp($now_size, $totalsize) >= 0)\r
- $finished = true;\r
- }\r
- if (!$finished) {\r
- // ignore not finished split packet\r
- $this->debug_message("*** p2p: ignore split packet, not finished");\r
- break;\r
- }\r
- //$new_id = ~$hdr_Identifier;\r
- /*\r
- $new_id++;\r
- $hdr = pack("LLLLLLLLLLLL", $hdr_SessionID,\r
- $new_id,\r
- 0, 0,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh,\r
- 0,\r
- 2,\r
- $hdr_Identifier,\r
- $hdr_AckID,\r
- $hdr_TotalDataSizeLow, $hdr_TotalDataSizeHigh);\r
- $footer = pack("L", 0);\r
- $message = "MIME-Version: 1.0\r\nContent-Type: application/x-msnmsgrp2p\r\nP2P-Dest: $from_email\r\n\r\n$hdr$footer";\r
- $len = strlen($message);\r
- $this->SB_writeln("MSG $id D $len");\r
- $id++;\r
- $this->SB_writedata($message);\r
- $this->log_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->ReceivedMessage($from_email,$sMsg,$network,false);\r
- break;\r
- case '217':\r
- $this->log_message("*** User $user is offline. Try OIM.");\r
- foreach($this->SwitchBoardMessageQueue as $Message)\r
- $this->SendMessage($Message,"$user@Offline");\r
- $SessionEnd=true;\r
- break;\r
- default:\r
- if (is_numeric($code))\r
- {\r
- $this->error = "Error code: $code, please check the detail information from: http://msnpiki.msnfanatic.com/index.php/Reference:Error_List";\r
- $this->debug_message("*** SB: $this->error");\r
- $SessionEnd=true;\r
- }\r
- break;\r
- }\r
- $LastActive = time();\r
- }\r
- if (feof($this->SBFp))\r
- {\r
- // lost connection? error? try OIM later\r
- @fclose($this->SBFp);\r
- return false;\r
- }\r
- $this->SB_writeln("OUT");\r
- @fclose($this->SBFp);\r
- return true;\r
- }\r
- private function switchboard_control($ip, $port, $cki_code, $user, $Messages)\r
- {\r
- $this->SwitchBoardProcess=1;\r
- $this->debug_message("*** SB: try to connect to switchboard server $ip:$port");\r
- $this->SBFp = @fsockopen($ip, $port, $errno, $errstr, 5);\r
- if (!$this->SBFp)\r
- {\r
- $this->debug_message("*** SB: Can't connect to $ip:$port, error => $errno, $errstr");\r
- return false;\r
- }\r
- return $this->DoSwitchBoard('Active',array('cki'=>$cki_code, 'user'=>$user,'Msg'=>$Messages));\r
- }\r
- private function switchboard_ring($ip, $port, $sid, $ticket,$user)\r
- {\r
- $this->SwitchBoardProcess=2;\r
- $this->debug_message("*** SB: try to connect to switchboard server $ip:$port");\r
- $this->SBFp = @fsockopen($ip, $port, $errno, $errstr, 5);\r
- if (!$this->SBFp)\r
- {\r
- $this->debug_message("*** SB: Can't connect to $ip:$port, error => $errno, $errstr");\r
- return false;\r
- }\r
- return $this->DoSwitchBoard('Passive',array('sid'=>$sid,'user'=>$user,'ticket'=>$ticket));\r