Example #1
0
 /**
  * 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;
 }
 /**
  * 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.
  * @param ProtocolNode $node
  * @param bool         $autoReceipt
  * @param              $type
  *
  * @throws Exception
  */
 protected function processInboundDataNode(ProtocolNode $node, $autoReceipt = true, $type = "read")
 {
     $this->debugPrint($node->nodeString("rx  ") . "\n");
     $this->serverReceivedId = $node->getAttribute('id');
     if ($node->getTag() == "challenge") {
         $this->processChallenge($node);
     } elseif ($node->getTag() == "failure") {
         $this->loginStatus = Constants::DISCONNECTED_STATUS;
         $this->eventManager()->fire("onLoginFailed", array($this->phoneNumber, $node->getChild(0)->getTag()));
     } elseif ($node->getTag() == "success") {
         if ($node->getAttribute("status") == "active") {
             $this->loginStatus = Constants::CONNECTED_STATUS;
             $challengeData = $node->getData();
             file_put_contents($this->challengeFilename, $challengeData);
             $this->writer->setKey($this->outputKey);
             $this->eventManager()->fire("onLoginSuccess", array($this->phoneNumber, $node->getAttribute("kind"), $node->getAttribute("status"), $node->getAttribute("creation"), $node->getAttribute("expiration")));
         } elseif ($node->getAttribute("status") == "expired") {
             $this->eventManager()->fire("onAccountExpired", array($this->phoneNumber, $node->getAttribute("kind"), $node->getAttribute("status"), $node->getAttribute("creation"), $node->getAttribute("expiration")));
         }
     } elseif ($node->getTag() == 'ack' && $node->getAttribute("class") == "message") {
         $this->eventManager()->fire("onMessageReceivedServer", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('class'), $node->getAttribute('t')));
     } elseif ($node->getTag() == 'receipt') {
         if ($node->hasChild("list")) {
             foreach ($node->getChild("list")->getChildren() as $child) {
                 $this->eventManager()->fire("onMessageReceivedClient", array($this->phoneNumber, $node->getAttribute('from'), $child->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('participant')));
             }
         }
         $this->eventManager()->fire("onMessageReceivedClient", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('participant')));
         $this->sendAck($node, 'receipt');
     }
     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') || $node->getChild('media'))) {
             $this->newMsgBind->process($node);
         }
         if ($node->getAttribute("type") == "text" && $node->getChild('body') != null) {
             $author = $node->getAttribute("participant");
             if ($autoReceipt) {
                 $this->sendReceipt($node, $type, $author);
             }
             if ($author == "") {
                 //private chat message
                 $this->eventManager()->fire("onGetMessage", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute("notify"), $node->getChild("body")->getData()));
                 if ($this->messageStore !== null) {
                     $this->messageStore->saveMessage(ExtractNumber($node->getAttribute('from')), $this->phoneNumber, $node->getChild("body")->getData(), $node->getAttribute('id'), $node->getAttribute('t'));
                 }
             } else {
                 //group chat message
                 $this->eventManager()->fire("onGetGroupMessage", array($this->phoneNumber, $node->getAttribute('from'), $author, $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute("notify"), $node->getChild("body")->getData()));
                 if ($this->messageStore !== null) {
                     $this->messageStore->saveMessage($author, $node->getAttribute('from'), $node->getChild("body")->getData(), $node->getAttribute('id'), $node->getAttribute('t'));
                 }
             }
         }
         if ($node->getAttribute("type") == "text" && $node->getChild(0)->getTag() == 'enc') {
             // TODO
             if ($autoReceipt) {
                 $this->sendReceipt($node, $type);
             }
         }
         if ($node->getAttribute("type") == "media" && $node->getChild('media') != null) {
             if ($node->getChild("media")->getAttribute('type') == 'image') {
                 if ($node->getAttribute("participant") == null) {
                     $this->eventManager()->fire("onGetImage", array($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(), $node->getChild("media")->getAttribute('caption')));
                 } else {
                     $this->eventManager()->fire("onGetGroupImage", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('participant'), $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(), $node->getChild("media")->getAttribute('caption')));
                 }
             } elseif ($node->getChild("media")->getAttribute('type') == 'video') {
                 if ($node->getAttribute("participant") == null) {
                     $this->eventManager()->fire("onGetVideo", array($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(), $node->getChild("media")->getAttribute('caption'), $node->getChild("media")->getAttribute('width'), $node->getChild("media")->getAttribute('height'), $node->getChild("media")->getAttribute('fps'), $node->getChild("media")->getAttribute('vbitrate'), $node->getChild("media")->getAttribute('asampfreq'), $node->getChild("media")->getAttribute('asampfmt'), $node->getChild("media")->getAttribute('abitrate')));
                 } else {
                     $this->eventManager()->fire("onGetGroupVideo", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('participant'), $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(), $node->getChild("media")->getAttribute('caption'), $node->getChild("media")->getAttribute('width'), $node->getChild("media")->getAttribute('height'), $node->getChild("media")->getAttribute('fps'), $node->getChild("media")->getAttribute('vbitrate'), $node->getChild("media")->getAttribute('asampfreq'), $node->getChild("media")->getAttribute('asampfmt'), $node->getChild("media")->getAttribute('abitrate')));
                 }
             } elseif ($node->getChild("media")->getAttribute('type') == 'audio') {
                 $author = $node->getAttribute("participant");
                 $this->eventManager()->fire("onGetAudio", array($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('seconds'), $node->getChild("media")->getAttribute('acodec'), $author));
             } elseif ($node->getChild("media")->getAttribute('type') == 'vcard') {
                 if ($node->getChild("media")->hasChild('vcard')) {
                     $name = $node->getChild("media")->getChild("vcard")->getAttribute('name');
                     $data = $node->getChild("media")->getChild("vcard")->getData();
                 } else {
                     $name = "NO_NAME";
                     $data = $node->getChild("media")->getData();
                 }
                 $author = $node->getAttribute("participant");
                 $this->eventManager()->fire("onGetvCard", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('notify'), $name, $data, $author));
             } elseif ($node->getChild("media")->getAttribute('type') == 'location') {
                 $url = $node->getChild("media")->getAttribute('url');
                 $name = $node->getChild("media")->getAttribute('name');
                 $author = $node->getAttribute("participant");
                 $this->eventManager()->fire("onGetLocation", array($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(), $author));
             }
             if ($autoReceipt) {
                 $this->sendReceipt($node, $type);
             }
         }
         if ($node->getChild('received') != null) {
             $this->eventManager()->fire("onMessageReceivedClient", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('participant')));
         }
     }
     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()->fire("onPresenceAvailable", array($this->phoneNumber, $node->getAttribute('from')));
         } else {
             $this->eventManager()->fire("onPresenceUnavailable", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('last')));
         }
     }
     if ($node->getTag() == "presence" && strncmp($node->getAttribute('from'), $this->phoneNumber, strlen($this->phoneNumber)) != 0 && strpos($node->getAttribute('from'), "-") !== false && $node->getAttribute('type') != null) {
         $groupId = Constants::parseJID($node->getAttribute('from'));
         if ($node->getAttribute('add') != null) {
             $this->eventManager()->fire("onGroupsParticipantsAdd", array($this->phoneNumber, $groupId, Constants::parseJID($node->getAttribute('add'))));
         } elseif ($node->getAttribute('remove') != null) {
             $this->eventManager()->fire("onGroupsParticipantsRemove", array($this->phoneNumber, $groupId, Constants::parseJID($node->getAttribute('remove'))));
         }
     }
     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()->fire("onMessageComposing", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), "composing", $node->getAttribute('t')));
         } else {
             $this->eventManager()->fire("onMessagePaused", array($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()->fire("onPing", array($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("sid"), $existingUsers, $failedNumbers);
         $this->eventManager()->fire("onGetSyncResult", array($result));
     }
     if ($node->getTag() == "receipt") {
         $this->eventManager()->fire("onGetReceipt", array($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 (isset($this->nodeId['privacy']) && $this->nodeId['privacy'] == $node->getAttribute('id')) {
                 $listChild = $node->getChild(0)->getChild(0);
                 foreach ($listChild->getChildren() as $child) {
                     $blockedJids[] = $child->getAttribute('value');
                 }
                 $this->eventManager()->fire("onGetPrivacyBlockedList", array($this->phoneNumber, $blockedJids));
                 return;
             }
             $this->eventManager()->fire("onGetRequestLastSeen", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getChild(0)->getAttribute('seconds')));
         }
         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()->fire("onGetServerProperties", array($this->phoneNumber, $node->getChild(0)->getAttribute("version"), $props));
         }
         if ($node->getChild("picture") != null) {
             $this->eventManager()->fire("onGetProfilePicture", array($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 (strpos($node->getAttribute("from"), Constants::WHATSAPP_GROUP_SERVER) !== false) {
             //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();
             $groupNodes = array();
             if ($node->getChild(0) != null && $node->getChild(0)->getChildren() != null) {
                 foreach ($node->getChild(0)->getChildren() as $child) {
                     $groupList[] = $child->getAttributes();
                     $groupNodes[] = $child;
                 }
             }
             if (isset($this->nodeId['groupcreate']) && $this->nodeId['groupcreate'] == $node->getAttribute('id')) {
                 $this->groupId = $node->getChild(0)->getAttribute('id');
                 $this->eventManager()->fire("onGroupsChatCreate", array($this->phoneNumber, $this->groupId));
             }
             if (isset($this->nodeId['leavegroup']) && $this->nodeId['leavegroup'] == $node->getAttribute('id')) {
                 $this->groupId = $node->getChild(0)->getChild(0)->getAttribute('id');
                 $this->eventManager()->fire("onGroupsChatEnd", array($this->phoneNumber, $this->groupId));
             }
             if (isset($this->nodeId['getgroups']) && $this->nodeId['getgroups'] == $node->getAttribute('id')) {
                 $this->eventManager()->fire("onGetGroups", array($this->phoneNumber, $groupList));
                 //getGroups returns a array of nodes which are exactly the same as from getGroupV2Info
                 //so lets call this event, we have all data at hand, no need to call getGroupV2Info for every
                 //group we are interested
                 foreach ($groupNodes as $groupNode) {
                     $this->handleGroupV2InfoResponse($groupNode, true);
                 }
             }
             if (isset($this->nodeId['get_groupv2_info']) && $this->nodeId['get_groupv2_info'] == $node->getAttribute('id')) {
                 $groupChild = $node->getChild(0);
                 if ($groupChild != null) {
                     $this->handleGroupV2InfoResponse($groupChild);
                 }
             }
         }
         if (isset($this->nodeId['get_lists']) && $this->nodeId['get_lists'] == $node->getAttribute('id')) {
             $broadcastLists = array();
             if ($node->getChild(0) != null) {
                 $childArray = $node->getChildren();
                 foreach ($childArray as $list) {
                     if ($list->getChildren() != null) {
                         foreach ($list->getChildren() as $sublist) {
                             $id = $sublist->getAttribute("id");
                             $name = $sublist->getAttribute("name");
                             $broadcastLists[$id]['name'] = $name;
                             $recipients = array();
                             foreach ($sublist->getChildren() as $recipient) {
                                 array_push($recipients, $recipient->getAttribute('jid'));
                             }
                             $broadcastLists[$id]['recipients'] = $recipients;
                         }
                     }
                 }
             }
             $this->eventManager()->fire("onGetBroadcastLists", array($this->phoneNumber, $broadcastLists));
         }
         if ($node->getChild("pricing") != null) {
             $this->eventManager()->fire("onGetServicePricing", array($this->phoneNumber, $node->getChild(0)->getAttribute("price"), $node->getChild(0)->getAttribute("cost"), $node->getChild(0)->getAttribute("currency"), $node->getChild(0)->getAttribute("expiration")));
         }
         if ($node->getChild("extend") != null) {
             $this->eventManager()->fire("onGetExtendAccount", array($this->phoneNumber, $node->getChild("account")->getAttribute("kind"), $node->getChild("account")->getAttribute("status"), $node->getChild("account")->getAttribute("creation"), $node->getChild("account")->getAttribute("expiration")));
         }
         if ($node->getChild("normalize") != null) {
             $this->eventManager()->fire("onGetNormalizedJid", array($this->phoneNumber, $node->getChild(0)->getAttribute("result")));
         }
         if ($node->getChild("status") != null) {
             $child = $node->getChild("status");
             foreach ($child->getChildren() as $status) {
                 $this->eventManager()->fire("onGetStatus", array($this->phoneNumber, $status->getAttribute("jid"), "requested", $node->getAttribute("id"), $status->getAttribute("t"), $status->getData()));
             }
         }
     }
     if ($node->getTag() == "iq" && $node->getAttribute('type') == "error") {
         $errorType = null;
         foreach ($this->nodeId as $type => $nodeID) {
             if ($nodeID == $node->getAttribute('id')) {
                 $errorType = $type;
                 break;
             }
         }
         $this->eventManager()->fire("onGetError", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getChild(0), $errorType));
     }
     if ($node->getTag() == "message" && $node->getAttribute('type') == "media" && $node->getChild(0)->getAttribute('type') == "image") {
         $msgId = $this->createIqId();
         $ackNode = new ProtocolNode("ack", array("url" => $node->getChild(0)->getAttribute('url')), null, null);
         $iqNode = new ProtocolNode("iq", array("id" => $msgId, "xmlns" => "w:m", "type" => "set", "to" => Constants::WHATSAPP_SERVER), array($ackNode), null);
         $this->sendNode($iqNode);
     }
     $children = $node->getChild(0);
     if ($node->getTag() == "stream:error" && !empty($children) && $node->getChild(0)->getTag() == "system-shutdown") {
         $this->eventManager()->fire("onStreamError", array($node->getChild(0)->getTag()));
     }
     if ($node->getTag() == "stream:error") {
         $this->eventManager()->fire("onStreamError", array($node->getChild(0)->getTag()));
     }
     if ($node->getTag() == "notification") {
         $name = $node->getAttribute("notify");
         $type = $node->getAttribute("type");
         switch ($type) {
             case "status":
                 $this->eventManager()->fire("onGetStatus", array($this->phoneNumber, $node->getAttribute("from"), $node->getChild(0)->getTag(), $node->getAttribute("id"), $node->getAttribute("t"), $node->getChild(0)->getData()));
                 break;
             case "picture":
                 if ($node->hasChild('set')) {
                     $this->eventManager()->fire("onProfilePictureChanged", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('t')));
                 } else {
                     if ($node->hasChild('delete')) {
                         $this->eventManager()->fire("onProfilePictureDeleted", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('t')));
                     }
                 }
                 //TODO
                 break;
             case "contacts":
                 $notification = $node->getChild(0)->getTag();
                 if ($notification == 'add') {
                     $this->eventManager()->fire("onNumberWasAdded", array($this->phoneNumber, $node->getChild(0)->getAttribute('jid')));
                 } elseif ($notification == 'remove') {
                     $this->eventManager()->fire("onNumberWasRemoved", array($this->phoneNumber, $node->getChild(0)->getAttribute('jid')));
                 } elseif ($notification == 'update') {
                     $this->eventManager()->fire("onNumberWasUpdated", array($this->phoneNumber, $node->getChild(0)->getAttribute('jid')));
                 }
                 break;
             case "encrypt":
                 $value = $node->getChild(0)->getAttribute('value');
                 if (is_numeric($value)) {
                     $this->eventManager()->fire("onGetKeysLeft", array($this->phoneNumber, $node->getChild(0)->getAttribute('value')));
                 } else {
                     echo "Corrupt Stream: value " . $value . "is not numeric";
                 }
                 break;
             case "w:gp2":
                 if ($node->hasChild('remove')) {
                     if ($node->getChild(0)->hasChild('participant')) {
                         $this->eventManager()->fire("onGroupsParticipantsRemove", array($this->phoneNumber, $node->getAttribute('from'), $node->getChild(0)->getChild(0)->getAttribute('jid')));
                     }
                 } else {
                     if ($node->hasChild('add')) {
                         $this->eventManager()->fire("onGroupsParticipantsAdd", array($this->phoneNumber, $node->getAttribute('from'), $node->getChild(0)->getChild(0)->getAttribute('jid')));
                     } else {
                         if ($node->hasChild('create')) {
                             $groupMembers = array();
                             foreach ($node->getChild(0)->getChild(0)->getChildren() as $cn) {
                                 $groupMembers[] = $cn->getAttribute('jid');
                             }
                             $this->eventManager()->fire("onGroupisCreated", array($this->phoneNumber, $node->getChild(0)->getChild(0)->getAttribute('creator'), $node->getChild(0)->getChild(0)->getAttribute('id'), $node->getChild(0)->getChild(0)->getAttribute('subject'), $node->getAttribute('participant'), $node->getChild(0)->getChild(0)->getAttribute('creation'), $groupMembers));
                         } else {
                             if ($node->hasChild('subject')) {
                                 $this->eventManager()->fire("onGetGroupsSubject", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('t'), $node->getAttribute('participant'), $node->getAttribute('notify'), $node->getChild(0)->getAttribute('subject')));
                             } else {
                                 if ($node->hasChild('promote')) {
                                     $promotedJIDs = array();
                                     foreach ($node->getChild(0)->getChildren() as $cn) {
                                         $promotedJIDs[] = $cn->getAttribute('jid');
                                     }
                                     $this->eventManager()->fire("onGroupsParticipantsPromote", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('t'), $node->getAttribute('participant'), $node->getAttribute('notify'), $promotedJIDs));
                                 } else {
                                     if ($node->hasChild('modify')) {
                                         $this->eventManager()->fire("onGroupsParticipantChangedNumber", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('t'), $node->getAttribute('participant'), $node->getAttribute('notify'), $node->getChild(0)->getChild(0)->getAttribute('jid')));
                                     }
                                 }
                             }
                         }
                     }
                 }
                 break;
             case "account":
                 if ($node->getChild(0)->getAttribute('author') == "") {
                     $author = "Paypal";
                 } else {
                     $author = $node->getChild(0)->getAttribute('author');
                 }
                 $this->eventManager()->fire("onPaidAccount", array($this->phoneNumber, $author, $node->getChild(0)->getChild(0)->getAttribute('kind'), $node->getChild(0)->getChild(0)->getAttribute('status'), $node->getChild(0)->getChild(0)->getAttribute('creation'), $node->getChild(0)->getChild(0)->getAttribute('expiration')));
                 break;
             case "features":
                 if ($node->getChild(0)->getChild(0) == "encrypt") {
                     $this->eventManager()->fire("onGetFeature", array($this->phoneNumber, $node->getAttribute('from'), $node->getChild(0)->getChild(0)->getAttribute('value')));
                 }
                 break;
             case "web":
                 if ($node->getChild(0)->getTag() == 'action' && $node->getChild(0)->getAttribute('type') == 'sync') {
                     $data = $node->getChild(0)->getChildren();
                     $this->eventManager()->fire("onWebSync", array($this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $data[0]->getData(), $data[1]->getData(), $data[2]->getData()));
                 }
                 break;
             default:
                 throw new Exception("Method {$type} not implemented");
         }
         $this->sendAck($node, 'notification');
     }
     if ($node->getTag() == "call") {
         if ($node->getChild(0)->getTag() == "offer") {
             $callId = $node->getChild(0)->getAttribute("call-id");
             $this->sendReceipt($node, null, null, $callId);
             $this->eventManager()->fire("onCallReceived", array($this->phoneNumber, $node->getAttribute("from"), $node->getAttribute("id"), $node->getAttribute("notify"), $node->getAttribute("t"), $node->getChild(0)->getAttribute("call-id")));
         } else {
             $this->sendAck($node, 'call');
         }
     }
     if ($node->getTag() == "ib") {
         foreach ($node->getChildren() as $child) {
             switch ($child->getTag()) {
                 case "dirty":
                     $this->sendClearDirty(array($child->getAttribute("type")));
                     break;
                 case "account":
                     $this->eventManager()->fire("onPaymentRecieved", array($this->phoneNumber, $child->getAttribute("kind"), $child->getAttribute("status"), $child->getAttribute("creation"), $child->getAttribute("expiration")));
                     break;
                 case "offline":
                     break;
                 default:
                     throw new Exception("ib handler for " . $child->getTag() . " not implemented");
             }
         }
     }
     // Disconnect socket on stream error.
     if ($node->getTag() == "stream:error") {
         $this->disconnect();
     }
 }
