port = "5222"; $this->resource = NULL; $this->packet_queue = $this->subscription_queue = array(); $this->iq_sleep_timer = $this->delay_disconnect = 1; $this->returned_keep_alive = TRUE; $this->txnid = 0; $this->iq_version_name = "Class.Jabber.PHP -- http://phpjabber.g-blog.net -- by Carlo 'Gossip' Zottmann, gossip@jabber.g-blog.net"; $this->iq_version_version = '0.4'; $this->iq_version_os = $_SERVER['SERVER_SOFTWARE']; $this->error_codes = array(400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Not Allowed', 406 => 'Not Acceptable', 407 => 'Registration Required', 408 => 'Request Timeout', 409 => 'Conflict', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Remove Server Error', 503 => 'Service Unavailable', 504 => 'Remove Server Timeout', 510 => 'Disconnected'); } function Connect() { $this->CONNECTOR = new CJP_StandardConnector; if ($this->CONNECTOR->OpenSocket($this->server, $this->port)) { $this->SendPacket("\n"); $this->SendPacket("\n"); sleep(2); if ($this->_check_connected()) { $this->connected = TRUE; // Nathan Fritz return TRUE; } else { return FALSE; } } else { return FALSE; } } function Disconnect() { if (is_int($this->delay_disconnect)) { sleep($this->delay_disconnect); } $this->SendPacket(''); $this->CONNECTOR->CloseSocket(); } function SendAuth() { $this->auth_id = 'auth_' . md5(time() . $_SERVER['REMOTE_ADDR']); $this->resource = 'Class.Jabber.PHP ' . md5($this->auth_id); $this->jid = "{$this->username}@{$this->server}/{$this->resource}"; // request available authentication methods $payload = "{$this->username}"; $packet = $this->SendIq(NULL, 'get', $this->auth_id, 'jabber:iq:auth', $payload); // was a result returned? if ($this->GetInfoFromIqType($packet) == 'result' && $this->GetInfoFromIqId($packet) == $this->auth_id) { // auth_0k if (@function_exists(mhash) && isset($packet['iq']['#']['query'][0]['#']['sequence'][0]["#"]) && isset($packet['iq']['#']['query'][0]['#']['token'][0]["#"])) { return $this->_sendauth_0k($packet['iq']['#']['query'][0]['#']['token'][0]["#"], $packet['iq']['#']['query'][0]['#']['sequence'][0]["#"]); } // digest elseif (@function_exists(mhash) && isset($packet['iq']['#']['query'][0]['#']['digest'])) { return $this->_sendauth_digest(); } // plain text elseif ($packet['iq']['#']['query'][0]['#']['password']) { return $this->_sendauth_plaintext(); } } else { // no result returned return FALSE; } } function AccountRegistration($reg_email = NULL, $reg_name = NULL) { $packet = $this->SendIq($this->server, 'get', 'reg_01', 'jabber:iq:register'); if ($packet) { $key = $this->GetInfoFromIqKey($packet); // just in case a key was passed back from the server unset($packet); $payload = "{$this->username} {$this->password} $reg_email $reg_name\n"; $payload .= ($key) ? "$key\n" : ''; $packet = $this->SendIq($this->server, 'set', 'reg_01', 'jabber:iq:register', $payload); if ($this->GetInfoFromIqType($packet) == 'result') { $return_code = (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) ? 1 : 2; $this->jid = ($this->resource) ? "{$this->username}@{$this->server}/{$this->resource}" : "{$this->username}@{$this->server}"; } elseif ($this->GetInfoFromIqType($packet) == 'error' && isset($packet['iq']['#']['error'][0]['#'])) { // "conflict" error, i.e. already registered if ($packet['iq']['#']['error'][0]['@']['code'] == '409') { $return_code = 1; } else { $return_code = 'Error ' . $packet['iq']['#']['error'][0]['@']['code'] . ': ' . $packet['iq']['#']['error'][0]['#']; } } return $return_code; } else { return 3; } } function SendPacket($xml) { $xml = trim($xml); return ($this->CONNECTOR->WriteToSocket($xml)) ? TRUE : FALSE; } function Listen() { unset($incoming); while ($line = $this->CONNECTOR->ReadFromSocket(4096)) { $incoming .= $line; } $incoming = trim($incoming); if ($incoming != '') { $temp = $this->_split_incoming($incoming); for ($a = 0; $a < count($temp); $a++) { $this->packet_queue[] = $this->xmlize($temp[$a]); } } return TRUE; } function StripJID($jid = NULL) { preg_match('#(.*)\/(.*)#Ui', $jid, $temp); return ($temp[1] != '') ? $temp[1] : $jid; } function SendMessage($to, $type = 'normal', $id = NULL, $content = NULL, $payload = NULL) { if ($to && is_array($content)) { if (!$id) { $id = $type . '_' . time(); } $content = $this->_array_htmlspecialchars($content); $xml = "\n"; if ($content['subject']) { $xml .= '' . $content['subject'] . "\n"; } if ($content['thread']) { $xml .= '' . $content['thread'] . "\n"; } $xml .= '' . $content['body'] . "\n"; $xml .= $payload; $xml .= "\n"; if ($this->SendPacket($xml)) { return TRUE; } else { return FALSE; } } else { return FALSE; } } function SendError($to, $id = NULL, $error_number, $error_message = NULL) { $xml = "error_codes[$error_number]; $xml .= "\n"; $xml .= ''; $this->SendPacket($xml); } function GetFirstFromQueue() { return array_shift($this->packet_queue); } function GetFromQueueById($packet_type, $id) { $found_message = FALSE; foreach ($this->packet_queue as $key => $value) { if ($value[$packet_type]['@']['id'] == $id) { $found_message = $value; unset($this->packet_queue[$key]); break; } } return (is_array($found_message)) ? $found_message : FALSE; } function CallHandler($packet = NULL) { $packet_type = $this->_get_packet_type($packet); if ($packet_type == 'message') { $type = $packet['message']['@']['type']; $type = ($type != '') ? $type : 'normal'; $funcmeth = "Handler_message_$type"; } elseif ($packet_type == 'iq') { $namespace = $packet['iq']['#']['query'][0]['@']['xmlns']; $namespace = str_replace(':', '_', $namespace); $funcmeth = "Handler_iq_$namespace"; } elseif ($packet_type == 'presence') { $type = $packet['presence']['@']['type']; $type = ($type != '') ? $type : 'available'; $funcmeth = "Handler_presence_$type"; } if ($funcmeth != '') { if (function_exists($funcmeth)) { call_user_func($funcmeth, $packet); } elseif (method_exists($this, $funcmeth)) { call_user_func(array(&$this, $funcmeth), $packet); } else { $this->Handler_NOT_IMPLEMENTED($packet); } } } function SendIq($to = NULL, $type = 'get', $id = NULL, $xmlns = NULL, $payload = NULL, $from = NULL) { if (!preg_match('#^(get|set|result|error)$#', $type)) { unset($type); return FALSE; } elseif ($id && $xmlns) { $xml = "SendPacket($xml); sleep($this->iq_sleep_timer); $this->Listen(); return (preg_match('#^(get|set)$#', $type)) ? $this->GetFromQueueById('iq', $id) : TRUE; } else { return FALSE; } } // get the transport registration fields // method written by Steve Blinch, http://www.blitzaffe.com function TransportRegistrationDetails($transport) { $this->txnid++; $packet = $this->SendIq($transport, 'get', "reg_{$this->txnid}", 'jabber:iq:register', NULL, $this->jid); if ($packet) { $res = array(); foreach ($packet['iq']['#']['query'][0]['#'] as $element => $data) { if ($element != 'instructions' && $element != 'key') { $res[] = $element; } } return $res; } else { return 3; } } // register with the transport // method written by Steve Blinch, http://www.blitzaffe.com function TransportRegistration($transport, $details) { $this->txnid++; $packet = $this->SendIq($transport, 'get', "reg_{$this->txnid}", 'jabber:iq:register', NULL, $this->jid); if ($packet) { $key = $this->GetInfoFromIqKey($packet); // just in case a key was passed back from the server unset($packet); $payload = ($key) ? "$key\n" : ''; foreach ($details as $element => $value) { $payload .= "<$element>$value\n"; } $packet = $this->SendIq($transport, 'set', "reg_{$this->txnid}", 'jabber:iq:register', $payload); if ($this->GetInfoFromIqType($packet) == 'result') { if (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) { $return_code = 1; } else { $return_code = 2; } } elseif ($this->GetInfoFromIqType($packet) == 'error') { if (isset($packet['iq']['#']['error'][0]['#'])) { $return_code = "Error " . $packet['iq']['#']['error'][0]['@']['code'] . ': ' . $packet['iq']['#']['error'][0]['#']; } } return $return_code; } else { return 3; } } // ====================================================================== // private methods // ====================================================================== function _sendauth_0k($zerok_token, $zerok_sequence) { // initial hash of password $zerok_hash = @mhash(MHASH_SHA1, $this->password); $zerok_hash = bin2hex($zerok_hash); // sequence 0: hash of hashed-password and token $zerok_hash = @mhash(MHASH_SHA1, $zerok_hash . $zerok_token); $zerok_hash = bin2hex($zerok_hash); // repeat as often as needed for ($a = 0; $a < $zerok_sequence; $a++) { $zerok_hash = @mhash(MHASH_SHA1, $zerok_hash); $zerok_hash = bin2hex($zerok_hash); } $payload = "{$this->username} $zerok_hash {$this->resource}"; $packet = $this->SendIq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); // was a result returned? return ($this->GetInfoFromIqType($packet) == 'result' && $this->GetInfoFromIqId($packet) == $this->auth_id) ? TRUE : FALSE; } function _sendauth_digest() { $payload = "{$this->username} {$this->resource} " . bin2hex(mhash(MHASH_SHA1, $this->stream_id . $this->password)) . ""; $packet = $this->SendIq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); // was a result returned? return ($this->GetInfoFromIqType($packet) == 'result' && $this->GetInfoFromIqId($packet) == $this->auth_id) ? TRUE : FALSE; } function _sendauth_plaintext() { $payload = "{$this->username} {$this->password} {$this->resource}"; $packet = $this->SendIq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); // was a result returned? return ($this->GetInfoFromIqType($packet) == 'result' && $this->GetInfoFromIqId($packet) == $this->auth_id) ? TRUE : FALSE; } function _listen_incoming() { unset($incoming); while ($line = $this->CONNECTOR->ReadFromSocket(4096)) { $incoming .= $line; } $incoming = trim($incoming); return $this->xmlize($incoming); } function _check_connected() { $incoming_array = $this->_listen_incoming(); if (is_array($incoming_array)) { if ($incoming_array['stream:stream']['@']['from'] == $this->server && $incoming_array['stream:stream']['@']['xmlns'] == 'jabber:client' && $incoming_array['stream:stream']['@']['xmlns:stream'] == 'http://etherx.jabber.org/streams') { $this->stream_id = $incoming_array['stream:stream']['@']['id']; return TRUE; } else { return FALSE; } } else { return FALSE; } } function _split_incoming($incoming) { $temp = preg_split('#<(message|iq|presence|stream)#', $incoming, -1, PREG_SPLIT_DELIM_CAPTURE); $array = array(); for ($a = 1; $a < count($temp); $a = $a + 2) { $array[] = '<' . $temp[$a] . $temp[($a + 1)]; } return $array; } function _get_packet_type($packet = NULL) { if (is_array($packet)) { reset($packet); $packet_type = key($packet); } return ($packet_type) ? $packet_type : FALSE; } // _array_htmlspecialchars() // applies htmlspecialchars() to all values in an array function _array_htmlspecialchars(&$array) { if (is_array($array)) { foreach ($array as $k => $v) { $v = (is_array($v)) ? $this->_array_htmlspecialchars($v) : htmlspecialchars($v); } } return $array; } // ====================================================================== // parsers // ====================================================================== function GetInfoFromMessageFrom($packet = NULL) { return (is_array($packet)) ? $packet['message']['@']['from'] : FALSE; } function GetInfoFromMessageType($packet = NULL) { return (is_array($packet)) ? $packet['message']['@']['type'] : FALSE; } function GetInfoFromMessageId($packet = NULL) { return (is_array($packet)) ? $packet['message']['@']['id'] : FALSE; } function GetInfoFromMessageThread($packet = NULL) { return (is_array($packet)) ? $packet['message']['#']['thread'][0]['#'] : FALSE; } function GetInfoFromMessageSubject($packet = NULL) { return (is_array($packet)) ? $packet['message']['#']['subject'][0]['#'] : FALSE; } function GetInfoFromMessageBody($packet = NULL) { return (is_array($packet)) ? $packet['message']['#']['body'][0]['#'] : FALSE; } function GetInfoFromMessageError($packet = NULL) { $error = preg_replace('#^\/$#', '', ($packet['message']['#']['error'][0]['@']['code'] . '/' . $packet['message']['#']['error'][0]['#'])); return (is_array($packet)) ? $error : FALSE; } // ====================================================================== // parsers // ====================================================================== function GetInfoFromIqFrom($packet = NULL) { return (is_array($packet)) ? $packet['iq']['@']['from'] : FALSE; } function GetInfoFromIqType($packet = NULL) { return (is_array($packet)) ? $packet['iq']['@']['type'] : FALSE; } function GetInfoFromIqId($packet = NULL) { return (is_array($packet)) ? $packet['iq']['@']['id'] : FALSE; } function GetInfoFromIqKey($packet = NULL) { return (is_array($packet)) ? $packet['iq']['#']['query'][0]['#']['key'][0]['#'] : FALSE; } function GetInfoFromIqError($packet = NULL) { $error = preg_replace('#^\/$#', '', ($packet['iq']['#']['error'][0]['@']['code'] . '/' . $packet['iq']['#']['error'][0]['#'])); return (is_array($packet)) ? $error : FALSE; } // ====================================================================== // handlers // ====================================================================== function Handler_message_normal($packet) { $from = $packet['message']['@']['from']; } function Handler_message_error($packet) { $from = $packet['message']['@']['from']; } // ====================================================================== // handlers // ====================================================================== // simple client authentication function Handler_iq_jabber_iq_auth($packet) { $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $this->SendError($from, $id, 501); } // method for interactive registration function Handler_iq_jabber_iq_register($packet) { $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $this->SendError($from, $id, 501); } // keepalive method, added by Nathan Fritz function Handler_iq_($packet) { if ($this->keep_alive_id == $this->GetInfoFromIqId($packet)) { $this->returned_keep_alive = TRUE; } } // ====================================================================== // Generic handlers // ====================================================================== // Generic handler for unsupported requests function Handler_NOT_IMPLEMENTED($packet) { $packet_type = $this->_get_packet_type($packet); $from = call_user_func(array(&$this, 'GetInfoFrom' . ucfirst($packet_type) . 'From'), $packet); $id = call_user_func(array(&$this, 'GetInfoFrom' . ucfirst($packet_type) . 'Id'), $packet); $this->SendError($from, $id, 501); } // Third party code // m@d pr0ps to the coders ;) // xmlize() // (c) Hans Anderson / http://www.hansanderson.com/php/xml/ function xmlize($data) { $vals = $index = $array = array(); $parser = @xml_parser_create(); @xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); @xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); @xml_parse_into_struct($parser, $data, $vals, $index); @xml_parser_free($parser); $i = 0; $tagname = $vals[$i]['tag']; $array[$tagname]['@'] = $vals[$i]['attributes']; $array[$tagname]['#'] = $this->_xml_depth($vals, $i); return $array; } // _xml_depth() // (c) Hans Anderson / http://www.hansanderson.com/php/xml/ function _xml_depth($vals, &$i) { $children = array(); if ($vals[$i]['value']) { array_push($children, trim($vals[$i]['value'])); } while (++$i < count($vals)) { switch ($vals[$i]['type']) { case 'cdata': array_push($children, trim($vals[$i]['value'])); break; case 'complete': $tagname = $vals[$i]['tag']; $size = sizeof($children[$tagname]); $children[$tagname][$size]['#'] = trim($vals[$i]['value']); if ($vals[$i]['attributes']) { $children[$tagname][$size]['@'] = $vals[$i]['attributes']; } break; case 'open': $tagname = $vals[$i]['tag']; $size = sizeof($children[$tagname]); if ($vals[$i]['attributes']) { $children[$tagname][$size]['@'] = $vals[$i]['attributes']; $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i); } else { $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i); } break; case 'close': return $children; break; } } return $children; } // TraverseXMLize() // (c) acebone@f2s.com, a HUGE help! function TraverseXMLize($array, $arrName = 'array', $level = 0) { if ($level == 0) { echo '
';
		}

		while (list($key, $val) = @each($array))
		{
			if (is_array($val))
			{
				$this->TraverseXMLize($val, $arrName . '[' . $key . ']', $level + 1);
			}
			else
			{
				echo '$' . $arrName . '[' . $key . '] = "' . $val . "\"\n";
			}
		}

		if ($level == 0)
		{
			echo '
'; } } } // class MakeXML extends Jabber { var $nodes; function MakeXML() { $nodes = array(); } function AddPacketDetails($string, $value = NULL) { if (preg_match('#\(([0-9]*)\)$#i', $string)) { $string .= '/["#"]'; } $temp = @explode('/', $string); for ($a = 0; $a < count($temp); $a++) { $temp[$a] = preg_replace('#^[@]{1}([a-z0-9_]*)$#i', '["@"]["\1"]', $temp[$a]); $temp[$a] = preg_replace('#^([a-z0-9_]*)\(([0-9]*)\)$/i', '["\1"][\2]', $temp[$a]); $temp[$a] = preg_replace('#^([a-z0-9_]*)$#i', '["\1"]', $temp[$a]); } $node = implode('', $temp); // Yeahyeahyeah, I know it's ugly... get over it. ;) echo '$this->nodes' . $node . ' = "' . htmlspecialchars($value) . '";
'; eval('$this->nodes' . $node . ' = "' . htmlspecialchars($value) . '";'); } function BuildPacket($array = NULL) { if (!$array) { $array = $this->nodes; } if (is_array($array)) { array_multisort($array, SORT_ASC, SORT_STRING); foreach ($array as $key => $value) { if (is_array($value) && $key == '@') { foreach ($value as $subkey => $subvalue) { $subvalue = htmlspecialchars($subvalue); $text .= " $subkey='$subvalue'"; } $text .= ">\n"; } elseif ($key == '#') { $text .= htmlspecialchars($value); } elseif (is_array($value)) { for ($a = 0; $a < count($value); $a++) { $text .= "<$key"; if (!$this->_preg_grep_keys('#^@#', $value[$a])) { $text .= '>'; } $text .= $this->BuildPacket($value[$a]); $text .= "\n"; } } else { $value = htmlspecialchars($value); $text .= "<$key>$value\n"; } } return $text; } } function _preg_grep_keys($pattern, $array) { foreach ($array as $key => $val) { if (preg_match($pattern, $key)) { $newarray[$key] = $val; } } return (is_array($newarray)) ? $newarray : FALSE; } } // class CJP_StandardConnector { var $active_socket; function OpenSocket($server, $port) { if ($this->active_socket = @fsockopen($server, $port, $err, $err2, 5)) { @socket_set_blocking($this->active_socket, 0); @socket_set_timeout($this->active_socket, 31536000); return TRUE; } else { return FALSE; } } function CloseSocket() { return @fclose($this->active_socket); } function WriteToSocket($data) { return @fwrite($this->active_socket, $data); } function ReadFromSocket($chunksize) { $buffer = @fread($this->active_socket, $chunksize); @set_magic_quotes_runtime(get_magic_quotes_gpc()); return $buffer; } } ?>