diff --git a/README.md b/README.md index e303b76..188ac5e 100644 --- a/README.md +++ b/README.md @@ -78,23 +78,15 @@ Checkout the latest version of transWhat from GitHub: Install required dependencies: - $ pip install --pre e4u protobuf mysql python-dateutil + $ pip install --pre e4u protobuf python-dateutil - **e4u**: is a simple emoji4unicode python bindings - [**yowsup**](https://github.com/tgalal/yowsup): is a python library that enables you build application which use WhatsApp service. - - **mysqldb**: MySQL client python bindings ##### Configuration -First create a new mySQL database named `transwhat` and fill it with the [schema](https://raw.githubusercontent.com/stv0g/transwhat/yowsup-2/conf/schema.sql) provided in the repo. - Then create a new file called `constants.py` in the newly checked out transWhat Git repository: - DB_HOST = "localhost" - DB_USER = "**fillin**" - DB_PASS = "**fillin**" - DB_TABLE = "transwhat" - BASE_PATH = "/location/to/transwhat" TOKEN_FILE = BASE_PATH + "/logs/tokens" diff --git a/Spectrum2/backend.py b/Spectrum2/backend.py index 92cd03d..feb2e94 100644 --- a/Spectrum2/backend.py +++ b/Spectrum2/backend.py @@ -19,6 +19,7 @@ class SpectrumBackend: @param host: Host where Spectrum2 NetworkPluginServer runs. @param port: Port. """ + def __init__(self): self.m_pingReceived = False self.m_data = "" @@ -344,6 +345,14 @@ class SpectrumBackend: groups = [g for g in payload.group] self.handleBuddyRemovedRequest(payload.userName, payload.buddyName, groups); + def handleBuddiesPayload(self, data): + payload = protocol_pb2.Buddies() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + + self.handleBuddies(payload); + def handleChatStatePayload(self, data, msgType): payload = protocol_pb2.Buddy() if (payload.ParseFromString(data) == False): @@ -428,6 +437,8 @@ class SpectrumBackend: self.handleConvMessageAckPayload(wrapper.payload) elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_RAW_XML: self.handleRawXmlRequest(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_BUDDIES: + self.handleBuddiesPayload(wrapper.payload) def send(self, data): header = struct.pack('!I',len(data)) @@ -488,6 +499,9 @@ class SpectrumBackend: raise NotImplementedError, "Implement me" + def handleBuddies(self, buddies): + pass + def handleLogoutRequest(self, user, legacyName): """ Called when XMPP user wants to disconnect legacy network. @@ -505,7 +519,7 @@ class SpectrumBackend: @param legacyName: Legacy network name of buddy or room. @param message: Plain text message. @param xhtml: XHTML message. - @param ID: message ID + @param ID: message ID """ raise NotImplementedError, "Implement me" diff --git a/Spectrum2/protocol.proto b/Spectrum2/protocol.proto index 8d48386..78a3b9a 100644 --- a/Spectrum2/protocol.proto +++ b/Spectrum2/protocol.proto @@ -63,6 +63,10 @@ message Buddy { optional bool blocked = 8; } +message Buddies { + repeated Buddy buddy = 1; +} + message ConversationMessage { required string userName = 1; required string buddyName = 2; @@ -182,6 +186,7 @@ message WrapperMessage { TYPE_ROOM_LIST = 32; TYPE_CONV_MESSAGE_ACK = 33; TYPE_RAW_XML = 34; + TYPE_BUDDIES = 35; } required Type type = 1; optional bytes payload = 2; diff --git a/Spectrum2/protocol_pb2.py b/Spectrum2/protocol_pb2.py index 638435c..13f0c5f 100644 --- a/Spectrum2/protocol_pb2.py +++ b/Spectrum2/protocol_pb2.py @@ -19,7 +19,7 @@ _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='protocol.proto', package='pbnetwork', - serialized_pb=_b('\n\x0eprotocol.proto\x12\tpbnetwork\"\x19\n\tConnected\x12\x0c\n\x04user\x18\x01 \x02(\t\"<\n\x0c\x44isconnected\x12\x0c\n\x04user\x18\x01 \x02(\t\x12\r\n\x05\x65rror\x18\x02 \x02(\x05\x12\x0f\n\x07message\x18\x03 \x01(\t\"P\n\x05Login\x12\x0c\n\x04user\x18\x01 \x02(\t\x12\x12\n\nlegacyName\x18\x02 \x02(\t\x12\x10\n\x08password\x18\x03 \x02(\t\x12\x13\n\x0b\x65xtraFields\x18\x04 \x03(\t\"*\n\x06Logout\x12\x0c\n\x04user\x18\x01 \x02(\t\x12\x12\n\nlegacyName\x18\x02 \x02(\t\"\xab\x01\n\x05\x42uddy\x12\x10\n\x08userName\x18\x01 \x02(\t\x12\x11\n\tbuddyName\x18\x02 \x02(\t\x12\r\n\x05\x61lias\x18\x03 \x01(\t\x12\r\n\x05group\x18\x04 \x03(\t\x12%\n\x06status\x18\x05 \x01(\x0e\x32\x15.pbnetwork.StatusType\x12\x15\n\rstatusMessage\x18\x06 \x01(\t\x12\x10\n\x08iconHash\x18\x07 \x01(\t\x12\x0f\n\x07\x62locked\x18\x08 \x01(\x08\"\xa9\x01\n\x13\x43onversationMessage\x12\x10\n\x08userName\x18\x01 \x02(\t\x12\x11\n\tbuddyName\x18\x02 \x02(\t\x12\x0f\n\x07message\x18\x03 \x02(\t\x12\x10\n\x08nickname\x18\x04 \x01(\t\x12\r\n\x05xhtml\x18\x05 \x01(\t\x12\x11\n\ttimestamp\x18\x06 \x01(\t\x12\x10\n\x08headline\x18\x07 \x01(\x08\x12\n\n\x02id\x18\x08 \x01(\t\x12\n\n\x02pm\x18\t \x01(\x08\"J\n\x04Room\x12\x10\n\x08userName\x18\x01 \x02(\t\x12\x10\n\x08nickname\x18\x02 \x02(\t\x12\x0c\n\x04room\x18\x03 \x02(\t\x12\x10\n\x08password\x18\x04 \x01(\t\"&\n\x08RoomList\x12\x0c\n\x04room\x18\x01 \x03(\t\x12\x0c\n\x04name\x18\x02 \x03(\t\"\x9c\x01\n\x0bParticipant\x12\x10\n\x08userName\x18\x01 \x02(\t\x12\x0c\n\x04room\x18\x02 \x02(\t\x12\x10\n\x08nickname\x18\x03 \x02(\t\x12\x0c\n\x04\x66lag\x18\x04 \x02(\x05\x12%\n\x06status\x18\x05 \x02(\x0e\x32\x15.pbnetwork.StatusType\x12\x15\n\rstatusMessage\x18\x06 \x01(\t\x12\x0f\n\x07newname\x18\x07 \x01(\t\"k\n\x05VCard\x12\x10\n\x08userName\x18\x01 \x02(\t\x12\x11\n\tbuddyName\x18\x02 \x02(\t\x12\n\n\x02id\x18\x03 \x02(\x05\x12\x10\n\x08\x66ullname\x18\x04 \x01(\t\x12\x10\n\x08nickname\x18\x05 \x01(\t\x12\r\n\x05photo\x18\x06 \x01(\x0c\"X\n\x06Status\x12\x10\n\x08userName\x18\x01 \x02(\t\x12%\n\x06status\x18\x03 \x02(\x0e\x32\x15.pbnetwork.StatusType\x12\x15\n\rstatusMessage\x18\x04 \x01(\t\"B\n\x05Stats\x12\x0b\n\x03res\x18\x01 \x02(\x05\x12\x10\n\x08init_res\x18\x02 \x02(\x05\x12\x0e\n\x06shared\x18\x03 \x02(\x05\x12\n\n\x02id\x18\x04 \x02(\t\"Y\n\x04\x46ile\x12\x10\n\x08userName\x18\x01 \x02(\t\x12\x11\n\tbuddyName\x18\x02 \x02(\t\x12\x10\n\x08\x66ileName\x18\x03 \x02(\t\x12\x0c\n\x04size\x18\x04 \x02(\x05\x12\x0c\n\x04\x66tID\x18\x05 \x01(\x05\".\n\x10\x46ileTransferData\x12\x0c\n\x04\x66tID\x18\x01 \x02(\x05\x12\x0c\n\x04\x64\x61ta\x18\x02 \x02(\x0c\"\x1f\n\rBackendConfig\x12\x0e\n\x06\x63onfig\x18\x01 \x02(\t\"\x9a\x06\n\x0eWrapperMessage\x12,\n\x04type\x18\x01 \x02(\x0e\x32\x1e.pbnetwork.WrapperMessage.Type\x12\x0f\n\x07payload\x18\x02 \x01(\x0c\"\xc8\x05\n\x04Type\x12\x12\n\x0eTYPE_CONNECTED\x10\x01\x12\x15\n\x11TYPE_DISCONNECTED\x10\x02\x12\x0e\n\nTYPE_LOGIN\x10\x03\x12\x0f\n\x0bTYPE_LOGOUT\x10\x04\x12\x16\n\x12TYPE_BUDDY_CHANGED\x10\x06\x12\x16\n\x12TYPE_BUDDY_REMOVED\x10\x07\x12\x15\n\x11TYPE_CONV_MESSAGE\x10\x08\x12\r\n\tTYPE_PING\x10\t\x12\r\n\tTYPE_PONG\x10\n\x12\x12\n\x0eTYPE_JOIN_ROOM\x10\x0b\x12\x13\n\x0fTYPE_LEAVE_ROOM\x10\x0c\x12\x1c\n\x18TYPE_PARTICIPANT_CHANGED\x10\r\x12\x1e\n\x1aTYPE_ROOM_NICKNAME_CHANGED\x10\x0e\x12\x1d\n\x19TYPE_ROOM_SUBJECT_CHANGED\x10\x0f\x12\x0e\n\nTYPE_VCARD\x10\x10\x12\x17\n\x13TYPE_STATUS_CHANGED\x10\x11\x12\x15\n\x11TYPE_BUDDY_TYPING\x10\x12\x12\x1d\n\x19TYPE_BUDDY_STOPPED_TYPING\x10\x13\x12\x14\n\x10TYPE_BUDDY_TYPED\x10\x14\x12\x15\n\x11TYPE_AUTH_REQUEST\x10\x15\x12\x12\n\x0eTYPE_ATTENTION\x10\x16\x12\x0e\n\nTYPE_STATS\x10\x17\x12\x11\n\rTYPE_FT_START\x10\x18\x12\x12\n\x0eTYPE_FT_FINISH\x10\x19\x12\x10\n\x0cTYPE_FT_DATA\x10\x1a\x12\x11\n\rTYPE_FT_PAUSE\x10\x1b\x12\x14\n\x10TYPE_FT_CONTINUE\x10\x1c\x12\r\n\tTYPE_EXIT\x10\x1d\x12\x17\n\x13TYPE_BACKEND_CONFIG\x10\x1e\x12\x0e\n\nTYPE_QUERY\x10\x1f\x12\x12\n\x0eTYPE_ROOM_LIST\x10 \x12\x19\n\x15TYPE_CONV_MESSAGE_ACK\x10!\x12\x10\n\x0cTYPE_RAW_XML\x10\"*\xb3\x05\n\x0f\x43onnectionError\x12\"\n\x1e\x43ONNECTION_ERROR_NETWORK_ERROR\x10\x00\x12%\n!CONNECTION_ERROR_INVALID_USERNAME\x10\x01\x12*\n&CONNECTION_ERROR_AUTHENTICATION_FAILED\x10\x02\x12.\n*CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE\x10\x03\x12#\n\x1f\x43ONNECTION_ERROR_NO_SSL_SUPPORT\x10\x04\x12%\n!CONNECTION_ERROR_ENCRYPTION_ERROR\x10\x05\x12 \n\x1c\x43ONNECTION_ERROR_NAME_IN_USE\x10\x06\x12%\n!CONNECTION_ERROR_INVALID_SETTINGS\x10\x07\x12&\n\"CONNECTION_ERROR_CERT_NOT_PROVIDED\x10\x08\x12#\n\x1f\x43ONNECTION_ERROR_CERT_UNTRUSTED\x10\t\x12!\n\x1d\x43ONNECTION_ERROR_CERT_EXPIRED\x10\n\x12\'\n#CONNECTION_ERROR_CERT_NOT_ACTIVATED\x10\x0b\x12+\n\'CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH\x10\x0c\x12.\n*CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH\x10\r\x12%\n!CONNECTION_ERROR_CERT_SELF_SIGNED\x10\x0e\x12%\n!CONNECTION_ERROR_CERT_OTHER_ERROR\x10\x0f\x12 \n\x1c\x43ONNECTION_ERROR_OTHER_ERROR\x10\x10*\x86\x01\n\nStatusType\x12\x11\n\rSTATUS_ONLINE\x10\x00\x12\x0f\n\x0bSTATUS_AWAY\x10\x01\x12\x0e\n\nSTATUS_FFC\x10\x02\x12\r\n\tSTATUS_XA\x10\x03\x12\x0e\n\nSTATUS_DND\x10\x04\x12\x0f\n\x0bSTATUS_NONE\x10\x05\x12\x14\n\x10STATUS_INVISIBLE\x10\x06*\x88\x02\n\x0fParticipantFlag\x12\x19\n\x15PARTICIPANT_FLAG_NONE\x10\x00\x12\x1e\n\x1aPARTICIPANT_FLAG_MODERATOR\x10\x01\x12\x1d\n\x19PARTICIPANT_FLAG_CONFLICT\x10\x02\x12\x1b\n\x17PARTICIPANT_FLAG_BANNED\x10\x04\x12#\n\x1fPARTICIPANT_FLAG_NOT_AUTHORIZED\x10\x08\x12\x17\n\x13PARTICIPANT_FLAG_ME\x10\x10\x12\x1b\n\x17PARTICIPANT_FLAG_KICKED\x10 \x12#\n\x1fPARTICIPANT_FLAG_ROOM_NOT_FOUND\x10@') + serialized_pb=_b('\n\x0eprotocol.proto\x12\tpbnetwork\"\x19\n\tConnected\x12\x0c\n\x04user\x18\x01 \x02(\t\"<\n\x0c\x44isconnected\x12\x0c\n\x04user\x18\x01 \x02(\t\x12\r\n\x05\x65rror\x18\x02 \x02(\x05\x12\x0f\n\x07message\x18\x03 \x01(\t\"P\n\x05Login\x12\x0c\n\x04user\x18\x01 \x02(\t\x12\x12\n\nlegacyName\x18\x02 \x02(\t\x12\x10\n\x08password\x18\x03 \x02(\t\x12\x13\n\x0b\x65xtraFields\x18\x04 \x03(\t\"*\n\x06Logout\x12\x0c\n\x04user\x18\x01 \x02(\t\x12\x12\n\nlegacyName\x18\x02 \x02(\t\"\xab\x01\n\x05\x42uddy\x12\x10\n\x08userName\x18\x01 \x02(\t\x12\x11\n\tbuddyName\x18\x02 \x02(\t\x12\r\n\x05\x61lias\x18\x03 \x01(\t\x12\r\n\x05group\x18\x04 \x03(\t\x12%\n\x06status\x18\x05 \x01(\x0e\x32\x15.pbnetwork.StatusType\x12\x15\n\rstatusMessage\x18\x06 \x01(\t\x12\x10\n\x08iconHash\x18\x07 \x01(\t\x12\x0f\n\x07\x62locked\x18\x08 \x01(\x08\"*\n\x07\x42uddies\x12\x1f\n\x05\x62uddy\x18\x01 \x03(\x0b\x32\x10.pbnetwork.Buddy\"\xa9\x01\n\x13\x43onversationMessage\x12\x10\n\x08userName\x18\x01 \x02(\t\x12\x11\n\tbuddyName\x18\x02 \x02(\t\x12\x0f\n\x07message\x18\x03 \x02(\t\x12\x10\n\x08nickname\x18\x04 \x01(\t\x12\r\n\x05xhtml\x18\x05 \x01(\t\x12\x11\n\ttimestamp\x18\x06 \x01(\t\x12\x10\n\x08headline\x18\x07 \x01(\x08\x12\n\n\x02id\x18\x08 \x01(\t\x12\n\n\x02pm\x18\t \x01(\x08\"J\n\x04Room\x12\x10\n\x08userName\x18\x01 \x02(\t\x12\x10\n\x08nickname\x18\x02 \x02(\t\x12\x0c\n\x04room\x18\x03 \x02(\t\x12\x10\n\x08password\x18\x04 \x01(\t\"&\n\x08RoomList\x12\x0c\n\x04room\x18\x01 \x03(\t\x12\x0c\n\x04name\x18\x02 \x03(\t\"\x9c\x01\n\x0bParticipant\x12\x10\n\x08userName\x18\x01 \x02(\t\x12\x0c\n\x04room\x18\x02 \x02(\t\x12\x10\n\x08nickname\x18\x03 \x02(\t\x12\x0c\n\x04\x66lag\x18\x04 \x02(\x05\x12%\n\x06status\x18\x05 \x02(\x0e\x32\x15.pbnetwork.StatusType\x12\x15\n\rstatusMessage\x18\x06 \x01(\t\x12\x0f\n\x07newname\x18\x07 \x01(\t\"k\n\x05VCard\x12\x10\n\x08userName\x18\x01 \x02(\t\x12\x11\n\tbuddyName\x18\x02 \x02(\t\x12\n\n\x02id\x18\x03 \x02(\x05\x12\x10\n\x08\x66ullname\x18\x04 \x01(\t\x12\x10\n\x08nickname\x18\x05 \x01(\t\x12\r\n\x05photo\x18\x06 \x01(\x0c\"X\n\x06Status\x12\x10\n\x08userName\x18\x01 \x02(\t\x12%\n\x06status\x18\x03 \x02(\x0e\x32\x15.pbnetwork.StatusType\x12\x15\n\rstatusMessage\x18\x04 \x01(\t\"B\n\x05Stats\x12\x0b\n\x03res\x18\x01 \x02(\x05\x12\x10\n\x08init_res\x18\x02 \x02(\x05\x12\x0e\n\x06shared\x18\x03 \x02(\x05\x12\n\n\x02id\x18\x04 \x02(\t\"Y\n\x04\x46ile\x12\x10\n\x08userName\x18\x01 \x02(\t\x12\x11\n\tbuddyName\x18\x02 \x02(\t\x12\x10\n\x08\x66ileName\x18\x03 \x02(\t\x12\x0c\n\x04size\x18\x04 \x02(\x05\x12\x0c\n\x04\x66tID\x18\x05 \x01(\x05\".\n\x10\x46ileTransferData\x12\x0c\n\x04\x66tID\x18\x01 \x02(\x05\x12\x0c\n\x04\x64\x61ta\x18\x02 \x02(\x0c\"\x1f\n\rBackendConfig\x12\x0e\n\x06\x63onfig\x18\x01 \x02(\t\"\xac\x06\n\x0eWrapperMessage\x12,\n\x04type\x18\x01 \x02(\x0e\x32\x1e.pbnetwork.WrapperMessage.Type\x12\x0f\n\x07payload\x18\x02 \x01(\x0c\"\xda\x05\n\x04Type\x12\x12\n\x0eTYPE_CONNECTED\x10\x01\x12\x15\n\x11TYPE_DISCONNECTED\x10\x02\x12\x0e\n\nTYPE_LOGIN\x10\x03\x12\x0f\n\x0bTYPE_LOGOUT\x10\x04\x12\x16\n\x12TYPE_BUDDY_CHANGED\x10\x06\x12\x16\n\x12TYPE_BUDDY_REMOVED\x10\x07\x12\x15\n\x11TYPE_CONV_MESSAGE\x10\x08\x12\r\n\tTYPE_PING\x10\t\x12\r\n\tTYPE_PONG\x10\n\x12\x12\n\x0eTYPE_JOIN_ROOM\x10\x0b\x12\x13\n\x0fTYPE_LEAVE_ROOM\x10\x0c\x12\x1c\n\x18TYPE_PARTICIPANT_CHANGED\x10\r\x12\x1e\n\x1aTYPE_ROOM_NICKNAME_CHANGED\x10\x0e\x12\x1d\n\x19TYPE_ROOM_SUBJECT_CHANGED\x10\x0f\x12\x0e\n\nTYPE_VCARD\x10\x10\x12\x17\n\x13TYPE_STATUS_CHANGED\x10\x11\x12\x15\n\x11TYPE_BUDDY_TYPING\x10\x12\x12\x1d\n\x19TYPE_BUDDY_STOPPED_TYPING\x10\x13\x12\x14\n\x10TYPE_BUDDY_TYPED\x10\x14\x12\x15\n\x11TYPE_AUTH_REQUEST\x10\x15\x12\x12\n\x0eTYPE_ATTENTION\x10\x16\x12\x0e\n\nTYPE_STATS\x10\x17\x12\x11\n\rTYPE_FT_START\x10\x18\x12\x12\n\x0eTYPE_FT_FINISH\x10\x19\x12\x10\n\x0cTYPE_FT_DATA\x10\x1a\x12\x11\n\rTYPE_FT_PAUSE\x10\x1b\x12\x14\n\x10TYPE_FT_CONTINUE\x10\x1c\x12\r\n\tTYPE_EXIT\x10\x1d\x12\x17\n\x13TYPE_BACKEND_CONFIG\x10\x1e\x12\x0e\n\nTYPE_QUERY\x10\x1f\x12\x12\n\x0eTYPE_ROOM_LIST\x10 \x12\x19\n\x15TYPE_CONV_MESSAGE_ACK\x10!\x12\x10\n\x0cTYPE_RAW_XML\x10\"\x12\x10\n\x0cTYPE_BUDDIES\x10#*\xb3\x05\n\x0f\x43onnectionError\x12\"\n\x1e\x43ONNECTION_ERROR_NETWORK_ERROR\x10\x00\x12%\n!CONNECTION_ERROR_INVALID_USERNAME\x10\x01\x12*\n&CONNECTION_ERROR_AUTHENTICATION_FAILED\x10\x02\x12.\n*CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE\x10\x03\x12#\n\x1f\x43ONNECTION_ERROR_NO_SSL_SUPPORT\x10\x04\x12%\n!CONNECTION_ERROR_ENCRYPTION_ERROR\x10\x05\x12 \n\x1c\x43ONNECTION_ERROR_NAME_IN_USE\x10\x06\x12%\n!CONNECTION_ERROR_INVALID_SETTINGS\x10\x07\x12&\n\"CONNECTION_ERROR_CERT_NOT_PROVIDED\x10\x08\x12#\n\x1f\x43ONNECTION_ERROR_CERT_UNTRUSTED\x10\t\x12!\n\x1d\x43ONNECTION_ERROR_CERT_EXPIRED\x10\n\x12\'\n#CONNECTION_ERROR_CERT_NOT_ACTIVATED\x10\x0b\x12+\n\'CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH\x10\x0c\x12.\n*CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH\x10\r\x12%\n!CONNECTION_ERROR_CERT_SELF_SIGNED\x10\x0e\x12%\n!CONNECTION_ERROR_CERT_OTHER_ERROR\x10\x0f\x12 \n\x1c\x43ONNECTION_ERROR_OTHER_ERROR\x10\x10*\x86\x01\n\nStatusType\x12\x11\n\rSTATUS_ONLINE\x10\x00\x12\x0f\n\x0bSTATUS_AWAY\x10\x01\x12\x0e\n\nSTATUS_FFC\x10\x02\x12\r\n\tSTATUS_XA\x10\x03\x12\x0e\n\nSTATUS_DND\x10\x04\x12\x0f\n\x0bSTATUS_NONE\x10\x05\x12\x14\n\x10STATUS_INVISIBLE\x10\x06*\x88\x02\n\x0fParticipantFlag\x12\x19\n\x15PARTICIPANT_FLAG_NONE\x10\x00\x12\x1e\n\x1aPARTICIPANT_FLAG_MODERATOR\x10\x01\x12\x1d\n\x19PARTICIPANT_FLAG_CONFLICT\x10\x02\x12\x1b\n\x17PARTICIPANT_FLAG_BANNED\x10\x04\x12#\n\x1fPARTICIPANT_FLAG_NOT_AUTHORIZED\x10\x08\x12\x17\n\x13PARTICIPANT_FLAG_ME\x10\x10\x12\x1b\n\x17PARTICIPANT_FLAG_KICKED\x10 \x12#\n\x1fPARTICIPANT_FLAG_ROOM_NOT_FOUND\x10@') ) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -100,8 +100,8 @@ _CONNECTIONERROR = _descriptor.EnumDescriptor( ], containing_type=None, options=None, - serialized_start=2102, - serialized_end=2793, + serialized_start=2164, + serialized_end=2855, ) _sym_db.RegisterEnumDescriptor(_CONNECTIONERROR) @@ -143,8 +143,8 @@ _STATUSTYPE = _descriptor.EnumDescriptor( ], containing_type=None, options=None, - serialized_start=2796, - serialized_end=2930, + serialized_start=2858, + serialized_end=2992, ) _sym_db.RegisterEnumDescriptor(_STATUSTYPE) @@ -190,8 +190,8 @@ _PARTICIPANTFLAG = _descriptor.EnumDescriptor( ], containing_type=None, options=None, - serialized_start=2933, - serialized_end=3197, + serialized_start=2995, + serialized_end=3259, ) _sym_db.RegisterEnumDescriptor(_PARTICIPANTFLAG) @@ -368,11 +368,15 @@ _WRAPPERMESSAGE_TYPE = _descriptor.EnumDescriptor( name='TYPE_RAW_XML', index=32, number=34, options=None, type=None), + _descriptor.EnumValueDescriptor( + name='TYPE_BUDDIES', index=33, number=35, + options=None, + type=None), ], containing_type=None, options=None, - serialized_start=1387, - serialized_end=2099, + serialized_start=1431, + serialized_end=2161, ) _sym_db.RegisterEnumDescriptor(_WRAPPERMESSAGE_TYPE) @@ -618,6 +622,36 @@ _BUDDY = _descriptor.Descriptor( ) +_BUDDIES = _descriptor.Descriptor( + name='Buddies', + full_name='pbnetwork.Buddies', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='buddy', full_name='pbnetwork.Buddies.buddy', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=418, + serialized_end=460, +) + + _CONVERSATIONMESSAGE = _descriptor.Descriptor( name='ConversationMessage', full_name='pbnetwork.ConversationMessage', @@ -699,8 +733,8 @@ _CONVERSATIONMESSAGE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=419, - serialized_end=588, + serialized_start=463, + serialized_end=632, ) @@ -750,8 +784,8 @@ _ROOM = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=590, - serialized_end=664, + serialized_start=634, + serialized_end=708, ) @@ -787,8 +821,8 @@ _ROOMLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=666, - serialized_end=704, + serialized_start=710, + serialized_end=748, ) @@ -859,8 +893,8 @@ _PARTICIPANT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=707, - serialized_end=863, + serialized_start=751, + serialized_end=907, ) @@ -924,8 +958,8 @@ _VCARD = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=865, - serialized_end=972, + serialized_start=909, + serialized_end=1016, ) @@ -968,8 +1002,8 @@ _STATUS = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=974, - serialized_end=1062, + serialized_start=1018, + serialized_end=1106, ) @@ -1019,8 +1053,8 @@ _STATS = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1064, - serialized_end=1130, + serialized_start=1108, + serialized_end=1174, ) @@ -1077,8 +1111,8 @@ _FILE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1132, - serialized_end=1221, + serialized_start=1176, + serialized_end=1265, ) @@ -1114,8 +1148,8 @@ _FILETRANSFERDATA = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1223, - serialized_end=1269, + serialized_start=1267, + serialized_end=1313, ) @@ -1144,8 +1178,8 @@ _BACKENDCONFIG = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1271, - serialized_end=1302, + serialized_start=1315, + serialized_end=1346, ) @@ -1182,11 +1216,12 @@ _WRAPPERMESSAGE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1305, - serialized_end=2099, + serialized_start=1349, + serialized_end=2161, ) _BUDDY.fields_by_name['status'].enum_type = _STATUSTYPE +_BUDDIES.fields_by_name['buddy'].message_type = _BUDDY _PARTICIPANT.fields_by_name['status'].enum_type = _STATUSTYPE _STATUS.fields_by_name['status'].enum_type = _STATUSTYPE _WRAPPERMESSAGE.fields_by_name['type'].enum_type = _WRAPPERMESSAGE_TYPE @@ -1196,6 +1231,7 @@ DESCRIPTOR.message_types_by_name['Disconnected'] = _DISCONNECTED DESCRIPTOR.message_types_by_name['Login'] = _LOGIN DESCRIPTOR.message_types_by_name['Logout'] = _LOGOUT DESCRIPTOR.message_types_by_name['Buddy'] = _BUDDY +DESCRIPTOR.message_types_by_name['Buddies'] = _BUDDIES DESCRIPTOR.message_types_by_name['ConversationMessage'] = _CONVERSATIONMESSAGE DESCRIPTOR.message_types_by_name['Room'] = _ROOM DESCRIPTOR.message_types_by_name['RoomList'] = _ROOMLIST @@ -1246,6 +1282,13 @@ Buddy = _reflection.GeneratedProtocolMessageType('Buddy', (_message.Message,), d )) _sym_db.RegisterMessage(Buddy) +Buddies = _reflection.GeneratedProtocolMessageType('Buddies', (_message.Message,), dict( + DESCRIPTOR = _BUDDIES, + __module__ = 'protocol_pb2' + # @@protoc_insertion_point(class_scope:pbnetwork.Buddies) + )) +_sym_db.RegisterMessage(Buddies) + ConversationMessage = _reflection.GeneratedProtocolMessageType('ConversationMessage', (_message.Message,), dict( DESCRIPTOR = _CONVERSATIONMESSAGE, __module__ = 'protocol_pb2' diff --git a/buddy.py b/buddy.py index a393a2c..54d9f1f 100644 --- a/buddy.py +++ b/buddy.py @@ -25,34 +25,10 @@ __status__ = "Prototype" from Spectrum2 import protocol_pb2 import logging -import threading - - -class Number(): - - def __init__(self, number, state, db): - self.number = number - self.db = db - self.state = state - - cur = self.db.cursor() - cur.execute("SELECT id FROM numbers WHERE number = %s AND state = %s", (self.number, self.state)) - if (cur.rowcount): - self.id = cur.fetchone()[0] - else: - cur.execute("REPLACE numbers (number, state) VALUES (%s, %s)", (self.number, self.state)) - self.db.commit() - self.id = cur.lastrowid - - def __str__(self): - return "%s (id=%s)" % (self.number, self.id) class Buddy(): - def __init__(self, owner, number, nick, groups, image_hash, id, db): - self.id = id - self.db = db - + def __init__(self, owner, number, nick, statusMsg, groups, image_hash): self.nick = nick self.owner = owner self.number = number @@ -69,121 +45,100 @@ class Buddy(): if image_hash is not None: self.image_hash = image_hash - groups = u",".join(groups).encode("latin-1") - cur = self.db.cursor() - cur.execute("UPDATE buddies SET nick = %s, groups = %s, image_hash = %s WHERE owner_id = %s AND buddy_id = %s", (self.nick, groups, self.image_hash, self.owner.id, self.number.id)) - self.db.commit() - - def delete(self): - cur = self.db.cursor() - cur.execute("DELETE FROM buddies WHERE owner_id = %s AND buddy_id = %s", (self.owner.id, self.number.id)) - self.db.commit() - self.id = None - - @staticmethod - def create(owner, number, nick, groups, image_hash, db): - groups = u",".join(groups).encode("latin-1") - cur = db.cursor() - cur.execute("REPLACE buddies (owner_id, buddy_id, nick, groups, image_hash) VALUES (%s, %s, %s, %s, %s)", (owner.id, number.id, nick, groups, image_hash)) - db.commit() - - return Buddy(owner, number, nick, groups, image_hash, cur.lastrowid, db) - def __str__(self): - return "%s (nick=%s, id=%s)" % (self.number, self.nick, self.id) + return "%s (nick=%s)" % (self.number, self.nick) class BuddyList(dict): - def __init__(self, owner, db): - self.db = db - self.owner = Number(owner, 1, db) - self.lock = threading.Lock() + def __init__(self, owner, backend, user, session): + self.owner = owner + self.backend = backend + self.session = session + self.user = user + self.logger = logging.getLogger(self.__class__.__name__) + self.synced = False + + def _load(self, buddies): + for buddy in buddies: + number = buddy.buddyName + nick = buddy.alias + statusMsg = buddy.statusMessage + groups = [g for g in buddy.group] + image_hash = buddy.iconHash + self[number] = Buddy(self.owner, number, nick, statusMsg, + groups, image_hash) + + self.logger.debug("Update roster") + +# old = self.buddies.keys() +# self.buddies.load() +# new = self.buddies.keys() +# contacts = new + contacts = self.keys() + + if self.synced == False: + self.session.sendSync(contacts, delta = False, interactive = True) + self.synced = True + +# 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(contacts))) + +# 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 contacts: + buddy = self[number] + if number != 'bot': + 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.session.subscribePresence(number) - def load(self): - self.clear() - self.lock.acquire() - - cur = self.db.cursor() - cur.execute("""SELECT - b.id AS id, - n.number AS number, - b.nick AS nick, - b.groups AS groups, - n.state AS state, - b.image_hash AS image_hash - FROM buddies AS b - LEFT JOIN numbers AS n - ON b.buddy_id = n.id - WHERE - b.owner_id IN (%s, 0) - AND n.state >= 1 - ORDER BY b.owner_id DESC""", self.owner.id) - - for i in range(cur.rowcount): - id, number, nick, groups, state, image_hash = cur.fetchone() - self[number] = Buddy(self.owner, Number(number, state, self.db), nick.decode('latin1'), groups.split(","), image_hash, id, self.db) - self.lock.release() - + def load(self, buddies): + if self.session.loggedIn: + self._load(buddies) + else: + self.session.loginQueue.append(lambda: self._load(buddies)) def update(self, number, nick, groups, image_hash): - self.lock.acquire() if number in self: buddy = self[number] buddy.update(nick, groups, image_hash) else: - buddy = self.add(number, nick, groups, 1, image_hash) - self.lock.release() + self.session.sendSync([number], delta = True, interactive = True) + self.session.subscribePresence(number) + buddy = Buddy(self.owner, number, nick, "", groups, image_hash) + self[number] = buddy + self.logger.debug("Roster add: %s", buddy) + + if buddy.presence == 0: + status = protocol_pb2.STATUS_NONE + elif buddy.presence == 'unavailable': + status = protocol_pb2.STATUS_AWAY + else: + status = protocol_pb2.STATUS_ONLINE + self.backend.handleBuddyChanged(self.user, number, buddy.nick, + buddy.groups, status, + iconHash = buddy.image_hash if buddy.image_hash is not None else "") return buddy - def add(self, number, nick, groups = [], state = 0, image_hash = ""): - return Buddy.create(self.owner, Number(number, state, self.db), nick, groups, image_hash, self.db) - def remove(self, number): try: buddy = self[number] - self.lock.acquire() - buddy.delete() - self.lock.release() + del self[number] + self.backend.handleBuddyChanged(self.user, number, "", [], + protocol_pb2.STATUS_NONE) + self.backend.handleBuddyRemoved(self.user, number) + self.session.unsubscribePresence(number) +# TODO Sync remove return buddy except KeyError: return None - - def prune(self): - self.lock.acquire() - - cur = self.db.cursor() - cur.execute("DELETE FROM buddies WHERE owner_id = %s", self.owner.id) - self.db.commit() - self.lock.release() - - - def sync(self, user, password): - self.lock.acquire() - cur = self.db.cursor() - cur.execute("""SELECT - n.number AS number, - n.state AS state - FROM buddies AS r - LEFT JOIN numbers AS n - ON r.buddy_id = n.id - WHERE - r.owner_id = %s""", self.owner.id) - - # prefix every number with leading 0 to force internation format - numbers = dict([("+" + number, state) for number, state in cur.fetchall()]) - - if len(numbers) == 0: - return 0 - - result = WAContactsSyncRequest(user, password, numbers.keys()).send() - - using = 0 - for number in result['c']: - cur = self.db.cursor() - cur.execute("UPDATE numbers SET state = %s WHERE number = %s", (number['w'], number['n'])) - self.db.commit() - using += number['w'] - self.lock.release() - return using diff --git a/conf/schema.sql b/conf/schema.sql deleted file mode 100644 index f6fb0e7..0000000 --- a/conf/schema.sql +++ /dev/null @@ -1,31 +0,0 @@ -SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; -SET time_zone = "+00:00"; - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; - - -CREATE TABLE IF NOT EXISTS `buddies` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `owner_id` int(11) NOT NULL, - `buddy_id` int(11) NOT NULL, - `nick` varchar(255) NOT NULL, - `groups` varchar(255) NOT NULL, - `image_hash` varchar(40), - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - -CREATE TABLE IF NOT EXISTS `numbers` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `number` varchar(32) NOT NULL, - `picture` blob NOT NULL, - `state` int(11) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `number` (`number`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/constants.py.sample b/constants.py.sample index 958c2e9..9aa7f0e 100644 --- a/constants.py.sample +++ b/constants.py.sample @@ -22,13 +22,8 @@ __status__ = "Prototype" along with transWhat. If not, see . """ -DB_HOST = "localhost" -DB_USER = "" -DB_PASS = "" -DB_TABLE = "transwhat" - BASE_PATH = "/opt/transwhat" TOKEN_FILE = BASE_PATH + "/logs/tokens" MOTD_FILE = BASE_PATH + "/conf/motd" -REQUESTS_FILE = BASE_PATH + "/logs/requests" \ No newline at end of file +REQUESTS_FILE = BASE_PATH + "/logs/requests" diff --git a/session.py b/session.py index 9060673..ac87258 100644 --- a/session.py +++ b/session.py @@ -28,7 +28,6 @@ import urllib import time from PIL import Image -import MySQLdb import sys import os @@ -57,14 +56,11 @@ class MsgIDs: class Session(YowsupApp): - def __init__(self, backend, user, legacyName, extra, db): + 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.db = db - self.db = MySQLdb.connect(DB_HOST, DB_USER, DB_PASS, DB_TABLE) - self.backend = backend self.user = user self.legacyName = legacyName @@ -74,12 +70,14 @@ class Session(YowsupApp): 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.shouldBeConnected = False + self.loggedIn = False self.timer = None self.password = None @@ -87,7 +85,7 @@ class Session(YowsupApp): self.lastMsgId = None self.synced = False - self.buddies = BuddyList(self.legacyName, self.db) + self.buddies = BuddyList(self.legacyName, self.backend, self.user, self) self.bot = Bot(self) self.imgMsgId = None @@ -102,6 +100,7 @@ class Session(YowsupApp): 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) @@ -132,39 +131,6 @@ class Session(YowsupApp): '\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") - - old = self.buddies.keys() - self.buddies.load() - new = self.buddies.keys() - contacts = new - - if self.synced == False: - self.sendSync(contacts, delta = False, interactive = True) - self.synced = True - - 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) - def _updateGroups(self, response, request): self.logger.debug('Received groups list %s', response) groups = response.getGroups() @@ -278,17 +244,19 @@ class Session(YowsupApp): #self.bot.call("welcome") self.initialized = True self.sendPresence(True) - self.updateRoster() + 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.shouldBeConnected = False + self.loggedIn = False # Called by superclass def onDisconnect(self): @@ -305,7 +273,7 @@ class Session(YowsupApp): 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.number, self.msgIDs[_id].xmppId) + 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] @@ -523,8 +491,8 @@ class Session(YowsupApp): if (lastseen == str(buddy.lastseen)) and (_type == buddy.presence): return - - if ((lastseen != "deny") and (lastseen != None) and (lastseen != "none")): + + if ((lastseen != "deny") and (lastseen != None) and (lastseen != "none")): buddy.lastseen = int(lastseen) if (_type == None): buddy.lastseen = time.time() @@ -533,22 +501,22 @@ class Session(YowsupApp): timestamp = time.localtime(buddy.lastseen) statusmsg = buddy.statusMsg + time.strftime("\n Last seen: %a, %d %b %Y %H:%M:%S", timestamp) - + if _type == "unavailable": self.onPresenceUnavailable(buddy, statusmsg) else: self.onPresenceAvailable(buddy, statusmsg) - - def onPresenceAvailable(self, buddy, statusmsg): + + def onPresenceAvailable(self, buddy, statusmsg): self.logger.info("Is available: %s", buddy) - self.backend.handleBuddyChanged(self.user, buddy.number.number, + self.backend.handleBuddyChanged(self.user, buddy.number, buddy.nick, buddy.groups, protocol_pb2.STATUS_ONLINE, statusmsg, buddy.image_hash) def onPresenceUnavailable(self, buddy, statusmsg): self.logger.info("Is unavailable: %s", buddy) - self.backend.handleBuddyChanged(self.user, buddy.number.number, + self.backend.handleBuddyChanged(self.user, buddy.number, buddy.nick, buddy.groups, protocol_pb2.STATUS_AWAY, statusmsg, buddy.image_hash) # spectrum RequestMethods @@ -789,19 +757,19 @@ class Session(YowsupApp): 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) - if self.initialized == True: - self.updateRoster() def removeBuddy(self, buddy): if buddy != "bot": self.logger.info("Buddy removed: %s", buddy) self.buddies.remove(buddy) - self.updateRoster() - def requestVCard(self, buddy, ID=None): def onSuccess(response, request): @@ -828,7 +796,7 @@ class Session(YowsupApp): 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" diff --git a/transwhat.py b/transwhat.py index 5875dc4..23fe84a 100755 --- a/transwhat.py +++ b/transwhat.py @@ -29,7 +29,6 @@ import traceback import logging import asyncore import sys, os -import MySQLdb import e4u import threading import Queue @@ -75,10 +74,11 @@ def connectionClosed(): closed = True # Main -db = MySQLdb.connect(DB_HOST, DB_USER, DB_PASS, DB_TABLE) io = IOChannel(args.host, args.port, handleTransportData, connectionClosed) -plugin = WhatsAppBackend(io, db, args.j) +plugin = WhatsAppBackend(io, args.j) + +plugin.handleBackendConfig('features', 'send_buddies_on_login', 1) while True: try: diff --git a/whatsappbackend.py b/whatsappbackend.py index 06fbe9b..6c0d9aa 100644 --- a/whatsappbackend.py +++ b/whatsappbackend.py @@ -30,11 +30,10 @@ from session import Session import logging class WhatsAppBackend(SpectrumBackend): - def __init__(self, io, db, spectrum_jid): + def __init__(self, io, 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 @@ -46,7 +45,7 @@ class WhatsAppBackend(SpectrumBackend): def handleLoginRequest(self, user, legacyName, password, extra): self.logger.debug("handleLoginRequest(user=%s, legacyName=%s)", user, legacyName) if user not in self.sessions: - self.sessions[user] = Session(self, user, legacyName, extra, self.db) + self.sessions[user] = Session(self, user, legacyName, extra) if user not in self.lastMessage: self.lastMessage[user] = {} @@ -87,6 +86,13 @@ class WhatsAppBackend(SpectrumBackend): self.sessions[user].changeStatusMessage(statusMessage) self.sessions[user].changeStatus(status) + def handleBuddies(self, buddies): + """Called when user logs in. Used to initialize roster.""" + self.logger.debug("handleBuddies(buddies=%s)", buddies) + buddies = [b for b in buddies.buddy] + user = buddies[0].userName + self.sessions[user].loadBuddies(buddies) + def handleBuddyUpdatedRequest(self, user, buddy, nick, groups): self.logger.debug("handleBuddyUpdatedRequest(user=%s, buddy=%s, nick=%s, groups=%s)", user, buddy, nick, str(groups)) self.sessions[user].updateBuddy(buddy, nick, groups) @@ -139,7 +145,7 @@ class WhatsAppBackend(SpectrumBackend): pass def handleMessageAckRequest(self, user, legacyName, ID = 0): - self.logger.info("Meassage ACK request for %s !!",leagcyName) + self.logger.info("Meassage ACK request for %s !!",legacyName) def sendData(self, data): self.io.sendData(data) diff --git a/yowsupwrapper.py b/yowsupwrapper.py index ef1928b..d7c3a79 100644 --- a/yowsupwrapper.py +++ b/yowsupwrapper.py @@ -216,6 +216,7 @@ class YowsupApp(object): - phone_number: (str) The cellphone number of the person to subscribe to """ + self.logger.debug("Subscribing to Presence updates from %s", (phone_number)) jid = phone_number + '@s.whatsapp.net' entity = SubscribePresenceProtocolEntity(jid) self.sendEntity(entity)