Example #3
0
 public function unsetPendingNode($jid)
 {
     unset($this->pending_nodes[ExtractNumber($jid)]);
 }
Example #4
0
 public function process($node)
 {
     if ($node->getAttribute("type") == 'text') {
         $text = $node->getChild('body');
         $text = $text->getData();
         $number = ExtractNumber($node->getAttribute("from"));
         $nickname = $number;
         echo "\n- " . $nickname . ": " . $text . "    " . date('H:i') . "\n";
     }
 }
Example #5
0
 public function decryptMessage($from, $ciphertext, $type, $id, $t, $retry_from = null, $skip_unpad = false)
 {
     $version = '1';
     $this->parent->debugPrint("\n-> Decrypted Message: ");
     if ($type == 'pkmsg') {
         if (in_array(ExtractNumber($from), $this->parent->getv2Jids())) {
             $version = '2';
         }
         try {
             $preKeyWhisperMessage = new PreKeyWhisperMessage(null, null, null, null, null, null, null, $ciphertext);
             $sessionCipher = $this->parent->getSessionCipher(ExtractNumber($from));
             $plaintext = $sessionCipher->decryptPkmsg($preKeyWhisperMessage);
             if ($version == '2' && !$skip_unpad) {
                 $plaintext = unpadV2Plaintext($plaintext);
             }
             $this->parent->debugPrint(parseText($plaintext) . "\n\n");
             return $plaintext;
         } catch (Exception $e) {
             if ($e instanceof UntrustedIdentityException) {
                 $this->parent->getAxolotlStore()->clearRecipient(ExtractNumber($from));
             }
             $this->parent->debugPrint($e->getMessage() . ' - ' . $e->getFile() . ' - ' . $e->getLine());
             // if ($e->getMessage() != "Null values!"){
             $this->parent->debugPrint("Message {$id} could not be decrypted, sending retry.\n\n");
             $participant = null;
             if ($retry_from != null) {
                 if (strpos($retry_from, '-') !== false) {
                     $participant = $from;
                 }
                 $from = $retry_from;
             }
             //$this->sendRetry($from, $id, $t, $participant);
             return false;
             //}
         }
     } elseif ($type == 'msg') {
         if (in_array(ExtractNumber($from), $this->parent->getv2Jids())) {
             $version = '2';
         }
         try {
             $whisperMessage = new WhisperMessage(null, null, null, null, null, null, null, null, $ciphertext);
             $sessionCipher = $this->parent->getSessionCipher(ExtractNumber($from));
             $plaintext = $sessionCipher->decryptMsg($whisperMessage);
             if ($version == '2' && !$skip_unpad) {
                 $plaintext = unpadV2Plaintext($plaintext);
             }
             $this->parent->debugPrint(parseText($plaintext) . "\n\n");
             return $plaintext;
         } catch (Exception $e) {
             $this->parent->debugPrint($e->getMessage() . ' - ' . $e->getFile() . ' - ' . $e->getLine());
             $this->parent->debugPrint("Message {$id} could not be decrypted, sending retry.\n\n");
             if ($retry_from != null) {
                 $from = $retry_from;
             }
             //$this->sendRetry($from, $id, $t);
             return false;
         }
     } elseif ($type == 'skmsg') {
         if (in_array($from[1], $this->parent->v2Jids)) {
             $version = '2';
         }
         try {
             $groupCipher = $this->parent->getGroupCipher(ExtractNumber($from[0]) . ':' . $from[1]);
             $plaintext = $groupCipher->decrypt($ciphertext);
             if ($version == '2' && !$skip_unpad) {
                 $plaintext = unpadV2Plaintext($plaintext);
             }
             $this->parent->debugPrint("Message {$id} decrypted to " . parseText($plaintext) . "\n\n");
             return $plaintext;
         } catch (Exception $e) {
             $this->parent->debugPrint($e->getMessage() . ' - ' . $e->getFile() . ' - ' . $e->getLine());
             if ($retry_from != null) {
                 $from = $retry_from;
             }
             $this->parent->sendRetry($this->node, $this->parent->getJID($from[0]), $id, $t);
             return false;
         }
     }
 }
