/** * @param ProtocolNode $node */ protected function writeInternal($node) { $len = 1; if ($node->getAttributes() != null) { $len += count($node->getAttributes()) * 2; } if (count($node->getChildren()) > 0) { $len += 1; } if (strlen($node->getData()) > 0) { $len += 1; } $this->writeListStart($len); $this->writeString($node->getTag()); $this->writeAttributes($node->getAttributes()); if (strlen($node->getData()) > 0) { $this->writeBytes($node->getData()); } if ($node->getChildren()) { $this->writeListStart(count($node->getChildren())); foreach ($node->getChildren() as $child) { $this->writeInternal($child); } } }
/** * Will process the data from the server after it's been decrypted and parsed. * * This also provides a convenient method to use to unit test the event framework. * */ protected function processInboundDataNode(ProtocolNode $node, $autoReceipt = true) { $this->debugPrint($node->nodeString("rx ") . "\n"); $this->serverReceivedId = $node->getAttribute('id'); if ($node->getTag() == "challenge") { $this->processChallenge($node); } elseif ($node->getTag() == "failure") { $this->loginStatus = static::DISCONNECTED_STATUS; } elseif ($node->getTag() == "success") { $this->loginStatus = static::CONNECTED_STATUS; $challengeData = $node->getData(); file_put_contents($this->challengeFilename, $challengeData); $this->writer->setKey($this->outputKey); } elseif ($node->getTag() == "failure") { $this->eventManager()->fireLoginFailed($this->phoneNumber, $node->getChild(0)->getTag()); } elseif ($node->getTag() == '' && $node->getAttribute("class") == "message") { $this->eventManager()->fireMessageReceivedServer($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('class')); } elseif ($node->getTag() == 'receipt') { $this->eventManager()->fireMessageReceivedClient($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('class'), $node->getAttribute('t')); } if ($node->getTag() == "message") { array_push($this->messageQueue, $node); if ($node->hasChild('x') && $this->lastId == $node->getAttribute('id')) { $this->sendNextMessage(); } if ($this->newMsgBind && $node->getChild('body')) { $this->newMsgBind->process($node); } if ($node->getAttribute("type") == "text" && $node->getChild('body') != null) { $author = $node->getAttribute("participant"); if ($author == "") { //private chat message $this->eventManager()->fireGetMessage($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute("notify"), $node->getChild("body")->getData()); } else { //group chat message $this->eventManager()->fireGetGroupMessage($this->phoneNumber, $node->getAttribute('from'), $author, $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute("notify"), $node->getChild("body")->getData()); } if ($autoReceipt) { $this->sendMessageReceived($node); } } if ($node->getAttribute("type") == "media" && $node->getChild('media') != null) { if ($node->getChild("media")->getAttribute('type') == 'image') { $this->eventManager()->fireGetImage($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('notify'), $node->getChild("media")->getAttribute('size'), $node->getChild("media")->getAttribute('url'), $node->getChild("media")->getAttribute('file'), $node->getChild("media")->getAttribute('mimetype'), $node->getChild("media")->getAttribute('filehash'), $node->getChild("media")->getAttribute('width'), $node->getChild("media")->getAttribute('height'), $node->getChild("media")->getData()); } elseif ($node->getChild("media")->getAttribute('type') == 'video') { $this->eventManager()->fireGetVideo($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('notify'), $node->getChild("media")->getAttribute('url'), $node->getChild("media")->getAttribute('file'), $node->getChild("media")->getAttribute('size'), $node->getChild("media")->getAttribute('mimetype'), $node->getChild("media")->getAttribute('filehash'), $node->getChild("media")->getAttribute('duration'), $node->getChild("media")->getAttribute('vcodec'), $node->getChild("media")->getAttribute('acodec'), $node->getChild("media")->getData()); } elseif ($node->getChild("media")->getAttribute('type') == 'audio') { $this->eventManager()->fireGetAudio($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('notify'), $node->getChild("media")->getAttribute('size'), $node->getChild("media")->getAttribute('url'), $node->getChild("media")->getAttribute('file'), $node->getChild("media")->getAttribute('mimetype'), $node->getChild("media")->getAttribute('filehash'), $node->getChild("media")->getAttribute('duration'), $node->getChild("media")->getAttribute('acodec')); } elseif ($node->getChild("media")->getAttribute('type') == 'vcard') { $this->eventManager()->fireGetvCard($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('notify'), $node->getChild("media")->getChild("vcard")->getAttribute('name'), $node->getChild("media")->getChild("vcard")->getData()); } elseif ($node->getChild("media")->getAttribute('type') == 'location') { $url = $node->getChild("media")->getAttribute('url'); $name = $node->getChild("media")->getAttribute('name'); $this->eventManager()->fireGetLocation($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('notify'), $name, $node->getChild("media")->getAttribute('longitude'), $node->getChild("media")->getAttribute('latitude'), $url, $node->getChild("media")->getData()); } if ($autoReceipt) { $this->sendMessageReceived($node); } } if ($node->getChild('received') != null) { $this->eventManager()->fireMessageReceivedClient($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t')); } } if ($node->getTag() == "presence" && $node->getAttribute("status") == "dirty") { //clear dirty $categories = array(); if (count($node->getChildren()) > 0) { foreach ($node->getChildren() as $child) { if ($child->getTag() == "category") { $categories[] = $child->getAttribute("name"); } } } $this->sendClearDirty($categories); } if (strcmp($node->getTag(), "presence") == 0 && strncmp($node->getAttribute('from'), $this->phoneNumber, strlen($this->phoneNumber)) != 0 && strpos($node->getAttribute('from'), "-") == false) { $presence = array(); if ($node->getAttribute('type') == null) { $this->eventManager()->firePresence($this->phoneNumber, $node->getAttribute('from'), $presence['type'] = "available"); } else { $this->eventManager()->firePresence($this->phoneNumber, $node->getAttribute('from'), $presence['type'] = "unavailable"); } } if ($node->getTag() == "presence" && strncmp($node->getAttribute('from'), $this->phoneNumber, strlen($this->phoneNumber)) != 0 && strpos($node->getAttribute('from'), "-") !== false && $node->getAttribute('type') != null) { $groupId = self::parseJID($node->getAttribute('from')); if ($node->getAttribute('add') != null) { $this->eventManager()->fireGroupsParticipantsAdd($this->phoneNumber, $groupId, self::parseJID($node->getAttribute('add'))); } elseif ($node->getAttribute('remove') != null) { $this->eventManager()->fireGroupsParticipantsRemove($this->phoneNumber, $groupId, self::parseJID($node->getAttribute('remove')), self::parseJID($node->getAttribute('author'))); } } if (strcmp($node->getTag(), "chatstate") == 0 && strncmp($node->getAttribute('from'), $this->phoneNumber, strlen($this->phoneNumber)) != 0 && strpos($node->getAttribute('from'), "-") == false) { if ($node->getChild(0)->getTag() == "composing") { $this->eventManager()->fireMessageComposing($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), "composing", $node->getAttribute('t')); } else { $this->eventManager()->fireMessagePaused($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), "paused", $node->getAttribute('t')); } } if ($node->getTag() == "iq" && $node->getAttribute('type') == "get" && $node->getAttribute('xmlns') == "urn:xmpp:ping") { $this->eventManager()->firePing($this->phoneNumber, $node->getAttribute('id')); $this->sendPong($node->getAttribute('id')); } if ($node->getTag() == "iq" && $node->getChild("sync") != null) { //sync result $sync = $node->getChild('sync'); $existing = $sync->getChild("in"); $nonexisting = $sync->getChild("out"); //process existing first $existingUsers = array(); if (!empty($existing)) { foreach ($existing->getChildren() as $child) { $existingUsers[$child->getData()] = $child->getAttribute("jid"); } } //now process failed numbers $failedNumbers = array(); if (!empty($nonexisting)) { foreach ($nonexisting->getChildren() as $child) { $failedNumbers[] = str_replace('+', '', $child->getData()); } } $index = $sync->getAttribute("index"); $result = new SyncResult($index, $sync->getAttribute("sync"), $existingUsers, $failedNumbers); $this->eventManager()->fireGetSyncResult($result); } if ($node->getTag() == "receipt") { $this->eventManager()->fireGetReceipt($node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('offline'), $node->getAttribute('retry')); } if ($node->getTag() == "iq" && $node->getAttribute('type') == "result") { if ($node->getChild("query") != null) { if ($node->getChild(0)->getAttribute('xmlns') == 'jabber:iq:privacy') { // ToDo: We need to get explicitly list out the children as arguments // here. $this->eventManager()->fireGetPrivacyBlockedList($this->phoneNumber, $node->getChild(0)->getChild(0)->getChildren()); } $this->eventManager()->fireGetRequestLastSeen($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getChild(0)->getAttribute('seconds')); array_push($this->messageQueue, $node); } if ($node->getChild("props") != null) { //server properties $props = array(); foreach ($node->getChild(0)->getChildren() as $child) { $props[$child->getAttribute("name")] = $child->getAttribute("value"); } $this->eventManager()->fireGetServerProperties($this->phoneNumber, $node->getChild(0)->getAttribute("version"), $props); } if ($node->getChild("picture") != null) { $this->eventManager()->fireGetProfilePicture($this->phoneNumber, $node->getAttribute("from"), $node->getChild("picture")->getAttribute("type"), $node->getChild("picture")->getData()); } if ($node->getChild("media") != null || $node->getChild("duplicate") != null) { $this->processUploadResponse($node); } if ($node->nodeIdContains("group")) { //There are multiple types of Group reponses. Also a valid group response can have NO children. //Events fired depend on text in the ID field. $groupList = array(); if ($node->getChild(0) != null) { foreach ($node->getChildren() as $child) { $groupList[] = $child->getAttributes(); } } if ($node->nodeIdContains('creategroup')) { $this->groupId = $node->getChild(0)->getAttribute('id'); $this->eventManager()->fireGroupsChatCreate($this->phoneNumber, $this->groupId); } if ($node->nodeIdContains('endgroup')) { $this->groupId = $node->getChild(0)->getChild(0)->getAttribute('id'); $this->eventManager()->fireGroupsChatEnd($this->phoneNumber, $this->groupId); } if ($node->nodeIdContains('getgroups')) { $this->eventManager()->fireGetGroups($this->phoneNumber, $groupList); } if ($node->nodeIdContains('getgroupinfo')) { $this->eventManager()->fireGetGroupsInfo($this->phoneNumber, $groupList); } if ($node->nodeIdContains('getgroupparticipants')) { $groupId = self::parseJID($node->getAttribute('from')); $this->eventManager()->fireGetGroupParticipants($this->phoneNumber, $groupId, $groupList); } } if ($node->getChild("status") != null) { $child = $node->getChild("status"); foreach ($child->getChildren() as $status) { $this->eventManager()->fireGetStatus($this->phoneNumber, $status->getAttribute("jid"), "requested", $node->getAttribute("id"), $status->getAttribute("t"), $status->getData()); } } } if ($node->getTag() == "iq" && $node->getAttribute('type') == "error") { $this->eventManager()->fireGetError($this->phoneNumber, $node->getAttribute('id'), $node->getChild(0)); } $children = $node->getChild(0); if ($node->getTag() == "stream:error" && empty($children) == false && $node->getChild(0)->getTag() == "system-shutdown") { throw new Exception('Error system-shutdown'); } if ($node->getTag() == "notification") { $name = $node->getAttribute("notify"); $type = $node->getAttribute("type"); switch ($type) { case "status": $this->eventManager()->fireGetStatus($this->phoneNumber, $node->getAttribute("from"), $node->getChild(0)->getTag(), $node->getAttribute("id"), $node->getAttribute("t"), $node->getChild(0)->getData()); //status message break; case "picture": if ($node->hasChild('set')) { $this->eventManager()->fireProfilePictureChanged($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('t')); } else { if ($node->hasChild('delete')) { $this->eventManager()->fireProfilePictureDeleted($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('t')); } } //TODO break; case "contacts": //TODO break; case "participant": if ($node->hasChild('remove')) { $this->eventManager()->fireGroupsParticipantsRemove($this->phoneNumber, $node->getAttribute('from'), $node->getChild(0)->getAttribute('jid'), $node->getChild(0)->getAttribute('author')); } else { if ($node->hasChild('add')) { $this->eventManager()->fireGroupsParticipantsAdd($this->phoneNumber, $node->getAttribute('from'), $node->getChild(0)->getAttribute('jid')); } } //TODO break; case "subject": $this->eventManager()->fireGetGroupsSubject($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('t'), $node->getAttribute('participant'), $node->getAttribute('participant'), $node->getAttribute('notify'), $node->getChild(0)->getData()); //TODO break; default: throw new Exception("Method {$type} not implemented"); } $this->sendNotificationAck($node); } if ($node->getTag() == "ib") { foreach ($node->getChildren() as $child) { switch ($child->getTag()) { case "dirty": $this->sendClearDirty(array($child->getAttribute("type"))); break; case "offline": break; default: throw new Exception("ib handler for " . $child->getTag() . " not implemented"); } } } if ($node->getTag() == "ack") { ////on get ack } }
/** * Send node to the servers. * * @param $to * @param ProtocolNode $node * @param null $id * * @return string Message ID. */ protected function sendMessageNode($to, $node, $id = null) { $msgId = $id == null ? $this->createMsgId() : $id; $to = $this->getJID($to); $messageNode = new ProtocolNode("message", array('to' => $to, 'type' => $node->getTag() == "body" ? 'text' : 'media', 'id' => $msgId, 't' => time()), array($node), ""); $this->sendNode($messageNode); $this->eventManager()->fire("onSendMessage", array($this->phoneNumber, $to, $msgId, $node)); $this->waitForServer($msgId); return $msgId; }
/** * Send node to the servers. * * @param $to * @param ProtocolNode $node * @param null $id * * @return string Message ID. */ protected function sendMessageNode($to, $node, $id = null) { $msgId = $id == null ? $this->createMsgId() : $id; $to = $this->getJID($to); if ($node->getTag() == "body" || $node->getTag() == "enc") { $type = 'text'; } else { $type = 'media'; } $messageNode = new ProtocolNode("message", array('to' => $to, 'type' => $type, 'id' => $msgId, 't' => time(), 'notify' => $this->name), array($node), ""); $this->sendNode($messageNode); $this->logFile('info', '{type} message with id {id} sent to {to}', array('type' => $type, 'id' => $msgId, 'to' => ExtractNumber($to))); $this->eventManager()->fire("onSendMessage", array($this->phoneNumber, $to, $msgId, $node)); $this->waitForServer($msgId); return $msgId; }
/** * Send node to the servers. * * @param $to * @param ProtocolNode $node * @param null $id * * @return string Message ID. */ protected function sendMessageNode($to, $node, $id = null, $plaintextNode = null) { $msgId = $id == null ? $this->createMsgId() : $id; $to = $this->getJID($to); if ($node->getTag() == 'body' || $node->getTag() == 'enc') { $type = 'text'; } else { $type = 'media'; } $messageNode = new ProtocolNode('message', ['to' => $to, 'type' => $type, 'id' => $msgId, 't' => time(), 'notify' => $this->name], [$node], ''); $this->sendNode($messageNode); if ($node->getTag() == 'enc') { $node = $plaintextNode; } $this->logFile('info', '{type} message with id {id} sent to {to}', ['type' => $type, 'id' => $msgId, 'to' => ExtractNumber($to)]); $this->eventManager()->fire('onSendMessage', [$this->phoneNumber, $to, $msgId, $node]); // $this->waitForServer($msgId); return $msgId; }
/** * Send node to the servers. * * @param $to * @param ProtocolNode $node * @param null $id * @return null|string */ protected function sendMessageNode($to, $node, $id = null) { $messageHash = array(); $messageHash["to"] = $this->getJID($to); if ($node->getTag() == "body") { $messageHash["type"] = "text"; } else { $messageHash["type"] = "media"; } $messageHash["id"] = $id == null ? $this->createMsgId("message") : $id; $messageHash["t"] = time(); $messageNode = new ProtocolNode("message", $messageHash, array($node), ""); $this->sendNode($messageNode); $this->eventManager()->fire("onSendMessage", array($this->phoneNumber, $this->getJID($to), $messageHash["id"], $node)); return $messageHash["id"]; }
/** * Send node to the servers. * * @param $to * @param ProtocolNode $node * @param null $id * * @return string Message ID. */ protected function sendMessageNode($to, $node, $id = null, $plaintextNode = null) { $msgId = $id == null ? $this->createMsgId() : $id; $to = $this->getJID($to); if ($node->getTag() == 'body' || $node->getTag() == 'enc') { $type = 'text'; } else { $type = 'media'; } $messageNode = new ProtocolNode('message', ['to' => $to, 'type' => $type, 'id' => $msgId, 't' => time(), 'notify' => $this->name], [$node], ''); $this->sendNode($messageNode); if ($node->getTag() == 'enc') { $node = $plaintextNode; } $this->logFile('info', Language::getMessageByKey("MESSAGE_WHATSPORT_WARNING_MESSAGE_SEND", self::FILE_PACK_LANGUAGE, Constants::LANGUAGE, array('TYPE' => $type, 'ID' => $msgId, 'TO' => ExtractNumber($to)))); $this->eventManager()->fire('onSendMessage', [$this->phoneNumber, $to, $msgId, $node]); // $this->waitForServer($msgId); return $msgId; }