diff --git a/Spectrum2/backend.py b/Spectrum2/backend.py index a59567a..92cd03d 100644 --- a/Spectrum2/backend.py +++ b/Spectrum2/backend.py @@ -4,11 +4,10 @@ import struct import sys import os import logging - import google.protobuf def WRAP(MESSAGE, TYPE): - wrap = protocol_pb2.WrapperMessage() + wrap = protocol_pb2.WrapperMessage() wrap.type = TYPE wrap.payload = MESSAGE return wrap.SerializeToString() @@ -20,7 +19,6 @@ class SpectrumBackend: @param host: Host where Spectrum2 NetworkPluginServer runs. @param port: Port. """ - def __init__(self): self.m_pingReceived = False self.m_data = "" @@ -39,6 +37,17 @@ class SpectrumBackend: message = WRAP(m.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_CONV_MESSAGE) self.send(message) + def handleMessageAck(self, user, legacyName, ID): + m = protocol_pb2.ConversationMessage() + m.userName = user + m.buddyName = legacyName + m.message = "" + m.id = ID + + message = WRAP(m.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_CONV_MESSAGE_ACK) + self.send(message) + + def handleAttention(self, user, buddyName, msg): m = protocol_pb2.ConversationMessage() m.userName = user @@ -206,7 +215,7 @@ class SpectrumBackend: def handleFTData(self, ftID, data): d = protocol_pb2.FileTransferData() - d.ftID = ftID + d.ftid = ftID d.data = data message = WRAP(d.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_FT_DATA); @@ -242,10 +251,20 @@ class SpectrumBackend: def handleConvMessagePayload(self, data): payload = protocol_pb2.ConversationMessage() + self.logger.error("handleConvMessagePayload") if (payload.ParseFromString(data) == False): #TODO: ERROR return - self.handleMessageSendRequest(payload.userName, payload.buddyName, payload.message, payload.xhtml) + self.handleMessageSendRequest(payload.userName, payload.buddyName, payload.message, payload.xhtml, payload.id) + + def handleConvMessageAckPayload(self, data): + payload = protocol_pb2.ConversationMessage() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + self.handleMessageAckRequest(payload.userName, payload.buddyName, payload.id) + + def handleAttentionPayload(self, data): payload = protocol_pb2.ConversationMessage() @@ -345,8 +364,10 @@ class SpectrumBackend: if (len(self.m_data) >= 4): expected_size = struct.unpack('!I', self.m_data[0:4])[0] if (len(self.m_data) - 4 < expected_size): + self.logger.debug("Data packet incomplete") return else: + self.logger.debug("Data packet incomplete") return packet = self.m_data[4:4+expected_size] @@ -355,12 +376,12 @@ class SpectrumBackend: parseFromString = wrapper.ParseFromString(packet) except: self.m_data = self.m_data[expected_size+4:] - self.logger.error("Parse from String exception") + self.logger.error("Parse from String exception. Skipping packet.") return if parseFromString == False: self.m_data = self.m_data[expected_size+4:] - self.logger.error("Parse from String failed") + self.logger.error("Parse from String failed. Skipping packet.") return self.m_data = self.m_data[4+expected_size:] @@ -403,6 +424,8 @@ class SpectrumBackend: self.handleFTContinuePayload(wrapper.payload) elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_EXIT: self.handleExitRequest() + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_CONV_MESSAGE_ACK: + self.handleConvMessageAckPayload(wrapper.payload) elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_RAW_XML: self.handleRawXmlRequest(wrapper.payload) @@ -475,17 +498,30 @@ class SpectrumBackend: raise NotImplementedError, "Implement me" - def handleMessageSendRequest(self, user, legacyName, message, xhtml = ""): + def handleMessageSendRequest(self, user, legacyName, message, xhtml = "", ID = 0): """ Called when XMPP user sends message to legacy network. @param user: XMPP JID of user for which this event occurs. @param legacyName: Legacy network name of buddy or room. @param message: Plain text message. @param xhtml: XHTML message. + @param ID: message ID """ raise NotImplementedError, "Implement me" + def handleMessageAckRequest(self, user, legacyName, ID = 0): + """ + Called when XMPP user sends message to legacy network. + @param user: XMPP JID of user for which this event occurs. + @param legacyName: Legacy network name of buddy or room. + @param ID: message ID + """ + + # raise NotImplementedError, "Implement me" + pass + + def handleVCardRequest(self, user, legacyName, ID): """ Called when XMPP user requests VCard of buddy. @param user: XMPP JID of user for which this event occurs. diff --git a/Spectrum2/protocol_pb2.py b/Spectrum2/protocol_pb2.py index e01bd27..638435c 100644 --- a/Spectrum2/protocol_pb2.py +++ b/Spectrum2/protocol_pb2.py @@ -1,88 +1,99 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! +# source: protocol.proto -from google.protobuf import descriptor -from google.protobuf import message -from google.protobuf import reflection +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) +_sym_db = _symbol_database.Default() -DESCRIPTOR = descriptor.FileDescriptor( + + + +DESCRIPTOR = _descriptor.FileDescriptor( name='protocol.proto', package='pbnetwork', - serialized_pb='\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\"\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@') +) +_sym_db.RegisterFileDescriptor(DESCRIPTOR) -_CONNECTIONERROR = descriptor.EnumDescriptor( +_CONNECTIONERROR = _descriptor.EnumDescriptor( name='ConnectionError', full_name='pbnetwork.ConnectionError', filename=None, file=DESCRIPTOR, values=[ - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_NETWORK_ERROR', index=0, number=0, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_INVALID_USERNAME', index=1, number=1, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_AUTHENTICATION_FAILED', index=2, number=2, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE', index=3, number=3, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_NO_SSL_SUPPORT', index=4, number=4, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_ENCRYPTION_ERROR', index=5, number=5, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_NAME_IN_USE', index=6, number=6, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_INVALID_SETTINGS', index=7, number=7, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_CERT_NOT_PROVIDED', index=8, number=8, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_CERT_UNTRUSTED', index=9, number=9, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_CERT_EXPIRED', index=10, number=10, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_CERT_NOT_ACTIVATED', index=11, number=11, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH', index=12, number=12, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH', index=13, number=13, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_CERT_SELF_SIGNED', index=14, number=14, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_CERT_OTHER_ERROR', index=15, number=15, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CONNECTION_ERROR_OTHER_ERROR', index=16, number=16, options=None, type=None), @@ -92,39 +103,40 @@ _CONNECTIONERROR = descriptor.EnumDescriptor( serialized_start=2102, serialized_end=2793, ) +_sym_db.RegisterEnumDescriptor(_CONNECTIONERROR) - -_STATUSTYPE = descriptor.EnumDescriptor( +ConnectionError = enum_type_wrapper.EnumTypeWrapper(_CONNECTIONERROR) +_STATUSTYPE = _descriptor.EnumDescriptor( name='StatusType', full_name='pbnetwork.StatusType', filename=None, file=DESCRIPTOR, values=[ - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='STATUS_ONLINE', index=0, number=0, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='STATUS_AWAY', index=1, number=1, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='STATUS_FFC', index=2, number=2, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='STATUS_XA', index=3, number=3, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='STATUS_DND', index=4, number=4, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='STATUS_NONE', index=5, number=5, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='STATUS_INVISIBLE', index=6, number=6, options=None, type=None), @@ -134,43 +146,44 @@ _STATUSTYPE = descriptor.EnumDescriptor( serialized_start=2796, serialized_end=2930, ) +_sym_db.RegisterEnumDescriptor(_STATUSTYPE) - -_PARTICIPANTFLAG = descriptor.EnumDescriptor( +StatusType = enum_type_wrapper.EnumTypeWrapper(_STATUSTYPE) +_PARTICIPANTFLAG = _descriptor.EnumDescriptor( name='ParticipantFlag', full_name='pbnetwork.ParticipantFlag', filename=None, file=DESCRIPTOR, values=[ - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='PARTICIPANT_FLAG_NONE', index=0, number=0, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='PARTICIPANT_FLAG_MODERATOR', index=1, number=1, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='PARTICIPANT_FLAG_CONFLICT', index=2, number=2, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='PARTICIPANT_FLAG_BANNED', index=3, number=4, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='PARTICIPANT_FLAG_NOT_AUTHORIZED', index=4, number=8, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='PARTICIPANT_FLAG_ME', index=5, number=16, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='PARTICIPANT_FLAG_KICKED', index=6, number=32, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='PARTICIPANT_FLAG_ROOM_NOT_FOUND', index=7, number=64, options=None, type=None), @@ -180,8 +193,9 @@ _PARTICIPANTFLAG = descriptor.EnumDescriptor( serialized_start=2933, serialized_end=3197, ) +_sym_db.RegisterEnumDescriptor(_PARTICIPANTFLAG) - +ParticipantFlag = enum_type_wrapper.EnumTypeWrapper(_PARTICIPANTFLAG) CONNECTION_ERROR_NETWORK_ERROR = 0 CONNECTION_ERROR_INVALID_USERNAME = 1 CONNECTION_ERROR_AUTHENTICATION_FAILED = 2 @@ -216,141 +230,141 @@ PARTICIPANT_FLAG_KICKED = 32 PARTICIPANT_FLAG_ROOM_NOT_FOUND = 64 -_WRAPPERMESSAGE_TYPE = descriptor.EnumDescriptor( +_WRAPPERMESSAGE_TYPE = _descriptor.EnumDescriptor( name='Type', full_name='pbnetwork.WrapperMessage.Type', filename=None, file=DESCRIPTOR, values=[ - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_CONNECTED', index=0, number=1, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_DISCONNECTED', index=1, number=2, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_LOGIN', index=2, number=3, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_LOGOUT', index=3, number=4, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_BUDDY_CHANGED', index=4, number=6, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_BUDDY_REMOVED', index=5, number=7, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_CONV_MESSAGE', index=6, number=8, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_PING', index=7, number=9, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_PONG', index=8, number=10, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_JOIN_ROOM', index=9, number=11, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_LEAVE_ROOM', index=10, number=12, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_PARTICIPANT_CHANGED', index=11, number=13, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_ROOM_NICKNAME_CHANGED', index=12, number=14, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_ROOM_SUBJECT_CHANGED', index=13, number=15, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_VCARD', index=14, number=16, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_STATUS_CHANGED', index=15, number=17, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_BUDDY_TYPING', index=16, number=18, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_BUDDY_STOPPED_TYPING', index=17, number=19, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_BUDDY_TYPED', index=18, number=20, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_AUTH_REQUEST', index=19, number=21, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_ATTENTION', index=20, number=22, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_STATS', index=21, number=23, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_FT_START', index=22, number=24, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_FT_FINISH', index=23, number=25, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_FT_DATA', index=24, number=26, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_FT_PAUSE', index=25, number=27, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_FT_CONTINUE', index=26, number=28, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_EXIT', index=27, number=29, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_BACKEND_CONFIG', index=28, number=30, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_QUERY', index=29, number=31, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_ROOM_LIST', index=30, number=32, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_CONV_MESSAGE_ACK', index=31, number=33, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='TYPE_RAW_XML', index=32, number=34, options=None, type=None), @@ -360,19 +374,20 @@ _WRAPPERMESSAGE_TYPE = descriptor.EnumDescriptor( serialized_start=1387, serialized_end=2099, ) +_sym_db.RegisterEnumDescriptor(_WRAPPERMESSAGE_TYPE) -_CONNECTED = descriptor.Descriptor( +_CONNECTED = _descriptor.Descriptor( name='Connected', full_name='pbnetwork.Connected', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='user', full_name='pbnetwork.Connected.user', index=0, number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -385,36 +400,38 @@ _CONNECTED = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=29, serialized_end=54, ) -_DISCONNECTED = descriptor.Descriptor( +_DISCONNECTED = _descriptor.Descriptor( name='Disconnected', full_name='pbnetwork.Disconnected', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='user', full_name='pbnetwork.Disconnected.user', index=0, number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='error', full_name='pbnetwork.Disconnected.error', index=1, number=2, type=5, cpp_type=1, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='message', full_name='pbnetwork.Disconnected.message', index=2, number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -427,40 +444,42 @@ _DISCONNECTED = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=56, serialized_end=116, ) -_LOGIN = descriptor.Descriptor( +_LOGIN = _descriptor.Descriptor( name='Login', full_name='pbnetwork.Login', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='user', full_name='pbnetwork.Login.user', index=0, number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='legacyName', full_name='pbnetwork.Login.legacyName', index=1, number=2, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='password', full_name='pbnetwork.Login.password', index=2, number=3, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='extraFields', full_name='pbnetwork.Login.extraFields', index=3, number=4, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], @@ -476,29 +495,31 @@ _LOGIN = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=118, serialized_end=198, ) -_LOGOUT = descriptor.Descriptor( +_LOGOUT = _descriptor.Descriptor( name='Logout', full_name='pbnetwork.Logout', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='user', full_name='pbnetwork.Logout.user', index=0, number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='legacyName', full_name='pbnetwork.Logout.legacyName', index=1, number=2, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -511,68 +532,70 @@ _LOGOUT = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=200, serialized_end=242, ) -_BUDDY = descriptor.Descriptor( +_BUDDY = _descriptor.Descriptor( name='Buddy', full_name='pbnetwork.Buddy', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='userName', full_name='pbnetwork.Buddy.userName', index=0, number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='buddyName', full_name='pbnetwork.Buddy.buddyName', index=1, number=2, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='alias', full_name='pbnetwork.Buddy.alias', index=2, number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='group', full_name='pbnetwork.Buddy.group', index=3, number=4, type=9, cpp_type=9, 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), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='status', full_name='pbnetwork.Buddy.status', index=4, number=5, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='statusMessage', full_name='pbnetwork.Buddy.statusMessage', index=5, number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='iconHash', full_name='pbnetwork.Buddy.iconHash', index=6, number=7, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='blocked', full_name='pbnetwork.Buddy.blocked', index=7, number=8, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, @@ -588,75 +611,77 @@ _BUDDY = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=245, serialized_end=416, ) -_CONVERSATIONMESSAGE = descriptor.Descriptor( +_CONVERSATIONMESSAGE = _descriptor.Descriptor( name='ConversationMessage', full_name='pbnetwork.ConversationMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='userName', full_name='pbnetwork.ConversationMessage.userName', index=0, number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='buddyName', full_name='pbnetwork.ConversationMessage.buddyName', index=1, number=2, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='message', full_name='pbnetwork.ConversationMessage.message', index=2, number=3, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='nickname', full_name='pbnetwork.ConversationMessage.nickname', index=3, number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='xhtml', full_name='pbnetwork.ConversationMessage.xhtml', index=4, number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='timestamp', full_name='pbnetwork.ConversationMessage.timestamp', index=5, number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='headline', full_name='pbnetwork.ConversationMessage.headline', index=6, number=7, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='id', full_name='pbnetwork.ConversationMessage.id', index=7, number=8, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='pm', full_name='pbnetwork.ConversationMessage.pm', index=8, number=9, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, @@ -672,43 +697,45 @@ _CONVERSATIONMESSAGE = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=419, serialized_end=588, ) -_ROOM = descriptor.Descriptor( +_ROOM = _descriptor.Descriptor( name='Room', full_name='pbnetwork.Room', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='userName', full_name='pbnetwork.Room.userName', index=0, number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='nickname', full_name='pbnetwork.Room.nickname', index=1, number=2, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='room', full_name='pbnetwork.Room.room', index=2, number=3, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='password', full_name='pbnetwork.Room.password', index=3, number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -721,26 +748,28 @@ _ROOM = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=590, serialized_end=664, ) -_ROOMLIST = descriptor.Descriptor( +_ROOMLIST = _descriptor.Descriptor( name='RoomList', full_name='pbnetwork.RoomList', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='room', full_name='pbnetwork.RoomList.room', index=0, number=1, type=9, cpp_type=9, 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), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='name', full_name='pbnetwork.RoomList.name', index=1, number=2, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], @@ -756,64 +785,66 @@ _ROOMLIST = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=666, serialized_end=704, ) -_PARTICIPANT = descriptor.Descriptor( +_PARTICIPANT = _descriptor.Descriptor( name='Participant', full_name='pbnetwork.Participant', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='userName', full_name='pbnetwork.Participant.userName', index=0, number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='room', full_name='pbnetwork.Participant.room', index=1, number=2, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='nickname', full_name='pbnetwork.Participant.nickname', index=2, number=3, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='flag', full_name='pbnetwork.Participant.flag', index=3, number=4, type=5, cpp_type=1, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='status', full_name='pbnetwork.Participant.status', index=4, number=5, type=14, cpp_type=8, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='statusMessage', full_name='pbnetwork.Participant.statusMessage', index=5, number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='newname', full_name='pbnetwork.Participant.newname', index=6, number=7, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -826,57 +857,59 @@ _PARTICIPANT = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=707, serialized_end=863, ) -_VCARD = descriptor.Descriptor( +_VCARD = _descriptor.Descriptor( name='VCard', full_name='pbnetwork.VCard', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='userName', full_name='pbnetwork.VCard.userName', index=0, number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='buddyName', full_name='pbnetwork.VCard.buddyName', index=1, number=2, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='id', full_name='pbnetwork.VCard.id', index=2, number=3, type=5, cpp_type=1, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='fullname', full_name='pbnetwork.VCard.fullname', index=3, number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='nickname', full_name='pbnetwork.VCard.nickname', index=4, number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='photo', full_name='pbnetwork.VCard.photo', index=5, number=6, type=12, cpp_type=9, label=1, - has_default_value=False, default_value="", + has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -889,36 +922,38 @@ _VCARD = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=865, serialized_end=972, ) -_STATUS = descriptor.Descriptor( +_STATUS = _descriptor.Descriptor( name='Status', full_name='pbnetwork.Status', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='userName', full_name='pbnetwork.Status.userName', index=0, number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='status', full_name='pbnetwork.Status.status', index=1, number=3, type=14, cpp_type=8, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='statusMessage', full_name='pbnetwork.Status.statusMessage', index=2, number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -931,43 +966,45 @@ _STATUS = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=974, serialized_end=1062, ) -_STATS = descriptor.Descriptor( +_STATS = _descriptor.Descriptor( name='Stats', full_name='pbnetwork.Stats', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='res', full_name='pbnetwork.Stats.res', index=0, number=1, type=5, cpp_type=1, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='init_res', full_name='pbnetwork.Stats.init_res', index=1, number=2, type=5, cpp_type=1, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='shared', full_name='pbnetwork.Stats.shared', index=2, number=3, type=5, cpp_type=1, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='id', full_name='pbnetwork.Stats.id', index=3, number=4, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -980,47 +1017,49 @@ _STATS = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=1064, serialized_end=1130, ) -_FILE = descriptor.Descriptor( +_FILE = _descriptor.Descriptor( name='File', full_name='pbnetwork.File', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='userName', full_name='pbnetwork.File.userName', index=0, number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='buddyName', full_name='pbnetwork.File.buddyName', index=1, number=2, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='fileName', full_name='pbnetwork.File.fileName', index=2, number=3, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='size', full_name='pbnetwork.File.size', index=3, number=4, type=5, cpp_type=1, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='ftID', full_name='pbnetwork.File.ftID', index=4, number=5, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, @@ -1036,29 +1075,31 @@ _FILE = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=1132, serialized_end=1221, ) -_FILETRANSFERDATA = descriptor.Descriptor( +_FILETRANSFERDATA = _descriptor.Descriptor( name='FileTransferData', full_name='pbnetwork.FileTransferData', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='ftID', full_name='pbnetwork.FileTransferData.ftID', index=0, number=1, type=5, cpp_type=1, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='data', full_name='pbnetwork.FileTransferData.data', index=1, number=2, type=12, cpp_type=9, label=2, - has_default_value=False, default_value="", + has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -1071,22 +1112,24 @@ _FILETRANSFERDATA = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=1223, serialized_end=1269, ) -_BACKENDCONFIG = descriptor.Descriptor( +_BACKENDCONFIG = _descriptor.Descriptor( name='BackendConfig', full_name='pbnetwork.BackendConfig', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='config', full_name='pbnetwork.BackendConfig.config', index=0, number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -1099,29 +1142,31 @@ _BACKENDCONFIG = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=1271, serialized_end=1302, ) -_WRAPPERMESSAGE = descriptor.Descriptor( +_WRAPPERMESSAGE = _descriptor.Descriptor( name='WrapperMessage', full_name='pbnetwork.WrapperMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='type', full_name='pbnetwork.WrapperMessage.type', index=0, number=1, type=14, cpp_type=8, label=2, has_default_value=False, default_value=1, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='payload', full_name='pbnetwork.WrapperMessage.payload', index=1, number=2, type=12, cpp_type=9, label=1, - has_default_value=False, default_value="", + has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -1135,111 +1180,148 @@ _WRAPPERMESSAGE = descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], + oneofs=[ + ], serialized_start=1305, serialized_end=2099, ) - _BUDDY.fields_by_name['status'].enum_type = _STATUSTYPE _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 -_WRAPPERMESSAGE_TYPE.containing_type = _WRAPPERMESSAGE; +_WRAPPERMESSAGE_TYPE.containing_type = _WRAPPERMESSAGE +DESCRIPTOR.message_types_by_name['Connected'] = _CONNECTED +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['ConversationMessage'] = _CONVERSATIONMESSAGE +DESCRIPTOR.message_types_by_name['Room'] = _ROOM +DESCRIPTOR.message_types_by_name['RoomList'] = _ROOMLIST +DESCRIPTOR.message_types_by_name['Participant'] = _PARTICIPANT +DESCRIPTOR.message_types_by_name['VCard'] = _VCARD +DESCRIPTOR.message_types_by_name['Status'] = _STATUS +DESCRIPTOR.message_types_by_name['Stats'] = _STATS +DESCRIPTOR.message_types_by_name['File'] = _FILE +DESCRIPTOR.message_types_by_name['FileTransferData'] = _FILETRANSFERDATA +DESCRIPTOR.message_types_by_name['BackendConfig'] = _BACKENDCONFIG +DESCRIPTOR.message_types_by_name['WrapperMessage'] = _WRAPPERMESSAGE +DESCRIPTOR.enum_types_by_name['ConnectionError'] = _CONNECTIONERROR +DESCRIPTOR.enum_types_by_name['StatusType'] = _STATUSTYPE +DESCRIPTOR.enum_types_by_name['ParticipantFlag'] = _PARTICIPANTFLAG -class Connected(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _CONNECTED - +Connected = _reflection.GeneratedProtocolMessageType('Connected', (_message.Message,), dict( + DESCRIPTOR = _CONNECTED, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.Connected) + )) +_sym_db.RegisterMessage(Connected) -class Disconnected(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _DISCONNECTED - +Disconnected = _reflection.GeneratedProtocolMessageType('Disconnected', (_message.Message,), dict( + DESCRIPTOR = _DISCONNECTED, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.Disconnected) + )) +_sym_db.RegisterMessage(Disconnected) -class Login(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _LOGIN - +Login = _reflection.GeneratedProtocolMessageType('Login', (_message.Message,), dict( + DESCRIPTOR = _LOGIN, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.Login) + )) +_sym_db.RegisterMessage(Login) -class Logout(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _LOGOUT - +Logout = _reflection.GeneratedProtocolMessageType('Logout', (_message.Message,), dict( + DESCRIPTOR = _LOGOUT, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.Logout) + )) +_sym_db.RegisterMessage(Logout) -class Buddy(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _BUDDY - +Buddy = _reflection.GeneratedProtocolMessageType('Buddy', (_message.Message,), dict( + DESCRIPTOR = _BUDDY, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.Buddy) + )) +_sym_db.RegisterMessage(Buddy) -class ConversationMessage(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _CONVERSATIONMESSAGE - +ConversationMessage = _reflection.GeneratedProtocolMessageType('ConversationMessage', (_message.Message,), dict( + DESCRIPTOR = _CONVERSATIONMESSAGE, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.ConversationMessage) + )) +_sym_db.RegisterMessage(ConversationMessage) -class Room(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _ROOM - +Room = _reflection.GeneratedProtocolMessageType('Room', (_message.Message,), dict( + DESCRIPTOR = _ROOM, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.Room) + )) +_sym_db.RegisterMessage(Room) -class RoomList(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _ROOMLIST - +RoomList = _reflection.GeneratedProtocolMessageType('RoomList', (_message.Message,), dict( + DESCRIPTOR = _ROOMLIST, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.RoomList) + )) +_sym_db.RegisterMessage(RoomList) -class Participant(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _PARTICIPANT - +Participant = _reflection.GeneratedProtocolMessageType('Participant', (_message.Message,), dict( + DESCRIPTOR = _PARTICIPANT, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.Participant) + )) +_sym_db.RegisterMessage(Participant) -class VCard(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _VCARD - +VCard = _reflection.GeneratedProtocolMessageType('VCard', (_message.Message,), dict( + DESCRIPTOR = _VCARD, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.VCard) + )) +_sym_db.RegisterMessage(VCard) -class Status(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _STATUS - +Status = _reflection.GeneratedProtocolMessageType('Status', (_message.Message,), dict( + DESCRIPTOR = _STATUS, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.Status) + )) +_sym_db.RegisterMessage(Status) -class Stats(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _STATS - +Stats = _reflection.GeneratedProtocolMessageType('Stats', (_message.Message,), dict( + DESCRIPTOR = _STATS, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.Stats) + )) +_sym_db.RegisterMessage(Stats) -class File(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _FILE - +File = _reflection.GeneratedProtocolMessageType('File', (_message.Message,), dict( + DESCRIPTOR = _FILE, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.File) + )) +_sym_db.RegisterMessage(File) -class FileTransferData(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _FILETRANSFERDATA - +FileTransferData = _reflection.GeneratedProtocolMessageType('FileTransferData', (_message.Message,), dict( + DESCRIPTOR = _FILETRANSFERDATA, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.FileTransferData) + )) +_sym_db.RegisterMessage(FileTransferData) -class BackendConfig(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _BACKENDCONFIG - +BackendConfig = _reflection.GeneratedProtocolMessageType('BackendConfig', (_message.Message,), dict( + DESCRIPTOR = _BACKENDCONFIG, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.BackendConfig) + )) +_sym_db.RegisterMessage(BackendConfig) -class WrapperMessage(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType - DESCRIPTOR = _WRAPPERMESSAGE - +WrapperMessage = _reflection.GeneratedProtocolMessageType('WrapperMessage', (_message.Message,), dict( + DESCRIPTOR = _WRAPPERMESSAGE, + __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:pbnetwork.WrapperMessage) + )) +_sym_db.RegisterMessage(WrapperMessage) + # @@protoc_insertion_point(module_scope) diff --git a/bot.py b/bot.py index aa9bd35..f6a39ba 100644 --- a/bot.py +++ b/bot.py @@ -31,20 +31,26 @@ import os import utils from constants import * +#from googleclient import GoogleClient -from Yowsup.Contacts.contacts import WAContactsSyncRequest +#from Yowsup.Contacts.contacts import WAContactsSyncRequest class Bot(): def __init__(self, session, name = "Bot"): self.session = session self.name = name + #self.google = GoogleClient() + self.commands = { + "import": self._import, "help": self._help, "prune": self._prune, "welcome": self._welcome, "fortune": self._fortune, - "sync": self._sync + "sync": self._sync, + "groups": self._groups, + "getgroups": self._getgroups } def parse(self, message): @@ -66,7 +72,7 @@ class Bot(): spec = inspect.getargspec(func) maxs = len(spec.args) - 1 reqs = maxs - len(spec.defaults or []) - if reqs > len(args) > maxs: + if (reqs > len(args)) or (len(args) > maxs): raise TypeError() thread = threading.Thread(target=func, args=tuple(args)) @@ -75,6 +81,41 @@ class Bot(): def send(self, message): self.session.backend.handleMessage(self.session.user, self.name, message) + def __do_import(self, token): + # Google + google = self.google.getContacts(token) + self.send("%d buddies imported from google" % len(google)) + + result = { } + for number, name in google.iteritems(): + number = re.sub("[^0-9]", "", number) + number = number if number[0] == "0" else "+" + number + + result[number] = { 'nick': name, 'state': 0 } + + # WhatsApp + user = self.session.legacyName + password = self.session.password + sync = WAContactsSyncRequest(user, password, result.keys()) + whatsapp = sync.send()['c'] + + for w in whatsapp: + result[w['p']]['state'] = w['w'] + result[w['p']]['number'] = w['n'] + + self.send("%d buddies are using whatsapp" % len(filter(lambda w: w['w'], whatsapp))) + + for r in result.values(): + if r['nick']: + self.session.buddies.add( + number = r['number'], + nick = r['nick'], + groups = [u'Google'], + state = r['state'] + ) + + self.send("%d buddies imported" % len(whatsapp)) + def __get_token(self, filename, timeout = 30): file = open(filename, 'r') file.seek(-1, 2) # look at the end @@ -96,6 +137,25 @@ class Bot(): file.close() # commands + def _import(self, token = None): + if not token: + token_url = self.google.getTokenUrl("http://whatsapp.0l.de/auth.py") + auth_url = "http://whatsapp.0l.de/auth.py?number=%s&auth_url=%s" % (self.session.legacyName, urllib.quote(token_url)) + short_url = utils.shorten(auth_url) + self.send("please visit this url to auth: %s" % short_url) + + self.send("waiting for authorization...") + token = self.__get_token(TOKEN_FILE) + if token: + self.send("got token: %s" % token) + self.__do_import(token) + self.session.updateRoster() + else: + self.send("timeout! please use \"\\import [token]\"") + else: + self.__do_import(token) + self.session.updateRoster() + def _sync(self): user = self.session.legacyName password = self.session.password @@ -112,14 +172,23 @@ class Bot(): self.send("""following bot commands are available: \\help show this message \\prune clear your buddylist +\\import [token] import buddies from Google \\sync sync your imported contacts with WhatsApp \\fortune [database] give me a quote +\\groups print all attended groups +\\getgroups get current groups from WA following user commands are available: -\\lastseen request last online timestamp from buddy""") +\\lastseen request last online timestamp from buddy + +following group commands are available +\\leave permanently leave group chat""") def _fortune(self, database = '', prefix=''): - if os.path.exists("/usr/share/games/fortunes/%s" % database): + if os.path.exists("/usr/share/fortune/%s" % database): + fortune = os.popen('/usr/bin/fortune %s' % database).read() + self.send(prefix + fortune[:-1]) + elif os.path.exists("/usr/share/games/fortunes/%s" % database): fortune = os.popen('/usr/games/fortune %s' % database).read() self.send(prefix + fortune[:-1]) else: @@ -134,3 +203,16 @@ following user commands are available: self.session.buddies.prune() self.session.updateRoster() self.send("buddy list cleared") + def _groups(self): + for group in self.session.groups: + buddy = self.session.groups[group].owner + try: + nick = self.session.buddies[buddy].nick + except KeyError: + nick = buddy + + self.send(self.session.groups[group].id + "@" + self.session.backend.spectrum_jid + " " + self.session.groups[group].subject + " Owner: " + nick ) + def _getgroups(self): + #self.session.call("group_getGroups", ("participating",)) + self.session.requestGroupsList(self.session._updateGroups) + diff --git a/buddy.py b/buddy.py index 1ab9944..a393a2c 100644 --- a/buddy.py +++ b/buddy.py @@ -23,9 +23,10 @@ __status__ = "Prototype" """ from Spectrum2 import protocol_pb2 -from Yowsup.Contacts.contacts import WAContactsSyncRequest import logging +import threading + class Number(): @@ -56,16 +57,21 @@ class Buddy(): self.owner = owner self.number = number self.groups = groups - self.image_hash = image_hash + self.image_hash = image_hash if image_hash is not None else "" + self.statusMsg = "" + self.lastseen = 0 + self.presence = 0 + def update(self, nick, groups, image_hash): self.nick = nick self.groups = groups - self.image_hash = image_hash + 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, image_hash, self.owner.id, self.number.id)) + 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): @@ -91,9 +97,12 @@ class BuddyList(dict): def __init__(self, owner, db): self.db = db self.owner = Number(owner, 1, db) + self.lock = threading.Lock() + def load(self): self.clear() + self.lock.acquire() cur = self.db.cursor() cur.execute("""SELECT @@ -114,13 +123,17 @@ class BuddyList(dict): 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 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() return buddy @@ -130,17 +143,24 @@ class BuddyList(dict): def remove(self, number): try: buddy = self[number] + self.lock.acquire() buddy.delete() + self.lock.release() 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, @@ -165,5 +185,5 @@ class BuddyList(dict): 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/group.py b/group.py index f5c703e..c612473 100644 --- a/group.py +++ b/group.py @@ -29,6 +29,7 @@ class Group(): self.subject = subject self.subjectOwner = subjectOwner self.owner = owner + self.joined = False self.nick = "me" - self.participants = { } + self.participants = [] diff --git a/session.py b/session.py index b86fa97..9060673 100644 --- a/session.py +++ b/session.py @@ -27,6 +27,15 @@ import logging import urllib import time +from PIL import Image +import MySQLdb +import sys +import os + +from yowsup.common.tools import TimeTools +from yowsup.layers.protocol_media.mediauploader import MediaUploader +from yowsup.layers.protocol_media.mediadownloader import MediaDownloader + from Spectrum2 import protocol_pb2 from buddy import BuddyList @@ -36,6 +45,16 @@ from bot import Bot from constants import * from yowsupwrapper import YowsupApp + +class MsgIDs: + def __init__(self, xmppId, waId): + self.xmppId = xmppId + self.waId = waId + self.cnt = 0 + + + + class Session(YowsupApp): def __init__(self, backend, user, legacyName, extra, db): @@ -43,51 +62,75 @@ class Session(YowsupApp): self.logger = logging.getLogger(self.__class__.__name__) self.logger.info("Created: %s", legacyName) - self.db = db + #self.db = db + self.db = MySQLdb.connect(DB_HOST, DB_USER, DB_PASS, DB_TABLE) + 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.gotGroupList = False + self.joinRoomQueue = [] self.presenceRequested = [] self.offlineQueue = [] + self.msgIDs = { } self.groupOfflineQueue = { } + self.shouldBeConnected = False self.timer = None self.password = None self.initialized = False - self.loggedin = False + self.lastMsgId = None + self.synced = False + self.buddies = BuddyList(self.legacyName, self.db) self.bot = Bot(self) + self.imgMsgId = None + self.imgPath = "" + self.imgBuddy = None + self.imgType = "" + + 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 + self.logger.info("%s logged out", self.user) super(Session, self).logout() def login(self, password): - self.loggedin = True + 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([room, group.subject]) + 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") @@ -95,6 +138,11 @@ class Session(YowsupApp): 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) @@ -103,27 +151,28 @@ class Session(YowsupApp): 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.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.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() + owner = group.getOwner().split('@')[0] + subjectOwner = group.getSubjectOwner().split('@')[0] + subject = utils.softToUni(group.getSubject()) if room in self.groups: oroom = self.groups[room] @@ -132,23 +181,82 @@ class Session(YowsupApp): oroom.subject = subject else: self.groups[room] = Group(room, owner, subject, subjectOwner) - # A crude implemtation of groups that act like buddies +# self.joinRoom(self._shortenGroupId(room), self.user.split("@")[0]) + self.groups[room].participants = group.getParticipants().keys() - 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) + #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.nick = nick + try: + ownerNick = self.buddies[group.subjectOwner].nick + except KeyError: + ownerNick = group.subjectOwner + + self._refreshParticipants(room) + 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 + ) + group.joined = True + 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 _refreshParticipants(self, room): + group = self.groups[room] + for jid in group.participants: + buddy = jid.split("@")[0] + self.logger.info("Added %s to room %s", buddy, room) + try: + nick = self.buddies[buddy].nick + except KeyError: + nick = buddy + if nick == "": + nick = buddy + + if buddy == group.owner: + flags = protocol_pb2.PARTICIPANT_FLAG_MODERATOR + else: + flags = protocol_pb2.PARTICIPANT_FLAG_NONE + if buddy == self.legacyName: + nick = group.nick + flags = flags | protocol_pb2.PARTICIPANT_FLAG_ME + self.backend.handleParticipantChanged( + 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))) @@ -163,23 +271,29 @@ class Session(YowsupApp): 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.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) - self.updateRoster() + self.logger.debug('Requesting groups list') + self.requestGroupsList(self._updateGroups) + # 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 + # 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): @@ -187,9 +301,17 @@ class Session(YowsupApp): ' '.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) + 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.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): @@ -198,8 +320,9 @@ class Session(YowsupApp): ) # Called by superclass - def onTextMessage(self, _id, _from, to, notify, timestamp, participant, offline, retry, body): - self.logger.debug('received TextMessage' + + 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 @@ -207,13 +330,24 @@ class Session(YowsupApp): ) buddy = _from.split('@')[0] messageContent = utils.softToUni(body) - self.sendReceipt(_id, _from, None, participant) + 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: + if participant is not None: # Group message partname = participant.split('@')[0] - message = partname + ': ' + messageContent - self.sendMessageToXMPP(buddy, message, timestamp) + try: + part = self.buddies[partname] + if part.nick == "": + part.nick = notify + self.backend.handleParticipantChanged( + self.user, partname, self._shortenGroupId(buddy), + protocol_pb2.PARTICIPANT_FLAG_NONE, + protocol_pb2.STATUS_ONLINE, "", part.nick + ) # TODO + except KeyError: + self.updateBuddy(partname, notify, []) + self.sendGroupMessageToXMPP(buddy, partname, messageContent, + timestamp) else: self.sendMessageToXMPP(buddy, messageContent, timestamp) # isBroadcast always returns false, I'm not sure how to get a broadcast @@ -227,39 +361,88 @@ class Session(YowsupApp): 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 - self.sendMessageToXMPP(buddy, message, image.timestamp) - self.sendReceipt(image._id, image._from, None, image.participant) + 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 - self.sendMessageToXMPP(buddy, message, audio.timestamp) - self.sendReceipt(audio._id, audio._from, None, audio.participant) + 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 - self.sendMessageToXMPP(buddy, message, video.timestamp) - self.sendReceipt(video._id, video._from, None, video.participant) + 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' + + 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) + 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) @@ -270,49 +453,103 @@ class Session(YowsupApp): # Called by superclass def onContactTyping(self, buddy): self.logger.info("Started typing: %s", buddy) - self.sendPresence(True) - self.backend.handleBuddyTyping(self.user, buddy) + if buddy != 'bot': + self.sendPresence(True) + self.backend.handleBuddyTyping(self.user, buddy) - if self.timer != None: - self.timer.cancel() + 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() + 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.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)) + + # Called by superclass + 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) + + # Called by superclass + def onParticipantsRemovedFromGroup(self, room, participants): + self.logger.debug("Participants removed from group: %s, %s", + room, participants) + group = self.groups[room] + for jid in participants: + group.participants.remove(jid) + 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_NONE + self.backend.handleParticipantChanged( + self.user, nick, self._shortenGroupId(room), flags, + protocol_pb2.STATUS_NONE, buddy) + 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)) + try: + buddy = self.buddies[buddy] + except KeyError: + self.logger.error("Buddy not found: %s", buddy) + return - 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 == 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() - if lastseen < 60: - self.onPresenceAvailable(buddy) + buddy.presence = _type + + 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.onPresenceUnavailable(buddy) + self.onPresenceAvailable(buddy, statusmsg) - 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) + + def onPresenceAvailable(self, buddy, statusmsg): + self.logger.info("Is available: %s", buddy) + self.backend.handleBuddyChanged(self.user, buddy.number.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, + buddy.nick, buddy.groups, protocol_pb2.STATUS_AWAY, statusmsg, buddy.image_hash) # spectrum RequestMethods def sendTypingStarted(self, buddy): @@ -329,29 +566,145 @@ class Session(YowsupApp): 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) + 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: - room, buddy = sender.split("/") - self.sendTextMessage(buddy + '@s.whatsapp.net', message) + if "/" in sender: # directed at single user + room, nick = sender.split("/") + for buddy, buddy3 in self.buddies.iteritems(): + self.logger.info("Group buddy=%s nick=%s", buddy, + buddy3.nick) + if buddy3.nick == nick: + nick = buddy + waId = self.sendTextMessage(nick + '@s.whatsapp.net', message) + self.msgIDs[waId] = MsgIDs( ID, waId) else: room = sender -# group = self.groups[room] + 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" -# self.backend.handleMessage(self.user, room, message, group.nick) - self.sendTextMessage(room + '@g.us', message) + 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: - self.sendTextMessage(sender + '@s.whatsapp.net', message) + 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: @@ -368,26 +721,53 @@ class Session(YowsupApp): "", timestamp) def sendGroupMessageToXMPP(self, room, buddy, messageContent, timestamp = ""): + # self._refreshParticipants(room) + try: + nick = self.buddies[buddy].nick + except KeyError: + nick = buddy + if nick == "": + nick = buddy + 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) + 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)) + 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) + self.logger.debug("Group message sent from %s (%s) to %s: %s", + buddy, nick, room, messageContent) + try: + group = self.groups[room] + 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, nick, "", 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: + if status == protocol_pb2.STATUS_ONLINE \ + or status == protocol_pb2.STATUS_FFC: self.sendPresence(True) else: self.sendPresence(False) @@ -398,10 +778,10 @@ class Session(YowsupApp): 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 + #if self.initialized == False: + # self.sendOfflineMessages() + # self.bot.call("welcome") + # self.initialized = True def sendOfflineMessages(self): # Flush Queues @@ -410,10 +790,11 @@ class Session(YowsupApp): 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 =""): + def updateBuddy(self, buddy, nick, groups, image_hash = None): if buddy != "bot": self.buddies.update(buddy, nick, groups, image_hash) - self.updateRoster() + if self.initialized == True: + self.updateRoster() def removeBuddy(self, buddy): if buddy != "bot": @@ -421,33 +802,83 @@ class Session(YowsupApp): 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 requestVCard(self, buddy, ID=None): 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) + if ID != None: + 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) + 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] @@ -458,36 +889,6 @@ class Session(YowsupApp): 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] @@ -512,3 +913,6 @@ class Session(YowsupApp): def onGroupPictureUpdated(self, jid, author, timestamp, messageId, pictureId, receiptRequested): # TODO if receiptRequested: self.call("notification_ack", (jid, messageId)) + + + 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 b7b9827..06fbe9b 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 = {} @@ -58,7 +59,7 @@ class WhatsAppBackend(SpectrumBackend): self.sessions[user].logout() del self.sessions[user] - def handleMessageSendRequest(self, user, buddy, message, xhtml = ""): + def handleMessageSendRequest(self, user, buddy, message, xhtml = "", ID = 0): self.logger.debug("handleMessageSendRequest(user=%s, buddy=%s, message=%s, xhtml = %s)", user, buddy, message, xhtml) # For some reason spectrum occasionally sends to identical messages to # a buddy, one to the bare jid and one to /bot. This causes duplicate @@ -67,15 +68,20 @@ class WhatsAppBackend(SpectrumBackend): # # TODO Proper fix, this work around drops all duplicate messages even # intentional ones. + # IDEA there is an ID field in ConvMessage. If it is extracted it will work usersMessage = self.lastMessage[user] if buddy not in usersMessage or usersMessage[buddy] != message: - self.sessions[user].sendMessageToWA(buddy, message) + self.sessions[user].sendMessageToWA(buddy, message, ID) usersMessage[buddy] = message def handleJoinRoomRequest(self, user, room, nickname, pasword): self.logger.debug("handleJoinRoomRequest(user=%s, room=%s, nickname=%s)", user, room, nickname) self.sessions[user].joinRoom(room, nickname) + def handleLeaveRoomRequest(self, user, room): + self.logger.debug("handleLeaveRoomRequest(user=%s, room=%s)", user, room) + self.sessions[user].leaveRoom(room) + def handleStatusChangeRequest(self, user, status, statusMessage): self.logger.debug("handleStatusChangeRequest(user=%s, status=%d, statusMessage=%s)", user, status, statusMessage) self.sessions[user].changeStatusMessage(statusMessage) @@ -105,13 +111,11 @@ class WhatsAppBackend(SpectrumBackend): self.logger.debug("handleVCardRequest(user=%s, buddy=%s, ID=%s)", user, buddy, ID) self.sessions[user].requestVCard(buddy, ID) + # TODO def handleBuddyBlockToggled(self, user, buddy, blocked): pass - def handleLeaveRoomRequest(self, user, room): - pass - def handleVCardUpdatedRequest(self, user, photo, nickname): pass @@ -134,6 +138,9 @@ class WhatsAppBackend(SpectrumBackend): def handleRawXmlRequest(self, xml): pass + def handleMessageAckRequest(self, user, legacyName, ID = 0): + self.logger.info("Meassage ACK request for %s !!",leagcyName) + def sendData(self, data): self.io.sendData(data) diff --git a/yowsupwrapper.py b/yowsupwrapper.py index 8058b10..ef1928b 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 @@ -30,15 +32,19 @@ from yowsup.layers.protocol_calls import YowCallsProtocolLayer from yowsup.layers.protocol_acks.protocolentities import * from yowsup.layers.protocol_chatstate.protocolentities import * +from yowsup.layers.protocol_contacts.protocolentities import * from yowsup.layers.protocol_groups.protocolentities import * from yowsup.layers.protocol_media.protocolentities import * from yowsup.layers.protocol_messages.protocolentities import * from yowsup.layers.protocol_presence.protocolentities import * from yowsup.layers.protocol_profiles.protocolentities import * from yowsup.layers.protocol_receipts.protocolentities import * +from yowsup.layers.protocol_media.mediauploader import MediaUploader from functools import partial +#from session import MsgIDs + class YowsupApp(object): def __init__(self): env.CURRENT_ENV = env.S40YowsupEnv() @@ -55,7 +61,6 @@ class YowsupApp(object): YowContactsIqProtocolLayer, YowChatstateProtocolLayer, YowCallsProtocolLayer, - YowMediaProtocolLayer, YowPrivacyProtocolLayer, YowProfilesProtocolLayer, YowGroupsProtocolLayer, @@ -66,6 +71,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) @@ -107,7 +113,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) @@ -131,6 +137,64 @@ class YowsupApp(object): """ messageEntity = TextMessageProtocolEntity(message, to = to) self.sendEntity(messageEntity) + return messageEntity.getId() + + def sendLocation(self, to, latitude, longitude): + messageEntity = LocationMediaMessageProtocolEntity(latitude,longitude, None, None, "raw", to = to) + self.sendEntity(messageEntity) + return messageEntity.getId() + + def image_send(self, jid, path, caption = None): + entity = RequestUploadIqProtocolEntity(RequestUploadIqProtocolEntity.MEDIA_TYPE_IMAGE, filePath=path) + successFn = lambda successEntity, originalEntity: self.onRequestUploadResult(jid, path, successEntity, originalEntity, caption) + errorFn = lambda errorEntity, originalEntity: self.onRequestUploadError(jid, path, errorEntity, originalEntity) + + self.sendIq(entity, successFn, errorFn) + + def onRequestUploadResult(self, jid, filePath, resultRequestUploadIqProtocolEntity, requestUploadIqProtocolEntity, caption = None): + + if requestUploadIqProtocolEntity.mediaType == RequestUploadIqProtocolEntity.MEDIA_TYPE_AUDIO: + doSendFn = self._doSendAudio + else: + doSendFn = self._doSendImage + + if resultRequestUploadIqProtocolEntity.isDuplicate(): + doSendFn(filePath, resultRequestUploadIqProtocolEntity.getUrl(), jid, + resultRequestUploadIqProtocolEntity.getIp(), caption) + else: + successFn = lambda filePath, jid, url: doSendFn(filePath, url, jid, resultRequestUploadIqProtocolEntity.getIp(), caption) + mediaUploader = MediaUploader(jid, self.legacyName, filePath, + resultRequestUploadIqProtocolEntity.getUrl(), + resultRequestUploadIqProtocolEntity.getResumeOffset(), + successFn, self.onUploadError, self.onUploadProgress, async=False) + mediaUploader.start() + + def onRequestUploadError(self, jid, path, errorRequestUploadIqProtocolEntity, requestUploadIqProtocolEntity): + self.logger.error("Request upload for file %s for %s failed" % (path, jid)) + + def onUploadError(self, filePath, jid, url): + #logger.error("Upload file %s to %s for %s failed!" % (filePath, url, jid)) + self.logger.error("Upload Error!") + + def onUploadProgress(self, filePath, jid, url, progress): + #sys.stdout.write("%s => %s, %d%% \r" % (os.path.basename(filePath), jid, progress)) + #sys.stdout.flush() + pass + + def doSendImage(self, filePath, url, to, ip = None, caption = None): + entity = ImageDownloadableMediaMessageProtocolEntity.fromFilePath(filePath, url, ip, to, caption = caption) + self.sendEntity(entity) + #self.msgIDs[entity.getId()] = MsgIDs(self.imgMsgId, entity.getId()) + return entity.getId() + + + def doSendAudio(self, filePath, url, to, ip = None, caption = None): + entity = AudioDownloadableMediaMessageProtocolEntity.fromFilePath(filePath, url, ip, to) + self.sendEntity(entity) + #self.msgIDs[entity.getId()] = MsgIDs(self.imgMsgId, entity.getId()) + return entity.getId() + + def sendPresence(self, available): """ @@ -167,7 +231,17 @@ class YowsupApp(object): jid = phone_number + '@s.whatsapp.net' entity = UnsubscribePresenceProtocolEntity(jid) self.sendEntity(entity) - + + def leaveGroup(self, group): + """ + Permanently leave a WhatsApp group + + Args: + - group: (str) the group id (e.g. 27831788123-144024456) + """ + entity = LeaveGroupsIqProtocolEntity([group + '@g.us']) + self.sendEntity(entity) + def setStatus(self, statusText): """ Send status to whatsapp @@ -197,6 +271,26 @@ class YowsupApp(object): ) self.sendEntity(state) + def sendSync(self, contacts, delta = False, interactive = True): + """ + You need to sync new contacts before you interact with + them, failure to do so could result in a temporary ban. + + Args: + - contacts: ([str]) a list of phone numbers of the + contacts you wish to sync + - delta: (bool; default: False) If true only send new + contacts to sync, if false you should send your full + contact list. + - interactive: (bool; default: True) Set to false if you are + sure this is the first time registering + """ + # TODO: Implement callbacks + mode = GetSyncIqProtocolEntity.MODE_DELTA if delta else GetSyncIqProtocolEntity.MODE_FULL + context = GetSyncIqProtocolEntity.CONTEXT_INTERACTIVE if interactive else GetSyncIqProtocolEntity.CONTEXT_REGISTRATION + iq = GetSyncIqProtocolEntity(contacts, mode, context) + self.sendIq(iq) + def requestLastSeen(self, phoneNumber, success = None, failure = None): """ Requests when user was last seen. @@ -219,8 +313,8 @@ class YowsupApp(object): Requests profile picture of whatsapp user Args: - phoneNumber: (str) the phone number of the user - - success: (func) called when request is successfully processed. - - failure: (func) called when request has failed + - onSuccess: (func) called when request is successfully processed. + - onFailure: (func) called when request has failed """ iq = GetPictureIqProtocolEntity(phoneNumber + '@s.whatsapp.net') self.sendIq(iq, onSuccess = onSuccess, onError = onFailure) @@ -229,6 +323,18 @@ class YowsupApp(object): iq = ListGroupsIqProtocolEntity() self.sendIq(iq, onSuccess = onSuccess, onError = onFailure) + def requestGroupInfo(self, group, onSuccess = None, onFailure = None): + """ + Request info on a specific group (includes participants, subject, owner etc.) + + Args: + - group: (str) the group id in the form of xxxxxxxxx-xxxxxxxx + - onSuccess: (func) called when request is successfully processed. + - onFailure: (func) called when request is has failed + """ + iq = InfoGroupsIqProtocolEntity(group + '@g.us') + self.sendIq(iq, onSuccess = onSuccess, onError = onFailure) + def onAuthSuccess(self, status, kind, creation, expiration, props, nonce, t): """ Called when login is successful. @@ -280,7 +386,7 @@ class YowsupApp(object): - timestamp """ pass - + def onPresenceReceived(self, _type, name, _from, last): """ Called when presence (e.g. available, unavailable) is received @@ -298,7 +404,7 @@ class YowsupApp(object): """ Called when disconnected from whatsapp """ - + def onContactTyping(self, number): """ Called when contact starts to type @@ -333,7 +439,7 @@ class YowsupApp(object): - body: The content of the message """ pass - + def onImage(self, entity): """ Called when image message is received @@ -351,7 +457,7 @@ class YowsupApp(object): - entity: AudioDownloadableMediaMessageProtocolEntity """ pass - + def onVideo(self, entity): """ @@ -361,7 +467,16 @@ class YowsupApp(object): - entity: VideoDownloadableMediaMessageProtocolEntity """ pass - + + def onLocation(self, entity): + """ + Called when location message is received + + Args: + - entity: LocationMediaMessageProtocolEntity + """ + pass + def onVCard(self, _id, _from, name, card_data, to, notify, timestamp, participant): """ Called when VCard message is received @@ -378,12 +493,29 @@ 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 onParticipantsRemovedFromGroup(self, group, participants): + """Called when participants have been removed from a group + + Args: + - group: (str) id of the group (e.g. 27831788123-144024456) + - participants: (list) jids of participants that are removed + """ + 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( @@ -408,6 +540,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() @@ -472,10 +605,21 @@ class YowsupAppLayer(YowInterfaceLayer): """ Sends ack automatically """ + self.logger.debug("Received notification (%s): %s", type(entity), entity) self.toLower(entity.ack()) - + if isinstance(entity, CreateGroupsNotificationProtocolEntity): + self.caller.onAddedToGroup(entity) + elif isinstance(entity, AddGroupsNotificationProtocolEntity): + self.caller.onParticipantsAddedToGroup(entity) + elif isinstance(entity, RemoveGroupsNotificationProtocolEntity): + self.caller.onParticipantsRemovedFromGroup( + entity.getGroupId().split('@')[0], + entity.getParticipants().keys() + ) + @ProtocolEntityCallback('message') def onMessageReceived(self, entity): + self.logger.debug("Received Message: %s", entity) if entity.getType() == MessageProtocolEntity.MESSAGE_TYPE_TEXT: self.caller.onTextMessage( entity._id, @@ -508,6 +652,8 @@ class YowsupAppLayer(YowInterfaceLayer): entity.timestamp, entity.participant ) + elif isinstance(entity, LocationMediaMessageProtocolEntity): + self.caller.onLocation(entity) @ProtocolEntityCallback('presence') def onPresenceReceived(self, presence): @@ -516,7 +662,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]