Example #6
0
 public function Process()
 {
     if ($this->node->getChild("query") != null) {
         if (isset($this->parent->getNodeId()['privacy']) && $this->parent->getNodeId()['privacy'] == $this->node->getAttribute('id')) {
             $listChild = $this->node->getChild(0)->getChild(0);
             foreach ($listChild->getChildren() as $child) {
                 $blockedJids[] = $child->getAttribute('value');
             }
             $this->parent->eventManager()->fire("onGetPrivacyBlockedList", array($this->phoneNumber, $blockedJids));
             return;
         }
     }
     if ($this->node->getAttribute('type') == "get" && $this->node->getAttribute('xmlns') == "urn:xmpp:ping") {
         $this->parent->eventManager()->fire("onPing", array($this->phoneNumber, $this->node->getAttribute('id')));
         $this->parent->sendPong($this->node->getAttribute('id'));
     }
     if ($this->node->getChild("sync") != null) {
         //sync result
         $sync = $this->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("sid"), $existingUsers, $failedNumbers);
         $this->parent->eventManager()->fire("onGetSyncResult", array($result));
     }
     if ($this->node->getChild("props") != null) {
         //server properties
         $props = array();
         foreach ($this->node->getChild(0)->getChildren() as $child) {
             $props[$child->getAttribute("name")] = $child->getAttribute("value");
         }
         $this->parent->eventManager()->fire("onGetServerProperties", array($this->phoneNumber, $this->node->getChild(0)->getAttribute("version"), $props));
     }
     if ($this->node->getChild("picture") != null) {
         $this->parent->eventManager()->fire("onGetProfilePicture", array($this->phoneNumber, $this->node->getAttribute("from"), $this->node->getChild("picture")->getAttribute("type"), $this->node->getChild("picture")->getData()));
     }
     if ($this->node->getChild("media") != null || $this->node->getChild("duplicate") != null) {
         $this->parent->processUploadResponse($this->node);
     }
     if (strpos($this->node->getAttribute("from"), Constants::WHATSAPP_GROUP_SERVER) !== false) {
         //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();
         $groupNodes = array();
         if ($this->node->getChild(0) != null && $this->node->getChild(0)->getChildren() != null) {
             foreach ($this->node->getChild(0)->getChildren() as $child) {
                 $groupList[] = $child->getAttributes();
                 $groupNodes[] = $child;
             }
         }
         if (isset($this->parent->getNodeId()['groupcreate']) && $this->parent->getNodeId()['groupcreate'] == $this->node->getAttribute('id')) {
             $this->parent->setGroupId($this->node->getChild(0)->getAttribute('id'));
             $this->parent->eventManager()->fire("onGroupsChatCreate", array($this->phoneNumber, $this->node->getChild(0)->getAttribute('id')));
         }
         if (isset($this->parent->getNodeId()['leavegroup']) && $this->parent->getNodeId()['leavegroup'] == $this->node->getAttribute('id')) {
             $this->parent->setGroupId($this->node->getChild(0)->getChild(0)->getAttribute('id'));
             $this->parent->eventManager()->fire("onGroupsChatEnd", array($this->phoneNumber, $this->node->getChild(0)->getChild(0)->getAttribute('id')));
         }
         if (isset($this->parent->getNodeId()['getgroups']) && $this->parent->getNodeId()['getgroups'] == $this->node->getAttribute('id')) {
             $this->parent->eventManager()->fire("onGetGroups", array($this->phoneNumber, $groupList));
             //getGroups returns a array of nodes which are exactly the same as from getGroupV2Info
             //so lets call this event, we have all data at hand, no need to call getGroupV2Info for every
             //group we are interested
             foreach ($groupNodes as $groupNode) {
                 $this->handleGroupV2InfoResponse($groupNode, true);
             }
         }
         if (isset($this->parent->getNodeId()['get_groupv2_info']) && $this->parent->getNodeId()['get_groupv2_info'] == $this->node->getAttribute('id')) {
             $groupChild = $this->node->getChild(0);
             if ($groupChild != null) {
                 $this->handleGroupV2InfoResponse($groupChild);
             }
         }
     }
     if (isset($this->parent->getNodeId()['get_lists']) && $this->parent->getNodeId()['get_lists'] == $this->node->getAttribute('id')) {
         $broadcastLists = array();
         if ($this->node->getChild(0) != null) {
             $childArray = $this->node->getChildren();
             foreach ($childArray as $list) {
                 if ($list->getChildren() != null) {
                     foreach ($list->getChildren() as $sublist) {
                         $id = $sublist->getAttribute("id");
                         $name = $sublist->getAttribute("name");
                         $broadcastLists[$id]['name'] = $name;
                         $recipients = array();
                         foreach ($sublist->getChildren() as $recipient) {
                             array_push($recipients, $recipient->getAttribute('jid'));
                         }
                         $broadcastLists[$id]['recipients'] = $recipients;
                     }
                 }
             }
         }
         $this->parent->eventManager()->fire("onGetBroadcastLists", array($this->phoneNumber, $broadcastLists));
     }
     if ($this->node->getChild("pricing") != null) {
         $this->parent->eventManager()->fire("onGetServicePricing", array($this->phoneNumber, $this->node->getChild(0)->getAttribute("price"), $this->node->getChild(0)->getAttribute("cost"), $this->node->getChild(0)->getAttribute("currency"), $this->node->getChild(0)->getAttribute("expiration")));
     }
     if ($this->node->getChild("extend") != null) {
         $this->parent->eventManager()->fire("onGetExtendAccount", array($this->phoneNumber, $this->node->getChild("account")->getAttribute("kind"), $this->node->getChild("account")->getAttribute("status"), $this->node->getChild("account")->getAttribute("creation"), $this->node->getChild("account")->getAttribute("expiration")));
     }
     if ($this->node->getChild("normalize") != null) {
         $this->parent->eventManager()->fire("onGetNormalizedJid", array($this->phoneNumber, $this->node->getChild(0)->getAttribute("result")));
     }
     if ($this->node->getChild("status") != null) {
         $child = $this->node->getChild("status");
         $childs = $child->getChildren();
         if (isset($childs) && !is_null($childs)) {
             foreach ($childs as $status) {
                 $this->parent->eventManager()->fire("onGetStatus", array($this->phoneNumber, $status->getAttribute("jid"), "requested", $this->node->getAttribute("id"), $status->getAttribute("t"), $status->getData()));
             }
         }
     }
     if ($this->node->getAttribute('type') == "error" && $this->node->getChild("error") != null) {
         $errorType = null;
         $this->parent->logFile('error', 'Iq error with {id} id', array('id' => $this->node->getAttribute('id')));
         foreach ($this->parent->getNodeId() as $type => $nodeID) {
             if ($nodeID == $this->node->getAttribute('id')) {
                 $errorType = $type;
                 break;
             }
         }
         $nodeIds = $this->parent->getNodeId();
         if (isset($nodeIds['sendcipherKeys']) && isset($nodeIds['sendcipherKeys']) == $this->node->getAttribute('id') && $this->node->getChild("error")->getAttribute('code') == "406") {
             $this->parent->sendSetPreKeys();
         }
         $this->parent->eventManager()->fire("onGetError", array($this->phoneNumber, $this->node->getAttribute('from'), $this->node->getAttribute('id'), $this->node->getChild(0), $errorType));
     }
     if (isset($this->parent->getNodeId()['cipherKeys']) && $this->parent->getNodeId()['cipherKeys'] == $this->node->getAttribute('id')) {
         $users = $this->node->getChild(0)->getChildren();
         foreach ($users as $user) {
             $jid = $user->getAttribute("jid");
             $registrationId = deAdjustId($user->getChild('registration')->getData());
             $identityKey = new IdentityKey(new DjbECPublicKey($user->getChild('identity')->getData()));
             $signedPreKeyId = deAdjustId($user->getChild('skey')->getChild('id')->getData());
             $signedPreKeyPub = new DjbECPublicKey($user->getChild('skey')->getChild('value')->getData());
             $signedPreKeySig = $user->getChild('skey')->getChild('signature')->getData();
             $preKeyId = deAdjustId($user->getChild('key')->getChild('id')->getData());
             $preKeyPublic = new DjbECPublicKey($user->getChild('key')->getChild('value')->getData());
             $preKeyBundle = new PreKeyBundle($registrationId, 1, $preKeyId, $preKeyPublic, $signedPreKeyId, $signedPreKeyPub, $signedPreKeySig, $identityKey);
             $sessionBuilder = new SessionBuilder($this->parent->getAxolotlStore(), $this->parent->getAxolotlStore(), $this->parent->getAxolotlStore(), $this->parent->getAxolotlStore(), ExtractNumber($jid), 1);
             $sessionBuilder->processPreKeyBundle($preKeyBundle);
             if (isset($this->parent->getPendingNodes()[ExtractNumber($jid)])) {
                 foreach ($this->parent->getPendingNodes()[ExtractNumber($jid)] as $pendingNode) {
                     $msgHandler = new MessageHandler($this->parent, $pendingNode);
                     $msgHandler->Process();
                 }
                 unset($this->parent->getPendingNodes()[ExtractNumber($jid)]);
             }
             $this->parent->sendPendingMessages($jid);
         }
     }
 }
