Created
November 4, 2014 04:38
-
-
Save sirpoot/ab9eeee7c4d31a8a221d to your computer and use it in GitHub Desktop.
Fixed sending location crashing iOS Whatsapp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
Copyright (c) <2012> Tarek Galal <tare2.galal@gmail.com> | |
Permission is hereby granted, free of charge, to any person obtaining a copy of this | |
software and associated documentation files (the "Software"), to deal in the Software | |
without restriction, including without limitation the rights to use, copy, modify, | |
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to | |
permit persons to whom the Software is furnished to do so, subject to the following | |
conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR | |
A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE | |
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
''' | |
from Yowsup.ConnectionIO.protocoltreenode import ProtocolTreeNode | |
from Yowsup.ConnectionIO.ioexceptions import ConnectionClosedException | |
from Yowsup.ConnectionIO.connectionengine import ConnectionEngine | |
from Yowsup.Common.utilities import Utilities | |
from Yowsup.Common.debugger import Debugger | |
import threading, select, time | |
from Yowsup.Common.watime import WATime | |
from .Auth.auth import YowsupAuth | |
from Yowsup.Common.constants import Constants | |
from Yowsup.Interfaces.Lib.LibInterface import LibMethodInterface, LibSignalInterface | |
import tempfile | |
from random import randrange | |
import socket | |
import hashlib | |
import base64 | |
import sys | |
import traceback | |
class YowsupConnectionManager: | |
def __init__(self): | |
Debugger.attach(self) | |
self.currKeyId = 1 | |
self.iqId = 0 | |
self.verbose = True | |
self.state = 0 | |
self.lock = threading.Lock() | |
self.autoPong = True | |
self.domain = "s.whatsapp.net" | |
#self.methodInterface = MethodInterface(authenticatedSocketConnection.getId()) | |
#self.signalInterface = SignalInterface(authenticatedSocketConnection.getId()) | |
self.readerThread = None | |
self.methodInterface = LibMethodInterface() | |
self.signalInterface = LibSignalInterface() | |
self.readerThread = ReaderThread() | |
self.readerThread.setSignalInterface(self.signalInterface) | |
self.bindMethods() | |
def setInterfaces(self, signalInterface, methodInterface): | |
self.methodInterface = methodInterface | |
self.signalInterface = signalInterface | |
self.readerThread.setSignalInterface(self.signalInterface) | |
self.bindMethods() | |
def getSignalsInterface(self): | |
return self.signalInterface | |
def getMethodsInterface(self): | |
return self.methodInterface | |
def setAutoPong(self, autoPong): | |
self.autoPong = self.readerThread.autoPong = autoPong | |
def startReader(self): | |
if self.readerThread.isAlive(): | |
self._d("Reader already started") | |
return 0 | |
self._d("starting reader") | |
try: | |
self.readerThread.start() | |
self._d("started") | |
except RuntimeError: | |
self._d("Reader already started before") | |
self.readerThread.sendDisconnected() | |
return 0 | |
return 1 | |
def block(self): | |
self.readerThread.join() | |
def bindMethods(self): | |
self.methodInterface.registerCallback("getVersion", lambda: Constants.v) | |
self.methodInterface.registerCallback("message_send",self.sendText) | |
self.methodInterface.registerCallback("message_imageSend",self.sendImage) | |
self.methodInterface.registerCallback("message_audioSend",self.sendAudio) | |
self.methodInterface.registerCallback("message_videoSend",self.sendVideo) | |
self.methodInterface.registerCallback("message_locationSend",self.sendLocation) | |
self.methodInterface.registerCallback("message_vcardSend",self.sendVCard) | |
self.methodInterface.registerCallback("message_broadcast",self.sendBroadcast) | |
self.methodInterface.registerCallback("message_ack",self.sendMessageReceipt) | |
self.methodInterface.registerCallback("notification_ack", self.sendNotificationReceipt) | |
self.methodInterface.registerCallback("clientconfig_send",self.sendClientConfig) | |
self.methodInterface.registerCallback("delivered_ack",self.sendDeliveredReceiptAck) | |
self.methodInterface.registerCallback("visible_ack",self.sendVisibleReceiptAck) | |
self.methodInterface.registerCallback("ping",self.sendPing) | |
self.methodInterface.registerCallback("pong",self.sendPong) | |
self.methodInterface.registerCallback("typing_send",self.sendTyping) | |
self.methodInterface.registerCallback("typing_paused",self.sendPaused) | |
self.methodInterface.registerCallback("subject_ack",self.sendSubjectReceived) | |
self.methodInterface.registerCallback("group_getGroups", self.sendGetGroups) | |
self.methodInterface.registerCallback("group_getInfo",self.sendGetGroupInfo) | |
self.methodInterface.registerCallback("group_create",self.sendCreateGroupChat) | |
self.methodInterface.registerCallback("group_addParticipants",self.sendAddParticipants) | |
self.methodInterface.registerCallback("group_removeParticipants",self.sendRemoveParticipants) | |
self.methodInterface.registerCallback("group_end",self.sendEndGroupChat) | |
self.methodInterface.registerCallback("group_setSubject",self.sendSetGroupSubject) | |
self.methodInterface.registerCallback("group_setPicture", self.sendSetPicture) | |
self.methodInterface.registerCallback("group_getPicture", self.sendGetPicture) | |
self.methodInterface.registerCallback("group_getParticipants",self.sendGetParticipants) | |
self.methodInterface.registerCallback("picture_get",self.sendGetPicture) | |
self.methodInterface.registerCallback("picture_getIds",self.sendGetPictureIds) | |
self.methodInterface.registerCallback("contact_getProfilePicture", self.sendGetPicture) | |
self.methodInterface.registerCallback("status_update",self.sendChangeStatus) | |
self.methodInterface.registerCallback("presence_request",self.getLastOnline) | |
#self.methodInterface.registerCallback("presence_unsubscribe",self.sendUnsubscribe)#@@TODO implement method | |
self.methodInterface.registerCallback("presence_subscribe",self.sendSubscribe) | |
self.methodInterface.registerCallback("presence_sendAvailableForChat",self.sendAvailableForChat) | |
self.methodInterface.registerCallback("presence_sendAvailable",self.sendAvailable) | |
self.methodInterface.registerCallback("presence_sendUnavailable",self.sendUnavailable) | |
self.methodInterface.registerCallback("profile_setPicture", self.sendSetProfilePicture) | |
self.methodInterface.registerCallback("profile_getPicture", self.sendGetProfilePicture) | |
self.methodInterface.registerCallback("profile_setStatus", self.sendChangeStatus) | |
self.methodInterface.registerCallback("disconnect", self.disconnect) | |
self.methodInterface.registerCallback("ready", self.startReader) | |
self.methodInterface.registerCallback("auth_login", self.auth ) | |
#self.methodInterface.registerCallback("auth_login", self.auth) | |
self.methodInterface.registerCallback("media_requestUpload", self.sendRequestUpload) | |
def disconnect(self, reason=""): | |
self._d("Disconnect sequence initiated") | |
self._d("Sending term signal to reader thread") | |
if self.readerThread.isAlive(): | |
self.readerThread.terminate() | |
self._d("Shutting down socket") | |
self.socket.close() | |
self._d("Waiting for readerThread to die") | |
self.readerThread.join() | |
self._d("Disconnected!") | |
self._d(reason) | |
self.state = 0 | |
self.readerThread.sendDisconnected(reason) | |
def getConnection(self): | |
return self.socket | |
def triggerEvent(self, eventName, stanza): | |
if eventName in self.events and self.events[eventName] is not None: | |
self.events[eventName](stanza) | |
def bindEvent(self, eventName, callback): | |
if eventName in self.events: | |
self.events[eventName] = callback | |
########################################################## | |
def _writeNode(self, node): | |
if self.state == 2: | |
try: | |
self.out.write(node) | |
return True | |
except ConnectionClosedException: | |
self._d("CONNECTION DOWN") | |
#self.disconnect("closed") | |
if self.readerThread.isAlive(): | |
self.readerThread.terminate() | |
self.readerThread.join() | |
self.readerThread.sendDisconnected("closed") | |
return False | |
def onDisconnected(self): | |
self._d("Setting state to 0") | |
self.state = 0 | |
def auth(self, username, password): | |
self._d(">>>>>>>> AUTH CALLED") | |
username = str(username) | |
#password = str(password) | |
#traceback.print_stack() | |
self.lock.acquire() | |
if self.state == 0 : | |
if self.readerThread.isAlive(): | |
raise Exception("TWO READER THREADS ON BOARD!!") | |
self.readerThread = ReaderThread() | |
self.readerThread.autoPong = self.autoPong | |
self.readerThread.setSignalInterface(self.signalInterface) | |
yAuth = YowsupAuth(ConnectionEngine()) | |
try: | |
self.state = 1 | |
tokenData = Utilities.readToken() | |
resource = tokenData["r"] if tokenData else Constants.tokenData["r"] | |
connection = yAuth.authenticate(username, password, Constants.domain, resource) | |
except socket.gaierror: | |
self._d("DNS ERROR") | |
self.readerThread.sendDisconnected("dns") | |
#self.signalInterface.send("disconnected", ("dns",)) | |
self.lock.release() | |
self.state = 0 | |
return 0 | |
except socket.error: | |
self._d("Socket error, connection timed out") | |
self.readerThread.sendDisconnected("closed") | |
#self.signalInterface.send("disconnected", ("closed",)) | |
self.lock.release() | |
self.state = 0 | |
return 0 | |
except ConnectionClosedException: | |
self._d("Conn closed Exception") | |
self.readerThread.sendDisconnected("closed") | |
#self.signalInterface.send("disconnected", ("closed",)) | |
self.lock.release() | |
self.state = 0 | |
return 0 | |
if not connection: | |
self.state = 0 | |
self.signalInterface.send("auth_fail", (username, "invalid")) | |
self.lock.release() | |
return 0 | |
self.state = 2 | |
self.socket = connection | |
self.jid = self.socket.jid | |
#@@TODO REPLACE PROPERLY | |
self.out = self.socket.writer | |
self.readerThread.setSocket(self.socket) | |
self.readerThread.disconnectedCallback = self.onDisconnected | |
self.readerThread.onPing = self.sendPong | |
self.readerThread.ping = self.sendPing | |
self.signalInterface.send("auth_success", (username,)) | |
self.lock.release() | |
def sendTyping(self,jid): | |
self._d("SEND TYPING TO JID") | |
composing = ProtocolTreeNode("composing",{"xmlns":"http://jabber.org/protocol/chatstates"}) | |
message = ProtocolTreeNode("message",{"to":jid,"type":"chat"},[composing]); | |
self._writeNode(message); | |
def sendPaused(self,jid): | |
self._d("SEND PAUSED TO JID") | |
composing = ProtocolTreeNode("paused",{"xmlns":"http://jabber.org/protocol/chatstates"}) | |
message = ProtocolTreeNode("message",{"to":jid,"type":"chat"},[composing]); | |
self._writeNode(message); | |
def getSubjectMessage(self,to,msg_id,child): | |
messageNode = ProtocolTreeNode("message",{"to":to,"type":"subject","id":msg_id},[child]); | |
return messageNode | |
def sendSubjectReceived(self,to,msg_id): | |
self._d("Sending subject recv receipt") | |
receivedNode = ProtocolTreeNode("received",{"xmlns": "urn:xmpp:receipts"}); | |
messageNode = self.getSubjectMessage(to,msg_id,receivedNode); | |
self._writeNode(messageNode); | |
def sendMessageReceipt(self, jid, msgId): | |
self.sendReceipt(jid, "chat", msgId) | |
def sendNotificationReceipt(self, jid, notificationId): | |
self.sendReceipt(jid, "notification", notificationId) | |
def sendReceipt(self,jid,mtype,mid): | |
self._d("sending message received to "+jid+" - type:"+mtype+" - id:"+mid) | |
receivedNode = ProtocolTreeNode("received",{"xmlns": "urn:xmpp:receipts"}) | |
messageNode = ProtocolTreeNode("message",{"to":jid,"type":mtype,"id":mid},[receivedNode]); | |
self._writeNode(messageNode); | |
def sendDeliveredReceiptAck(self,to,msg_id): | |
self._writeNode(self.getReceiptAck(to,msg_id,"delivered")); | |
def sendVisibleReceiptAck(self,to,msg_id): | |
self._writeNode(self.getReceiptAck(to,msg_id,"visible")); | |
def getReceiptAck(self,to,msg_id,receiptType): | |
ackNode = ProtocolTreeNode("ack",{"xmlns":"urn:xmpp:receipts","type":receiptType}) | |
messageNode = ProtocolTreeNode("message",{"to":to,"type":"chat","id":msg_id},[ackNode]); | |
return messageNode; | |
def makeId(self,prefix): | |
self.iqId += 1 | |
idx = "" | |
if self.verbose: | |
idx += prefix + str(self.iqId); | |
else: | |
idx = "%x" % self.iqId | |
return idx | |
def sendPing(self): | |
idx = self.makeId("ping_") | |
self.readerThread.requests[idx] = self.readerThread.parsePingResponse; | |
pingNode = ProtocolTreeNode("ping",{"xmlns":"w:p"}); | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"type":"get","to":self.domain},[pingNode]); | |
self._writeNode(iqNode); | |
return idx | |
def sendPong(self,idx): | |
iqNode = ProtocolTreeNode("iq",{"type":"result","to":self.domain,"id":idx}) | |
self._writeNode(iqNode); | |
def getLastOnline(self,jid): | |
if len(jid.split('-')) == 2 or jid == "Server@s.whatsapp.net": #SUPER CANCEL SUBSCRIBE TO GROUP AND SERVER | |
return | |
self.sendSubscribe(jid); | |
self._d("presence request Initiated for %s"%(jid)) | |
idx = self.makeId("last_") | |
self.readerThread.requests[idx] = self.readerThread.parseLastOnline; | |
query = ProtocolTreeNode("query",{"xmlns":"jabber:iq:last"}); | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"type":"get","to":jid},[query]); | |
self._writeNode(iqNode) | |
def sendIq(self): | |
node = ProtocolTreeNode("iq",{"to":"g.us","type":"get","id":str(int(time.time()))+"-0"},None,'expired'); | |
self._writeNode(node); | |
node = ProtocolTreeNode("iq",{"to":"s.whatsapp.net","type":"set","id":str(int(time.time()))+"-1"},None,'expired'); | |
self._writeNode(node); | |
def sendAvailableForChat(self, pushname): | |
presenceNode = ProtocolTreeNode("presence",{"name":pushname}) | |
self._writeNode(presenceNode); | |
def sendAvailable(self): | |
presenceNode = ProtocolTreeNode("presence",{"type":"available"}) | |
self._writeNode(presenceNode); | |
def sendUnavailable(self): | |
presenceNode = ProtocolTreeNode("presence",{"type":"unavailable"}) | |
self._writeNode(presenceNode); | |
def sendSubscribe(self,to): | |
presenceNode = ProtocolTreeNode("presence",{"type":"subscribe","to":to}); | |
self._writeNode(presenceNode); | |
def mediaNode(fn): | |
def wrapped(self, *args): | |
mediaType = fn(self, *args) | |
url = args[1] | |
name = args[2] | |
size = args[3] | |
mmNode = ProtocolTreeNode("media", {"xmlns":"urn:xmpp:whatsapp:mms","type":mediaType,"file":name,"size":size,"url":url},None, args[4:][0] if args[4:] else None); | |
return mmNode | |
return wrapped | |
def sendMessage(fn): | |
def wrapped(self, *args): | |
node = fn(self, *args) | |
jid = "broadcast" if type(args[0]) == list else args[0] | |
messageNode = self.getMessageNode(jid, node) | |
self._writeNode(messageNode); | |
return messageNode.getAttributeValue("id") | |
return wrapped | |
def sendChangeStatus(self,status): | |
self._d("updating status to: %s"%(status)) | |
bodyNode = ProtocolTreeNode("body",None,None,status); | |
messageNode = self.getMessageNode("s.us",bodyNode) | |
self._writeNode(messageNode); | |
return messageNode.getAttributeValue("id") | |
@sendMessage | |
def sendText(self,jid, content): | |
return ProtocolTreeNode("body",None,None,content); | |
@sendMessage | |
@mediaNode | |
def sendImage(self, jid, url, name, size, preview): | |
return "image" | |
@sendMessage | |
@mediaNode | |
def sendVideo(self, jid, url, name, size, preview): | |
return "video" | |
@sendMessage | |
@mediaNode | |
def sendAudio(self, jid, url, name, size): | |
return "audio" | |
@sendMessage | |
# sirpoot | |
def sendLocation(self, jid, name, latitude, longitude, preview): | |
self._d("sending location (" + latitude + ":" + longitude + ")") | |
#sirpoot | |
#return ProtocolTreeNode("media", {"xmlns":"urn:xmpp:whatsapp:mms","type":"location","latitude":latitude,"longitude":longitude},None,preview) | |
return ProtocolTreeNode("media", {"xmlns":"urn:xmpp:whatsapp:mms","type":"location","latitude":latitude,"longitude":longitude, "name":name},None,preview) | |
@sendMessage | |
def sendVCard(self, jid, data, name): | |
cardNode = ProtocolTreeNode("vcard",{"name":name},None,data); | |
return ProtocolTreeNode("media", {"xmlns":"urn:xmpp:whatsapp:mms","type":"vcard"},[cardNode]) | |
@sendMessage | |
def sendBroadcast(self, jids, content): | |
broadcastNode = ProtocolTreeNode("broadcast", None, [ProtocolTreeNode("to", {"jid": jid}) for jid in jids]) | |
messageNode = ProtocolTreeNode("body",None,None,content); | |
return [broadcastNode, messageNode] | |
def sendClientConfig(self,sound,pushID,preview,platform): | |
idx = self.makeId("config_"); | |
configNode = ProtocolTreeNode("config",{"xmlns":"urn:xmpp:whatsapp:push","sound":sound,"id":pushID,"preview":"1" if preview else "0","platform":platform}) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"type":"set","to":self.domain},[configNode]); | |
self._writeNode(iqNode); | |
# gtype should be either "participating" or "owning" | |
def sendGetGroups(self,gtype): | |
self._d("getting groups %s"%(gtype)) | |
idx = self.makeId("get_groups_") | |
self.readerThread.requests[idx] = self.readerThread.parseGroups; | |
queryNode = ProtocolTreeNode("list",{"xmlns":"w:g","type":gtype}) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"type":"get","to":"g.us"},[queryNode]) | |
self._writeNode(iqNode) | |
def sendGetGroupInfo(self,jid, dummy): | |
self._d("getting group info for %s"%(jid)) | |
idx = self.makeId("get_g_info_") | |
self.readerThread.requests[idx] = self.readerThread.parseGroupInfo; | |
queryNode = ProtocolTreeNode("query",{"xmlns":"w:g"}) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"type":"get","to":jid},[queryNode]) | |
self._writeNode(iqNode) | |
def sendCreateGroupChat(self,subject): | |
self._d("creating group: %s"%(subject)) | |
idx = self.makeId("create_group_") | |
self.readerThread.requests[idx] = self.readerThread.parseGroupCreated; | |
queryNode = ProtocolTreeNode("group",{"xmlns":"w:g","action":"create","subject":subject}) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"type":"set","to":"g.us"},[queryNode]) | |
self._writeNode(iqNode) | |
def sendAddParticipants(self, gjid, participants): | |
self._d("opening group: %s"%(gjid)) | |
self._d("adding participants: %s"%(participants)) | |
idx = self.makeId("add_group_participants_") | |
self.readerThread.requests[idx] = self.readerThread.parseAddedParticipants; | |
innerNodeChildren = [] | |
for part in participants: | |
innerNodeChildren.append( ProtocolTreeNode("participant",{"jid":part}) ) | |
queryNode = ProtocolTreeNode("add",{"xmlns":"w:g"},innerNodeChildren) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"type":"set","to":gjid},[queryNode]) | |
self._writeNode(iqNode) | |
def sendRemoveParticipants(self,gjid, participants): | |
self._d("opening group: %s"%(gjid)) | |
self._d("removing participants: %s"%(participants)) | |
idx = self.makeId("remove_group_participants_") | |
self.readerThread.requests[idx] = self.readerThread.parseRemovedParticipants; | |
innerNodeChildren = [] | |
for part in participants: | |
innerNodeChildren.append( ProtocolTreeNode("participant",{"jid":part}) ) | |
queryNode = ProtocolTreeNode("remove",{"xmlns":"w:g"},innerNodeChildren) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"type":"set","to":gjid},[queryNode]) | |
self._writeNode(iqNode) | |
def sendEndGroupChat(self,gjid): | |
self._d("removing group: %s"%(gjid)) | |
idx = self.makeId("leave_group_") | |
self.readerThread.requests[idx] = self.readerThread.parseGroupEnded; | |
innerNodeChildren = [] | |
innerNodeChildren.append( ProtocolTreeNode("group",{"id":gjid}) ) | |
queryNode = ProtocolTreeNode("leave",{"xmlns":"w:g"},innerNodeChildren) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"type":"set","to":"g.us"},[queryNode]) | |
self._writeNode(iqNode) | |
def sendSetGroupSubject(self,gjid,subject): | |
#subject = subject.encode('utf-8') | |
#self._d("setting group subject of " + gjid + " to " + subject) | |
idx = self.makeId("set_group_subject_") | |
self.readerThread.requests[idx] = self.readerThread.parseGroupSubject | |
queryNode = ProtocolTreeNode("subject",{"xmlns":"w:g","value":subject}) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"type":"set","to":gjid},[queryNode]); | |
self._writeNode(iqNode) | |
def sendGetParticipants(self,jid): | |
idx = self.makeId("get_participants_") | |
self.readerThread.requests[idx] = self.readerThread.parseParticipants | |
listNode = ProtocolTreeNode("list",{"xmlns":"w:g"}) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"type":"get","to":jid},[listNode]); | |
self._writeNode(iqNode) | |
def sendGetPicture(self,jid): | |
self._d("GETTING PICTURE FROM " + jid) | |
idx = self.makeId("get_picture_") | |
#@@TODO, ?! | |
self.readerThread.requests[idx] = self.readerThread.parseGetPicture | |
listNode = ProtocolTreeNode("picture",{"xmlns":"w:profile:picture","type":"image"}) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"to":jid,"type":"get"},[listNode]); | |
self._writeNode(iqNode) | |
def sendGetPictureIds(self,jids): | |
idx = self.makeId("get_picture_ids_") | |
self.readerThread.requests[idx] = self.readerThread.parseGetPictureIds | |
innerNodeChildren = [] | |
for jid in jids: | |
innerNodeChildren.append( ProtocolTreeNode("user",{"jid": jid}) ) | |
queryNode = ProtocolTreeNode("list",{"xmlns":"w:profile:picture"},innerNodeChildren) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"type":"get"},[queryNode]) | |
self._writeNode(iqNode) | |
def sendGetProfilePicture(self): | |
return self.sendGetPicture(self.jid) | |
def sendSetProfilePicture(self, filepath): | |
return self.sendSetPicture(self.jid, filepath) | |
def sendSetPicture(self, jid, imagePath): | |
f = open(imagePath, 'rb') | |
imageData = f.read() | |
imageData = bytearray(imageData) | |
f.close() | |
idx = self.makeId("set_picture_") | |
self.readerThread.requests[idx] = self.readerThread.parseSetPicture | |
listNode = ProtocolTreeNode("picture",{"xmlns":"w:profile:picture","type":"image"}, None, imageData) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"to":jid,"type":"set"},[listNode]) | |
self._writeNode(iqNode) | |
def sendRequestUpload(self, b64Hash, t, size, b64OrigHash = None): | |
idx = self.makeId("upload_") | |
self.readerThread.requests[idx] = lambda iqresnode: self.readerThread.parseRequestUpload(iqresnode, b64Hash) | |
if type(size) is not str: | |
size = str(size) | |
attribs = {"xmlns":"w:m","hash":b64Hash, "type":t, "size":size} | |
if b64OrigHash: | |
attribs["orighash"] = b64OrigHash | |
mediaNode = ProtocolTreeNode("media", attribs) | |
iqNode = ProtocolTreeNode("iq",{"id":idx,"to":"s.whatsapp.net","type":"set"},[mediaNode]) | |
self._writeNode(iqNode) | |
def getMessageNode(self, jid, child): | |
requestNode = None; | |
serverNode = ProtocolTreeNode("server",None); | |
xNode = ProtocolTreeNode("x",{"xmlns":"jabber:x:event"},[serverNode]); | |
childCount = (0 if requestNode is None else 1) +2; | |
messageChildren = []#[None]*childCount; | |
if requestNode is not None: | |
messageChildren.append(requestNode); | |
#System.currentTimeMillis() / 1000L + "-"+1 | |
messageChildren.append(xNode) | |
if type(child) == list: | |
messageChildren.extend(child) | |
else: | |
messageChildren.append(child) | |
msgId = str(int(time.time()))+"-"+ str(self.currKeyId) | |
messageNode = ProtocolTreeNode("message",{"to":jid,"type":"chat","id":msgId},messageChildren) | |
self.currKeyId += 1 | |
return messageNode; | |
class ReaderThread(threading.Thread): | |
def __init__(self): | |
Debugger.attach(self); | |
self.signalInterface = None | |
#self.socket = connection | |
self.terminateRequested = False | |
self.disconnectedSent = False | |
self.timeout = 180 | |
self.selectTimeout = 3 | |
self.requests = {}; | |
self.lock = threading.Lock() | |
self.disconnectedCallback = None | |
self.autoPong = True | |
self.onPing = self.ping = None | |
self.lastPongTime = int(time.time()) | |
super(ReaderThread,self).__init__(); | |
self.daemon = True | |
def setSocket(self, connection): | |
self.socket = connection | |
def setSignalInterface(self, signalInterface): | |
self.signalInterface = signalInterface | |
def terminate(self): | |
self._d("attempting to exit gracefully") | |
self.terminateRequested = True | |
def sendDisconnected(self, reason="noreason"): | |
self._d("Sending disconnected because of %s" % reason) | |
self.lock.acquire() | |
if not self.disconnectedSent: | |
self.disconnectedSent = True | |
if self.disconnectedCallback: | |
self.disconnectedCallback() | |
self.lock.release() | |
self.signalInterface.send("disconnected", (reason,)) | |
def run(self): | |
self._d("Read thread startedX"); | |
while True: | |
countdown = self.timeout - ((int(time.time()) - self.lastPongTime)) | |
remainder = countdown % self.selectTimeout | |
countdown = countdown - remainder | |
if countdown <= 0: | |
self._d("No hope, dying!") | |
self.sendDisconnected("closed") | |
return | |
else: | |
if countdown % (self.selectTimeout*10) == 0 or countdown < 11: | |
self._d("Waiting, time to die: T-%i seconds" % countdown ) | |
if self.timeout-countdown == 150 and self.ping and self.autoPong: | |
self.ping() | |
self.selectTimeout = 1 if countdown < 11 else 3 | |
try: | |
ready = select.select([self.socket.reader.rawIn], [], [], self.selectTimeout) | |
except: | |
self._d("Error in ready") | |
raise | |
return | |
if self.terminateRequested: | |
return | |
if ready[0]: | |
try: | |
node = self.socket.reader.nextTree() | |
except ConnectionClosedException: | |
#print traceback.format_exc() | |
self._d("Socket closed, got 0 bytes!") | |
#self.signalInterface.send("disconnected", ("closed",)) | |
self.sendDisconnected("closed") | |
return | |
self.lastPongTime = int(time.time()); | |
if node is not None: | |
if ProtocolTreeNode.tagEquals(node,"iq"): | |
iqType = node.getAttributeValue("type") | |
idx = node.getAttributeValue("id") | |
if iqType is None: | |
raise Exception("iq doesn't have type") | |
if iqType == "result": | |
if idx in self.requests: | |
self.requests[idx](node) | |
del self.requests[idx] | |
elif idx.startswith(self.connection.user): | |
accountNode = node.getChild(0) | |
ProtocolTreeNode.require(accountNode,"account") | |
kind = accountNode.getAttributeValue("kind") | |
if kind == "paid": | |
self.connection.account_kind = 1 | |
elif kind == "free": | |
self.connection.account_kind = 0 | |
else: | |
self.connection.account_kind = -1 | |
expiration = accountNode.getAttributeValue("expiration") | |
if expiration is None: | |
raise Exception("no expiration") | |
try: | |
self.connection.expire_date = long(expiration) | |
except ValueError: | |
raise IOError("invalid expire date %s"%(expiration)) | |
self.eventHandler.onAccountChanged(self.connection.account_kind,self.connection.expire_date) | |
elif iqType == "error": | |
if idx in self.requests: | |
self.requests[idx](node) | |
del self.requests[idx] | |
elif iqType == "get": | |
childNode = node.getChild(0) | |
if ProtocolTreeNode.tagEquals(childNode,"ping"): | |
if self.autoPong: | |
self.onPing(idx) | |
self.signalInterface.send("ping", (idx,)) | |
elif ProtocolTreeNode.tagEquals(childNode,"query") and node.getAttributeValue("from") is not None and "http://jabber.org/protocol/disco#info" == childNode.getAttributeValue("xmlns"): | |
pin = childNode.getAttributeValue("pin"); | |
timeoutString = childNode.getAttributeValue("timeout"); | |
try: | |
timeoutSeconds = int(timeoutString) if timeoutString is not None else None | |
except ValueError: | |
raise Exception("relay-iq exception parsing timeout %s "%(timeoutString)) | |
if pin is not None: | |
self.eventHandler.onRelayRequest(pin,timeoutSeconds,idx) | |
elif iqType == "set": | |
childNode = node.getChild(0) | |
if ProtocolTreeNode.tagEquals(childNode,"query"): | |
xmlns = childNode.getAttributeValue("xmlns") | |
if xmlns == "jabber:iq:roster": | |
itemNodes = childNode.getAllChildren("item"); | |
ask = "" | |
for itemNode in itemNodes: | |
jid = itemNode.getAttributeValue("jid") | |
subscription = itemNode.getAttributeValue("subscription") | |
ask = itemNode.getAttributeValue("ask") | |
else: | |
raise Exception("Unkown iq type %s"%(iqType)) | |
elif ProtocolTreeNode.tagEquals(node,"presence"): | |
xmlns = node.getAttributeValue("xmlns") | |
jid = node.getAttributeValue("from") | |
if (xmlns is None or xmlns == "urn:xmpp") and jid is not None: | |
presenceType = node.getAttributeValue("type") | |
if presenceType == "unavailable": | |
self.signalInterface.send("presence_unavailable", (jid,)) | |
elif presenceType is None or presenceType == "available": | |
self.signalInterface.send("presence_available", (jid,)) | |
elif xmlns == "w" and jid is not None: | |
status = node.getAttributeValue("status") | |
if status == "dirty": | |
#categories = self.parseCategories(node); #@@TODO, send along with signal | |
self._d("WILL SEND DIRTY") | |
self.signalInterface.send("status_dirty") | |
self._d("SENT DIRTY") | |
elif ProtocolTreeNode.tagEquals(node,"message"): | |
self.parseMessage(node) | |
self._d("Reader thread terminating now!") | |
def parseOfflineMessageStamp(self,stamp): | |
watime = WATime(); | |
parsed = watime.parseIso(stamp) | |
local = watime.utcToLocal(parsed) | |
stamp = watime.datetimeToTimestamp(local) | |
return stamp | |
def parsePingResponse(self, node): | |
idx = node.getAttributeValue("id") | |
self.lastPongTime = int(time.time()) | |
def parseLastOnline(self,node): | |
jid = node.getAttributeValue("from"); | |
firstChild = node.getChild(0); | |
if "error" in firstChild.toString(): | |
return | |
ProtocolTreeNode.require(firstChild,"query"); | |
seconds = firstChild.getAttributeValue("seconds"); | |
status = None | |
status = firstChild.data #@@TODO discarded? | |
try: | |
if seconds is not None and jid is not None: | |
self.signalInterface.send("presence_updated", (jid, int(seconds))) | |
except: | |
self._d("Ignored exception in handleLastOnline "+ sys.exc_info()[1]) | |
def parseGroups(self,node): | |
children = node.getAllChildren("group"); | |
for groupNode in children: | |
jid = groupNode.getAttributeValue("id") + "@g.us" | |
owner = groupNode.getAttributeValue("owner") | |
subject = groupNode.getAttributeValue("subject") if sys.version_info < (3, 0) else groupNode.getAttributeValue("subject").encode('latin-1').decode() | |
subjectT = groupNode.getAttributeValue("s_t") | |
subjectOwner = groupNode.getAttributeValue("s_o") | |
creation = groupNode.getAttributeValue("creation") | |
self.signalInterface.send("group_gotInfo",(jid, owner, subject, subjectOwner, int(subjectT),int(creation))) | |
def parseGroupInfo(self,node): | |
jid = node.getAttributeValue("from"); | |
groupNode = node.getChild(0) | |
if "error code" in groupNode.toString(): | |
self.signalInterface.send("group_infoError",(0,)) #@@TODO replace with real error code | |
else: | |
ProtocolTreeNode.require(groupNode,"group") | |
#gid = groupNode.getAttributeValue("id") | |
owner = groupNode.getAttributeValue("owner") | |
subject = groupNode.getAttributeValue("subject") if sys.version_info < (3, 0) else groupNode.getAttributeValue("subject").encode('latin-1').decode(); | |
subjectT = groupNode.getAttributeValue("s_t") | |
subjectOwner = groupNode.getAttributeValue("s_o") | |
creation = groupNode.getAttributeValue("creation") | |
self.signalInterface.send("group_gotInfo",(jid, owner, subject, subjectOwner, int(subjectT),int(creation))) | |
def parseAddedParticipants(self, node): | |
jid = node.getAttributeValue("from"); | |
jids = [] | |
addNodes = node.getAllChildren("add") | |
for a in addNodes: | |
t = a.getAttributeValue("type") | |
if t == "success": | |
jids.append(a.getAttributeValue("participant")) | |
else: | |
self._d("Failed to add %s" % jids.append(a.getAttributeValue("participant"))) | |
self.signalInterface.send("group_addParticipantsSuccess", (jid, jids)) | |
def parseRemovedParticipants(self,node): #fromm, successVector=None,failTable=None | |
jid = node.getAttributeValue("from"); | |
jids = [] | |
addNodes = node.getAllChildren("remove") | |
for a in addNodes: | |
t = a.getAttributeValue("type") | |
if t == "success": | |
jids.append(a.getAttributeValue("participant")) | |
else: | |
self._d("Failed to add %s" % jids.append(a.getAttributeValue("participant"))) | |
self._d("handleRemovedParticipants DONE!"); | |
self.signalInterface.send("group_removeParticipantsSuccess", (jid, jids)) | |
def parseGroupCreated(self,node): | |
jid = node.getAttributeValue("from"); | |
groupNode = node.getChild(0) | |
if ProtocolTreeNode.tagEquals(groupNode,"error"): | |
errorCode = groupNode.getAttributeValue("code") | |
self.signalInterface.send("group_createFail", (errorCode,)) | |
return | |
ProtocolTreeNode.require(groupNode,"group") | |
group_id = groupNode.getAttributeValue("id") | |
self.signalInterface.send("group_createSuccess", (group_id + "@g.us",)) | |
def parseGroupEnded(self,node): | |
#jid = node.getAttributeValue("from"); | |
leaveNode = node.getChild(0) | |
groupNode = leaveNode.getChild(0) | |
jid = groupNode.getAttributeValue("id") | |
self.signalInterface.send("group_endSuccess", (jid,)) | |
def parseGroupSubject(self,node): | |
jid = node.getAttributeValue("from"); | |
self.signalInterface.send("group_setSubjectSuccess", (jid,)) | |
def parseParticipants(self,node): | |
jid = node.getAttributeValue("from"); | |
children = node.getAllChildren("participant"); | |
jids = [] | |
for c in children: | |
jids.append(c.getAttributeValue("jid")) | |
self.signalInterface.send("group_gotParticipants", (jid, jids)) | |
#@@TODO PICTURE STUFF | |
def createTmpFile(self, data, mode = "w"): | |
tmp = tempfile.mkstemp()[1] | |
tmpfile = open(tmp, mode) | |
tmpfile.write(data) | |
tmpfile.close() | |
return tmp | |
def parseGetPicture(self,node): | |
jid = node.getAttributeValue("from"); | |
if "error code" in node.toString(): | |
return; | |
pictureNode = node.getChild("picture") | |
if pictureNode.data is not None: | |
tmp = self.createTmpFile(pictureNode.data if sys.version_info < (3, 0) else pictureNode.data.encode('latin-1'), "wb") | |
pictureId = int(pictureNode.getAttributeValue('id')) | |
try: | |
jid.index('-') | |
self.signalInterface.send("group_gotPicture", (jid, pictureId, tmp)) | |
except ValueError: | |
self.signalInterface.send("contact_gotProfilePicture", (jid, pictureId, tmp)) | |
def parseGetPictureIds(self,node): | |
jid = node.getAttributeValue("from"); | |
groupNode = node.getChild("list") | |
#self._d(groupNode.toString()) | |
children = groupNode.getAllChildren("user"); | |
#pids = [] | |
for c in children: | |
if c.getAttributeValue("id") is not None: | |
#pids.append({"jid":c.getAttributeValue("jid"),"id":c.getAttributeValue("id")}) | |
self.signalInterface.send("contact_gotProfilePictureId", (c.getAttributeValue("jid"), c.getAttributeValue("id"))) | |
#self.signalInterface.send("contact_gotProfilePictureIds", (pids,)) | |
def parseSetPicture(self,node): | |
jid = node.getAttributeValue("from"); | |
picNode = node.getChild("picture") | |
try: | |
jid.index('-') | |
if picNode is None: | |
self.signalInterface.send("group_setPictureError", (jid,0)) #@@TODO SEND correct error code | |
else: | |
pictureId = int(picNode.getAttributeValue("id")) | |
self.signalInterface.send("group_setPictureSuccess", (jid, pictureId)) | |
except ValueError: | |
if picNode is None: | |
self.signalInterface.send("profile_setPictureError", (0,)) #@@TODO SEND correct error code | |
else: | |
pictureId = int(picNode.getAttributeValue("id")) | |
self.signalInterface.send("profile_setPictureSuccess", (pictureId,)) | |
def parseRequestUpload(self, iqNode, _hash): | |
mediaNode = iqNode.getChild("media") | |
if mediaNode: | |
url = mediaNode.getAttributeValue("url") | |
resumeFrom = mediaNode.getAttributeValue("resume") | |
if not resumeFrom: | |
resumeFrom = 0 | |
if url: | |
self.signalInterface.send("media_uploadRequestSuccess", (_hash, url, resumeFrom)) | |
else: | |
self.signalInterface.send("media_uploadRequestFailed", (_hash,)) | |
else: | |
duplicateNode = iqNode.getChild("duplicate") | |
if duplicateNode: | |
url = duplicateNode.getAttributeValue("url") | |
self.signalInterface.send("media_uploadRequestDuplicate", (_hash, url)) | |
else: | |
self.signalInterface.send("media_uploadRequestFailed", (_hash,)) | |
def parseMessage(self,messageNode): | |
bodyNode = messageNode.getChild("body"); | |
# offlineNode = messageNode.getChild("offline") | |
newSubject = "" if bodyNode is None else bodyNode.data; | |
msgData = None | |
# timestamp =long(time.time()*1000) if not offlineNode else int(messageNode.getAttributeValue("t"))*1000; | |
timestamp =int(messageNode.getAttributeValue("t")) | |
isGroup = False | |
isBroadcast = False | |
if newSubject.find("New version of WhatsApp Messenger is now available")>-1: | |
self._d("Rejecting whatsapp server message") | |
return #REJECT THIS FUCKING MESSAGE! | |
fromAttribute = messageNode.getAttributeValue("from"); | |
try: | |
fromAttribute.index('-') | |
isGroup = True | |
except: | |
pass | |
author = messageNode.getAttributeValue("author"); | |
#@@TODO reactivate blocked contacts check from client | |
'''if fromAttribute is not None and fromAttribute in self.eventHandler.blockedContacts: | |
self._d("CONTACT BLOCKED!") | |
return | |
if author is not None and author in self.eventHandler.blockedContacts: | |
self._d("CONTACT BLOCKED!") | |
return | |
''' | |
pushName = None | |
notifNode = messageNode.getChild("notify") | |
if notifNode is not None: | |
pushName = notifNode.getAttributeValue("name"); | |
#pushName = pushName.decode("utf8") | |
msgId = messageNode.getAttributeValue("id"); | |
attribute_t = messageNode.getAttributeValue("t"); | |
typeAttribute = messageNode.getAttributeValue("type"); | |
if typeAttribute == "error": | |
errorCode = 0; | |
errorNodes = messageNode.getAllChildren("error"); | |
for errorNode in errorNodes: | |
codeString = errorNode.getAttributeValue("code") | |
try: | |
errorCode = int(codeString); | |
except ValueError: | |
'''catch value error''' | |
self.signalInterface.send("message_error", (msgId, fromAttribute, errorCode)) | |
elif typeAttribute == "notification": | |
receiptRequested = False; | |
pictureUpdated = None | |
pictureUpdated = messageNode.getChild("notification").getAttributeValue("type"); | |
wr = None | |
wr = messageNode.getChild("request").getAttributeValue("xmlns"); | |
if wr == "urn:xmpp:receipts": | |
receiptRequested = True | |
if pictureUpdated == "picture": | |
notifNode = messageNode.getChild("notification"); | |
#bodyNode = messageNode.getChild("notification").getChild("set") or messageNode.getChild("notification").getChild("delete") | |
bodyNode = notifNode.getChild("set") | |
if bodyNode: | |
pictureId = int(bodyNode.getAttributeValue("id")) | |
if isGroup: | |
self.signalInterface.send("notification_groupPictureUpdated",(bodyNode.getAttributeValue("jid"), bodyNode.getAttributeValue("author"), timestamp, msgId, pictureId, receiptRequested)) | |
else: | |
self.signalInterface.send("notification_contactProfilePictureUpdated",(bodyNode.getAttributeValue("jid"), timestamp, msgId, pictureId, receiptRequested)) | |
else: | |
bodyNode = notifNode.getChild("delete") | |
if bodyNode: | |
if isGroup: | |
self.signalInterface.send("notification_groupPictureRemoved",(bodyNode.getAttributeValue("jid"), bodyNode.getAttributeValue("author"), timestamp, msgId, receiptRequested)) | |
else: | |
self.signalInterface.send("notification_contactProfilePictureRemoved",(bodyNode.getAttributeValue("jid"), timestamp, msgId, receiptRequested)) | |
#if isGroup: | |
# | |
# self.signalInterface.send("notification_groupPictureUpdated",(bodyNode.getAttributeValue("jid"), bodyNode.getAttributeValue("author"), timestamp, msgId, receiptRequested)) | |
#else: | |
# self.signalInterface.send("notification_contactProfilePictureUpdated",(bodyNode.getAttributeValue("jid"), timestamp, msgId, receiptRequested)) | |
else: | |
addSubject = None | |
removeSubject = None | |
author = None | |
bodyNode = messageNode.getChild("notification").getChild("add"); | |
if bodyNode is not None: | |
addSubject = bodyNode.getAttributeValue("jid"); | |
author = bodyNode.getAttributeValue("author") or addSubject | |
bodyNode = messageNode.getChild("notification").getChild("remove"); | |
if bodyNode is not None: | |
removeSubject = bodyNode.getAttributeValue("jid"); | |
author = bodyNode.getAttributeValue("author") or removeSubject | |
if addSubject is not None: | |
self.signalInterface.send("notification_groupParticipantAdded", (fromAttribute, addSubject, author, timestamp, msgId, receiptRequested)) | |
if removeSubject is not None: | |
self.signalInterface.send("notification_groupParticipantRemoved", (fromAttribute, removeSubject, author, timestamp, msgId, receiptRequested)) | |
elif typeAttribute == "subject": | |
receiptRequested = False; | |
requestNodes = messageNode.getAllChildren("request"); | |
for requestNode in requestNodes: | |
if requestNode.getAttributeValue("xmlns") == "urn:xmpp:receipts": | |
receiptRequested = True; | |
bodyNode = messageNode.getChild("body"); | |
newSubject = None if bodyNode is None else (bodyNode.data if sys.version_info < (3, 0) else bodyNode.data.encode('latin-1').decode()); | |
if newSubject is not None: | |
self.signalInterface.send("group_subjectReceived",(msgId, fromAttribute, author, newSubject, int(attribute_t), receiptRequested)) | |
elif typeAttribute == "chat": | |
wantsReceipt = False; | |
messageChildren = [] if messageNode.children is None else messageNode.children | |
for childNode in messageChildren: | |
if ProtocolTreeNode.tagEquals(childNode,"request"): | |
wantsReceipt = True; | |
if ProtocolTreeNode.tagEquals(childNode,"broadcast"): | |
isBroadcast = True | |
elif ProtocolTreeNode.tagEquals(childNode,"composing"): | |
self.signalInterface.send("contact_typing", (fromAttribute,)) | |
elif ProtocolTreeNode.tagEquals(childNode,"paused"): | |
self.signalInterface.send("contact_paused",(fromAttribute,)) | |
elif ProtocolTreeNode.tagEquals(childNode,"media") and msgId is not None: | |
self._d("MULTIMEDIA MESSAGE!"); | |
mediaUrl = messageNode.getChild("media").getAttributeValue("url"); | |
mediaType = messageNode.getChild("media").getAttributeValue("type") | |
mediaSize = messageNode.getChild("media").getAttributeValue("size") | |
encoding = messageNode.getChild("media").getAttributeValue("encoding") | |
mediaPreview = None | |
if mediaType == "image": | |
mediaPreview = messageNode.getChild("media").data | |
if encoding == "raw" and mediaPreview: | |
mediaPreview = base64.b64encode(mediaPreview) if sys.version_info < (3, 0) else base64.b64encode(mediaPreview.encode('latin-1')).decode() | |
if isGroup: | |
self.signalInterface.send("group_imageReceived", (msgId, fromAttribute, author, mediaPreview, mediaUrl, mediaSize, wantsReceipt)) | |
else: | |
self.signalInterface.send("image_received", (msgId, fromAttribute, mediaPreview, mediaUrl, mediaSize, wantsReceipt, isBroadcast)) | |
elif mediaType == "video": | |
mediaPreview = messageNode.getChild("media").data | |
if encoding == "raw" and mediaPreview: | |
mediaPreview = base64.b64encode(mediaPreview) if sys.version_info < (3, 0) else base64.b64encode(mediaPreview.encode('latin-1')).decode() | |
if isGroup: | |
self.signalInterface.send("group_videoReceived", (msgId, fromAttribute, author, mediaPreview, mediaUrl, mediaSize, wantsReceipt)) | |
else: | |
self.signalInterface.send("video_received", (msgId, fromAttribute, mediaPreview, mediaUrl, mediaSize, wantsReceipt, isBroadcast)) | |
elif mediaType == "audio": | |
mediaPreview = messageNode.getChild("media").data | |
if isGroup: | |
self.signalInterface.send("group_audioReceived", (msgId, fromAttribute, author, mediaUrl, mediaSize, wantsReceipt)) | |
else: | |
self.signalInterface.send("audio_received", (msgId, fromAttribute, mediaUrl, mediaSize, wantsReceipt, isBroadcast)) | |
elif mediaType == "location": | |
mlatitude = messageNode.getChild("media").getAttributeValue("latitude") | |
mlongitude = messageNode.getChild("media").getAttributeValue("longitude") | |
name = messageNode.getChild("media").getAttributeValue("name") | |
if name and not sys.version_info < (3, 0): | |
name = name.encode('latin-1').decode() | |
mediaPreview = messageNode.getChild("media").data | |
if encoding == "raw" and mediaPreview: | |
mediaPreview = base64.b64encode(mediaPreview) if sys.version_info < (3, 0) else base64.b64encode(mediaPreview.encode('latin-1')).decode() | |
if isGroup: | |
self.signalInterface.send("group_locationReceived", (msgId, fromAttribute, author, name or "", mediaPreview, mlatitude, mlongitude, wantsReceipt)) | |
else: | |
self.signalInterface.send("location_received", (msgId, fromAttribute, name or "", mediaPreview, mlatitude, mlongitude, wantsReceipt, isBroadcast)) | |
elif mediaType =="vcard": | |
#return | |
#mediaItem.preview = messageNode.getChild("media").data | |
vcardData = messageNode.getChild("media").getChild("vcard").toString() | |
vcardName = messageNode.getChild("media").getChild("vcard").getAttributeValue("name") | |
if vcardName and not sys.version_info < (3, 0): | |
vcardName = vcardName.encode('latin-1').decode() | |
if vcardData is not None: | |
n = vcardData.find(">") +1 | |
vcardData = vcardData[n:] | |
vcardData = vcardData.replace("</vcard>","") | |
if isGroup: | |
self.signalInterface.send("group_vcardReceived", (msgId, fromAttribute, author, vcardName, vcardData, wantsReceipt)) | |
else: | |
self.signalInterface.send("vcard_received", (msgId, fromAttribute, vcardName, vcardData, wantsReceipt, isBroadcast)) | |
else: | |
self._d("Unknown media type") | |
return | |
elif ProtocolTreeNode.tagEquals(childNode,"body") and msgId is not None: | |
msgData = childNode.data; | |
#fmsg.setData({"status":0,"key":key.toString(),"content":msgdata,"type":WAXMPP.message_store.store.Message.TYPE_RECEIVED}); | |
elif ProtocolTreeNode.tagEquals(childNode,"received") and fromAttribute is not None and msgId is not None: | |
if fromAttribute == "s.us": | |
self.signalInterface.send("profile_setStatusSuccess", ("s.us", msgId,)) | |
return; | |
#@@TODO autosend ack from client | |
#print "NEW MESSAGE RECEIVED NOTIFICATION!!!" | |
#self.connection.sendDeliveredReceiptAck(fromAttribute,msg_id); | |
self.signalInterface.send("receipt_messageDelivered", (fromAttribute, msgId)) | |
return | |
elif not (ProtocolTreeNode.tagEquals(childNode,"active")): | |
if ProtocolTreeNode.tagEquals(childNode,"request"): | |
wantsReceipt = True; | |
elif ProtocolTreeNode.tagEquals(childNode,"notify"): | |
notify_name = childNode.getAttributeValue("name"); | |
elif ProtocolTreeNode.tagEquals(childNode,"delay"): | |
xmlns = childNode.getAttributeValue("xmlns"); | |
if "urn:xmpp:delay" == xmlns: | |
stamp_str = childNode.getAttributeValue("stamp"); | |
if stamp_str is not None: | |
stamp = stamp_str | |
timestamp = self.parseOfflineMessageStamp(stamp)*1000; | |
elif ProtocolTreeNode.tagEquals(childNode,"x"): | |
xmlns = childNode.getAttributeValue("xmlns"); | |
if "jabber:x:event" == xmlns and msgId is not None: | |
if fromAttribute == "broadcast": | |
self.signalInterface.send("receipt_broadcastSent", (msgId,)) | |
else: | |
self.signalInterface.send("receipt_messageSent", (fromAttribute, msgId)) | |
elif "jabber:x:delay" == xmlns: | |
continue; #@@TODO FORCED CONTINUE, WHAT SHOULD I DO HERE? #wtf? | |
stamp_str = childNode.getAttributeValue("stamp"); | |
if stamp_str is not None: | |
stamp = stamp_str | |
timestamp = stamp; | |
else: | |
if ProtocolTreeNode.tagEquals(childNode,"delay") or not ProtocolTreeNode.tagEquals(childNode,"received") or msgId is None: | |
continue; | |
receipt_type = childNode.getAttributeValue("type"); | |
if receipt_type is None or receipt_type == "delivered": | |
self.signalInterface.send("receipt_messageDelivered", (fromAttribute, msgId)) | |
elif receipt_type == "visible": | |
self.signalInterface.send("receipt_visible", (fromAttribute, msgId)) | |
if msgData: | |
msgData = msgData if sys.version_info < (3, 0) else msgData.encode('latin-1').decode() | |
if isGroup: | |
self.signalInterface.send("group_messageReceived", (msgId, fromAttribute, author, msgData, timestamp, wantsReceipt, pushName)) | |
else: | |
self.signalInterface.send("message_received", (msgId, fromAttribute, msgData, timestamp, wantsReceipt, pushName, isBroadcast)) | |
##@@TODO FROM CLIENT | |
'''if conversation.type == "group": | |
if conversation.subject is None: | |
signal = False | |
self._d("GETTING GROUP INFO") | |
self.connection.sendGetGroupInfo(fromAttribute) | |
''' | |
#if not len(conversation.getContacts()): | |
# self._d("GETTING GROUP CONTACTS") | |
# self.connection.sendGetParticipants(fromAttribute) | |
'''@@TODO FROM CLIENT | |
if ret is None: | |
conversation.incrementNew(); | |
WAXMPP.message_store.pushMessage(fromAttribute,fmsg) | |
fmsg.key = key | |
else: | |
fmsg.key = eval(ret.key) | |
duplicate = True; | |
''' | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment