def __init__(self, backend, user, legacyName, extra, db): super(Session, self).__init__() self.logger = logging.getLogger(self.__class__.__name__) self.logger.info("Created: %s", legacyName) self.db = db self.backend = backend self.user = user self.legacyName = legacyName self.buddies = BuddyList(self.legacyName, self.db) self.bot = Bot(self) self.status = protocol_pb2.STATUS_NONE self.statusMessage = '' self.groups = {} self.presenceRequested = [] self.offlineQueue = [] self.groupOfflineQueue = {} self.timer = None self.password = None self.initialized = False self.loggedin = False self.bot = Bot(self)
def __init__(self, backend, user, legacyName, extra, db): self.logger = logging.getLogger(self.__class__.__name__) self.logger.info("Created: %s", legacyName) self.db = db self.backend = backend self.user = user self.legacyName = legacyName self.status = protocol_pb2.STATUS_NONE self.statusMessage = '' self.groups = {} self.presenceRequested = [] self.offlineQueue = [] self.groupOfflineQueue = {} self.timer = None self.password = None self.initialized = False self.buddies = BuddyList(legacyName, db) self.frontend = YowsupConnectionManager() self.bot = Bot(self) # Events self.listen("auth_success", self.onAuthSuccess) self.listen("auth_fail", self.onAuthFailed) self.listen("disconnected", self.onDisconnected) self.listen("contact_typing", self.onContactTyping) self.listen("contact_paused", self.onContactPaused) self.listen("presence_updated", self.onPrecenceUpdated) self.listen("presence_available", self.onPrecenceAvailable) self.listen("presence_unavailable", self.onPrecenceUnavailable) self.listen("message_received", self.onMessageReceived) self.listen("image_received", self.onMediaReceived) self.listen("video_received", self.onMediaReceived) self.listen("audio_received", self.onMediaReceived) self.listen("location_received", self.onLocationReceived) self.listen("vcard_received", self.onVcardReceived) self.listen("group_messageReceived", self.onGroupMessageReceived) self.listen("group_gotInfo", self.onGroupGotInfo) self.listen("group_gotParticipants", self.onGroupGotParticipants) self.listen("group_subjectReceived", self.onGroupSubjectReceived) self.listen("notification_groupParticipantAdded", self.onGroupParticipantAdded) self.listen("notification_groupParticipantRemoved", self.onGroupParticipantRemoved) self.listen("notification_contactProfilePictureUpdated", self.onContactProfilePictureUpdated) self.listen("notification_groupPictureUpdated", self.onGroupPictureUpdated)
def __init__(self, backend, user, legacyName, extra, db): self.logger = logging.getLogger(self.__class__.__name__) self.logger.info("Created: %s", legacyName) self.db = db self.backend = backend self.user = user self.legacyName = legacyName self.status = protocol_pb2.STATUS_NONE self.statusMessage = '' self.groups = {} self.presenceRequested = [] self.offlineQueue = [] self.groupOfflineQueue = { } self.timer = None self.password = None self.initialized = False self.buddies = BuddyList(legacyName, db) self.frontend = YowsupConnectionManager() self.bot = Bot(self) # Events self.listen("auth_success", self.onAuthSuccess) self.listen("auth_fail", self.onAuthFailed) self.listen("disconnected", self.onDisconnected) self.listen("contact_typing", self.onContactTyping) self.listen("contact_paused", self.onContactPaused) self.listen("presence_updated", self.onPrecenceUpdated) self.listen("presence_available", self.onPrecenceAvailable) self.listen("presence_unavailable", self.onPrecenceUnavailable) self.listen("message_received", self.onMessageReceived) self.listen("image_received", self.onMediaReceived) self.listen("video_received", self.onMediaReceived) self.listen("audio_received", self.onMediaReceived) self.listen("location_received", self.onLocationReceived) self.listen("vcard_received", self.onVcardReceived) self.listen("group_messageReceived", self.onGroupMessageReceived) self.listen("group_gotInfo", self.onGroupGotInfo) self.listen("group_gotParticipants", self.onGroupGotParticipants) self.listen("group_subjectReceived", self.onGroupSubjectReceived) self.listen("notification_groupParticipantAdded", self.onGroupParticipantAdded) self.listen("notification_groupParticipantRemoved", self.onGroupParticipantRemoved) self.listen("notification_contactProfilePictureUpdated", self.onContactProfilePictureUpdated) self.listen("notification_groupPictureUpdated", self.onGroupPictureUpdated)
def __init__(self, backend, user, legacyName, extra): super(Session, self).__init__() self.logger = logging.getLogger(self.__class__.__name__) self.logger.info("Created: %s" % legacyName) self.backend = backend self.user = user self.legacyName = legacyName self.status = protocol_pb2.STATUS_NONE self.statusMessage = '' self.groups = {} self.gotGroupList = False # Functions to exectute when logged in via yowsup self.loginQueue = [] self.joinRoomQueue = [] self.presenceRequested = [] self.offlineQueue = [] self.msgIDs = {} self.groupOfflineQueue = {} self.loggedIn = False self.recvMsgIDs = [] self.timer = None self.password = None self.initialized = False self.lastMsgId = None self.synced = False self.buddies = BuddyList(self.legacyName, self.backend, self.user, self) self.bot = Bot(self) self.imgMsgId = None self.imgPath = "" self.imgBuddy = None self.imgType = ""
class Session: def __init__(self, backend, user, legacyName, extra, db): self.logger = logging.getLogger(self.__class__.__name__) self.logger.info("Created: %s", legacyName) self.db = db self.backend = backend self.user = user self.legacyName = legacyName self.status = protocol_pb2.STATUS_NONE self.statusMessage = '' self.groups = {} self.presenceRequested = [] self.offlineQueue = [] self.groupOfflineQueue = { } self.timer = None self.password = None self.initialized = False self.buddies = BuddyList(legacyName, db) self.frontend = YowsupConnectionManager() self.bot = Bot(self) # Events self.listen("auth_success", self.onAuthSuccess) self.listen("auth_fail", self.onAuthFailed) self.listen("disconnected", self.onDisconnected) self.listen("contact_typing", self.onContactTyping) self.listen("contact_paused", self.onContactPaused) self.listen("presence_updated", self.onPrecenceUpdated) self.listen("presence_available", self.onPrecenceAvailable) self.listen("presence_unavailable", self.onPrecenceUnavailable) self.listen("message_received", self.onMessageReceived) self.listen("image_received", self.onMediaReceived) self.listen("video_received", self.onMediaReceived) self.listen("audio_received", self.onMediaReceived) self.listen("location_received", self.onLocationReceived) self.listen("vcard_received", self.onVcardReceived) self.listen("group_messageReceived", self.onGroupMessageReceived) self.listen("group_gotInfo", self.onGroupGotInfo) self.listen("group_gotParticipants", self.onGroupGotParticipants) self.listen("group_subjectReceived", self.onGroupSubjectReceived) self.listen("notification_groupParticipantAdded", self.onGroupParticipantAdded) self.listen("notification_groupParticipantRemoved", self.onGroupParticipantRemoved) self.listen("notification_contactProfilePictureUpdated", self.onContactProfilePictureUpdated) self.listen("notification_groupPictureUpdated", self.onGroupPictureUpdated) def __del__(self): # handleLogoutRequest self.logout() def call(self, method, args = ()): args = [str(s) for s in args] self.logger.debug("%s(%s)", method, ", ".join(args)) self.frontend.methodInterface.call(method, args) def listen(self, event, callback): self.frontend.signalInterface.registerListener(event, callback) def logout(self): self.call("disconnect", ("logout",)) def login(self, password): self.password = utils.decodePassword(password) self.call("auth_login", (self.legacyName, self.password)) def updateRoomList(self): rooms = [] for room, group in self.groups.iteritems(): rooms.append([room, group.subject]) self.backend.handleRoomList(rooms) # spectrum RequestMethods def sendTypingStarted(self, buddy): if buddy != "bot": self.logger.info("Started typing: %s to %s", self.legacyName, buddy) self.call("typing_send", (buddy + "@s.whatsapp.net",)) def sendTypingStopped(self, buddy): if buddy != "bot": self.logger.info("Stopped typing: %s to %s", self.legacyName, buddy) self.call("typing_paused", (buddy + "@s.whatsapp.net",)) def sendMessageToWA(self, sender, message): self.logger.info("Message sent from %s to %s: %s", self.legacyName, sender, message) message = message.encode("utf-8") if sender == "bot": self.bot.parse(message) elif "-" in sender: # group msg if "/" in sender: room, buddy = sender.split("/") self.call("message_send", (buddy + "@s.whatsapp.net", message)) else: room = sender group = self.groups[room] self.backend.handleMessage(self.user, room, message, group.nick) self.call("message_send", (room + "@g.us", message)) else: # private msg buddy = sender if message == "\\lastseen": self.presenceRequested.append(buddy) self.call("presence_request", (buddy + "@s.whatsapp.net",)) else: self.call("message_send", (buddy + "@s.whatsapp.net", message)) def sendMessageToXMPP(self, buddy, messageContent, timestamp = ""): if timestamp: timestamp = time.strftime("%Y%m%dT%H%M%S", time.gmtime(timestamp)) if self.initialized == False: self.logger.debug("Message queued from %s to %s: %s", buddy, self.legacyName, messageContent) self.offlineQueue.append((buddy, messageContent, timestamp)) else: self.logger.debug("Message sent from %s to %s: %s", buddy, self.legacyName, messageContent) self.backend.handleMessage(self.user, buddy, messageContent, "", "", timestamp) def sendGroupMessageToXMPP(self, room, buddy, messageContent, timestamp = ""): if timestamp: timestamp = time.strftime("%Y%m%dT%H%M%S", time.gmtime(timestamp)) if self.initialized == False: self.logger.debug("Group message queued from %s to %s: %s", buddy, room, messageContent) if room not in self.groupOfflineQueue: self.groupOfflineQueue[room] = [ ] self.groupOfflineQueue[room].append((buddy, messageContent, timestamp)) else: self.logger.debug("Group message sent from %s to %s: %s", buddy, room, messageContent) self.backend.handleMessage(self.user, room, messageContent, buddy, "", timestamp) def changeStatus(self, status): if status != self.status: self.logger.info("Status changed: %s", status) self.status = status if status == protocol_pb2.STATUS_ONLINE or status == protocol_pb2.STATUS_FFC: self.call("presence_sendAvailable") else: self.call("presence_sendUnavailable") def changeStatusMessage(self, statusMessage): if statusMessage != self.statusMessage: self.statusMessage = statusMessage self.call("profile_setStatus", (statusMessage.encode("utf-8"),)) self.logger.info("Status message changed: %s", statusMessage) if self.initialized == False: self.sendOfflineMessages() self.bot.call("welcome") self.initialized = True def sendOfflineMessages(self): # Flush Queues while self.offlineQueue: msg = self.offlineQueue.pop(0) self.backend.handleMessage(self.user, msg[0], msg[1], "", "", msg[2]) # also for adding a new buddy def updateBuddy(self, buddy, nick, groups): if buddy != "bot": self.buddies.update(buddy, nick, groups) self.updateRoster() def removeBuddy(self, buddy): if buddy != "bot": self.logger.info("Buddy removed: %s", buddy) self.buddies.remove(buddy) self.updateRoster() def joinRoom(self, room, nick): if room in self.groups: group = self.groups[room] self.logger.info("Joining room: %s room=%s, nick=%s", self.legacyName, room, nick) group.nick = nick self.call("group_getParticipants", (room + "@g.us",)) self.backend.handleSubject(self.user, room, group.subject, group.subjectOwner) else: self.logger.warn("Room doesn't exist: %s", room) def updateRoster(self): self.logger.debug("Update roster") old = self.buddies.keys() self.buddies.load() new = self.buddies.keys() add = set(new) - set(old) remove = set(old) - set(new) self.logger.debug("Roster remove: %s", str(list(remove))) self.logger.debug("Roster add: %s", str(list(add))) for number in remove: self.backend.handleBuddyChanged(self.user, number, "", [], protocol_pb2.STATUS_NONE) self.backend.handleBuddyRemoved(self.user, number) self.call("presence_unsubscribe", (number + "@s.whatsapp.net",)) for number in add: buddy = self.buddies[number] self.backend.handleBuddyChanged(self.user, number, buddy.nick, buddy.groups, protocol_pb2.STATUS_NONE) self.call("presence_request", (number + "@s.whatsapp.net",)) # includes presence_subscribe # yowsup Signals def onAuthSuccess(self, user): self.logger.info("Auth success: %s", user) self.backend.handleConnected(self.user) self.backend.handleBuddyChanged(self.user, "bot", self.bot.name, ["Admin"], protocol_pb2.STATUS_ONLINE) self.updateRoster() self.call("ready") self.call("group_getGroups", ("participating",)) def onAuthFailed(self, user, reason): self.logger.info("Auth failed: %s (%s)", user, reason) self.backend.handleDisconnected(self.user, 0, reason) self.password = None def onDisconnected(self, reason): self.logger.info("Disconnected from whatsapp: %s (%s)", self.legacyName, reason) self.backend.handleDisconnected(self.user, 0, reason) def onMessageReceived(self, messageId, jid, messageContent, timestamp, receiptRequested, pushName, isBroadCast): buddy = jid.split("@")[0] messageContent = utils.softToUni(messageContent) if isBroadCast: self.logger.info("Broadcast received from %s to %s: %s (at ts=%s)", buddy, self.legacyName, messageContent, timestamp) messageContent = "[Broadcast] " + messageContent else: self.logger.info("Message received from %s to %s: %s (at ts=%s)", buddy, self.legacyName, messageContent, timestamp) self.sendMessageToXMPP(buddy, messageContent, timestamp) if receiptRequested: self.call("message_ack", (jid, messageId)) def onMediaReceived(self, messageId, jid, preview, url, size, receiptRequested, isBroadcast): buddy = jid.split("@")[0] self.logger.info("Media received from %s: %s", buddy, url) self.sendMessageToXMPP(buddy, utils.shorten(url)) if receiptRequested: self.call("message_ack", (jid, messageId)) def onLocationReceived(self, messageId, jid, name, preview, latitude, longitude, receiptRequested, isBroadcast): buddy = jid.split("@")[0] self.logger.info("Location received from %s: %s, %s", buddy, latitude, longitude) url = "http://maps.google.de?%s" % urllib.urlencode({ "q": "%s %s" % (latitude, longitude) }) self.sendMessageToXMPP(buddy, utils.shorten(url)) if receiptRequested: self.call("message_ack", (jid, messageId)) def onVcardReceived(self, messageId, jid, name, data, receiptRequested, isBroadcast): # TODO buddy = jid.split("@")[0] self.logger.info("VCard received from %s", buddy) self.sendMessageToXMPP(buddy, "Received VCard (not implemented yet)") if receiptRequested: self.call("message_ack", (jid, messageId)) def onContactTyping(self, jid): buddy = jid.split("@")[0] self.logger.info("Started typing: %s", buddy) self.backend.handleBuddyTyping(self.user, buddy) if self.timer != None: self.timer.cancel() def onContactPaused(self, jid): buddy = jid.split("@")[0] self.logger.info("Paused typing: %s", buddy) self.backend.handleBuddyTyped(self.user, jid.split("@")[0]) self.timer = Timer(3, self.backend.handleBuddyStoppedTyping, (self.user, buddy)).start() def onPrecenceUpdated(self, jid, lastseen): buddy = jid.split("@")[0] self.logger.info("Lastseen: %s %s", buddy, utils.ago(lastseen)) if buddy in self.presenceRequested: timestamp = time.localtime(time.time() - lastseen) timestring = time.strftime("%a, %d %b %Y %H:%M:%S", timestamp) self.sendMessageToXMPP(buddy, "%s (%s)" % (timestring, utils.ago(lastseen))) self.presenceRequested.remove(buddy) if lastseen < 60: self.onPrecenceAvailable(jid) else: self.onPrecenceUnavailable(jid) def onPrecenceAvailable(self, jid): buddy = jid.split("@")[0] try: buddy = self.buddies[buddy] self.logger.info("Is available: %s", buddy) self.backend.handleBuddyChanged(self.user, buddy.number.number, buddy.nick, buddy.groups, protocol_pb2.STATUS_ONLINE) except KeyError: self.logger.error("Buddy not found: %s", buddy) def onPrecenceUnavailable(self, jid): buddy = jid.split("@")[0] try: buddy = self.buddies[buddy] self.logger.info("Is unavailable: %s", buddy) self.backend.handleBuddyChanged(self.user, buddy.number.number, buddy.nick, buddy.groups, protocol_pb2.STATUS_XA) except KeyError: self.logger.error("Buddy not found: %s", buddy) def onGroupGotInfo(self, gjid, owner, subject, subjectOwner, subjectTimestamp, creationTimestamp): room = gjid.split("@")[0] owner = owner.split("@")[0] subjectOwner = subjectOwner.split("@")[0] if room in self.groups: room = self.groups[room] room.owner = owner room.subjectOwner = subjectOwner room.subject = subject else: self.groups[room] = Group(room, owner, subject, subjectOwner) self.updateRoomList() def onGroupGotParticipants(self, gjid, jids): room = gjid.split("@")[0] group = self.groups[room] for jid in jids: buddy = jid.split("@")[0] self.logger.info("Added %s to room %s", buddy, room) if buddy == group.owner: flags = protocol_pb2.PARTICIPANT_FLAG_MODERATOR else: flags = protocol_pb2.PARTICIPANT_FLAG_NONE self.backend.handleParticipantChanged(self.user, buddy, room, flags, protocol_pb2.STATUS_ONLINE) # TODO check status if room in self.groupOfflineQueue: while self.groupOfflineQueue[room]: msg = self.groupOfflineQueue[room].pop(0) self.backend.handleMessage(self.user, room, msg[1], msg[0], "", msg[2]) self.logger.debug("Send queued group message to: %s %s %s", msg[0],msg[1], msg[2]) def onGroupMessageReceived(self, messageId, gjid, jid, messageContent, timestamp, receiptRequested, pushName): buddy = jid.split("@")[0] room = gjid.split("@")[0] self.logger.info("Group message received in %s from %s: %s", room, buddy, messageContent) self.sendGroupMessageToXMPP(room, buddy, utils.softToUni(messageContent), timestamp) if receiptRequested: self.call("message_ack", (gjid, messageId)) def onGroupSubjectReceived(self, messageId, gjid, jid, subject, timestamp, receiptRequested): room = gjid.split("@")[0] buddy = jid.split("@")[0] self.backend.handleSubject(self.user, room, subject, buddy) if receiptRequested: self.call("subject_ack", (gjid, messageId)) # Yowsup Notifications def onGroupParticipantAdded(self, gjid, jid, author, timestamp, messageId, receiptRequested): room = gjid.split("@")[0] buddy = jid.split("@")[0] loggin.info("Added % to room %s", buddy, room) self.backend.handleParticipantChanged(self.user, buddy, room, protocol_pb2.PARTICIPANT_FLAG_NONE, protocol_pb2.STATUS_ONLINE) if receiptRequested: self.call("notification_ack", (gjid, messageId)) def onGroupParticipantRemoved(self, gjid, jid, author, timestamp, messageId, receiptRequested): room = gjid.split("@")[0] buddy = jid.split("@")[0] self.logger.info("Removed %s from room %s", buddy, room) self.backend.handleParticipantChanged(self.user, buddy, room, protocol_pb2.PARTICIPANT_FLAG_NONE, protocol_pb2.STATUS_NONE) # TODO if receiptRequested: self.call("notification_ack", (gjid, messageId)) def onContactProfilePictureUpdated(self, jid, timestamp, messageId, pictureId, receiptRequested): # TODO if receiptRequested: self.call("notification_ack", (jid, messageId)) def onGroupPictureUpdated(self, jid, author, timestamp, messageId, pictureId, receiptRequested): # TODO if receiptRequested: self.call("notification_ack", (jid, messageId))
class Session(YowsupApp): broadcast_prefix = '\U0001F4E2 ' def __init__(self, backend, user, legacyName, extra): super(Session, self).__init__() self.logger = logging.getLogger(self.__class__.__name__) self.logger.info("Created: %s" % legacyName) self.backend = backend self.user = user self.legacyName = legacyName self.status = protocol_pb2.STATUS_NONE self.statusMessage = '' self.groups = {} self.gotGroupList = False # Functions to exectute when logged in via yowsup self.loginQueue = [] self.joinRoomQueue = [] self.presenceRequested = [] self.offlineQueue = [] self.msgIDs = {} self.groupOfflineQueue = {} self.loggedIn = False self.recvMsgIDs = [] self.timer = None self.password = None self.initialized = False self.lastMsgId = None self.synced = False self.buddies = BuddyList(self.legacyName, self.backend, self.user, self) self.bot = Bot(self) self.imgMsgId = None self.imgPath = "" self.imgBuddy = None self.imgType = "" def __del__(self): # handleLogoutRequest self.logout() def logout(self): self.logger.info("%s logged out" % self.user) super(Session, self).logout() self.loggedIn = False def login(self, password): self.logger.info("%s attempting login" % self.user) self.password = password self.shouldBeConncted = True super(Session, self).login(self.legacyName, self.password) def _shortenGroupId(self, gid): # FIXME: might have problems if number begins with 0 return gid # return '-'.join(hex(int(s))[2:] for s in gid.split('-')) def _lengthenGroupId(self, gid): return gid # FIXME: might have problems if number begins with 0 # return '-'.join(str(int(s, 16)) for s in gid.split('-')) def updateRoomList(self): rooms = [] text = [] for room, group in self.groups.iteritems(): rooms.append([self._shortenGroupId(room), group.subject]) text.append( self._shortenGroupId(room) + '@' + self.backend.spectrum_jid + ' :' + group.subject) self.logger.debug("Got rooms: %s" % rooms) self.backend.handleRoomList(rooms) message = "Note, you are a participant of the following groups:\n" + \ "\n".join(text) + "\nIf you do not join them you will lose messages" #self.bot.send(message) def _updateGroups(self, response, _): self.logger.debug('Received groups list %s' % response) groups = response.getGroups() for group in groups: room = group.getId() # ensure self.groups[room] exists if room not in self.groups: owner = group.getOwner().split('@')[0] subjectOwner = group.getSubjectOwner().split('@')[0] subject = utils.softToUni(group.getSubject()) self.groups[room] = Group(room, owner, subject, subjectOwner, self.backend, self.user) # add/update room participants self.groups[room].addParticipants(group.getParticipants().keys(), self.buddies, self.legacyName) self.gotGroupList = True # join rooms while self.joinRoomQueue: self.joinRoom(*self.joinRoomQueue.pop(0)) # deliver queued offline messages for room in self.groupOfflineQueue: while self.groupOfflineQueue[room]: msg = self.groupOfflineQueue[room].pop(0) self.backend.handleMessage(self.user, room, msg[1], msg[0], "", msg[2]) self.logger.debug("Send queued group message to: %s %s %s" % (msg[0], msg[1], msg[2])) # pass update to backend self.updateRoomList() def joinRoom(self, room, nick): if not self.gotGroupList: self.joinRoomQueue.append((room, nick)) return room = self._lengthenGroupId(room) if room in self.groups: self.logger.info("Joining room: %s room=%s, nick=%s" % (self.legacyName, room, nick)) group = self.groups[room] group.joined = True group.nick = nick group.participants[self.legacyName] = nick try: ownerNick = group.participants[group.subjectOwner] except KeyError: ownerNick = group.subjectOwner group.sendParticipantsToSpectrum(self.legacyName) self.backend.handleSubject(self.user, self._shortenGroupId(room), group.subject, ownerNick) self.logger.debug("Room subject: room=%s, subject=%s" % (room, group.subject)) self.backend.handleRoomNicknameChanged(self.user, self._shortenGroupId(room), group.subject) else: self.logger.warn("Room doesn't exist: %s" % room) def leaveRoom(self, room): if room in self.groups: self.logger.info("Leaving room: %s room=%s" % (self.legacyName, room)) group = self.groups[room] group.joined = False else: self.logger.warn("Room doesn't exist: %s. Unable to leave." % room) def _lastSeen(self, number, seconds): self.logger.debug("Last seen %s at %s seconds" % (number, seconds)) if seconds < 60: self.onPresenceAvailable(number) else: self.onPresenceUnavailable(number) def sendReadReceipts(self, buddy): for _id, _from, participant, t in self.recvMsgIDs: if _from.split('@')[0] == buddy: self.sendReceipt(_id, _from, 'read', participant) self.recvMsgIDs.remove((_id, _from, participant, t)) self.logger.debug("Send read receipt to %s (ID: %s)", _from, _id) # Called by superclass def onAuthSuccess(self, status, kind, creation, expiration, props, nonce, t): self.logger.info("Auth success: %s" % self.user) self.backend.handleConnected(self.user) self.backend.handleBuddyChanged(self.user, "bot", self.bot.name, ["Admin"], protocol_pb2.STATUS_ONLINE) # Initialisation? self.requestPrivacyList() self.requestClientConfig() self.requestServerProperties() # ? self.logger.debug('Requesting groups list') self.requestGroupsList(self._updateGroups) # self.requestBroadcastList() # This should handle, sync, statuses, and presence self.sendPresence(True) for func in self.loginQueue: func() if self.initialized == False: self.sendOfflineMessages() #self.bot.call("welcome") self.initialized = True self.loggedIn = True # Called by superclass def onAuthFailed(self, reason): self.logger.info("Auth failed: %s (%s)" % (self.user, reason)) self.backend.handleDisconnected(self.user, 0, reason) self.password = None self.loggedIn = False # Called by superclass def onDisconnect(self): self.logger.debug('Disconnected') self.backend.handleDisconnected(self.user, 0, 'Disconnected for unknown reasons') # Called by superclass def onReceipt(self, _id, _from, timestamp, type, participant, offline, items): self.logger.debug( "received receipt, sending ack: %s" % [_id, _from, timestamp, type, participant, offline, items]) try: number = _from.split('@')[0] self.backend.handleMessageAck(self.user, number, self.msgIDs[_id].xmppId) self.msgIDs[_id].cnt = self.msgIDs[_id].cnt + 1 if self.msgIDs[_id].cnt == 2: del self.msgIDs[_id] except KeyError: self.logger.error("Message %s not found. Unable to send ack" % _id) # Called by superclass def onAck(self, _id, _class, _from, timestamp): self.logger.debug('received ack: %s' % [_id, _class, _from, timestamp]) # Called by superclass def onTextMessage(self, _id, _from, to, notify, timestamp, participant, offline, retry, body): buddy = _from.split('@')[0] messageContent = utils.softToUni(body) self.sendReceipt(_id, _from, None, participant) self.recvMsgIDs.append((_id, _from, participant, timestamp)) self.logger.info("Message received from %s to %s: %s (at ts=%s)" % (buddy, self.legacyName, messageContent, timestamp)) if participant is not None: # Group message or broadcast partname = participant.split('@')[0] if _from.split('@')[1] == 'broadcast': # Broadcast message message = self.broadcast_prefix + messageContent self.sendMessageToXMPP(partname, message, timestamp) else: # Group message if notify is None: notify = "" self.sendGroupMessageToXMPP(buddy, partname, messageContent, timestamp, notify) else: self.sendMessageToXMPP(buddy, messageContent, timestamp) # Called by superclass def onImage(self, image): if image.caption is None: image.caption = '' self.onMedia(image, "image") # Called by superclass def onAudio(self, audio): self.onMedia(audio, "audio") # Called by superclass def onVideo(self, video): self.onMedia(video, "video") def onMedia(self, media, type): self.logger.debug('Received %s message: %s' % (type, media)) buddy = media._from.split('@')[0] participant = media.participant caption = '' if media.isEncrypted(): self.logger.debug('Received encrypted media message') if self.backend.specConf is not None and self.backend.specConf.__getitem__( "service.web_directory" ) is not None and self.backend.specConf.__getitem__( "service.web_url") is not None: ipath = "/" + str(media.timestamp) + media.getExtension() with open( self.backend.specConf.__getitem__( "service.web_directory") + ipath, "wb") as f: f.write(media.getMediaContent()) url = self.backend.specConf.__getitem__( "service.web_url") + ipath else: self.logger.warn( 'Received encrypted media: web storage not set in config!') url = media.url else: url = media.url if type == 'image': caption = media.caption if participant is not None: # Group message partname = participant.split('@')[0] if media._from.split('@')[1] == 'broadcast': # Broadcast message self.sendMessageToXMPP(partname, self.broadcast_prefix, media.timestamp) self.sendMessageToXMPP(partname, url, media.timestamp) self.sendMessageToXMPP(partname, caption, media.timestamp) else: # Group message self.sendGroupMessageToXMPP(buddy, partname, url, media.timestamp) self.sendGroupMessageToXMPP(buddy, partname, caption, media.timestamp) else: self.sendMessageToXMPP(buddy, url, media.timestamp) self.sendMessageToXMPP(buddy, caption, media.timestamp) self.sendReceipt(media._id, media._from, None, media.participant) self.recvMsgIDs.append( (media._id, media._from, media.participant, media.timestamp)) def onLocation(self, location): buddy = location._from.split('@')[0] latitude = location.getLatitude() longitude = location.getLongitude() url = location.getLocationURL() participant = location.participant latlong = 'geo:' + latitude + ',' + longitude self.logger.debug("Location received from %s: %s, %s", (buddy, latitude, longitude)) if participant is not None: # Group message partname = participant.split('@')[0] if location._from.split( '@')[1] == 'broadcast': # Broadcast message self.sendMessageToXMPP(partname, self.broadcast_prefix, location.timestamp) if url is not None: self.sendMessageToXMPP(partname, url, location.timestamp) self.sendMessageToXMPP(partname, latlong, location.timestamp) else: # Group message if url is not None: self.sendGroupMessageToXMPP(buddy, partname, url, location.timestamp) self.sendGroupMessageToXMPP(buddy, partname, latlong, location.timestamp) else: if url is not None: self.sendMessageToXMPP(buddy, url, location.timestamp) self.sendMessageToXMPP(buddy, latlong, location.timestamp) self.sendReceipt(location._id, location._from, None, location.participant) self.recvMsgIDs.append((location._id, location._from, location.participant, location.timestamp)) # Called by superclass def onVCard(self, _id, _from, name, card_data, to, notify, timestamp, participant): self.logger.debug( 'received VCard: %s' % [_id, _from, name, card_data, to, notify, timestamp, participant]) message = "Received VCard (not implemented yet)" buddy = _from.split("@")[0] if participant is not None: # Group message partname = participant.split('@')[0] if _from.split('@')[1] == 'broadcast': # Broadcast message message = self.broadcast_prefix + message self.sendMessageToXMPP(partname, message, timestamp) else: # Group message self.sendGroupMessageToXMPP(buddy, partname, message, timestamp) else: self.sendMessageToXMPP(buddy, message, timestamp) # self.sendMessageToXMPP(buddy, card_data) #self.transferFile(buddy, str(name), card_data) self.sendReceipt(_id, _from, None, participant) self.recvMsgIDs.append((_id, _from, participant, timestamp)) def transferFile(self, buddy, name, data): # Not working self.logger.debug('transfering file: %s' % name) self.backend.handleFTStart(self.user, buddy, name, len(data)) self.backend.handleFTData(0, data) self.backend.handleFTFinish(self.user, buddy, name, len(data), 0) # Called by superclass def onContactTyping(self, buddy): self.logger.info("Started typing: %s" % buddy) if buddy != 'bot': self.sendPresence(True) self.backend.handleBuddyTyping(self.user, buddy) if self.timer != None: self.timer.cancel() # Called by superclass def onContactPaused(self, buddy): self.logger.info("Paused typing: %s" % buddy) if buddy != 'bot': self.backend.handleBuddyTyped(self.user, buddy) self.timer = Timer(3, self.backend.handleBuddyStoppedTyping, (self.user, buddy)).start() # Called by superclass def onAddedToGroup(self, group): self.logger.debug("Added to group: %s" % group) room = group.getGroupId() owner = group.getCreatorJid(full=False) subjectOwner = group.getSubjectOwnerJid(full=False) subject = utils.softToUni(group.getSubject()) self.groups[room] = Group(room, owner, subject, subjectOwner, self.backend, self.user) self.groups[room].addParticipants(group.getParticipants(), self.buddies, self.legacyName) self.bot.send( "You have been added to group: %s@%s (%s)" % (self._shortenGroupId(room), subject, self.backend.spectrum_jid)) # Called by superclass def onParticipantsAddedToGroup(self, group): self.logger.debug("Participants added to group: %s" % group) room = group.getGroupId().split('@')[0] self.groups[room].addParticipants(group.getParticipants(), self.buddies, self.legacyName) self.groups[room].sendParticipantsToSpectrum(self.legacyName) # Called by superclass def onSubjectChanged(self, room, subject, subjectOwner, timestamp): self.logger.debug( "onSubjectChange(rrom=%s, subject=%s, subjectOwner=%s, timestamp=%s)" % (room, subject, subjectOwner, timestamp)) try: group = self.groups[room] except KeyError: self.logger.error("Subject of non-existant group (%s) changed" % group) else: group.subject = subject group.subjectOwner = subjectOwner if not group.joined: # We have not joined group so we should not send subject return self.backend.handleSubject(self.user, room, subject, subjectOwner) self.backend.handleRoomNicknameChanged(self.user, room, subject) # Called by superclass def onParticipantsRemovedFromGroup(self, room, participants): self.logger.debug("Participants removed from group: %s, %s" % (room, participants)) self.groups[room].removeParticipants(participants) # Called by superclass def onContactStatusChanged(self, number, status): self.logger.debug("%s changed their status to %s" % (number, status)) try: buddy = self.buddies[number] buddy.statusMsg = status self.buddies.updateSpectrum(buddy) except KeyError: self.logger.debug("%s not in buddy list" % number) # Called by superclass def onContactPictureChanged(self, number): self.logger.debug("%s changed their profile picture" % number) self.buddies.requestVCard(number) # Called by superclass def onContactAdded(self, number, nick): self.logger.debug("Adding new contact %s (%s)" % (nick, number)) self.updateBuddy(number, nick, []) # Called by superclass def onContactRemoved(self, number): self.logger.debug("Removing contact %s" % number) self.removeBuddy(number) def onContactUpdated(self, oldnumber, newnumber): self.logger.debug("Contact has changed number from %s to %s" % (oldnumber, newnumber)) if newnumber in self.buddies: self.logger.warn("Contact %s exists, just updating" % newnumber) self.buddies.refresh(newnumber) try: buddy = self.buddies[oldnumber] except KeyError: self.logger.warn( "Old contact (%s) not found. Adding new contact (%s)" % (oldnumber, newnumber)) nick = "" else: self.removeBuddy(buddy.number) nick = buddy.nick self.updateBuddy(newnumber, nick, []) def onPresenceReceived(self, _type, name, jid, lastseen): self.logger.info("Presence received: %s %s %s %s" % (_type, name, jid, lastseen)) buddy = jid.split("@")[0] try: buddy = self.buddies[buddy] except KeyError: # Sometimes whatsapp send our own presence if buddy != self.legacyName: self.logger.error("Buddy not found: %s" % buddy) return if (lastseen == buddy.lastseen) and (_type == buddy.presence): return if ((lastseen != "deny") and (lastseen != None) and (lastseen != "none")): buddy.lastseen = int(lastseen) if (_type == None): buddy.lastseen = time.time() buddy.presence = _type if _type == "unavailable": self.onPresenceUnavailable(buddy) else: self.onPresenceAvailable(buddy) def onPresenceAvailable(self, buddy): self.logger.info("Is available: %s" % buddy) self.buddies.updateSpectrum(buddy) def onPresenceUnavailable(self, buddy): self.logger.info("Is unavailable: %s" % buddy) self.buddies.updateSpectrum(buddy) # spectrum RequestMethods def sendTypingStarted(self, buddy): if buddy != "bot": self.logger.info("Started typing: %s to %s" % (self.legacyName, buddy)) self.sendTyping(buddy, True) self.sendReadReceipts(buddy) # If he is typing he is present # I really don't know where else to put this. # Ideally, this should be sent if the user is looking at his client self.sendPresence(True) def sendTypingStopped(self, buddy): if buddy != "bot": self.logger.info("Stopped typing: %s to %s" % (self.legacyName, buddy)) self.sendTyping(buddy, False) self.sendReadReceipts(buddy) def sendImage(self, message, ID, to): if (".jpg" in message.lower()): imgType = "jpg" if (".webp" in message.lower()): imgType = "webp" success = deferred.Deferred() error = deferred.Deferred() self.downloadMedia(message, success.run, error.run) # Success path = success.arg(0) call(self.logger.info, "Success: Image downloaded to %s" % path) pathWithExt = path.then(lambda p: p + "." + imgType) call(os.rename, path, pathWithExt) pathJpg = path.then(lambda p: p + ".jpg") if imgType != "jpg": im = call(Image.open, pathWithExt) call(im.save, pathJpg) call(os.remove, pathWithExt) call(self.logger.info, "Sending image to %s" % to) waId = deferred.Deferred() call(super(Session, self).sendImage, to, pathJpg, onSuccess=waId.run) call(self.setWaId, ID, waId) waId.when(call, os.remove, pathJpg) waId.when(self.logger.info, "Image sent") # Error error.when(self.logger.info, "Download Error. Sending message as is.") waId = error.when(self.sendTextMessage, to, message) call(self.setWaId, ID, waId) def setWaId(self, XmppId, waId): self.msgIDs[waId] = MsgIDs(XmppId, waId) def sendMessageToWA(self, sender, message, ID, xhtml=""): self.logger.info("Message sent from %s to %s: %s (xhtml=%s)" % (self.legacyName, sender, message, xhtml)) self.sendReadReceipts(sender) if sender == "bot": self.bot.parse(message) elif "-" in sender: # group msg if "/" in sender: # directed at single user room, nick = sender.split("/") group = self.groups[room] number = None for othernumber, othernick in group.participants.iteritems(): if othernick == nick: number = othernumber break if number is not None: self.logger.debug("Private message sent from %s to %s" % (self.legacyName, number)) waId = self.sendTextMessage(number + '@s.whatsapp.net', message) self.msgIDs[waId] = MsgIDs(ID, waId) else: self.logger.error( "Attempted to send private message to non-existent user" ) self.logger.debug("%s to %s in %s" % (self.legacyName, nick, room)) else: room = sender if message[0] == '\\' and message[:1] != '\\\\': self.logger.debug("Executing command %s in %s" % (message, room)) self.executeCommand(message, room) else: try: group = self.groups[self._lengthenGroupId(room)] self.logger.debug( "Group Message from %s to %s Groups: %s" % (group.nick, group, self.groups)) self.backend.handleMessage(self.user, room, message, group.nick, xhtml=xhtml) except KeyError: self.logger.error('Group not found: %s' % room) if (".jpg" in message.lower()) or (".webp" in message.lower()): self.sendImage(message, ID, room + '@g.us') elif "geo:" in message.lower(): self._sendLocation(room + "@g.us", message, ID) else: self.sendTextMessage(room + '@g.us', message) else: # private msg buddy = sender if message.split(" ").pop(0) == "\\lastseen": self.presenceRequested.append(buddy) self._requestLastSeen(buddy) elif message.split(" ").pop(0) == "\\gpp": self.sendMessageToXMPP(buddy, "Fetching Profile Picture") self.requestVCard(buddy) elif (".jpg" in message.lower()) or (".webp" in message.lower()): self.sendImage(message, ID, buddy + "@s.whatsapp.net") elif "geo:" in message.lower(): self._sendLocation(buddy + "@s.whatsapp.net", message, ID) else: waId = self.sendTextMessage(sender + '@s.whatsapp.net', message) self.msgIDs[waId] = MsgIDs(ID, waId) # self.logger.info("WA Message send to %s with ID %s", buddy, waId) def executeCommand(self, command, room): if command == '\\leave': self.logger.debug("Leaving room %s", room) self.leaveGroup(room) # Leave group on whatsapp side group = self.groups[room] group.leaveRoom() # Delete Room on spectrum side del self.groups[room] def _requestLastSeen(self, buddy): def onSuccess(buddy, lastseen): timestamp = time.localtime(time.localtime() - lastseen) timestring = time.strftime("%a, %d %b %Y %H:%M:%S", timestamp) self.sendMessageToXMPP( buddy, "%s (%s) %s" % (timestring, utils.ago(lastseen), str(lastseen))) def onError(errorIqEntity, originalIqEntity): self.sendMessageToXMPP(errorIqEntity.getFrom(), "LastSeen Error") self.requestLastSeen(buddy, onSuccess, onError) def _sendLocation(self, buddy, message, ID): latitude, longitude = message.split(':')[1].split(',') waId = self.sendLocation(buddy, float(latitude), float(longitude)) self.msgIDs[waId] = MsgIDs(ID, waId) self.logger.info("WA Location Message send to %s with ID %s", buddy, waId) def sendMessageToXMPP(self, buddy, messageContent, timestamp="", nickname=""): if timestamp: timestamp = time.strftime("%Y%m%dT%H%M%S", time.gmtime(timestamp)) if self.initialized == False: self.logger.debug("Message queued from %s to %s: %s" % (buddy, self.legacyName, messageContent)) self.offlineQueue.append((buddy, messageContent, timestamp)) else: self.logger.debug("Message sent from %s to %s: %s" % (buddy, self.legacyName, messageContent)) self.backend.handleMessage(self.user, buddy, messageContent, "", "", timestamp) def sendGroupMessageToXMPP(self, room, number, messageContent, timestamp="", defaultname=""): if timestamp: timestamp = time.strftime("%Y%m%dT%H%M%S", time.gmtime(timestamp)) if self.initialized == False: self.logger.debug("Group message queued from %s to %s: %s" % (number, room, messageContent)) if room not in self.groupOfflineQueue: self.groupOfflineQueue[room] = [] self.groupOfflineQueue[room].append( (number, messageContent, timestamp)) else: self.logger.debug("Group message sent from %s to %s: %s" % (number, room, messageContent)) try: group = self.groups[room] # Update nickname try: if defaultname != "" and group.participants[ number] == number: group.changeNick(number, defaultname) if self.buddies[number].nick != "": group.changeNick(number, self.buddies[number].nick) except KeyError: pass nick = group.participants[number] if group.joined: self.backend.handleMessage(self.user, room, messageContent, nick, "", timestamp) else: self.bot.send( "You have received a message in group: %s@%s" % (room, self.backend.spectrum_jid)) self.bot.send("Join the group in order to reply") self.bot.send("%s: %s" % (nick, messageContent)) except KeyError: self.logger.warn("Group is not in group list") self.backend.handleMessage(self.user, self._shortenGroupId(room), messageContent, number, "", timestamp) def changeStatus(self, status): if status != self.status: self.logger.info("Status changed: %s" % status) self.status = status if status == protocol_pb2.STATUS_ONLINE \ or status == protocol_pb2.STATUS_FFC: self.sendPresence(True) else: self.sendPresence(False) def changeStatusMessage(self, statusMessage): if (statusMessage != self.statusMessage) or (self.initialized == False): self.statusMessage = statusMessage self.setStatus(statusMessage) self.logger.info("Status message changed: %s" % statusMessage) #if self.initialized == False: # self.sendOfflineMessages() # self.bot.call("welcome") # self.initialized = True def sendOfflineMessages(self): # Flush Queues while self.offlineQueue: msg = self.offlineQueue.pop(0) self.backend.handleMessage(self.user, msg[0], msg[1], "", "", msg[2]) # Called when user logs in to initialize the roster def loadBuddies(self, buddies): self.buddies.load(buddies) # also for adding a new buddy def updateBuddy(self, buddy, nick, groups, image_hash=None): if buddy != "bot": self.buddies.update(buddy, nick, groups, image_hash) def removeBuddy(self, buddy): if buddy != "bot": self.logger.info("Buddy removed: %s" % buddy) self.buddies.remove(buddy) def requestVCard(self, buddy, ID=None): self.buddies.requestVCard(buddy, ID) def createThumb(self, size=100, raw=False): img = Image.open(self.imgPath) width, height = img.size img_thumbnail = self.imgPath + '_thumbnail' if width > height: nheight = float(height) / width * size nwidth = size else: nwidth = float(width) / height * size nheight = size img.thumbnail((nwidth, nheight), Image.ANTIALIAS) img.save(img_thumbnail, 'JPEG') with open(img_thumbnail, 'rb') as imageFile: raw = base64.b64encode(imageFile.read()) return raw # Not used def onLocationReceived(self, messageId, jid, name, preview, latitude, longitude, receiptRequested, isBroadcast): buddy = jid.split("@")[0] self.logger.info("Location received from %s: %s, %s" % (buddy, latitude, longitude)) url = "http://maps.google.de?%s" % urllib.urlencode( {"q": "%s %s" % (latitude, longitude)}) self.sendMessageToXMPP(buddy, utils.shorten(url)) if receiptRequested: self.call("message_ack", (jid, messageId)) def onGroupSubjectReceived(self, messageId, gjid, jid, subject, timestamp, receiptRequested): room = gjid.split("@")[0] buddy = jid.split("@")[0] self.backend.handleSubject(self.user, room, subject, buddy) if receiptRequested: self.call("subject_ack", (gjid, messageId)) # Yowsup Notifications def onGroupParticipantRemoved(self, gjid, jid, author, timestamp, messageId, receiptRequested): room = gjid.split("@")[0] buddy = jid.split("@")[0] self.logger.info("Removed %s from room %s" % (buddy, room)) self.backend.handleParticipantChanged( self.user, buddy, room, protocol_pb2.PARTICIPANT_FLAG_NONE, protocol_pb2.STATUS_NONE) # TODO if receiptRequested: self.call("notification_ack", (gjid, messageId)) def onContactProfilePictureUpdated(self, jid, timestamp, messageId, pictureId, receiptRequested): # TODO if receiptRequested: self.call("notification_ack", (jid, messageId)) def onGroupPictureUpdated(self, jid, author, timestamp, messageId, pictureId, receiptRequested): # TODO if receiptRequested: self.call("notification_ack", (jid, messageId))
class Session(YowsupApp): def __init__(self, backend, user, legacyName, extra, db): super(Session, self).__init__() self.logger = logging.getLogger(self.__class__.__name__) self.logger.info("Created: %s", legacyName) self.db = db self.backend = backend self.user = user self.legacyName = legacyName self.buddies = BuddyList(self.legacyName, self.db) self.bot = Bot(self) self.status = protocol_pb2.STATUS_NONE self.statusMessage = '' self.groups = {} self.presenceRequested = [] self.offlineQueue = [] self.groupOfflineQueue = {} self.timer = None self.password = None self.initialized = False self.loggedin = False self.bot = Bot(self) def __del__(self): # handleLogoutRequest self.logout() def call(self, method, **kwargs): self.logger.debug( "%s(%s)", method, ", ".join(str(k) + ': ' + str(v) for k, v in kwargs.items())) ##self.stack.broadcastEvent(YowLayerEvent(method, **kwargs)) def logout(self): self.loggedin = False super(Session, self).logout() def login(self, password): self.loggedin = True self.password = password super(Session, self).login(self.legacyName, self.password) def updateRoomList(self): rooms = [] for room, group in self.groups.iteritems(): rooms.append([room, group.subject]) self.logger.debug("Got rooms: %s", rooms) self.backend.handleRoomList(rooms) def updateRoster(self): self.logger.debug("Update roster") old = self.buddies.keys() self.buddies.load() new = self.buddies.keys() add = set(new) - set(old) remove = set(old) - set(new) self.logger.debug("Roster remove: %s", str(list(remove))) self.logger.debug("Roster add: %s", str(list(add))) for number in remove: self.backend.handleBuddyChanged(self.user, number, "", [], protocol_pb2.STATUS_NONE) self.backend.handleBuddyRemoved(self.user, number) self.unsubscribePresence(number) for number in add: buddy = self.buddies[number] self.subscribePresence(number) self.backend.handleBuddyChanged( self.user, number, buddy.nick, buddy.groups, protocol_pb2.STATUS_NONE, iconHash=buddy.image_hash if buddy.image_hash is not None else "") #self.requestLastSeen(number, self._lastSeen) self.logger.debug('Requesting groups list') self.requestGroupsList(self._updateGroups) def _updateGroups(self, response, request): self.logger.debug('Received groups list %s', response) # This XMPP client is not receiving this for some reason. groups = response.getGroups() for group in groups: room = group.getId() owner = group.getOwner() subjectOwner = group.getSubjectOwner() subject = group.getSubject() if room in self.groups: oroom = self.groups[room] oroom.owner = owner oroom.subjectOwner = subjectOwner oroom.subject = subject else: self.groups[room] = Group(room, owner, subject, subjectOwner) # A crude implemtation of groups that act like buddies self.backend.handleBuddyChanged(self.user, room, subject, [], protocol_pb2.STATUS_NONE) # This XMPP client is not receiving this for some reason. # self.updateRoomList() # for group in groups: # room = group.getId() # subjectOwner = group.getSubjectOwner() # subject = group.getSubject() # self.backend.handleSubject(self.user, room, subject, subjectOwner) # for participant in group.getParticipants(): # buddy = participant.split('@')[0] # self.logger.debug("Added %s to room %s", buddy, room) # self.backend.handleParticipantChanged(self.user, buddy, room, # protocol_pb2.PARTICIPANT_FLAG_NONE, protocol_pb2.STATUS_ONLINE) def _lastSeen(self, number, seconds): self.logger.debug("Last seen %s at %s seconds" % (number, str(seconds))) if seconds < 60: self.onPresenceAvailable(number) else: self.onPresenceUnavailable(number) # Called by superclass def onAuthSuccess(self, status, kind, creation, expiration, props, nonce, t): self.logger.info("Auth success: %s", self.user) self.backend.handleConnected(self.user) self.backend.handleBuddyChanged(self.user, "bot", self.bot.name, ["Admin"], protocol_pb2.STATUS_ONLINE) self.initialized = True self.sendPresence(True) self.updateRoster() # Called by superclass def onAuthFailed(self, reason): self.logger.info("Auth failed: %s (%s)", self.user, reason) self.backend.handleDisconnected(self.user, 0, reason) self.password = None # Called by superclass def onDisconnect(self): self.logger.debug('Disconnected') self.backend.handleDisconnected(self.user, 0, 'Disconnected for unknown reasons') self.loggedin = False # Called by superclass def onReceipt(self, _id, _from, timestamp, type, participant, offline, items): self.logger.debug("received receipt, sending ack: " + ' '.join( map(str, [_id, _from, timestamp, type, participant, offline, items]))) buddy = self.buddies[_from.split('@')[0]] self.backend.handleBuddyChanged(self.user, buddy.number.number, buddy.nick, buddy.groups, protocol_pb2.STATUS_ONLINE) # Called by superclass def onAck(self, _id, _class, _from, timestamp): self.logger.debug('received ack ' + ' '.join(map(str, [ _id, _class, _from, timestamp, ]))) # Called by superclass def onTextMessage(self, _id, _from, to, notify, timestamp, participant, offline, retry, body): self.logger.debug('received TextMessage' + ' '.join( map(str, [ _id, _from, to, notify, timestamp, participant, offline, retry, body ]))) buddy = _from.split('@')[0] messageContent = utils.softToUni(body) self.sendReceipt(_id, _from, None, participant) self.logger.info("Message received from %s to %s: %s (at ts=%s)", buddy, self.legacyName, messageContent, timestamp) if participant is not None: partname = participant.split('@')[0] message = partname + ': ' + messageContent self.sendMessageToXMPP(buddy, message, timestamp) else: self.sendMessageToXMPP(buddy, messageContent, timestamp) # isBroadcast always returns false, I'm not sure how to get a broadcast # message. #if messageEntity.isBroadcast(): # self.logger.info("Broadcast received from %s to %s: %s (at ts=%s)",\ # buddy, self.legacyName, messageContent, timestamp) # messageContent = "[Broadcast] " + messageContent # Called by superclass def onImage(self, image): self.logger.debug('Received image message %s', str(image)) buddy = image._from.split('@')[0] message = image.url + ' ' + image.caption self.sendMessageToXMPP(buddy, message, image.timestamp) self.sendReceipt(image._id, image._from, None, image.participant) # Called by superclass def onAudio(self, audio): self.logger.debug('Received audio message %s', str(audio)) buddy = audio._from.split('@')[0] message = audio.url self.sendMessageToXMPP(buddy, message, audio.timestamp) self.sendReceipt(audio._id, audio._from, None, audio.participant) # Called by superclass def onVideo(self, video): self.logger.debug('Received video message %s', str(video)) buddy = video._from.split('@')[0] message = video.url self.sendMessageToXMPP(buddy, message, video.timestamp) self.sendReceipt(video._id, video._from, None, video.participant) # Called by superclass def onVCard(self, _id, _from, name, card_data, to, notify, timestamp, participant): self.logger.debug('received VCard' + ' '.join( map(str, [ _id, _from, name, card_data, to, notify, timestamp, participant ]))) buddy = _from.split("@")[0] self.sendMessageToXMPP(buddy, "Received VCard (not implemented yet)") self.sendMessageToXMPP(buddy, card_data) self.transferFile(buddy, str(name), card_data) self.sendReceipt(_id, _from, None, participant) def transferFile(self, buddy, name, data): # Not working self.logger.debug('transfering file %s', name) self.backend.handleFTStart(self.user, buddy, name, len(data)) self.backend.handleFTData(0, data) self.backend.handleFTFinish(self.user, buddy, name, len(data), 0) # Called by superclass def onContactTyping(self, buddy): self.logger.info("Started typing: %s", buddy) self.sendPresence(True) self.backend.handleBuddyTyping(self.user, buddy) if self.timer != None: self.timer.cancel() # Called by superclass def onContactPaused(self, buddy): self.logger.info("Paused typing: %s", buddy) self.backend.handleBuddyTyped(self.user, buddy) self.timer = Timer(3, self.backend.handleBuddyStoppedTyping, (self.user, buddy)).start() def onPresenceReceived(self, _type, name, jid, lastseen): self.logger.info("Presence received: %s %s %s %s", _type, name, jid, lastseen) buddy = jid.split("@")[0] # seems to be causing an error # self.logger.info("Lastseen: %s %s", buddy, utils.ago(lastseen)) if buddy in self.presenceRequested: timestamp = time.localtime(time.time() - lastseen) timestring = time.strftime("%a, %d %b %Y %H:%M:%S", timestamp) self.sendMessageToXMPP( buddy, "%s (%s)" % (timestring, utils.ago(lastseen))) self.presenceRequested.remove(buddy) if lastseen < 60: self.onPresenceAvailable(buddy) else: self.onPresenceUnavailable(buddy) def onPresenceAvailable(self, buddy): try: buddy = self.buddies[buddy] self.logger.info("Is available: %s", buddy) self.backend.handleBuddyChanged(self.user, buddy.number.number, buddy.nick, buddy.groups, protocol_pb2.STATUS_ONLINE) except KeyError: self.logger.error("Buddy not found: %s", buddy) def onPresenceUnavailable(self, buddy): try: buddy = self.buddies[buddy] self.logger.info("Is unavailable: %s", buddy) self.backend.handleBuddyChanged(self.user, buddy.number.number, buddy.nick, buddy.groups, protocol_pb2.STATUS_XA) except KeyError: self.logger.error("Buddy not found: %s", buddy) # spectrum RequestMethods def sendTypingStarted(self, buddy): if buddy != "bot": self.logger.info("Started typing: %s to %s", self.legacyName, buddy) self.sendTyping(buddy, True) # If he is typing he is present # I really don't know where else to put this. # Ideally, this should be sent if the user is looking at his client self.sendPresence(True) def sendTypingStopped(self, buddy): if buddy != "bot": self.logger.info("Stopped typing: %s to %s", self.legacyName, buddy) self.sendTyping(buddy, False) def sendMessageToWA(self, sender, message): self.logger.info("Message sent from %s to %s: %s", self.legacyName, sender, message) message = message.encode("utf-8") if sender == "bot": self.bot.parse(message) elif "-" in sender: # group msg if "/" in sender: room, buddy = sender.split("/") self.sendTextMessage(buddy + '@s.whatsapp.net', message) else: room = sender # group = self.groups[room] # self.backend.handleMessage(self.user, room, message, group.nick) self.sendTextMessage(room + '@g.us', message) else: # private msg buddy = sender # if message == "\\lastseen": # self.call("presence_request", buddy = (buddy + "@s.whatsapp.net",)) # else: self.sendTextMessage(sender + '@s.whatsapp.net', message) def sendMessageToXMPP(self, buddy, messageContent, timestamp="", nickname=""): if timestamp: timestamp = time.strftime("%Y%m%dT%H%M%S", time.gmtime(timestamp)) if self.initialized == False: self.logger.debug("Message queued from %s to %s: %s", buddy, self.legacyName, messageContent) self.offlineQueue.append((buddy, messageContent, timestamp)) else: self.logger.debug("Message sent from %s to %s: %s", buddy, self.legacyName, messageContent) self.backend.handleMessage(self.user, buddy, messageContent, "", "", timestamp) def sendGroupMessageToXMPP(self, room, buddy, messageContent, timestamp=""): if timestamp: timestamp = time.strftime("%Y%m%dT%H%M%S", time.gmtime(timestamp)) if self.initialized == False: self.logger.debug("Group message queued from %s to %s: %s", buddy, room, messageContent) if room not in self.groupOfflineQueue: self.groupOfflineQueue[room] = [] self.groupOfflineQueue[room].append( (buddy, messageContent, timestamp)) else: self.logger.debug("Group message sent from %s to %s: %s", buddy, room, messageContent) self.backend.handleMessage(self.user, room, messageContent, buddy, "", timestamp) def changeStatus(self, status): if status != self.status: self.logger.info("Status changed: %s", status) self.status = status if status == protocol_pb2.STATUS_ONLINE or status == protocol_pb2.STATUS_FFC: self.sendPresence(True) else: self.sendPresence(False) def changeStatusMessage(self, statusMessage): if (statusMessage != self.statusMessage) or (self.initialized == False): self.statusMessage = statusMessage self.setStatus(statusMessage.encode('utf-8')) self.logger.info("Status message changed: %s", statusMessage) if self.initialized == False: self.sendOfflineMessages() self.bot.call("welcome") self.initialized = True def sendOfflineMessages(self): # Flush Queues while self.offlineQueue: msg = self.offlineQueue.pop(0) self.backend.handleMessage(self.user, msg[0], msg[1], "", "", msg[2]) # also for adding a new buddy def updateBuddy(self, buddy, nick, groups, image_hash=""): if buddy != "bot": self.buddies.update(buddy, nick, groups, image_hash) self.updateRoster() def removeBuddy(self, buddy): if buddy != "bot": self.logger.info("Buddy removed: %s", buddy) self.buddies.remove(buddy) self.updateRoster() def joinRoom(self, room, nick): if room in self.groups: group = self.groups[room] self.logger.info("Joining room: %s room=%s, nick=%s", self.legacyName, room, nick) group.nick = nick self.call("group_getParticipants", (room + "@g.us", )) self.backend.handleSubject(self.user, room, group.subject, group.subjectOwner) else: self.logger.warn("Room doesn't exist: %s", room) def requestVCard(self, buddy, ID): def onSuccess(response, request): self.logger.debug('Sending VCard (%s) with image id %s', ID, response.pictureId) image_hash = utils.sha1hash(response.pictureData) self.logger.debug('Image hash is %s', image_hash) self.backend.handleVCard(self.user, ID, buddy, "", "", response.pictureData) obuddy = self.buddies[buddy] self.updateBuddy(buddy, obuddy.nick, obuddy.groups, image_hash) self.logger.debug('Requesting profile picture of %s', buddy) self.requestProfilePicture(buddy, onSuccess=onSuccess) # Not used def onLocationReceived(self, messageId, jid, name, preview, latitude, longitude, receiptRequested, isBroadcast): buddy = jid.split("@")[0] self.logger.info("Location received from %s: %s, %s", buddy, latitude, longitude) url = "http://maps.google.de?%s" % urllib.urlencode( {"q": "%s %s" % (latitude, longitude)}) self.sendMessageToXMPP(buddy, utils.shorten(url)) if receiptRequested: self.call("message_ack", (jid, messageId)) def onGroupGotParticipants(self, gjid, jids): room = gjid.split("@")[0] group = self.groups[room] for jid in jids: buddy = jid.split("@")[0] self.logger.info("Added %s to room %s", buddy, room) if buddy == group.owner: flags = protocol_pb2.PARTICIPANT_FLAG_MODERATOR else: flags = protocol_pb2.PARTICIPANT_FLAG_NONE self.backend.handleParticipantChanged( self.user, buddy, room, flags, protocol_pb2.STATUS_ONLINE) # TODO check status if room in self.groupOfflineQueue: while self.groupOfflineQueue[room]: msg = self.groupOfflineQueue[room].pop(0) self.backend.handleMessage(self.user, room, msg[1], msg[0], "", msg[2]) self.logger.debug("Send queued group message to: %s %s %s", msg[0], msg[1], msg[2]) def onGroupMessageReceived(self, messageId, gjid, jid, messageContent, timestamp, receiptRequested, pushName): buddy = jid.split("@")[0] room = gjid.split("@")[0] self.logger.info("Group message received in %s from %s: %s", room, buddy, messageContent) self.sendGroupMessageToXMPP(room, buddy, utils.softToUni(messageContent), timestamp) if receiptRequested: self.call("message_ack", (gjid, messageId)) def onGroupSubjectReceived(self, messageId, gjid, jid, subject, timestamp, receiptRequested): room = gjid.split("@")[0] buddy = jid.split("@")[0] self.backend.handleSubject(self.user, room, subject, buddy) if receiptRequested: self.call("subject_ack", (gjid, messageId)) # Yowsup Notifications def onGroupParticipantRemoved(self, gjid, jid, author, timestamp, messageId, receiptRequested): room = gjid.split("@")[0] buddy = jid.split("@")[0] self.logger.info("Removed %s from room %s", buddy, room) self.backend.handleParticipantChanged( self.user, buddy, room, protocol_pb2.PARTICIPANT_FLAG_NONE, protocol_pb2.STATUS_NONE) # TODO if receiptRequested: self.call("notification_ack", (gjid, messageId)) def onContactProfilePictureUpdated(self, jid, timestamp, messageId, pictureId, receiptRequested): # TODO if receiptRequested: self.call("notification_ack", (jid, messageId)) def onGroupPictureUpdated(self, jid, author, timestamp, messageId, pictureId, receiptRequested): # TODO if receiptRequested: self.call("notification_ack", (jid, messageId))
class Session: def __init__(self, backend, user, legacyName, extra, db): self.logger = logging.getLogger(self.__class__.__name__) self.logger.info("Created: %s", legacyName) self.db = db self.backend = backend self.user = user self.legacyName = legacyName self.status = protocol_pb2.STATUS_NONE self.statusMessage = '' self.groups = {} self.presenceRequested = [] self.offlineQueue = [] self.groupOfflineQueue = {} self.timer = None self.password = None self.initialized = False self.buddies = BuddyList(legacyName, db) self.frontend = YowsupConnectionManager() self.bot = Bot(self) # Events self.listen("auth_success", self.onAuthSuccess) self.listen("auth_fail", self.onAuthFailed) self.listen("disconnected", self.onDisconnected) self.listen("contact_typing", self.onContactTyping) self.listen("contact_paused", self.onContactPaused) self.listen("presence_updated", self.onPrecenceUpdated) self.listen("presence_available", self.onPrecenceAvailable) self.listen("presence_unavailable", self.onPrecenceUnavailable) self.listen("message_received", self.onMessageReceived) self.listen("image_received", self.onMediaReceived) self.listen("video_received", self.onMediaReceived) self.listen("audio_received", self.onMediaReceived) self.listen("location_received", self.onLocationReceived) self.listen("vcard_received", self.onVcardReceived) self.listen("group_messageReceived", self.onGroupMessageReceived) self.listen("group_gotInfo", self.onGroupGotInfo) self.listen("group_gotParticipants", self.onGroupGotParticipants) self.listen("group_subjectReceived", self.onGroupSubjectReceived) self.listen("notification_groupParticipantAdded", self.onGroupParticipantAdded) self.listen("notification_groupParticipantRemoved", self.onGroupParticipantRemoved) self.listen("notification_contactProfilePictureUpdated", self.onContactProfilePictureUpdated) self.listen("notification_groupPictureUpdated", self.onGroupPictureUpdated) def __del__(self): # handleLogoutRequest self.logout() def call(self, method, args=()): args = [str(s) for s in args] self.logger.debug("%s(%s)", method, ", ".join(args)) self.frontend.methodInterface.call(method, args) def listen(self, event, callback): self.frontend.signalInterface.registerListener(event, callback) def logout(self): self.call("disconnect", ("logout", )) def login(self, password): self.password = utils.decodePassword(password) self.call("auth_login", (self.legacyName, self.password)) def updateRoomList(self): rooms = [] for room, group in self.groups.iteritems(): rooms.append([room, group.subject]) self.backend.handleRoomList(rooms) # spectrum RequestMethods def sendTypingStarted(self, buddy): if buddy != "bot": self.logger.info("Started typing: %s to %s", self.legacyName, buddy) self.call("typing_send", (buddy + "@s.whatsapp.net", )) def sendTypingStopped(self, buddy): if buddy != "bot": self.logger.info("Stopped typing: %s to %s", self.legacyName, buddy) self.call("typing_paused", (buddy + "@s.whatsapp.net", )) def sendMessageToWA(self, sender, message): self.logger.info("Message sent from %s to %s: %s", self.legacyName, sender, message) message = message.encode("utf-8") if sender == "bot": self.bot.parse(message) elif "-" in sender: # group msg if "/" in sender: room, buddy = sender.split("/") self.call("message_send", (buddy + "@s.whatsapp.net", message)) else: room = sender group = self.groups[room] self.backend.handleMessage(self.user, room, message, group.nick) self.call("message_send", (room + "@g.us", message)) else: # private msg buddy = sender if message == "\\lastseen": self.presenceRequested.append(buddy) self.call("presence_request", (buddy + "@s.whatsapp.net", )) else: self.call("message_send", (buddy + "@s.whatsapp.net", message)) def sendMessageToXMPP(self, buddy, messageContent, timestamp=""): if timestamp: timestamp = time.strftime("%Y%m%dT%H%M%S", time.gmtime(timestamp)) if self.initialized == False: self.logger.debug("Message queued from %s to %s: %s", buddy, self.legacyName, messageContent) self.offlineQueue.append((buddy, messageContent, timestamp)) else: self.logger.debug("Message sent from %s to %s: %s", buddy, self.legacyName, messageContent) self.backend.handleMessage(self.user, buddy, messageContent, "", "", timestamp) def sendGroupMessageToXMPP(self, room, buddy, messageContent, timestamp=""): if timestamp: timestamp = time.strftime("%Y%m%dT%H%M%S", time.gmtime(timestamp)) if self.initialized == False: self.logger.debug("Group message queued from %s to %s: %s", buddy, room, messageContent) if room not in self.groupOfflineQueue: self.groupOfflineQueue[room] = [] self.groupOfflineQueue[room].append( (buddy, messageContent, timestamp)) else: self.logger.debug("Group message sent from %s to %s: %s", buddy, room, messageContent) self.backend.handleMessage(self.user, room, messageContent, buddy, "", timestamp) def changeStatus(self, status): if status != self.status: self.logger.info("Status changed: %s", status) self.status = status if status == protocol_pb2.STATUS_ONLINE or status == protocol_pb2.STATUS_FFC: self.call("presence_sendAvailable") else: self.call("presence_sendUnavailable") def changeStatusMessage(self, statusMessage): if (statusMessage != self.statusMessage) or (self.initialized == False): self.statusMessage = statusMessage self.call("profile_setStatus", (statusMessage.encode("utf-8"), )) self.logger.info("Status message changed: %s", statusMessage) if self.initialized == False: self.sendOfflineMessages() self.bot.call("welcome") self.initialized = True def sendOfflineMessages(self): # Flush Queues while self.offlineQueue: msg = self.offlineQueue.pop(0) self.backend.handleMessage(self.user, msg[0], msg[1], "", "", msg[2]) # also for adding a new buddy def updateBuddy(self, buddy, nick, groups): if buddy != "bot": self.buddies.update(buddy, nick, groups) self.updateRoster() def removeBuddy(self, buddy): if buddy != "bot": self.logger.info("Buddy removed: %s", buddy) self.buddies.remove(buddy) self.updateRoster() def joinRoom(self, room, nick): if room in self.groups: group = self.groups[room] self.logger.info("Joining room: %s room=%s, nick=%s", self.legacyName, room, nick) group.nick = nick self.call("group_getParticipants", (room + "@g.us", )) self.backend.handleSubject(self.user, room, group.subject, group.subjectOwner) else: self.logger.warn("Room doesn't exist: %s", room) def updateRoster(self): self.logger.debug("Update roster") old = self.buddies.keys() self.buddies.load() new = self.buddies.keys() add = set(new) - set(old) remove = set(old) - set(new) self.logger.debug("Roster remove: %s", str(list(remove))) self.logger.debug("Roster add: %s", str(list(add))) for number in remove: self.backend.handleBuddyChanged(self.user, number, "", [], protocol_pb2.STATUS_NONE) self.backend.handleBuddyRemoved(self.user, number) self.call("presence_unsubscribe", (number + "@s.whatsapp.net", )) for number in add: buddy = self.buddies[number] self.backend.handleBuddyChanged(self.user, number, buddy.nick, buddy.groups, protocol_pb2.STATUS_NONE) self.call( "presence_request", (number + "@s.whatsapp.net", )) # includes presence_subscribe # yowsup Signals def onAuthSuccess(self, user): self.logger.info("Auth success: %s", user) self.backend.handleConnected(self.user) self.backend.handleBuddyChanged(self.user, "bot", self.bot.name, ["Admin"], protocol_pb2.STATUS_ONLINE) self.updateRoster() self.call("ready") self.call("group_getGroups", ("participating", )) def onAuthFailed(self, user, reason): self.logger.info("Auth failed: %s (%s)", user, reason) self.backend.handleDisconnected(self.user, 0, reason) self.password = None def onDisconnected(self, reason): self.logger.info("Disconnected from whatsapp: %s (%s)", self.legacyName, reason) self.backend.handleDisconnected(self.user, 0, reason) def onMessageReceived(self, messageId, jid, messageContent, timestamp, receiptRequested, pushName, isBroadCast): buddy = jid.split("@")[0] messageContent = utils.softToUni(messageContent) if isBroadCast: self.logger.info("Broadcast received from %s to %s: %s (at ts=%s)", buddy, self.legacyName, messageContent, timestamp) messageContent = "[Broadcast] " + messageContent else: self.logger.info("Message received from %s to %s: %s (at ts=%s)", buddy, self.legacyName, messageContent, timestamp) self.sendMessageToXMPP(buddy, messageContent, timestamp) if receiptRequested: self.call("message_ack", (jid, messageId)) def onMediaReceived(self, messageId, jid, preview, url, size, receiptRequested, isBroadcast): buddy = jid.split("@")[0] self.logger.info("Media received from %s: %s", buddy, url) self.sendMessageToXMPP(buddy, utils.shorten(url)) if receiptRequested: self.call("message_ack", (jid, messageId)) def onLocationReceived(self, messageId, jid, name, preview, latitude, longitude, receiptRequested, isBroadcast): buddy = jid.split("@")[0] self.logger.info("Location received from %s: %s, %s", buddy, latitude, longitude) url = "http://maps.google.de?%s" % urllib.urlencode( {"q": "%s %s" % (latitude, longitude)}) self.sendMessageToXMPP(buddy, utils.shorten(url)) if receiptRequested: self.call("message_ack", (jid, messageId)) def onVcardReceived(self, messageId, jid, name, data, receiptRequested, isBroadcast): # TODO buddy = jid.split("@")[0] self.logger.info("VCard received from %s", buddy) self.sendMessageToXMPP(buddy, "Received VCard (not implemented yet)") if receiptRequested: self.call("message_ack", (jid, messageId)) def onContactTyping(self, jid): buddy = jid.split("@")[0] self.logger.info("Started typing: %s", buddy) self.backend.handleBuddyTyping(self.user, buddy) if self.timer != None: self.timer.cancel() def onContactPaused(self, jid): buddy = jid.split("@")[0] self.logger.info("Paused typing: %s", buddy) self.backend.handleBuddyTyped(self.user, jid.split("@")[0]) self.timer = Timer(3, self.backend.handleBuddyStoppedTyping, (self.user, buddy)).start() def onPrecenceUpdated(self, jid, lastseen): buddy = jid.split("@")[0] self.logger.info("Lastseen: %s %s", buddy, utils.ago(lastseen)) if buddy in self.presenceRequested: timestamp = time.localtime(time.time() - lastseen) timestring = time.strftime("%a, %d %b %Y %H:%M:%S", timestamp) self.sendMessageToXMPP( buddy, "%s (%s)" % (timestring, utils.ago(lastseen))) self.presenceRequested.remove(buddy) if lastseen < 60: self.onPrecenceAvailable(jid) else: self.onPrecenceUnavailable(jid) def onPrecenceAvailable(self, jid): buddy = jid.split("@")[0] try: buddy = self.buddies[buddy] self.logger.info("Is available: %s", buddy) self.backend.handleBuddyChanged(self.user, buddy.number.number, buddy.nick, buddy.groups, protocol_pb2.STATUS_ONLINE) except KeyError: self.logger.error("Buddy not found: %s", buddy) def onPrecenceUnavailable(self, jid): buddy = jid.split("@")[0] try: buddy = self.buddies[buddy] self.logger.info("Is unavailable: %s", buddy) self.backend.handleBuddyChanged(self.user, buddy.number.number, buddy.nick, buddy.groups, protocol_pb2.STATUS_XA) except KeyError: self.logger.error("Buddy not found: %s", buddy) def onGroupGotInfo(self, gjid, owner, subject, subjectOwner, subjectTimestamp, creationTimestamp): room = gjid.split("@")[0] owner = owner.split("@")[0] subjectOwner = subjectOwner.split("@")[0] if room in self.groups: room = self.groups[room] room.owner = owner room.subjectOwner = subjectOwner room.subject = subject else: self.groups[room] = Group(room, owner, subject, subjectOwner) self.updateRoomList() def onGroupGotParticipants(self, gjid, jids): room = gjid.split("@")[0] group = self.groups[room] for jid in jids: buddy = jid.split("@")[0] self.logger.info("Added %s to room %s", buddy, room) if buddy == group.owner: flags = protocol_pb2.PARTICIPANT_FLAG_MODERATOR else: flags = protocol_pb2.PARTICIPANT_FLAG_NONE self.backend.handleParticipantChanged( self.user, buddy, room, flags, protocol_pb2.STATUS_ONLINE) # TODO check status if room in self.groupOfflineQueue: while self.groupOfflineQueue[room]: msg = self.groupOfflineQueue[room].pop(0) self.backend.handleMessage(self.user, room, msg[1], msg[0], "", msg[2]) self.logger.debug("Send queued group message to: %s %s %s", msg[0], msg[1], msg[2]) def onGroupMessageReceived(self, messageId, gjid, jid, messageContent, timestamp, receiptRequested, pushName): buddy = jid.split("@")[0] room = gjid.split("@")[0] self.logger.info("Group message received in %s from %s: %s", room, buddy, messageContent) self.sendGroupMessageToXMPP(room, buddy, utils.softToUni(messageContent), timestamp) if receiptRequested: self.call("message_ack", (gjid, messageId)) def onGroupSubjectReceived(self, messageId, gjid, jid, subject, timestamp, receiptRequested): room = gjid.split("@")[0] buddy = jid.split("@")[0] self.backend.handleSubject(self.user, room, subject, buddy) if receiptRequested: self.call("subject_ack", (gjid, messageId)) # Yowsup Notifications def onGroupParticipantAdded(self, gjid, jid, author, timestamp, messageId, receiptRequested): room = gjid.split("@")[0] buddy = jid.split("@")[0] loggin.info("Added % to room %s", buddy, room) self.backend.handleParticipantChanged( self.user, buddy, room, protocol_pb2.PARTICIPANT_FLAG_NONE, protocol_pb2.STATUS_ONLINE) if receiptRequested: self.call("notification_ack", (gjid, messageId)) def onGroupParticipantRemoved(self, gjid, jid, author, timestamp, messageId, receiptRequested): room = gjid.split("@")[0] buddy = jid.split("@")[0] self.logger.info("Removed %s from room %s", buddy, room) self.backend.handleParticipantChanged( self.user, buddy, room, protocol_pb2.PARTICIPANT_FLAG_NONE, protocol_pb2.STATUS_NONE) # TODO if receiptRequested: self.call("notification_ack", (gjid, messageId)) def onContactProfilePictureUpdated(self, jid, timestamp, messageId, pictureId, receiptRequested): # TODO if receiptRequested: self.call("notification_ack", (jid, messageId)) def onGroupPictureUpdated(self, jid, author, timestamp, messageId, pictureId, receiptRequested): # TODO if receiptRequested: self.call("notification_ack", (jid, messageId))
class Session(YowsupApp): def __init__(self, backend, user, legacyName, extra): super(Session, self).__init__() self.logger = logging.getLogger(self.__class__.__name__) self.logger.info("Created: %s", legacyName) self.backend = backend self.user = user self.legacyName = legacyName self.status = protocol_pb2.STATUS_NONE self.statusMessage = '' self.groups = {} self.gotGroupList = False # Functions to exectute when logged in via yowsup self.loginQueue = [] self.joinRoomQueue = [] self.presenceRequested = [] self.offlineQueue = [] self.msgIDs = {} self.groupOfflineQueue = {} self.loggedIn = False self.timer = None self.password = None self.initialized = False self.lastMsgId = None self.synced = False self.buddies = BuddyList(self.legacyName, self.backend, self.user, self) self.bot = Bot(self) self.imgMsgId = None self.imgPath = "" self.imgBuddy = None self.imgType = "" def __del__(self): # handleLogoutRequest self.logout() def logout(self): self.logger.info("%s logged out", self.user) super(Session, self).logout() self.loggedIn = False def login(self, password): self.logger.info("%s attempting login", self.user) self.password = password self.shouldBeConncted = True super(Session, self).login(self.legacyName, self.password) def _shortenGroupId(self, gid): # FIXME: might have problems if number begins with 0 return gid # return '-'.join(hex(int(s))[2:] for s in gid.split('-')) def _lengthenGroupId(self, gid): return gid # FIXME: might have problems if number begins with 0 # return '-'.join(str(int(s, 16)) for s in gid.split('-')) def updateRoomList(self): rooms = [] text = [] for room, group in self.groups.iteritems(): rooms.append([self._shortenGroupId(room), group.subject]) text.append( self._shortenGroupId(room) + '@' + self.backend.spectrum_jid + ' :' + group.subject) self.logger.debug("Got rooms: %s", rooms) self.backend.handleRoomList(rooms) message = "Note, you are a participant of the following groups:\n" +\ '\n'.join(text) + '\nIf you do not join them you will lose messages' #self.bot.send(message) def _updateGroups(self, response, request): self.logger.debug('Received groups list %s', response) groups = response.getGroups() for group in groups: room = group.getId() owner = group.getOwner().split('@')[0] subjectOwner = group.getSubjectOwner().split('@')[0] subject = utils.softToUni(group.getSubject()) if room in self.groups: oroom = self.groups[room] oroom.owner = owner oroom.subjectOwner = subjectOwner oroom.subject = subject else: self.groups[room] = Group(room, owner, subject, subjectOwner, self.backend, self.user) # self.joinRoom(self._shortenGroupId(room), self.user.split("@")[0]) self.groups[room].addParticipants(group.getParticipants().keys(), self.buddies, self.legacyName) #self._addParticipantsToRoom(room, group.getParticipants()) if room in self.groupOfflineQueue: while self.groupOfflineQueue[room]: msg = self.groupOfflineQueue[room].pop(0) self.backend.handleMessage(self.user, room, msg[1], msg[0], "", msg[2]) self.logger.debug("Send queued group message to: %s %s %s", msg[0], msg[1], msg[2]) self.gotGroupList = True for room, nick in self.joinRoomQueue: self.joinRoom(room, nick) self.joinRoomQueue = [] self.updateRoomList() def joinRoom(self, room, nick): if not self.gotGroupList: self.joinRoomQueue.append((room, nick)) return room = self._lengthenGroupId(room) if room in self.groups: self.logger.info("Joining room: %s room=%s, nick=%s", self.legacyName, room, nick) group = self.groups[room] group.joined = True group.nick = nick group.participants[self.legacyName] = nick try: ownerNick = group.participants[group.subjectOwner] except KeyError: ownerNick = group.subjectOwner group.sendParticipantsToSpectrum(self.legacyName) self.backend.handleSubject(self.user, self._shortenGroupId(room), group.subject, ownerNick) self.logger.debug("Room subject: room=%s, subject=%s", room, group.subject) self.backend.handleRoomNicknameChanged(self.user, self._shortenGroupId(room), group.subject) else: self.logger.warn("Room doesn't exist: %s", room) def leaveRoom(self, room): if room in self.groups: self.logger.info("Leaving room: %s room=%s", self.legacyName, room) group = self.groups[room] group.joined = False else: self.logger.warn("Room doesn't exist: %s. Unable to leave.", room) def _lastSeen(self, number, seconds): self.logger.debug("Last seen %s at %s seconds" % (number, str(seconds))) if seconds < 60: self.onPresenceAvailable(number) else: self.onPresenceUnavailable(number) # Called by superclass def onAuthSuccess(self, status, kind, creation, expiration, props, nonce, t): self.logger.info("Auth success: %s", self.user) self.backend.handleConnected(self.user) self.backend.handleBuddyChanged(self.user, "bot", self.bot.name, ["Admin"], protocol_pb2.STATUS_ONLINE) if self.initialized == False: self.sendOfflineMessages() #self.bot.call("welcome") self.initialized = True self.sendPresence(True) for func in self.loginQueue: func() self.logger.debug('Requesting groups list') self.requestGroupsList(self._updateGroups) self.loggedIn = True # Called by superclass def onAuthFailed(self, reason): self.logger.info("Auth failed: %s (%s)", self.user, reason) self.backend.handleDisconnected(self.user, 0, reason) self.password = None self.loggedIn = False # Called by superclass def onDisconnect(self): self.logger.debug('Disconnected') self.backend.handleDisconnected(self.user, 0, 'Disconnected for unknown reasons') # Called by superclass def onReceipt(self, _id, _from, timestamp, type, participant, offline, items): self.logger.debug("received receipt, sending ack: " + ' '.join( map(str, [_id, _from, timestamp, type, participant, offline, items]))) try: buddy = self.buddies[_from.split('@')[0]] #self.backend.handleBuddyChanged(self.user, buddy.number.number, # buddy.nick, buddy.groups, protocol_pb2.STATUS_ONLINE) self.backend.handleMessageAck(self.user, buddy.number, self.msgIDs[_id].xmppId) self.msgIDs[_id].cnt = self.msgIDs[_id].cnt + 1 if self.msgIDs[_id].cnt == 2: del self.msgIDs[_id] except KeyError: pass # Called by superclass def onAck(self, _id, _class, _from, timestamp): self.logger.debug('received ack ' + ' '.join(map(str, [ _id, _class, _from, timestamp, ]))) # Called by superclass def onTextMessage(self, _id, _from, to, notify, timestamp, participant, offline, retry, body): self.logger.debug('received TextMessage' + ' '.join( map(str, [ _id, _from, to, notify, timestamp, participant, offline, retry, body ]))) buddy = _from.split('@')[0] messageContent = utils.softToUni(body) self.sendReceipt(_id, _from, None, participant) self.logger.info("Message received from %s to %s: %s (at ts=%s)", buddy, self.legacyName, messageContent, timestamp) if participant is not None: # Group message partname = participant.split('@')[0] if notify is None: notify = "" self.sendGroupMessageToXMPP(buddy, partname, messageContent, timestamp, notify) else: self.sendMessageToXMPP(buddy, messageContent, timestamp) # isBroadcast always returns false, I'm not sure how to get a broadcast # message. #if messageEntity.isBroadcast(): # self.logger.info("Broadcast received from %s to %s: %s (at ts=%s)",\ # buddy, self.legacyName, messageContent, timestamp) # messageContent = "[Broadcast] " + messageContent # Called by superclass def onImage(self, image): self.logger.debug('Received image message %s', str(image)) buddy = image._from.split('@')[0] participant = image.participant if image.caption is None: image.caption = '' message = image.url + ' ' + image.caption if participant is not None: # Group message partname = participant.split('@')[0] self.sendGroupMessageToXMPP(buddy, partname, message, image.timestamp) else: self.sendMessageToXMPP(buddy, message, image.timestamp) self.sendReceipt(image._id, image._from, None, image.participant) # Called by superclass def onAudio(self, audio): self.logger.debug('Received audio message %s', str(audio)) buddy = audio._from.split('@')[0] participant = audio.participant message = audio.url if participant is not None: # Group message partname = participant.split('@')[0] self.sendGroupMessageToXMPP(buddy, partname, message, audio.timestamp) else: self.sendMessageToXMPP(buddy, message, audio.timestamp) self.sendReceipt(audio._id, audio._from, None, audio.participant) # Called by superclass def onVideo(self, video): self.logger.debug('Received video message %s', str(video)) buddy = video._from.split('@')[0] participant = video.participant message = video.url if participant is not None: # Group message partname = participant.split('@')[0] self.sendGroupMessageToXMPP(buddy, partname, message, video.timestamp) else: self.sendMessageToXMPP(buddy, message, video.timestamp) self.sendReceipt(video._id, video._from, None, video.participant) def onLocation(self, location): buddy = location._from.split('@')[0] latitude = location.getLatitude() longitude = location.getLongitude() url = location.getLocationUrl() participant = location.participant self.logger.debug("Location received from %s: %s, %s", buddy, latitude, longitude) if participant is not None: # Group message partname = participant.split('@')[0] self.sendGroupMessageToXMPP(buddy, partname, url, location.timestamp) self.sendGroupMessageToXMPP(buddy, partname, 'geo:' + latitude + ',' + longitude, location.timestamp) else: self.sendMessageToXMPP(buddy, url, location.timestamp) self.sendMessageToXMPP(buddy, 'geo:' + latitude + ',' + longitude, location.timestamp) self.sendReceipt(location._id, location._from, None, location.participant, location.timestamp) # Called by superclass def onVCard(self, _id, _from, name, card_data, to, notify, timestamp, participant): self.logger.debug('received VCard' + ' '.join( map(str, [ _id, _from, name, card_data, to, notify, timestamp, participant ]))) buddy = _from.split("@")[0] if participant is not None: # Group message partname = participant.split('@')[0] self.sendGroupMessageToXMPP( buddy, partname, "Received VCard (not implemented yet)", timestamp) else: self.sendMessageToXMPP(buddy, "Received VCard (not implemented yet)") # self.sendMessageToXMPP(buddy, card_data) #self.transferFile(buddy, str(name), card_data) self.sendReceipt(_id, _from, None, participant) def transferFile(self, buddy, name, data): # Not working self.logger.debug('transfering file %s', name) self.backend.handleFTStart(self.user, buddy, name, len(data)) self.backend.handleFTData(0, data) self.backend.handleFTFinish(self.user, buddy, name, len(data), 0) # Called by superclass def onContactTyping(self, buddy): self.logger.info("Started typing: %s", buddy) if buddy != 'bot': self.sendPresence(True) self.backend.handleBuddyTyping(self.user, buddy) if self.timer != None: self.timer.cancel() # Called by superclass def onContactPaused(self, buddy): self.logger.info("Paused typing: %s", buddy) if buddy != 'bot': self.backend.handleBuddyTyped(self.user, buddy) self.timer = Timer(3, self.backend.handleBuddyStoppedTyping, (self.user, buddy)).start() # Called by superclass def onAddedToGroup(self, group): self.logger.debug("Added to group: %s", group) room = group.getGroupId() owner = group.getCreatorJid(full=False) subjectOwner = group.getSubjectOwnerJid(full=False) subject = utils.softToUni(group.getSubject()) self.groups[room] = Group(room, owner, subject, subjectOwner, self.backend, self.user) self.groups[room].addParticipants(group.getParticipants, self.buddies, self.legacyName) self.bot.send( "You have been added to group: %s@%s (%s)" % (self._shortenGroupId(room), subject, self.backend.spectrum_jid)) # Called by superclass def onParticipantsAddedToGroup(self, group): self.logger.debug("Participants added to group: %s", group) room = group.getGroupId().split('@')[0] self.groups[room].addParticipants(group.getParticipants(), self.buddies, self.legacyName) self.groups[room].sendParticipantsToSpectrum(self.legacyName) # Called by superclass def onParticipantsRemovedFromGroup(self, room, participants): self.logger.debug("Participants removed from group: %s, %s", room, participants) self.groups[room].removeParticipants(participants) def onPresenceReceived(self, _type, name, jid, lastseen): self.logger.info("Presence received: %s %s %s %s", _type, name, jid, lastseen) buddy = jid.split("@")[0] try: buddy = self.buddies[buddy] except KeyError: # Sometimes whatsapp send our own presence if buddy != self.legacyName: self.logger.error("Buddy not found: %s", buddy) return if (lastseen == str(buddy.lastseen)) and (_type == buddy.presence): return if ((lastseen != "deny") and (lastseen != None) and (lastseen != "none")): buddy.lastseen = int(lastseen) if (_type == None): buddy.lastseen = time.time() buddy.presence = _type if _type == "unavailable": self.onPresenceUnavailable(buddy) else: self.onPresenceAvailable(buddy) def onPresenceAvailable(self, buddy): self.logger.info("Is available: %s", buddy) self.buddies.updateSpectrum(buddy) def onPresenceUnavailable(self, buddy): self.logger.info("Is unavailable: %s", buddy) self.buddies.updateSpectrum(buddy) # spectrum RequestMethods def sendTypingStarted(self, buddy): if buddy != "bot": self.logger.info("Started typing: %s to %s", self.legacyName, buddy) self.sendTyping(buddy, True) # If he is typing he is present # I really don't know where else to put this. # Ideally, this should be sent if the user is looking at his client self.sendPresence(True) def sendTypingStopped(self, buddy): if buddy != "bot": self.logger.info("Stopped typing: %s to %s", self.legacyName, buddy) self.sendTyping(buddy, False) def sendMessageToWA(self, sender, message, ID): self.logger.info("Message sent from %s to %s: %s", self.legacyName, sender, message) message = message.encode("utf-8") # FIXME: Fragile, should pass this in to onDlerror self.dlerror_message = message self.dlerror_sender = sender self.dlerror_ID = ID # End Fragile if sender == "bot": self.bot.parse(message) elif "-" in sender: # group msg if "/" in sender: # directed at single user room, nick = sender.split("/") group = self.groups[room] number = None for othernumber, othernick in group.participants.iteritems(): if othernick == nick: number = othernumber break if number is not None: self.logger.debug("Private message sent from %s to %s", self.legacyName, number) waId = self.sendTextMessage(number + '@s.whatsapp.net', message) self.msgIDs[waId] = MsgIDs(ID, waId) else: self.logger.error( "Attempted to send private message to non-existent user" ) self.logger.debug("%s to %s in %s", self.legacyName, nick, room) else: room = sender if message[0] == '\\' and message[:1] != '\\\\': self.logger.debug("Executing command %s in %s", message, room) self.executeCommand(message, room) else: try: group = self.groups[self._lengthenGroupId(room)] self.logger.debug( "Group Message from %s to %s Groups: %s", group.nick, group, self.groups) self.backend.handleMessage(self.user, room, message.decode('utf-8'), group.nick) except KeyError: self.logger.error('Group not found: %s', room) if (".jpg" in message.lower()) or (".webp" in message.lower()): if (".jpg" in message.lower()): self.imgType = "jpg" if (".webp" in message.lower()): self.imgType = "webp" self.imgMsgId = ID self.imgBuddy = room + "@g.us" downloader = MediaDownloader(self.onDlsuccess, self.onDlerror) downloader.download(message) #self.imgMsgId = ID #self.imgBuddy = room + "@g.us" elif "geo:" in message.lower(): self._sendLocation(room + "@g.us", message, ID) else: self.sendTextMessage( self._lengthenGroupId(room) + '@g.us', message) else: # private msg buddy = sender # if message == "\\lastseen": # self.call("presence_request", buddy = (buddy + "@s.whatsapp.net",)) # else: if message.split(" ").pop(0) == "\\lastseen": self.presenceRequested.append(buddy) #self.call("presence_request", (buddy + "@s.whatsapp.net",)) self._requestLastSeen(buddy) elif message.split(" ").pop(0) == "\\gpp": self.logger.info("Get Profile Picture! ") self.sendMessageToXMPP(buddy, "Fetching Profile Picture") #self.call("contact_getProfilePicture", (buddy + "@s.whatsapp.net",)) self.requestVCard(buddy) else: if (".jpg" in message.lower()) or (".webp" in message.lower()): #waId = self.call("message_imageSend", (buddy + "@s.whatsapp.net", message, None, 0, None)) #waId = self.call("message_send", (buddy + "@s.whatsapp.net", message)) if (".jpg" in message.lower()): self.imgType = "jpg" if (".webp" in message.lower()): self.imgType = "webp" self.imgMsgId = ID self.imgBuddy = buddy + "@s.whatsapp.net" downloader = MediaDownloader(self.onDlsuccess, self.onDlerror) downloader.download(message) #self.imgMsgId = ID #self.imgBuddy = buddy + "@s.whatsapp.net" elif "geo:" in message.lower(): self._sendLocation(buddy + "@s.whatsapp.net", message, ID) else: waId = self.sendTextMessage(sender + '@s.whatsapp.net', message) self.msgIDs[waId] = MsgIDs(ID, waId) self.logger.info("WA Message send to %s with ID %s", buddy, waId) #self.sendTextMessage(sender + '@s.whatsapp.net', message) def executeCommand(self, command, room): if command == '\\leave': self.logger.debug("Leaving room %s", room) # Leave group on whatsapp side self.leaveGroup(room) # Delete Room on spectrum side group = self.groups[room] for jid in group.participants: buddy = jid.split("@")[0] try: nick = self.buddies[buddy].nick except KeyError: nick = buddy if nick == "": nick = buddy if buddy == self.legacyName: nick = group.nick flags = protocol_pb2.PARTICIPANT_FLAG_ROOM_NOT_FOUND self.backend.handleParticipantChanged( self.user, nick, self._shortenGroupId(room), flags, protocol_pb2.STATUS_NONE, buddy) del self.groups[room] def _requestLastSeen(self, buddy): def onSuccess(buddy, lastseen): timestamp = time.localtime(time.localtime() - lastseen) timestring = time.strftime("%a, %d %b %Y %H:%M:%S", timestamp) self.sendMessageToXMPP( buddy, "%s (%s) %s" % (timestring, utils.ago(lastseen), str(lastseen))) def onError(errorIqEntity, originalIqEntity): self.sendMessageToXMPP(errorIqEntity.getFrom(), "LastSeen Error") self.requestLastSeen(buddy, onSuccess, onError) def _sendLocation(self, buddy, message, ID): #with open('/opt/transwhat/map.jpg', 'rb') as imageFile: # raw = base64.b64encode(imageFile.read()) latitude, longitude = message.split(':')[1].split(',') waId = self.sendLocation(buddy, float(latitude), float(longitude)) self.msgIDs[waId] = MsgIDs(ID, waId) self.logger.info("WA Location Message send to %s with ID %s", buddy, waId) def sendMessageToXMPP(self, buddy, messageContent, timestamp="", nickname=""): if timestamp: timestamp = time.strftime("%Y%m%dT%H%M%S", time.gmtime(timestamp)) if self.initialized == False: self.logger.debug("Message queued from %s to %s: %s", buddy, self.legacyName, messageContent) self.offlineQueue.append((buddy, messageContent, timestamp)) else: self.logger.debug("Message sent from %s to %s: %s", buddy, self.legacyName, messageContent) self.backend.handleMessage(self.user, buddy, messageContent, "", "", timestamp) def sendGroupMessageToXMPP(self, room, number, messageContent, timestamp=u"", defaultname=u""): if timestamp: timestamp = time.strftime("%Y%m%dT%H%M%S", time.gmtime(timestamp)) if self.initialized == False: self.logger.debug("Group message queued from %s to %s: %s", number, room, messageContent) if room not in self.groupOfflineQueue: self.groupOfflineQueue[room] = [] self.groupOfflineQueue[room].append( (number, messageContent, timestamp)) else: self.logger.debug("Group message sent from %s to %s: %s", number, room, messageContent) try: group = self.groups[room] # Update nickname try: if defaultname != "" and group.participants[ number] == number: group.changeNick(number, defaultname) if self.buddies[number].nick != "": group.changeNick(number, self.buddies[number].nick) except KeyError: pass nick = group.participants[number] if group.joined: self.backend.handleMessage(self.user, room, messageContent, nick, "", timestamp) else: self.bot.send( "You have received a message in group: %s@%s" % (room, self.backend.spectrum_jid)) self.bot.send("Join the group in order to reply") self.bot.send("%s: %s" % (nick, messageContent)) except KeyError: self.logger.warn("Group is not in group list") self.backend.handleMessage(self.user, self._shortenGroupId(room), messageContent, number, "", timestamp) def changeStatus(self, status): if status != self.status: self.logger.info("Status changed: %s", status) self.status = status if status == protocol_pb2.STATUS_ONLINE \ or status == protocol_pb2.STATUS_FFC: self.sendPresence(True) else: self.sendPresence(False) def changeStatusMessage(self, statusMessage): if (statusMessage != self.statusMessage) or (self.initialized == False): self.statusMessage = statusMessage self.setStatus(statusMessage.encode('utf-8')) self.logger.info("Status message changed: %s", statusMessage) #if self.initialized == False: # self.sendOfflineMessages() # self.bot.call("welcome") # self.initialized = True def sendOfflineMessages(self): # Flush Queues while self.offlineQueue: msg = self.offlineQueue.pop(0) self.backend.handleMessage(self.user, msg[0], msg[1], "", "", msg[2]) # Called when user logs in to initialize the roster def loadBuddies(self, buddies): self.buddies.load(buddies) # also for adding a new buddy def updateBuddy(self, buddy, nick, groups, image_hash=None): if buddy != "bot": self.buddies.update(buddy, nick, groups, image_hash) def removeBuddy(self, buddy): if buddy != "bot": self.logger.info("Buddy removed: %s", buddy) self.buddies.remove(buddy) def requestVCard(self, buddy, ID=None): self.buddies.requestVCard(buddy, ID) def onDlsuccess(self, path): self.logger.info("Success: Image downloaded to %s", path) os.rename(path, path + "." + self.imgType) if self.imgType != "jpg": im = Image.open(path + "." + self.imgType) im.save(path + ".jpg") self.imgPath = path + ".jpg" statinfo = os.stat(self.imgPath) name = os.path.basename(self.imgPath) self.logger.info("Buddy %s", self.imgBuddy) self.image_send(self.imgBuddy, self.imgPath) #self.logger.info("Sending picture %s of size %s with name %s",self.imgPath, statinfo.st_size, name) #mtype = "image" #sha1 = hashlib.sha256() #fp = open(self.imgPath, 'rb') #try: # sha1.update(fp.read()) # hsh = base64.b64encode(sha1.digest()) # self.call("media_requestUpload", (hsh, mtype, os.path.getsize(self.imgPath))) #finally: # fp.close() def onDlerror(self): self.logger.info("Download Error. Sending message as is.") waId = self.sendTextMessage(self.dlerror_sender + '@s.whatsapp.net', self.dlerror_message) self.msgIDs[waId] = MsgIDs(self.dlerror_ID, waId) def _doSendImage(self, filePath, url, to, ip=None, caption=None): waId = self.doSendImage(filePath, url, to, ip, caption) self.msgIDs[waId] = MsgIDs(self.imgMsgId, waId) def _doSendAudio(self, filePath, url, to, ip=None, caption=None): waId = self.doSendAudio(filePath, url, to, ip, caption) self.msgIDs[waId] = MsgIDs(self.imgMsgId, waId) def createThumb(self, size=100, raw=False): img = Image.open(self.imgPath) width, height = img.size img_thumbnail = self.imgPath + '_thumbnail' if width > height: nheight = float(height) / width * size nwidth = size else: nwidth = float(width) / height * size nheight = size img.thumbnail((nwidth, nheight), Image.ANTIALIAS) img.save(img_thumbnail, 'JPEG') with open(img_thumbnail, 'rb') as imageFile: raw = base64.b64encode(imageFile.read()) return raw # Not used def onLocationReceived(self, messageId, jid, name, preview, latitude, longitude, receiptRequested, isBroadcast): buddy = jid.split("@")[0] self.logger.info("Location received from %s: %s, %s", buddy, latitude, longitude) url = "http://maps.google.de?%s" % urllib.urlencode( {"q": "%s %s" % (latitude, longitude)}) self.sendMessageToXMPP(buddy, utils.shorten(url)) if receiptRequested: self.call("message_ack", (jid, messageId)) def onGroupSubjectReceived(self, messageId, gjid, jid, subject, timestamp, receiptRequested): room = gjid.split("@")[0] buddy = jid.split("@")[0] self.backend.handleSubject(self.user, room, subject, buddy) if receiptRequested: self.call("subject_ack", (gjid, messageId)) # Yowsup Notifications def onGroupParticipantRemoved(self, gjid, jid, author, timestamp, messageId, receiptRequested): room = gjid.split("@")[0] buddy = jid.split("@")[0] self.logger.info("Removed %s from room %s", buddy, room) self.backend.handleParticipantChanged( self.user, buddy, room, protocol_pb2.PARTICIPANT_FLAG_NONE, protocol_pb2.STATUS_NONE) # TODO if receiptRequested: self.call("notification_ack", (gjid, messageId)) def onContactProfilePictureUpdated(self, jid, timestamp, messageId, pictureId, receiptRequested): # TODO if receiptRequested: self.call("notification_ack", (jid, messageId)) def onGroupPictureUpdated(self, jid, author, timestamp, messageId, pictureId, receiptRequested): # TODO if receiptRequested: self.call("notification_ack", (jid, messageId))