Example #7
0
 public function process($node)
 {
     if ($node->getAttribute('type') == 'text') {
         $text = $node->getChild('body');
         $text = $text->getData();
         $number = ExtractNumber($node->getAttribute('from'));
         $nickname = findNicknameByPhone($number);
         echo "\n- " . $nickname . ': ' . $text . '    ' . date('H:i') . "\n";
     }
 }
Example #8
0
 function decryptMessage($from, $ciphertext, $type, $id, $t, $retry_from = null, $skip_unpad = false)
 {
     $version = "1";
     $this->parent->debugPrint("\n-> Decrypted Message: ");
     if ($type == "pkmsg") {
         if (in_array(ExtractNumber($from), $this->parent->getv2Jids())) {
             $version = "2";
         }
         try {
             $preKeyWhisperMessage = new PreKeyWhisperMessage(null, null, null, null, null, null, null, $ciphertext);
             $sessionCipher = $this->parent->getSessionCipher(ExtractNumber($from));
             $plaintext = $sessionCipher->decryptPkmsg($preKeyWhisperMessage);
             if ($version == "2" && !$skip_unpad) {
                 $plaintext = unpadV2Plaintext($plaintext);
             }
             $this->parent->debugPrint(parseText($plaintext) . "\n\n");
             return $plaintext;
         } catch (Exception $e) {
             $this->parent->debugPrint($e->getMessage() . " - " . $e->getFile() . " - " . $e->getLine());
             if ($e->getMessage() != "Null values!") {
                 $this->parent->debugPrint("Message {$id} could not be decrypted, sending retry.\n\n");
                 $participant = null;
                 if ($retry_from != null) {
                     if (strpos($retry_from, "-") !== false) {
                         $participant = $from;
                     }
                     $from = $retry_from;
                 }
                 //$this->sendRetry($from, $id, $t, $participant);
                 return false;
             }
         }
     } else {
         if ($type == "msg") {
             if (in_array(ExtractNumber($from), $this->parent->getv2Jids())) {
                 $version = "2";
             }
             try {
                 $whisperMessage = new WhisperMessage(null, null, null, null, null, null, null, null, $ciphertext);
                 $sessionCipher = $this->parent->getSessionCipher(ExtractNumber($from));
                 $plaintext = $sessionCipher->decryptMsg($whisperMessage);
                 if ($version == "2" && !$skip_unpad) {
                     $plaintext = unpadV2Plaintext($plaintext);
                 }
                 $this->parent->debugPrint(parseText($plaintext) . "\n\n");
                 return $plaintext;
             } catch (Exception $e) {
                 $this->parent->debugPrint($e->getMessage() . " - " . $e->getFile() . " - " . $e->getLine());
                 $this->parent->debugPrint("Message {$id} could not be decrypted, sending retry.\n\n");
                 if ($retry_from != null) {
                     $from = $retry_from;
                 }
                 //$this->sendRetry($from, $id, $t);
                 return false;
             }
         } else {
             if ($type == "skmsg") {
                 if (in_array($from[1], $this->v2Jids)) {
                     $version = "2";
                 }
                 try {
                     $groupCipher = $this->parent->getGroupCipher(ExtractNumber($from[0]) . ":" . $from[1]);
                     $plaintext = $groupCipher->decrypt($ciphertext);
                     if ($version == "2" && !$skip_unpad) {
                         $plaintext = unpadV2Plaintext($plaintext);
                     }
                     $this->parent->debugPrint("Message {$id} decrypted to " . parseText($plaintext) . "\n\n");
                     return $plaintext;
                 } catch (Exception $e) {
                     $this->parent->debugPrint($e->getMessage() . " - " . $e->getFile() . " - " . $e->getLine());
                     if ($retry_from != null) {
                         $from = $retry_from;
                     }
                     $this->parent->sendRetry($this->parent->getJID($from[0]), $id, $t);
                     return false;
                 }
             }
         }
     }
 }
