diff --git a/session.py b/session.py index 7193be3..a8a4bbd 100644 --- a/session.py +++ b/session.py @@ -52,6 +52,8 @@ class Session(YowsupApp): self.statusMessage = '' self.groups = {} + self.gotGroupList = False + self.joinRoomQueue = [] self.presenceRequested = [] self.offlineQueue = [] self.groupOfflineQueue = { } @@ -79,20 +81,27 @@ class Session(YowsupApp): super(Session, self).login(self.legacyName, self.password) def _shortenGroupId(self, gid): - # FIXME: will have problems if number begins with 0 - return '-'.join(hex(int(s))[2:] for s in gid.split('-')) - + # 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): - # FIXME: will have problems if number begins with 0 - return '-'.join(str(int(s, 16)) for s in gid.split('-')) + 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 updateRoster(self): self.logger.debug("Update roster") @@ -143,9 +152,10 @@ class Session(YowsupApp): oroom.subject = subject else: self.groups[room] = Group(room, owner, subject, subjectOwner) - self.joinRoom(self._shortenGroupId(room), self.user.split("@")[0]) +# self.joinRoom(self._shortenGroupId(room), self.user.split("@")[0]) + self.groups[room].participants = group.getParticipants().keys() - self._addParticipantsToRoom(room, group.getParticipants()) + #self._addParticipantsToRoom(room, group.getParticipants()) if room in self.groupOfflineQueue: while self.groupOfflineQueue[room]: @@ -154,9 +164,16 @@ class Session(YowsupApp): 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", @@ -169,13 +186,14 @@ class Session(YowsupApp): except KeyError: ownerNick = group.subjectOwner + self._refreshParticipants(room) self.backend.handleSubject(self.user, self._shortenGroupId(room), - group.subject, - ownerNick) + group.subject) + self.logger.debug("Room subject: room=%s, subject=%s", + room, group.subject) self.backend.handleRoomNicknameChanged( self.user, self._shortenGroupId(room), group.subject ) - self._refreshParticipants(room) else: self.logger.warn("Room doesn't exist: %s", room) @@ -191,7 +209,6 @@ class Session(YowsupApp): if nick == "": nick = buddy - buddyFull = buddy if buddy == group.owner: flags = protocol_pb2.PARTICIPANT_FLAG_MODERATOR else: @@ -199,38 +216,9 @@ class Session(YowsupApp): if buddy == self.legacyName: nick = group.nick flags = flags | protocol_pb2.PARTICIPANT_FLAG_ME - buddyFull = self.user self.backend.handleParticipantChanged( - self.user, buddyFull, self._shortenGroupId(room), flags, - protocol_pb2.STATUS_ONLINE, buddy, nick) - - def _addParticipantsToRoom(self, room, participants): - group = self.groups[room] - group.participants = participants - - for jid, _type in participants.iteritems(): - buddy = jid.split("@")[0] - buddyFull = buddy - self.logger.info("Added %s to room %s", buddy, room) - try: - nick = self.buddies[buddy].nick - except KeyError: - nick = buddy - buddyFull = buddy - if _type == 'admin': - flags = protocol_pb2.PARTICIPANT_FLAG_MODERATOR - else: - flags = protocol_pb2.PARTICIPANT_FLAG_NONE - if buddy == self.legacyName: - nick = group.nick - flags = protocol_pb2.PARTICIPANT_FLAG_ME - buddyFull = self.user - - self.backend.handleParticipantChanged( - self.user, buddyFull, self._shortenGroupId(room), flags, - protocol_pb2.STATUS_ONLINE, buddy, nick - ) - + self.user, nick, self._shortenGroupId(room), flags, + protocol_pb2.STATUS_ONLINE, buddy) def _lastSeen(self, number, seconds): self.logger.debug("Last seen %s at %s seconds" % (number, str(seconds))) @@ -309,9 +297,9 @@ class Session(YowsupApp): if part.nick == "": part.nick = notify self.backend.handleParticipantChanged( - self.user, partname, buddy, + self.user, partname, self._shortenGroupId(buddy), protocol_pb2.PARTICIPANT_FLAG_NONE, - protocol_pb2.STATUS_NONE, "", part.nick + protocol_pb2.STATUS_ONLINE, "", part.nick ) # TODO except KeyError: self.updateBuddy(partname, notify, []) @@ -402,6 +390,28 @@ class Session(YowsupApp): 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.groups[room].participants = group.getParticipants().keys() +# self.joinRoom(self._shortenGroupId(room), self.user.split("@")[0]) + + #self._addParticipantsToRoom(room, group.getParticipants()) + self.bot.send("You have been added to group: %s@%s (%s)" + % (self._shortenGroupId(room), subject, self.backend.spectrum_jid)) + + def onParticipantsAddedToGroup(self, group): + self.logger.debug("Participants added to group: %s", group) + room = group.getGroupId().split('@')[0] + self.groups[room].participants.extend(group.getParticipants()) + self._refreshParticipants(room) + def onPresenceReceived(self, _type, name, jid, lastseen): self.logger.info("Presence received: %s %s %s %s", _type, name, jid, lastseen) buddy = jid.split("@")[0] @@ -504,7 +514,7 @@ class Session(YowsupApp): "", timestamp) def sendGroupMessageToXMPP(self, room, buddy, messageContent, timestamp = ""): - self._refreshParticipants(room) + # self._refreshParticipants(room) try: nick = self.buddies[buddy].nick except KeyError: diff --git a/transwhat.py b/transwhat.py index 84abc31..5875dc4 100755 --- a/transwhat.py +++ b/transwhat.py @@ -78,7 +78,7 @@ def connectionClosed(): db = MySQLdb.connect(DB_HOST, DB_USER, DB_PASS, DB_TABLE) io = IOChannel(args.host, args.port, handleTransportData, connectionClosed) -plugin = WhatsAppBackend(io, db) +plugin = WhatsAppBackend(io, db, args.j) while True: try: diff --git a/whatsappbackend.py b/whatsappbackend.py index b973f76..c645330 100644 --- a/whatsappbackend.py +++ b/whatsappbackend.py @@ -30,12 +30,13 @@ from session import Session import logging class WhatsAppBackend(SpectrumBackend): - def __init__(self, io, db): + def __init__(self, io, db, spectrum_jid): SpectrumBackend.__init__(self) self.logger = logging.getLogger(self.__class__.__name__) self.io = io self.db = db self.sessions = { } + self.spectrum_jid = spectrum_jid # Used to prevent duplicate messages self.lastMessage = {} diff --git a/yowsupwrapper.py b/yowsupwrapper.py index 2a8349b..7ed3d4a 100644 --- a/yowsupwrapper.py +++ b/yowsupwrapper.py @@ -1,3 +1,5 @@ +import logging + from yowsup import env from yowsup.stacks import YowStack from yowsup.common import YowConstants @@ -67,6 +69,7 @@ class YowsupApp(object): YowStanzaRegulator, YowNetworkLayer ) + self.logger = logging.getLogger(self.__class__.__name__) self.stack = YowStack(layers) self.stack.broadcastEvent( YowLayerEvent(YowsupAppLayer.EVENT_START, caller = self) @@ -108,7 +111,7 @@ class YowsupApp(object): Logout from whatsapp """ self.stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_DISCONNECT)) - + def sendReceipt(self, _id, _from, read, participant): """ Send a receipt (delivered: double-tick, read: blue-ticks) @@ -168,7 +171,7 @@ class YowsupApp(object): jid = phone_number + '@s.whatsapp.net' entity = UnsubscribePresenceProtocolEntity(jid) self.sendEntity(entity) - + def setStatus(self, statusText): """ Send status to whatsapp @@ -313,7 +316,7 @@ class YowsupApp(object): - timestamp """ pass - + def onPresenceReceived(self, _type, name, _from, last): """ Called when presence (e.g. available, unavailable) is received @@ -331,7 +334,7 @@ class YowsupApp(object): """ Called when disconnected from whatsapp """ - + def onContactTyping(self, number): """ Called when contact starts to type @@ -366,7 +369,7 @@ class YowsupApp(object): - body: The content of the message """ pass - + def onImage(self, entity): """ Called when image message is received @@ -384,7 +387,7 @@ class YowsupApp(object): - entity: AudioDownloadableMediaMessageProtocolEntity """ pass - + def onVideo(self, entity): """ @@ -403,7 +406,7 @@ class YowsupApp(object): - entity: LocationMediaMessageProtocolEntity """ pass - + def onVCard(self, _id, _from, name, card_data, to, notify, timestamp, participant): """ Called when VCard message is received @@ -420,12 +423,20 @@ class YowsupApp(object): """ pass + def onAddedToGroup(self, entity): + """Called when the user has been added to a new group""" + pass + + def onParticipantsAddedToGroup(self, entity): + """Called when participants have been added to a group""" + pass + def sendEntity(self, entity): """Sends an entity down the stack (as if YowsupAppLayer called toLower)""" self.stack.broadcastEvent(YowLayerEvent(YowsupAppLayer.TO_LOWER_EVENT, entity = entity )) - + def sendIq(self, iq, onSuccess = None, onError = None): self.stack.broadcastEvent( YowLayerEvent( @@ -450,6 +461,7 @@ class YowsupAppLayer(YowInterfaceLayer): # return True otherwise if layerEvent.getName() == YowsupAppLayer.EVENT_START: self.caller = layerEvent.getArg('caller') + self.logger = logging.getLogger(self.__class__.__name__) return True elif layerEvent.getName() == YowNetworkLayer.EVENT_STATE_DISCONNECTED: self.caller.onDisconnect() @@ -514,8 +526,13 @@ class YowsupAppLayer(YowInterfaceLayer): """ Sends ack automatically """ + self.logger.debug("Received notification: %s", entity) self.toLower(entity.ack()) - + if isinstance(entity, CreateGroupsNotificationProtocolEntity): + self.caller.onAddedToGroup(entity) + elif isinstance(entity, AddGroupsNotificationProtocolEntity): + self.caller.onParticipantsAddedToGroup(entity) + @ProtocolEntityCallback('message') def onMessageReceived(self, entity): if entity.getType() == MessageProtocolEntity.MESSAGE_TYPE_TEXT: @@ -560,7 +577,7 @@ class YowsupAppLayer(YowInterfaceLayer): _from = presence.getFrom() last = presence.getLast() self.caller.onPresenceReceived(_type, name, _from, last) - + @ProtocolEntityCallback('chatstate') def onChatstate(self, chatstate): number = chatstate._from.split('@')[0]