Example #9
0
 public function onGetAudio($mynumber, $from, $id, $type, $time, $name, $size, $url, $file, $mimeType, $fileHash, $duration, $acodec, $fromJID_ifGroup = null)
 {
     $number = ExtractNumber($from);
     $nickname = $number;
     $path = "data/media/{$nickname}/";
     if (!file_exists($path)) {
         mkdir($path);
     }
     $filename = __DIR__ . DIRECTORY_SEPARATOR . $path . time() . ".jpg";
     $data = file_get_contents($url);
     $fp = @fopen($filename, "w");
     if ($fp) {
         fwrite($fp, $data);
         fclose($fp);
     }
     echo " < Received audio from {$nickname} >\n";
 }
Example #10
0
 static function handleMessageReceived($mynumber, $from, $id, $type, $time, $name, $body)
 {
     $number = ExtractNumber($from);
     $contact = getUserInfo($number);
     if (!$contact) {
         addContact($number, $name);
         $contact = getUserInfo($number);
         $main_menu = GenieConstants::searchElement(GenieConstants::$MAIN_MENU_CONTEXT, GenieConstants::$REGISTRATION_MENU_CONTEXT, 'subMenu');
         setMessageContext($main_menu, NULL, $contact['phone']);
     }
     //Handle ShortCut in request
     $requestArray = $data = preg_split('/\\s+/', $body);
     if ($requestArray[0][0] == '#') {
         self::handleShortCuts($contact, $requestArray);
         return;
     }
     $context = getMessageContext($number);
     $callBackFunction = 'initializeService';
     if ($context['main_menu'] == -1) {
         self::handleGeneralConversation($body, $context, $contact);
         return;
     }
     if ($context['main_menu'] == 0) {
         if (GenieConstants::searchElement(GenieConstants::$MAIN_MENU_CONTEXT, $body, 'id') != NULL) {
             updateMessageContext($body, NULL, $contact['phone']);
             PubSub::publish(GenieConstants::$MAIN_MENU_CONTEXT[$body]->menuItem, $callBackFunction, $contact);
         } else {
             MessaggingController::sendMessage($contact, GenieConstants::$INVALID_SERVICE);
             MessaggingController::sendMessage($contact, GenieConstants::$MAIN_MENU_STRING);
         }
         return;
     }
     if ($context['main_menu'] != 0 && $context['main_menu'] != 8 && $context['sub_menu'] == NULL) {
         $subMenuKey = GenieConstants::searchElement(GenieConstants::$MAIN_MENU_CONTEXT[$context['main_menu']]->subMenu, $body, 'id');
         $SubMenuDict = GenieConstants::$MAIN_MENU_CONTEXT[$context['main_menu']]->subMenu;
         if ($subMenuKey != NULL) {
             updateMessageContext($context['main_menu'], $body, $contact['phone']);
             $callBackFunction = $SubMenuDict[$subMenuKey]->callBackMethod;
             PubSub::publish(GenieConstants::$MAIN_MENU_CONTEXT[$context['main_menu']]->menuItem, $callBackFunction, $contact);
         } else {
             MessaggingController::sendMessage($contact, GenieConstants::$INVALID_SERVICE);
             PubSub::publish(GenieConstants::$MAIN_MENU_CONTEXT[$context['main_menu']]->menuItem, $callBackFunction, $contact);
         }
         return;
     } else {
         if ($context['main_menu'] != 0 && $context['main_menu'] != 8 && $context['sub_menu'] != NULL) {
             $SubMenuDict = GenieConstants::$MAIN_MENU_CONTEXT[$context['main_menu']]->subMenu;
             $callBackFunction = $SubMenuDict[$context['sub_menu']]->requestServer;
             PubSub::publish(GenieConstants::$MAIN_MENU_CONTEXT[$context['main_menu']]->menuItem, $callBackFunction, $contact, $body);
             return;
         } else {
             if ($context['sub_menu'] != NULL) {
                 $callBackFunction = GenieConstants::$MAIN_MENU_CONTEXT[$context['main_menu']]->subMenu[$context['sub_menu']]->callBackMethod;
             } else {
                 if (GenieConstants::$MAIN_MENU_CONTEXT[$context['main_menu']]->callBackMethod != NULL) {
                     $callBackFunction = GenieConstants::$MAIN_MENU_CONTEXT[$context['main_menu']]->callBackMethod;
                 }
             }
         }
     }
     PubSub::publish(GenieConstants::$MAIN_MENU_CONTEXT[$context['main_menu']]->menuItem, $callBackFunction, $contact, $body);
 }
Example #11
0
 /**
  * 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.
  * @param ProtocolNode $node
  * @param bool $autoReceipt
  * @param $type
  *
  * @throws \Exception
  */
 protected function processInboundDataNode(ProtocolNode $node, $autoReceipt = true, $type = 'read')
 {
     $this->debugPrint($node->nodeString('rx  ') . "\n");
     $this->serverReceivedId = $node->getAttribute('id');
     if ($node->getTag() == 'challenge') {
         $this->processChallenge($node);
     } elseif ($node->getTag() == 'failure') {
         $this->loginStatus = DISCONNECTED_STATUS;
         $this->eventsManager()->fire('onLoginFailed', [$this->phoneNumber, $node->getChild(0)->getTag()]);
     } elseif ($node->getTag() == 'success') {
         if ($node->getAttribute('status') == 'active') {
             $this->loginStatus = CONNECTED_STATUS;
             $challengeData = $node->getData();
             file_put_contents($this->challengeFilename, $challengeData);
             $this->writer->setKey($this->outputKey);
             $this->eventsManager()->fire('onLoginSuccess', [$this->phoneNumber, $node->getAttribute('kind'), $node->getAttribute('status'), $node->getAttribute('creation'), $node->getAttribute('expiration')]);
         } elseif ($node->getAttribute('status') == 'expired') {
             $this->eventsManager()->fire('onAccountExpired', [$this->phoneNumber, $node->getAttribute('kind'), $node->getAttribute('status'), $node->getAttribute('creation'), $node->getAttribute('expiration')]);
         }
     } elseif ($node->getTag() == 'ack' && $node->getAttribute('class') == 'message') {
         $this->eventsManager()->fire('onMessageReceivedServer', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('class'), $node->getAttribute('t')]);
     } elseif ($node->getTag() == 'receipt') {
         if ($node->hasChild('list')) {
             foreach ($node->getChild('list')->getChildren() as $child) {
                 $this->eventsManager()->fire('onMessageReceivedClient', [$this->phoneNumber, $node->getAttribute('from'), $child->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('participant')]);
             }
         }
         $this->eventsManager()->fire('onMessageReceivedClient', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('participant')]);
         $this->sendAck($node, 'receipt');
     }
     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') || $node->getChild('media'))) {
             $this->newMsgBind->process($node);
         }
         if ($node->getAttribute('type') == 'text' && $node->getChild('body') != null) {
             $author = $node->getAttribute('participant');
             if ($autoReceipt) {
                 $this->sendReceipt($node, $type, $author);
             }
             if ($author == '') {
                 //private chat message
                 $this->eventsManager()->fire('onGetMessage', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('notify'), $node->getChild('body')->getData()]);
                 if ($this->messageStore !== null) {
                     $this->messageStore->saveMessage(ExtractNumber($node->getAttribute('from')), $this->phoneNumber, $node->getChild('body')->getData(), $node->getAttribute('id'), $node->getAttribute('t'));
                 }
             } else {
                 //group chat message
                 $this->eventsManager()->fire('onGetGroupMessage', [$this->phoneNumber, $node->getAttribute('from'), $author, $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('notify'), $node->getChild('body')->getData()]);
                 if ($this->messageStore !== null) {
                     $this->messageStore->saveMessage($author, $node->getAttribute('from'), $node->getChild('body')->getData(), $node->getAttribute('id'), $node->getAttribute('t'));
                 }
             }
         }
         if ($node->getAttribute('type') == 'text' && $node->getChild(0)->getTag() == 'enc') {
             // TODO
             if ($autoReceipt) {
                 $this->sendReceipt($node, $type);
             }
         }
         if ($node->getAttribute('type') == 'media' && $node->getChild('media') != null) {
             if ($node->getChild('media')->getAttribute('type') == 'image') {
                 if ($node->getAttribute('participant') == null) {
                     $this->eventsManager()->fire('onGetImage', [$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(), $node->getChild('media')->getAttribute('caption')]);
                 } else {
                     $this->eventsManager()->fire('onGetGroupImage', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('participant'), $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(), $node->getChild('media')->getAttribute('caption')]);
                 }
             } elseif ($node->getChild('media')->getAttribute('type') == 'video') {
                 if ($node->getAttribute('participant') == null) {
                     $this->eventsManager()->fire('onGetVideo', [$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(), $node->getChild('media')->getAttribute('caption')]);
                 } else {
                     $this->eventsManager()->fire('onGetGroupVideo', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('participant'), $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(), $node->getChild('media')->getAttribute('caption')]);
                 }
             } elseif ($node->getChild('media')->getAttribute('type') == 'audio') {
                 $author = $node->getAttribute('participant');
                 $this->eventsManager()->fire('onGetAudio', [$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('seconds'), $node->getChild('media')->getAttribute('acodec'), $author]);
             } elseif ($node->getChild('media')->getAttribute('type') == 'vcard') {
                 if ($node->getChild('media')->hasChild('vcard')) {
                     $name = $node->getChild('media')->getChild('vcard')->getAttribute('name');
                     $data = $node->getChild('media')->getChild('vcard')->getData();
                 } else {
                     $name = 'NO_NAME';
                     $data = $node->getChild('media')->getData();
                 }
                 $author = $node->getAttribute('participant');
                 $this->eventsManager()->fire('onGetvCard', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('notify'), $name, $data, $author]);
             } elseif ($node->getChild('media')->getAttribute('type') == 'location') {
                 $url = $node->getChild('media')->getAttribute('url');
                 $name = $node->getChild('media')->getAttribute('name');
                 $author = $node->getAttribute('participant');
                 $this->eventsManager()->fire('onGetLocation', [$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(), $author]);
             }
             if ($autoReceipt) {
                 $this->sendReceipt($node, $type);
             }
         }
         if ($node->getChild('received') != null) {
             $this->eventsManager()->fire('onMessageReceivedClient', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('type'), $node->getAttribute('t'), $node->getAttribute('participant')]);
         }
     }
     if ($node->getTag() == 'presence' && $node->getAttribute('status') == 'dirty') {
         //clear dirty
         $categories = [];
         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 = [];
         if ($node->getAttribute('type') == null) {
             $this->eventsManager()->fire('onPresenceAvailable', [$this->phoneNumber, $node->getAttribute('from')]);
         } else {
             $this->eventsManager()->fire('onPresenceUnavailable', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('last')]);
         }
     }
     if ($node->getTag() == 'presence' && strncmp($node->getAttribute('from'), $this->phoneNumber, strlen($this->phoneNumber)) != 0 && strpos($node->getAttribute('from'), '-') !== false && $node->getAttribute('type') != null) {
         $groupId = parseJID($node->getAttribute('from'));
         if ($node->getAttribute('add') != null) {
             $this->eventsManager()->fire('onGroupsParticipantsAdd', [$this->phoneNumber, $groupId, parseJID($node->getAttribute('add'))]);
         } elseif ($node->getAttribute('remove') != null) {
             $this->eventsManager()->fire('onGroupsParticipantsRemove', [$this->phoneNumber, $groupId, parseJID($node->getAttribute('remove'))]);
         }
     }
     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->eventsManager()->fire('onMessageComposing', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), 'composing', $node->getAttribute('t')]);
         } else {
             $this->eventsManager()->fire('onMessagePaused', [$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->eventsManager()->fire('onPing', [$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 = [];
         if (!empty($existing)) {
             foreach ($existing->getChildren() as $child) {
                 $existingUsers[$child->getData()] = $child->getAttribute('jid');
             }
         }
         //now process failed numbers
         $failedNumbers = [];
         if (!empty($nonexisting)) {
             foreach ($nonexisting->getChildren() as $child) {
                 $failedNumbers[] = str_replace('+', '', $child->getData());
             }
         }
         $index = $sync->getAttribute('index');
         $result = new SyncResult($index, $sync->getAttribute('sid'), $existingUsers, $failedNumbers);
         $this->eventsManager()->fire('onGetSyncResult', [$result]);
     }
     if ($node->getTag() == 'receipt') {
         $this->eventsManager()->fire('onGetReceipt', [$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 (isset($this->nodeId['privacy']) && $this->nodeId['privacy'] == $node->getAttribute('id')) {
                 $listChild = $node->getChild(0)->getChild(0);
                 foreach ($listChild->getChildren() as $child) {
                     $blockedJids[] = $child->getAttribute('value');
                 }
                 $this->eventsManager()->fire('onGetPrivacyBlockedList', [$this->phoneNumber, $blockedJids]);
                 return;
             }
             $this->eventsManager()->fire('onGetRequestLastSeen', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getChild(0)->getAttribute('seconds')]);
         }
         if ($node->getChild('props') != null) {
             //server properties
             $props = [];
             foreach ($node->getChild(0)->getChildren() as $child) {
                 $props[$child->getAttribute('name')] = $child->getAttribute('value');
             }
             $this->eventsManager()->fire('onGetServerProperties', [$this->phoneNumber, $node->getChild(0)->getAttribute('version'), $props]);
         }
         if ($node->getChild('picture') != null) {
             $this->eventsManager()->fire('onGetProfilePicture', [$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 (strpos($node->getAttribute('from'), WHATSAPP_GROUP_SERVER) !== false) {
             //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 = [];
             $groupNodes = [];
             if ($node->getChild(0) != null && $node->getChild(0)->getChildren() != null) {
                 foreach ($node->getChild(0)->getChildren() as $child) {
                     $groupList[] = $child->getAttributes();
                     $groupNodes[] = $child;
                 }
             }
             if (isset($this->nodeId['groupcreate']) && $this->nodeId['groupcreate'] == $node->getAttribute('id')) {
                 $this->groupId = $node->getChild(0)->getAttribute('id');
                 $this->eventsManager()->fire('onGroupsChatCreate', [$this->phoneNumber, $this->groupId]);
             }
             if (isset($this->nodeId['leavegroup']) && $this->nodeId['leavegroup'] == $node->getAttribute('id')) {
                 $this->groupId = $node->getChild(0)->getChild(0)->getAttribute('id');
                 $this->eventsManager()->fire('onGroupsChatEnd', [$this->phoneNumber, $this->groupId]);
             }
             if (isset($this->nodeId['getgroups']) && $this->nodeId['getgroups'] == $node->getAttribute('id')) {
                 $this->eventsManager()->fire('onGetGroups', [$this->phoneNumber, $groupList]);
                 //getGroups returns a array of nodes which are exactly the same as from getGroupV2Info
                 //so lets call this event, we have all data at hand, no need to call getGroupV2Info for every
                 //group we are interested
                 foreach ($groupNodes as $groupNode) {
                     $this->handleGroupV2InfoResponse($groupNode, true);
                 }
             }
             if (isset($this->nodeId['get_groupv2_info']) && $this->nodeId['get_groupv2_info'] == $node->getAttribute('id')) {
                 $groupChild = $node->getChild(0);
                 if ($groupChild != null) {
                     $this->handleGroupV2InfoResponse($groupChild);
                 }
             }
         }
         if (isset($this->nodeId['get_lists']) && $this->nodeId['get_lists'] == $node->getAttribute('id')) {
             $broadcastLists = [];
             if ($node->getChild(0) != null) {
                 $childArray = $node->getChildren();
                 foreach ($childArray as $list) {
                     if ($list->getChildren() != null) {
                         foreach ($list->getChildren() as $sublist) {
                             $id = $sublist->getAttribute('id');
                             $name = $sublist->getAttribute('name');
                             $broadcastLists[$id]['name'] = $name;
                             $recipients = [];
                             foreach ($sublist->getChildren() as $recipient) {
                                 array_push($recipients, $recipient->getAttribute('jid'));
                             }
                             $broadcastLists[$id]['recipients'] = $recipients;
                         }
                     }
                 }
             }
             $this->eventsManager()->fire('onGetBroadcastLists', [$this->phoneNumber, $broadcastLists]);
         }
         if ($node->getChild('pricing') != null) {
             $this->eventsManager()->fire('onGetServicePricing', [$this->phoneNumber, $node->getChild(0)->getAttribute('price'), $node->getChild(0)->getAttribute('cost'), $node->getChild(0)->getAttribute('currency'), $node->getChild(0)->getAttribute('expiration')]);
         }
         if ($node->getChild('extend') != null) {
             $this->eventsManager()->fire('onGetExtendAccount', [$this->phoneNumber, $node->getChild('account')->getAttribute('kind'), $node->getChild('account')->getAttribute('status'), $node->getChild('account')->getAttribute('creation'), $node->getChild('account')->getAttribute('expiration')]);
         }
         if ($node->getChild('normalize') != null) {
             $this->eventsManager()->fire('onGetNormalizedJid', [$this->phoneNumber, $node->getChild(0)->getAttribute('result')]);
         }
         if ($node->getChild('status') != null) {
             $child = $node->getChild('status');
             foreach ($child->getChildren() as $status) {
                 $this->eventsManager()->fire('onGetStatus', [$this->phoneNumber, $status->getAttribute('jid'), 'requested', $node->getAttribute('id'), $status->getAttribute('t'), $status->getData()]);
             }
         }
     }
     if ($node->getTag() == 'iq' && $node->getAttribute('type') == 'error') {
         $errorType = null;
         foreach ($this->nodeId as $type => $nodeID) {
             if ($nodeID == $node->getAttribute('id')) {
                 $errorType = $type;
                 break;
             }
         }
         $this->eventsManager()->fire('onGetError', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getChild(0), $errorType]);
     }
     if ($node->getTag() == 'message' && $node->getAttribute('type') == 'media' && $node->getChild(0)->getAttribute('type') == 'image') {
         $msgId = $this->createIqId();
         $ackNode = new ProtocolNode('ack', ['url' => $node->getChild(0)->getAttribute('url')]);
         $iqNode = new ProtocolNode('iq', ['id' => $msgId, 'xmlns' => 'w:m', 'type' => 'set', 'to' => WHATSAPP_SERVER], [$ackNode]);
         $this->sendNode($iqNode);
     }
     $children = $node->getChild(0);
     if ($node->getTag() == 'stream:error' && !empty($children) && $node->getChild(0)->getTag() == 'system-shutdown') {
         $this->eventsManager()->fire('onStreamError', [$node->getChild(0)->getTag()]);
     }
     if ($node->getTag() == 'stream:error') {
         $this->eventsManager()->fire('onStreamError', [$node->getChild(0)->getTag()]);
     }
     if ($node->getTag() == 'notification') {
         $name = $node->getAttribute('notify');
         $type = $node->getAttribute('type');
         switch ($type) {
             case 'status':
                 $this->eventsManager()->fire('onGetStatus', [$this->phoneNumber, $node->getAttribute('from'), $node->getChild(0)->getTag(), $node->getAttribute('id'), $node->getAttribute('t'), $node->getChild(0)->getData()]);
                 break;
             case 'picture':
                 if ($node->hasChild('set')) {
                     $this->eventsManager()->fire('onProfilePictureChanged', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('t')]);
                 } else {
                     if ($node->hasChild('delete')) {
                         $this->eventsManager()->fire('onProfilePictureDeleted', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('t')]);
                     }
                 }
                 //TODO
                 break;
             case 'contacts':
                 $notification = $node->getChild(0)->getTag();
                 if ($notification == 'add') {
                     $this->eventsManager()->fire('onNumberWasAdded', [$this->phoneNumber, $node->getChild(0)->getAttribute('jid')]);
                 } elseif ($notification == 'remove') {
                     $this->eventsManager()->fire('onNumberWasRemoved', [$this->phoneNumber, $node->getChild(0)->getAttribute('jid')]);
                 } elseif ($notification == 'update') {
                     $this->eventsManager()->fire('onNumberWasUpdated', [$this->phoneNumber, $node->getChild(0)->getAttribute('jid')]);
                 }
                 break;
             case 'encrypt':
                 $value = $node->getChild(0)->getAttribute('value');
                 if (is_numeric($value)) {
                     $this->eventsManager()->fire('onGetKeysLeft', [$this->phoneNumber, $node->getChild(0)->getAttribute('value')]);
                 } else {
                     echo 'Corrupt Stream: value ' . $value . 'is not numeric';
                 }
                 break;
             case 'w:gp2':
                 if ($node->hasChild('remove')) {
                     if ($node->getChild(0)->hasChild('participant')) {
                         $this->eventsManager()->fire('onGroupsParticipantsRemove', [$this->phoneNumber, $node->getAttribute('from'), $node->getChild(0)->getChild(0)->getAttribute('jid')]);
                     }
                 } else {
                     if ($node->hasChild('add')) {
                         $this->eventsManager()->fire('onGroupsParticipantsAdd', [$this->phoneNumber, $node->getAttribute('from'), $node->getChild(0)->getChild(0)->getAttribute('jid')]);
                     } else {
                         if ($node->hasChild('create')) {
                             $groupMembers = [];
                             foreach ($node->getChild(0)->getChild(0)->getChildren() as $cn) {
                                 $groupMembers[] = $cn->getAttribute('jid');
                             }
                             $this->eventsManager()->fire('onGroupisCreated', [$this->phoneNumber, $node->getChild(0)->getChild(0)->getAttribute('creator'), $node->getChild(0)->getChild(0)->getAttribute('id'), $node->getChild(0)->getChild(0)->getAttribute('subject'), $node->getAttribute('participant'), $node->getChild(0)->getChild(0)->getAttribute('creation'), $groupMembers]);
                         } else {
                             if ($node->hasChild('subject')) {
                                 $this->eventsManager()->fire('onGetGroupsSubject', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('t'), $node->getAttribute('participant'), $node->getAttribute('notify'), $node->getChild(0)->getAttribute('subject')]);
                             } else {
                                 if ($node->hasChild('promote')) {
                                     $promotedJIDs = [];
                                     foreach ($node->getChild(0)->getChildren() as $cn) {
                                         $promotedJIDs[] = $cn->getAttribute('jid');
                                     }
                                     $this->eventsManager()->fire('onGroupsParticipantsPromote', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('t'), $node->getAttribute('participant'), $node->getAttribute('notify'), $promotedJIDs]);
                                 }
                             }
                         }
                     }
                 }
                 break;
             case 'account':
                 if ($node->getChild(0)->getAttribute('author') == '') {
                     $author = 'Paypal';
                 } else {
                     $author = $node->getChild(0)->getAttribute('author');
                 }
                 $this->eventsManager()->fire('onPaidAccount', [$this->phoneNumber, $author, $node->getChild(0)->getChild(0)->getAttribute('kind'), $node->getChild(0)->getChild(0)->getAttribute('status'), $node->getChild(0)->getChild(0)->getAttribute('creation'), $node->getChild(0)->getChild(0)->getAttribute('expiration')]);
                 break;
             case 'features':
                 if ($node->getChild(0)->getChild(0) == 'encrypt') {
                     $this->eventsManager()->fire('onGetFeature', [$this->phoneNumber, $node->getAttribute('from'), $node->getChild(0)->getChild(0)->getAttribute('value')]);
                 }
                 break;
             case 'web':
                 if ($node->getChild(0)->getTag() == 'action' && $node->getChild(0)->getAttribute('type') == 'sync') {
                     $data = $node->getChild(0)->getChildren();
                     $this->eventsManager()->fire('onWebSync', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $data[0]->getData(), $data[1]->getData(), $data[2]->getData()]);
                 }
                 break;
             default:
                 throw new \Exception('Method $type not implemented');
         }
         $this->sendAck($node, 'notification');
     }
     if ($node->getTag() == 'call') {
         if ($node->getChild(0)->getTag() == 'offer') {
             $callId = $node->getChild(0)->getAttribute('call-id');
             $this->sendReceipt($node, null, null, $callId);
             $this->eventsManager()->fire('onCallReceived', [$this->phoneNumber, $node->getAttribute('from'), $node->getAttribute('id'), $node->getAttribute('notify'), $node->getAttribute('t'), $node->getChild(0)->getAttribute('call-id')]);
         } else {
             $this->sendAck($node, 'call');
         }
     }
     if ($node->getTag() == 'ib') {
         foreach ($node->getChildren() as $child) {
             switch ($child->getTag()) {
                 case 'dirty':
                     $this->sendClearDirty([$child->getAttribute('type')]);
                     break;
                 case 'account':
                     $this->eventsManager()->fire('onPaymentRecieved', [$this->phoneNumber, $child->getAttribute('kind'), $child->getAttribute('status'), $child->getAttribute('creation'), $child->getAttribute('expiration')]);
                     break;
                 case 'offline':
                     break;
                 default:
                     throw new \Exception('ib handler for ' . $child->getTag() . ' not implemented');
             }
         }
     }
     // Disconnect socket on stream error.
     if ($node->getTag() == 'stream:error') {
         $this->disconnect();
     }
 }