diff --git a/Spectrum2/__init__.py b/Spectrum2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Spectrum2/backend.py b/Spectrum2/backend.py new file mode 100644 index 0000000..7d17fe0 --- /dev/null +++ b/Spectrum2/backend.py @@ -0,0 +1,543 @@ +import protocol_pb2, socket, struct, sys, os + +def WRAP(MESSAGE, TYPE): + wrap = protocol_pb2.WrapperMessage() + wrap.type = TYPE + wrap.payload = MESSAGE + return wrap.SerializeToString() + +class SpectrumBackend: + """ + Creates new NetworkPlugin and connects the Spectrum2 NetworkPluginServer. + @param loop: Event loop. + @param host: Host where Spectrum2 NetworkPluginServer runs. + @param port: Port. + """ + + def __init__(self): + self.m_pingReceived = False + self.m_data = "" + self.m_init_res = 0 + + def handleMessage(self, user, legacyName, msg, nickname = "", xhtml = "", timestamp = ""): + m = protocol_pb2.ConversationMessage() + m.userName = user + m.buddyName = legacyName + m.message = msg + m.nickname = nickname + m.xhtml = xhtml + #m.timestamp = str(timestamp) + + message = WRAP(m.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_CONV_MESSAGE) + self.send(message) + + def handleAttention(self, user, buddyName, msg): + m = protocol_pb2.ConversationMessage() + m.userName = user + m.buddyName = buddyName + m.message = msg + + message = WRAP(m.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_ATTENTION) + self.send(message) + + def handleVCard(self, user, ID, legacyName, fullName, nickname, photo): + vcard = protocol_pb2.VCard() + vcard.userName = user + vcard.buddyName = legacyName + vcard.id = ID + vcard.fullname = fullName + vcard.nickname = nickname + vcard.photo = photo + + message = WRAP(vcard.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_VCARD) + self.send(message) + + + def handleSubject(self, user, legacyName, msg, nickname = ""): + m = protocol_pb2.ConversationMessage() + m.userName = user + m.buddyName = legacyName + m.message = msg + m.nickname = nickname + + message = WRAP(m.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_ROOM_SUBJECT_CHANGED) + self.send(message) + + def handleBuddyChanged(self, user, buddyName, alias, groups, status, statusMessage = "", iconHash = "", blocked = False): + buddy = protocol_pb2.Buddy() + buddy.userName = user + buddy.buddyName = buddyName + buddy.alias = alias + buddy.group.extend(groups) + buddy.status = status + buddy.statusMessage = statusMessage + buddy.iconHash = iconHash + buddy.blocked = blocked + + message = WRAP(buddy.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_BUDDY_CHANGED) + self.send(message) + + + def handleBuddyTyping(self, user, buddyName): + buddy = protocol_pb2.Buddy() + buddy.userName = user + buddy.buddyName = buddyName + + message = WRAP(buddy.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_BUDDY_TYPING) + self.send(message); + + def handleBuddyTyped(self, user, buddyName): + buddy = protocol_pb2.Buddy() + buddy.userName = user + buddy.buddyName = buddyName + + message = WRAP(buddy.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_BUDDY_TYPED) + self.send(message); + + def handleBuddyStoppedTyping(self, user, buddyName): + buddy = protocol_pb2.Buddy() + buddy.userName = user + buddy.buddyName = buddyName + + message = WRAP(buddy.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_BUDDY_STOPPED_TYPING) + self.send(message) + + def handleAuthorization(self, user, buddyName): + buddy = protocol_pb2.Buddy() + buddy.userName = user + buddy.buddyName = buddyName + + message = WRAP(buddy.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_AUTH_REQUEST) + self.send(message) + + + def handleConnected(self, user): + d = protocol_pb2.Connected() + d.user = user + + message = WRAP(d.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_CONNECTED) + self.send(message); + + + def handleDisconnected(self, user, error = 0, msg = ""): + d = protocol_pb2.Disconnected() + d.user = user + d.error = error + d.message = msg + + message = WRAP(d.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_DISCONNECTED) + self.send(message); + + + def handleParticipantChanged(self, user, nickname, room, flags, status, statusMessage = "", newname = ""): + d = protocol_pb2.Participant() + d.userName = user + d.nickname = nickname + d.room = room + d.flag = flags + d.newname = newname + d.status = status + d.statusMessage = statusMessage + + message = WRAP(d.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_PARTICIPANT_CHANGED) + self.send(message); + + + def handleRoomNicknameChanged(self, user, r, nickname): + room = protocol_pb2.Room() + room.userName = user + room.nickname = nickname + room.room = r + room.password = "" + + message = WRAP(room.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_ROOM_NICKNAME_CHANGED) + self.send(message); + + def handleRoomList(self, rooms): + roomList = protocol_pb2.RoomList() + + for room in rooms: + roomList.room.append(room[0]) + roomList.name.append(room[1]) + + message = WRAP(roomList.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_ROOM_LIST) + self.send(message); + + + def handleFTStart(self, user, buddyName, fileName, size): + room = protocol_pb2.File() + room.userName = user + room.buddyName = buddyName + room.fileName = fileName + room.size = size + + message = WRAP(room.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_FT_START) + self.send(message); + + def handleFTFinish(self, user, buddyName, fileName, size, ftid): + room = protocol_pb2.File() + room.userName = user + room.buddyName = buddyName + room.fileName = fileName + room.size = size + + # Check later + if ftid != 0: + room.ftID = ftid + + message = WRAP(room.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_FT_FINISH) + self.send(message) + + + def handleFTData(self, ftID, data): + d = protocol_pb2.FileTransferData() + d.ftid = ftID + d.data = data + + message = WRAP(d.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_FT_DATA); + self.send(message) + + def handleBackendConfig(self, section, key, value): + c = protocol_pb2.BackendConfig() + c.config = "[%s]\n%s = %s\n" % (section, key, value) + + message = WRAP(c.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_BACKEND_CONFIG); + self.send(message) + + def handleLoginPayload(self, data): + payload = protocol_pb2.Login() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + self.handleLoginRequest(payload.user, payload.legacyName, payload.password, payload.extraFields) + + def handleLogoutPayload(self, data): + payload = protocol_pb2.Logout() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + self.handleLogoutRequest(payload.user, payload.legacyName) + + def handleStatusChangedPayload(self, data): + payload = protocol_pb2.Status() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + self.handleStatusChangeRequest(payload.userName, payload.status, payload.statusMessage) + + def handleConvMessagePayload(self, data): + payload = protocol_pb2.ConversationMessage() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + self.handleMessageSendRequest(payload.userName, payload.buddyName, payload.message, payload.xhtml) + + def handleAttentionPayload(self, data): + payload = protocol_pb2.ConversationMessage() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + self.handleAttentionRequest(payload.userName, payload.buddyName, payload.message) + + def handleFTStartPayload(self, data): + payload = protocol_pb2.File() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + self.handleFTStartRequest(payload.userName, payload.buddyName, payload.fileName, payload.size, payload.ftID); + + def handleFTFinishPayload(self, data): + payload = protocol_pb2.File() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + self.handleFTFinishRequest(payload.userName, payload.buddyName, payload.fileName, payload.size, payload.ftID) + + def handleFTPausePayload(self, data): + payload = protocol_pb2.FileTransferData() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + self.handleFTPauseRequest(payload.ftID) + + def handleFTContinuePayload(self, data): + payload = protocol_pb2.FileTransferData() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + self.handleFTContinueRequest(payload.ftID) + + def handleJoinRoomPayload(self, data): + payload = protocol_pb2.Room() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + self.handleJoinRoomRequest(payload.userName, payload.room, payload.nickname, payload.password) + + def handleLeaveRoomPayload(self, data): + payload = protocol_pb2.Room() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + self.handleLeaveRoomRequest(payload.userName, payload.room) + + def handleVCardPayload(self, data): + payload = protocol_pb2.VCard() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + if payload.HasField('photo'): + self.handleVCardUpdatedRequest(payload.userName, payload.photo, payload.nickname) + elif len(payload.buddyName) > 0: + self.handleVCardRequest(payload.userName, payload.buddyName, payload.id) + + def handleBuddyChangedPayload(self, data): + payload = protocol_pb2.Buddy() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + if payload.HasField('blocked'): + self.handleBuddyBlockToggled(payload.userName, payload.buddyName, payload.blocked) + else: + groups = [g for g in payload.group] + self.handleBuddyUpdatedRequest(payload.userName, payload.buddyName, payload.alias, groups); + + def handleBuddyRemovedPayload(self, data): + payload = protocol_pb2.Buddy() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + groups = [g for g in payload.group] + self.handleBuddyRemovedRequest(payload.userName, payload.buddyName, groups); + + def handleChatStatePayload(self, data, msgType): + payload = protocol_pb2.Buddy() + if (payload.ParseFromString(data) == False): + #TODO: ERROR + return + if msgType == protocol_pb2.WrapperMessage.TYPE_BUDDY_TYPING: + self.handleTypingRequest(payload.userName, payload.buddyName) + elif msgType == protocol_pb2.WrapperMessage.TYPE_BUDDY_TYPED: + self.handleTypedRequest(payload.userName, payload.buddyName) + elif msgType == protocol_pb2.WrapperMessage.TYPE_BUDDY_STOPPED_TYPING: + self.handleStoppedTypingRequest(payload.userName, payload.buddyName) + + + def handleDataRead(self, data): + self.m_data += data + while len(self.m_data) != 0: + expected_size = 0 + 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): + return + else: + return + + wrapper = protocol_pb2.WrapperMessage() + if (wrapper.ParseFromString(self.m_data[4:]) == False): + self.m_data = self.m_data[expected_size+4:] + return + + self.m_data = self.m_data[4+expected_size:] + + if wrapper.type == protocol_pb2.WrapperMessage.TYPE_LOGIN: + self.handleLoginPayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_LOGOUT: + self.handleLogoutPayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_PING: + self.sendPong() + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_CONV_MESSAGE: + self.handleConvMessagePayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_JOIN_ROOM: + self.handleJoinRoomPayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_LEAVE_ROOM: + self.handleLeaveRoomPayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_VCARD: + self.handleVCardPayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_BUDDY_CHANGED: + self.handleBuddyChangedPayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_BUDDY_REMOVED: + self.handleBuddyRemovedPayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_STATUS_CHANGED: + self.handleStatusChangedPayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_BUDDY_TYPING: + self.handleChatStatePayload(wrapper.payload, protocol_pb2.WrapperMessage.TYPE_BUDDY_TYPING) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_BUDDY_TYPED: + self.handleChatStatePayload(wrapper.payload, protocol_pb2.WrapperMessage.TYPE_BUDDY_TYPED) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_BUDDY_STOPPED_TYPING: + self.handleChatStatePayload(wrapper.payload, protocol_pb2.WrapperMessage.TYPE_BUDDY_STOPPED_TYPING) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_ATTENTION: + self.handleAttentionPayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_FT_START: + self.handleFTStartPayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_FT_FINISH: + self.handleFTFinishPayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_FT_PAUSE: + self.handleFTPausePayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_FT_CONTINUE: + self.handleFTContinuePayload(wrapper.payload) + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_EXIT: + self.handleExitRequest() + elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_RAW_XML: + self.handleRawXmlRequest(wrapper.payload) + + def send(self, data): + header = struct.pack('!I',len(data)) + self.sendData(header + data) + + def checkPing(self): + if (self.m_pingReceived == False): + self.handleExitRequest() + self.m_pingReceived = False + + + def sendPong(self): + self.m_pingReceived = True + wrap = protocol_pb2.WrapperMessage() + wrap.type = protocol_pb2.WrapperMessage.TYPE_PONG + message = wrap.SerializeToString() + self.send(message) + self.sendMemoryUsage() + + + def sendMemoryUsage(self): + stats = protocol_pb2.Stats() + + stats.init_res = self.m_init_res + res = 0 + shared = 0 + + e_res, e_shared = self.handleMemoryUsage() + + stats.res = res + e_res + stats.shared = shared + e_shared + stats.id = str(os.getpid()) + + message = WRAP(stats.SerializeToString(), protocol_pb2.WrapperMessage.TYPE_STATS) + self.send(message) + + + def handleLoginRequest(self, user, legacyName, password, extra): + """ + Called when XMPP user wants to connect legacy network. + You should connect him to legacy network and call handleConnected or handleDisconnected function later. + @param user: XMPP JID of user for which this event occurs. + @param legacyName: Legacy network name of this user used for login. + @param password: Legacy network password of this user. + """ + + #\msc + #NetworkPlugin,YourNetworkPlugin,LegacyNetwork; + #NetworkPlugin->YourNetworkPlugin [label="handleLoginRequest(...)", URL="\ref NetworkPlugin::handleLoginRequest()"]; + #YourNetworkPlugin->LegacyNetwork [label="connect the legacy network"]; + #--- [label="If password was valid and user is connected and logged in"]; + #YourNetworkPlugin<-LegacyNetwork [label="connected"]; + #YourNetworkPlugin->NetworkPlugin [label="handleConnected()", URL="\ref NetworkPlugin::handleConnected()"]; + #--- [label="else"]; + #YourNetworkPlugin<-LegacyNetwork [label="disconnected"]; + #YourNetworkPlugin->NetworkPlugin [label="handleDisconnected()", URL="\ref NetworkPlugin::handleDisconnected()"]; + #\endmsc + + raise NotImplementedError, "Implement me" + + def handleLogoutRequest(self, user, legacyName): + """ + Called when XMPP user wants to disconnect legacy network. + You should disconnect him from legacy network. + @param user: XMPP JID of user for which this event occurs. + @param legacyName: Legacy network name of this user used for login. + """ + + raise NotImplementedError, "Implement me" + + def handleMessageSendRequest(self, user, legacyName, message, xhtml = ""): + """ + 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. + """ + + raise NotImplementedError, "Implement me" + + 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. + @param legacyName: Legacy network name of buddy whose VCard is requested. + @param ID: ID which is associated with this request. You have to pass it to handleVCard function when you receive VCard.""" + + #\msc + #NetworkPlugin,YourNetworkPlugin,LegacyNetwork; + #NetworkPlugin->YourNetworkPlugin [label="handleVCardRequest(...)", URL="\ref NetworkPlugin::handleVCardRequest()"]; + #YourNetworkPlugin->LegacyNetwork [label="start VCard fetching"]; + #YourNetworkPlugin<-LegacyNetwork [label="VCard fetched"]; + #YourNetworkPlugin->NetworkPlugin [label="handleVCard()", URL="\ref NetworkPlugin::handleVCard()"]; + #\endmsc + + pass + + + def handleVCardUpdatedRequest(self, user, photo, nickname): + """ + Called when XMPP user updates his own VCard. + You should update the VCard in legacy network too. + @param user: XMPP JID of user for which this event occurs. + @param photo: Raw photo data. + """ + pass + + def handleJoinRoomRequest(self, user, room, nickname, pasword): + pass + + def handleLeaveRoomRequest(self, user, room): + pass + + def handleStatusChangeRequest(self, user, status, statusMessage): + pass + + def handleBuddyUpdatedRequest(self, user, buddyName, alias, groups): + pass + + def handleBuddyRemovedRequest(self, user, buddyName, groups): + pass + + def handleBuddyBlockToggled(self, user, buddyName, blocked): + pass + + def handleTypingRequest(self, user, buddyName): + pass + + def handleTypedRequest(self, user, buddyName): + pass + + def handleStoppedTypingRequest(self, user, buddyName): + pass + + def handleAttentionRequest(self, user, buddyName, message): + pass + + def handleFTStartRequest(self, user, buddyName, fileName, size, ftID): + pass + + def handleFTFinishRequest(self, user, buddyName, fileName, size, ftID): + pass + + def handleFTPauseRequest(self, ftID): + pass + + def handleFTContinueRequest(self, ftID): + pass + + def handleMemoryUsage(self): + return (0,0) + + def handleExitRequest(self): + sys.exit(1) + + def handleRawXmlRequest(self, xml): + pass + + def sendData(self, data): + pass diff --git a/Spectrum2/iochannel.py b/Spectrum2/iochannel.py new file mode 100644 index 0000000..0b5ffad --- /dev/null +++ b/Spectrum2/iochannel.py @@ -0,0 +1,34 @@ +import asyncore, socket + +class IOChannel(asyncore.dispatcher): + def __init__(self, host, port, callback): + asyncore.dispatcher.__init__(self) + + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.connect((host, port)) + + self.callback = callback + self.buffer = "" + + def sendData(self, data): + self.buffer += data + + def handle_connect(self): + pass + + def handle_close(self): + self.close() + + def handle_read(self): + data = self.recv(65536) + self.callback(data) + + def handle_write(self): + sent = self.send(self.buffer) + self.buffer = self.buffer[sent:] + + def writable(self): + return (len(self.buffer) > 0) + + def readable(self): + return True diff --git a/Spectrum2/protocol.proto b/Spectrum2/protocol.proto new file mode 100644 index 0000000..8d48386 --- /dev/null +++ b/Spectrum2/protocol.proto @@ -0,0 +1,189 @@ +package pbnetwork; + +enum ConnectionError { + CONNECTION_ERROR_NETWORK_ERROR = 0; + CONNECTION_ERROR_INVALID_USERNAME = 1; + CONNECTION_ERROR_AUTHENTICATION_FAILED = 2; + CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE = 3; + CONNECTION_ERROR_NO_SSL_SUPPORT = 4; + CONNECTION_ERROR_ENCRYPTION_ERROR = 5; + CONNECTION_ERROR_NAME_IN_USE = 6; + CONNECTION_ERROR_INVALID_SETTINGS = 7; + CONNECTION_ERROR_CERT_NOT_PROVIDED = 8; + CONNECTION_ERROR_CERT_UNTRUSTED = 9; + CONNECTION_ERROR_CERT_EXPIRED = 10; + CONNECTION_ERROR_CERT_NOT_ACTIVATED = 11; + CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH = 12; + CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH = 13; + CONNECTION_ERROR_CERT_SELF_SIGNED = 14; + CONNECTION_ERROR_CERT_OTHER_ERROR = 15; + CONNECTION_ERROR_OTHER_ERROR = 16; +} + +enum StatusType { + STATUS_ONLINE = 0; + STATUS_AWAY = 1; + STATUS_FFC = 2; + STATUS_XA = 3; + STATUS_DND = 4; + STATUS_NONE = 5; + STATUS_INVISIBLE = 6; +} + +message Connected { + required string user = 1; +} + +message Disconnected { + required string user = 1; + required int32 error = 2; + optional string message = 3; +} + +message Login { + required string user = 1; + required string legacyName = 2; + required string password = 3; + repeated string extraFields = 4; +} + +message Logout { + required string user = 1; + required string legacyName = 2; +} + +message Buddy { + required string userName = 1; + required string buddyName = 2; + optional string alias = 3; + repeated string group = 4; + optional StatusType status = 5; + optional string statusMessage = 6; + optional string iconHash = 7; + optional bool blocked = 8; +} + +message ConversationMessage { + required string userName = 1; + required string buddyName = 2; + required string message = 3; + optional string nickname = 4; + optional string xhtml = 5; + optional string timestamp = 6; + optional bool headline = 7; + optional string id = 8; + optional bool pm = 9; +} + +message Room { + required string userName = 1; + required string nickname = 2; + required string room = 3; + optional string password = 4; +} + +message RoomList { + repeated string room = 1; + repeated string name = 2; +} + +enum ParticipantFlag { + PARTICIPANT_FLAG_NONE = 0; + PARTICIPANT_FLAG_MODERATOR = 1; + PARTICIPANT_FLAG_CONFLICT = 2; + PARTICIPANT_FLAG_BANNED = 4; + PARTICIPANT_FLAG_NOT_AUTHORIZED = 8; + PARTICIPANT_FLAG_ME = 16; + PARTICIPANT_FLAG_KICKED = 32; + PARTICIPANT_FLAG_ROOM_NOT_FOUND = 64; +} + +message Participant { + required string userName = 1; + required string room = 2; + required string nickname = 3; + required int32 flag = 4; + required StatusType status = 5; + optional string statusMessage = 6; + optional string newname = 7; +} + +message VCard { + required string userName = 1; + required string buddyName = 2; + required int32 id = 3; + optional string fullname = 4; + optional string nickname = 5; + optional bytes photo = 6; +} + +message Status { + required string userName = 1; + required StatusType status = 3; + optional string statusMessage = 4; +} + +message Stats { + required int32 res = 1; + required int32 init_res = 2; + required int32 shared = 3; + required string id = 4; +} + +message File { + required string userName = 1; + required string buddyName = 2; + required string fileName = 3; + required int32 size = 4; + optional int32 ftID = 5; +} + +message FileTransferData { + required int32 ftID = 1; + required bytes data = 2; +} + +message BackendConfig { + required string config = 1; +} + +message WrapperMessage { + enum Type { + TYPE_CONNECTED = 1; + TYPE_DISCONNECTED = 2; + TYPE_LOGIN = 3; + TYPE_LOGOUT = 4; + TYPE_BUDDY_CHANGED = 6; + TYPE_BUDDY_REMOVED = 7; + TYPE_CONV_MESSAGE = 8; + TYPE_PING = 9; + TYPE_PONG = 10; + TYPE_JOIN_ROOM = 11; + TYPE_LEAVE_ROOM = 12; + TYPE_PARTICIPANT_CHANGED = 13; + TYPE_ROOM_NICKNAME_CHANGED = 14; + TYPE_ROOM_SUBJECT_CHANGED = 15; + TYPE_VCARD = 16; + TYPE_STATUS_CHANGED = 17; + TYPE_BUDDY_TYPING = 18; + TYPE_BUDDY_STOPPED_TYPING = 19; + TYPE_BUDDY_TYPED = 20; + TYPE_AUTH_REQUEST = 21; + TYPE_ATTENTION = 22; + TYPE_STATS = 23; + TYPE_FT_START = 24; + TYPE_FT_FINISH = 25; + TYPE_FT_DATA = 26; + TYPE_FT_PAUSE = 27; + TYPE_FT_CONTINUE = 28; + TYPE_EXIT = 29; + TYPE_BACKEND_CONFIG = 30; + TYPE_QUERY = 31; + TYPE_ROOM_LIST = 32; + TYPE_CONV_MESSAGE_ACK = 33; + TYPE_RAW_XML = 34; + } + required Type type = 1; + optional bytes payload = 2; +} +; diff --git a/Spectrum2/protocol_pb2.py b/Spectrum2/protocol_pb2.py new file mode 100644 index 0000000..e01bd27 --- /dev/null +++ b/Spectrum2/protocol_pb2.py @@ -0,0 +1,1245 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! + +from google.protobuf import descriptor +from google.protobuf import message +from google.protobuf import reflection +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + + +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@') + +_CONNECTIONERROR = descriptor.EnumDescriptor( + name='ConnectionError', + full_name='pbnetwork.ConnectionError', + filename=None, + file=DESCRIPTOR, + values=[ + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_NETWORK_ERROR', index=0, number=0, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_INVALID_USERNAME', index=1, number=1, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_AUTHENTICATION_FAILED', index=2, number=2, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE', index=3, number=3, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_NO_SSL_SUPPORT', index=4, number=4, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_ENCRYPTION_ERROR', index=5, number=5, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_NAME_IN_USE', index=6, number=6, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_INVALID_SETTINGS', index=7, number=7, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_CERT_NOT_PROVIDED', index=8, number=8, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_CERT_UNTRUSTED', index=9, number=9, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_CERT_EXPIRED', index=10, number=10, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_CERT_NOT_ACTIVATED', index=11, number=11, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH', index=12, number=12, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH', index=13, number=13, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_CERT_SELF_SIGNED', index=14, number=14, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_CERT_OTHER_ERROR', index=15, number=15, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CONNECTION_ERROR_OTHER_ERROR', index=16, number=16, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=2102, + serialized_end=2793, +) + + +_STATUSTYPE = descriptor.EnumDescriptor( + name='StatusType', + full_name='pbnetwork.StatusType', + filename=None, + file=DESCRIPTOR, + values=[ + descriptor.EnumValueDescriptor( + name='STATUS_ONLINE', index=0, number=0, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='STATUS_AWAY', index=1, number=1, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='STATUS_FFC', index=2, number=2, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='STATUS_XA', index=3, number=3, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='STATUS_DND', index=4, number=4, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='STATUS_NONE', index=5, number=5, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='STATUS_INVISIBLE', index=6, number=6, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=2796, + serialized_end=2930, +) + + +_PARTICIPANTFLAG = descriptor.EnumDescriptor( + name='ParticipantFlag', + full_name='pbnetwork.ParticipantFlag', + filename=None, + file=DESCRIPTOR, + values=[ + descriptor.EnumValueDescriptor( + name='PARTICIPANT_FLAG_NONE', index=0, number=0, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='PARTICIPANT_FLAG_MODERATOR', index=1, number=1, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='PARTICIPANT_FLAG_CONFLICT', index=2, number=2, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='PARTICIPANT_FLAG_BANNED', index=3, number=4, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='PARTICIPANT_FLAG_NOT_AUTHORIZED', index=4, number=8, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='PARTICIPANT_FLAG_ME', index=5, number=16, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='PARTICIPANT_FLAG_KICKED', index=6, number=32, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='PARTICIPANT_FLAG_ROOM_NOT_FOUND', index=7, number=64, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=2933, + serialized_end=3197, +) + + +CONNECTION_ERROR_NETWORK_ERROR = 0 +CONNECTION_ERROR_INVALID_USERNAME = 1 +CONNECTION_ERROR_AUTHENTICATION_FAILED = 2 +CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE = 3 +CONNECTION_ERROR_NO_SSL_SUPPORT = 4 +CONNECTION_ERROR_ENCRYPTION_ERROR = 5 +CONNECTION_ERROR_NAME_IN_USE = 6 +CONNECTION_ERROR_INVALID_SETTINGS = 7 +CONNECTION_ERROR_CERT_NOT_PROVIDED = 8 +CONNECTION_ERROR_CERT_UNTRUSTED = 9 +CONNECTION_ERROR_CERT_EXPIRED = 10 +CONNECTION_ERROR_CERT_NOT_ACTIVATED = 11 +CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH = 12 +CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH = 13 +CONNECTION_ERROR_CERT_SELF_SIGNED = 14 +CONNECTION_ERROR_CERT_OTHER_ERROR = 15 +CONNECTION_ERROR_OTHER_ERROR = 16 +STATUS_ONLINE = 0 +STATUS_AWAY = 1 +STATUS_FFC = 2 +STATUS_XA = 3 +STATUS_DND = 4 +STATUS_NONE = 5 +STATUS_INVISIBLE = 6 +PARTICIPANT_FLAG_NONE = 0 +PARTICIPANT_FLAG_MODERATOR = 1 +PARTICIPANT_FLAG_CONFLICT = 2 +PARTICIPANT_FLAG_BANNED = 4 +PARTICIPANT_FLAG_NOT_AUTHORIZED = 8 +PARTICIPANT_FLAG_ME = 16 +PARTICIPANT_FLAG_KICKED = 32 +PARTICIPANT_FLAG_ROOM_NOT_FOUND = 64 + + +_WRAPPERMESSAGE_TYPE = descriptor.EnumDescriptor( + name='Type', + full_name='pbnetwork.WrapperMessage.Type', + filename=None, + file=DESCRIPTOR, + values=[ + descriptor.EnumValueDescriptor( + name='TYPE_CONNECTED', index=0, number=1, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_DISCONNECTED', index=1, number=2, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_LOGIN', index=2, number=3, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_LOGOUT', index=3, number=4, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_BUDDY_CHANGED', index=4, number=6, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_BUDDY_REMOVED', index=5, number=7, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_CONV_MESSAGE', index=6, number=8, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_PING', index=7, number=9, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_PONG', index=8, number=10, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_JOIN_ROOM', index=9, number=11, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_LEAVE_ROOM', index=10, number=12, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_PARTICIPANT_CHANGED', index=11, number=13, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_ROOM_NICKNAME_CHANGED', index=12, number=14, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_ROOM_SUBJECT_CHANGED', index=13, number=15, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_VCARD', index=14, number=16, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_STATUS_CHANGED', index=15, number=17, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_BUDDY_TYPING', index=16, number=18, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_BUDDY_STOPPED_TYPING', index=17, number=19, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_BUDDY_TYPED', index=18, number=20, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_AUTH_REQUEST', index=19, number=21, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_ATTENTION', index=20, number=22, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_STATS', index=21, number=23, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_FT_START', index=22, number=24, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_FT_FINISH', index=23, number=25, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_FT_DATA', index=24, number=26, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_FT_PAUSE', index=25, number=27, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_FT_CONTINUE', index=26, number=28, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_EXIT', index=27, number=29, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_BACKEND_CONFIG', index=28, number=30, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_QUERY', index=29, number=31, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_ROOM_LIST', index=30, number=32, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_CONV_MESSAGE_ACK', index=31, number=33, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='TYPE_RAW_XML', index=32, number=34, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=1387, + serialized_end=2099, +) + + +_CONNECTED = descriptor.Descriptor( + name='Connected', + full_name='pbnetwork.Connected', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=29, + serialized_end=54, +) + + +_DISCONNECTED = descriptor.Descriptor( + name='Disconnected', + full_name='pbnetwork.Disconnected', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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( + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=56, + serialized_end=116, +) + + +_LOGIN = descriptor.Descriptor( + name='Login', + full_name='pbnetwork.Login', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=118, + serialized_end=198, +) + + +_LOGOUT = descriptor.Descriptor( + name='Logout', + full_name='pbnetwork.Logout', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=200, + serialized_end=242, +) + + +_BUDDY = descriptor.Descriptor( + name='Buddy', + full_name='pbnetwork.Buddy', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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( + 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( + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=245, + serialized_end=416, +) + + +_CONVERSATIONMESSAGE = descriptor.Descriptor( + name='ConversationMessage', + full_name='pbnetwork.ConversationMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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( + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=419, + serialized_end=588, +) + + +_ROOM = descriptor.Descriptor( + name='Room', + full_name='pbnetwork.Room', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=590, + serialized_end=664, +) + + +_ROOMLIST = descriptor.Descriptor( + name='RoomList', + full_name='pbnetwork.RoomList', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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( + name='name', full_name='pbnetwork.RoomList.name', index=1, + number=2, 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), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=666, + serialized_end=704, +) + + +_PARTICIPANT = descriptor.Descriptor( + name='Participant', + full_name='pbnetwork.Participant', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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( + 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( + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=707, + serialized_end=863, +) + + +_VCARD = descriptor.Descriptor( + name='VCard', + full_name='pbnetwork.VCard', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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( + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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="", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=865, + serialized_end=972, +) + + +_STATUS = descriptor.Descriptor( + name='Status', + full_name='pbnetwork.Status', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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( + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=974, + serialized_end=1062, +) + + +_STATS = descriptor.Descriptor( + name='Stats', + full_name='pbnetwork.Stats', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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( + 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( + 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( + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=1064, + serialized_end=1130, +) + + +_FILE = descriptor.Descriptor( + name='File', + full_name='pbnetwork.File', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + 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( + 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, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=1132, + serialized_end=1221, +) + + +_FILETRANSFERDATA = descriptor.Descriptor( + name='FileTransferData', + full_name='pbnetwork.FileTransferData', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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( + name='data', full_name='pbnetwork.FileTransferData.data', index=1, + number=2, type=12, cpp_type=9, label=2, + has_default_value=False, default_value="", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=1223, + serialized_end=1269, +) + + +_BACKENDCONFIG = descriptor.Descriptor( + name='BackendConfig', + full_name='pbnetwork.BackendConfig', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=1271, + serialized_end=1302, +) + + +_WRAPPERMESSAGE = descriptor.Descriptor( + name='WrapperMessage', + full_name='pbnetwork.WrapperMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + 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( + name='payload', full_name='pbnetwork.WrapperMessage.payload', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value="", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _WRAPPERMESSAGE_TYPE, + ], + options=None, + is_extendable=False, + extension_ranges=[], + 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; + +class Connected(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _CONNECTED + + # @@protoc_insertion_point(class_scope:pbnetwork.Connected) + +class Disconnected(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _DISCONNECTED + + # @@protoc_insertion_point(class_scope:pbnetwork.Disconnected) + +class Login(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _LOGIN + + # @@protoc_insertion_point(class_scope:pbnetwork.Login) + +class Logout(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _LOGOUT + + # @@protoc_insertion_point(class_scope:pbnetwork.Logout) + +class Buddy(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _BUDDY + + # @@protoc_insertion_point(class_scope:pbnetwork.Buddy) + +class ConversationMessage(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _CONVERSATIONMESSAGE + + # @@protoc_insertion_point(class_scope:pbnetwork.ConversationMessage) + +class Room(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _ROOM + + # @@protoc_insertion_point(class_scope:pbnetwork.Room) + +class RoomList(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _ROOMLIST + + # @@protoc_insertion_point(class_scope:pbnetwork.RoomList) + +class Participant(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _PARTICIPANT + + # @@protoc_insertion_point(class_scope:pbnetwork.Participant) + +class VCard(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _VCARD + + # @@protoc_insertion_point(class_scope:pbnetwork.VCard) + +class Status(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _STATUS + + # @@protoc_insertion_point(class_scope:pbnetwork.Status) + +class Stats(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _STATS + + # @@protoc_insertion_point(class_scope:pbnetwork.Stats) + +class File(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _FILE + + # @@protoc_insertion_point(class_scope:pbnetwork.File) + +class FileTransferData(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _FILETRANSFERDATA + + # @@protoc_insertion_point(class_scope:pbnetwork.FileTransferData) + +class BackendConfig(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _BACKENDCONFIG + + # @@protoc_insertion_point(class_scope:pbnetwork.BackendConfig) + +class WrapperMessage(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _WRAPPERMESSAGE + + # @@protoc_insertion_point(class_scope:pbnetwork.WrapperMessage) + +# @@protoc_insertion_point(module_scope) diff --git a/group.py b/group.py new file mode 100644 index 0000000..39bc52e --- /dev/null +++ b/group.py @@ -0,0 +1,8 @@ + +class Group(): + + def __init__(self, id, subject, owner): + self.id = id + self.subject = subject + self.owner = owner + self.participants = { } diff --git a/roster.py b/roster.py new file mode 100644 index 0000000..297bb4d --- /dev/null +++ b/roster.py @@ -0,0 +1,90 @@ + +import logging + +class Number(): + + def __init__(self, number, db): + self.number = number + self.db = db + + cur = self.db.cursor() + cur.execute("SELECT id FROM numbers WHERE number = %s", self.number) + if (cur.rowcount): + self.id = cur.fetchone()[0] + logging.info("sql: found existing number %s (id=%s)", self.number, self.id) + else: + cur.execute("INSERT INTO numbers (number) VALUES (%s)", (self.number)) + self.db.commit() + self.id = cur.lastrowid + logging.info("sql: added new number %s (id=%s)", self.number, self.id) + + def __str__(self): + return "%s (id=%s)" % (self.number, self.id) + + +class Buddy(): + + def __init__(self, owner, number, nick, id, db): + self.owner = owner + self.number = number + self.nick = nick + self.id = id + self.db = db + + def update(self, nick): + self.nick = nick + cur = self.db.cursor() + cur.execute("UPDATE roster SET nick = %s WHERE owner_id = %s AND buddy_id = %s", (self.nick, self.owner.id, self.number.id)) + self.db.commit() + + def delete(self): + cur = self.db.cursor() + cur.execute("DELETE FROM roster WHERE owner_id = %s AND buddy_id = %s", (self.owner.id, self.number.id)) + self.db.commit() + self.id = None + + @staticmethod + def create(owner, number, nick, db): + cur = db.cursor() + cur.execute("INSERT INTO roster (owner_id, buddy_id, nick) VALUES (%s, %s, %s)", (owner.id, number.id, nick)) + db.commit() + + return Buddy(owner, number, nick, cur.lastrowid, db) + + def __str__(self): + return "%s (nick=%s, id=%s)" % (self.number, self.nick, self.id) + +class Roster(): + + def __init__(self, owner, db): + self.db = db + self.owner = Number(owner, db) + self.buddies = { } + + def load(self): + cur = self.db.cursor() + cur.execute("""SELECT + r.id AS id, + nb.number AS number, + r.nick AS nick + FROM roster AS r + LEFT JOIN numbers AS nb + ON r.buddy_id = nb.id + WHERE + r.owner_id = %s""", self.owner.id) + + for i in range(cur.rowcount): + id, number, nick, = cur.fetchone() + buddy = Buddy(self.owner, Number(number, self.db), nick.decode('latin1'), id, self.db) + self.buddies[number] = buddy + logging.info("roster load: %s", buddy) + + def add(self, number, nick): + buddy = Buddy.create(self.owner, Number(number, self.db), nick, self.db) + self.buddies[number] = buddy + logging.info("roster add: %s <- %s", self.owner, buddy) + + def remove(self, number): + logging.info("roster delete: %s", number) + self.buddies[number].delete() + del self.buddies[number] diff --git a/session.py b/session.py new file mode 100644 index 0000000..127b8f1 --- /dev/null +++ b/session.py @@ -0,0 +1,257 @@ +from Yowsup.connectionmanager import YowsupConnectionManager + +from Spectrum2 import protocol_pb2 + +from roster import Roster +from threading import Timer +from group import Group + + +import base64 +import logging +import urllib +import e4u + +class Session: + + def __init__(self, backend, user, legacyName, password, extra, db): + logging.info("new session: %s %s", legacyName, extra) + + password = base64.b64decode(bytes(password.encode('utf-8'))) + + e4u.load() + + self.db = db + self.backend = backend + self.user = user + self.status = protocol_pb2.STATUS_NONE + self.statusMessage = '' + self.legacyName = legacyName + self.groups = { } + self.timer = None + + self.roster = Roster(legacyName, db) + self.frontend = YowsupConnectionManager() + + # Events + self.listen("auth_success", self.onAuthSuccess) + self.listen("auth_fail", self.onAuthFailed) + + self.listen("contact_typing", self.onContactTyping) + self.listen("contact_paused", self.onContactPaused) + + self.listen("presence_updated", self.onPrecenceUpdated) + self.listen("presence_available", self.onPrecenceAvailable) + self.listen("presence_unavailable", self.onPrecenceUnavailable) + + self.listen("message_received", self.onMessageReceived) + self.listen("image_received", self.onMediaReceived) + self.listen("video_received", self.onMediaReceived) + self.listen("audio_received", self.onMediaReceived) + self.listen("location_received", self.onLocationReceived) + self.listen("vcard_received", self.onVcardReceived) + + self.listen("group_messageReceived", self.onGroupMessageReceived) + self.listen("group_gotInfo", self.onGroupGotInfo) + self.listen("group_gotParticipants", self.onGroupGotParticipants) + self.listen("group_subjectReceived", self.onGroupSubjectReceived) + self.listen("notification_groupParticipantAdded", self.onGroupParticipantAdded) + self.listen("notification_groupParticipantRemoved", self.onGroupParticipantRemoved) + self.call("auth_login", (legacyName, password)) + + def __del__(self): + self.call("disconnect", ("logout",)) + + def _softToUni(self, message): + message = unicode(message, "utf-8") + return e4u.translate(message, reverse=False, **e4u.SOFTBANK_TRANSLATE_PROFILE) + + def call(self, method, args = ()): + self.frontend.methodInterface.call(method, args) + + def listen(self, event, callback): + self.frontend.signalInterface.registerListener(event, callback) + + # RequestMethods + def sendTypingStarted(self, buddy): + logging.info("started typing: %s to %s", self.legacyName, buddy) + self.call("typing_send", (buddy + "@s.whatsapp.net",)) + + def sendTypingStopped(self, buddy): + logging.info("stopped typing: %s to %s", self.legacyName, buddy) + self.call("typing_paused", (buddy + "@s.whatsapp.net",)) + + def sendMessage(self, sender, message): + logging.info("message send to %s: %s", sender, message) + message = message.encode("utf-8") + + if ("-" in sender): # group msg + if ("/" in sender): + room, buddy = sender.split("/") + self.call("message_send", (buddy + "@s.whatsapp.net", message)) + else: + room = sender + self.backend.handleMessage(self.user, room, message, "me") # TODO + self.call("message_send", (room + "@g.us", message)) + else: # private msg + buddy = sender + self.call("message_send", (buddy + "@s.whatsapp.net", message)) + + def changeStatus(self, status): + if (status == self.status): return + + logging.info("status changed: %s", status) + self.status = status + if (status == protocol_pb2.STATUS_ONLINE): + self.call("presence_sendAvailable") + elif (status == protocol_pb2.STATUS_FFC): + self.call("presence_sendAvailableForChat") + else: + self.call("presence_sendUnavailable") + + def changeStatusMessage(self, statusMessage): + if (statusMessage == self.statusMessage): return + + logging.info("status message changed: %s", statusMessage) + self.statusMessage = statusMessage + self.call("profile_setStatus", (statusMessage.encode("utf-8"),)) + + def updateBuddy(self, buddy, nick, groups): + if self.roster.buddies.has_key(buddy): + buddy = self.roster.buddies[buddy] + buddy.update(nick) + logging.info("buddy renamed: %s", buddy) + self.call("presence_request", (buddy.number.number + "@s.whatsapp.net",)) + else: + self.roster.add(buddy, nick) + self.call("presence_request", (buddy + "@s.whatsapp.net",)) + self.backend.handleBuddyChanged(self.user, buddy, nick, [], protocol_pb2.STATUS_NONE) + + def removeBuddy(self, buddy): + self.roster.remove(buddy) + + def joinRoom(self, room): + self.call("group_getParticipants", (room + "@g.us",)) + + # EventHandlers + def onAuthSuccess(self, user): + logging.info("auth success: %s", user) + self.backend.handleConnected(self.user) + self.call("ready") + + self.call("group_getGroups", ("participating",)) + + self.roster.load() + for number, buddy in self.roster.buddies.iteritems(): + logging.info("request presence: %s", buddy) + self.call("presence_request", (buddy.number.number + "@s.whatsapp.net",)) + self.backend.handleBuddyChanged(self.user, buddy.number.number, buddy.nick, [], protocol_pb2.STATUS_NONE) + + def onAuthFailed(self, user, reason): + logging.info("auth failed: %s (%s)", user, reason) + self.backend.handleDisconnected(self.user, 0, reason) + + def onMessageReceived(self, messageId, jid, messageContent, timestamp, receiptRequested, pushName, isBroadCast): + buddy = jid.split("@")[0] + logging.info("message received from %s: %s", buddy, messageContent) + self.backend.handleMessage(self.user, buddy, self._softToUni(messageContent), timestamp=timestamp) + if receiptRequested: self.call("message_ack", (jid, messageId)) + + def onMediaReceived(self, messageId, jid, preview, url, size, receiptRequested, isBroadcast): + buddy = jid.split("@")[0] + logging.info("message received from %s: %s", buddy, url) + self.backend.handleMessage(self.user, buddy, url) + if receiptRequested: self.call("message_ack", (jid, messageId)) + + def onLocationReceived(self, messageId, jid, name, preview, latitude, longitude, receiptRequested, isBroadcast): + buddy = jid.split("@")[0] + logging.info("location received from %s: %s, %s", buddy, latitude, longitude) + self.backend.handleMessage(self.user, buddy, "http://maps.google.de?%s" % urllib.urlencode({ "q": "%s %s" % (latitude, longitude) })) + if receiptRequested: self.call("message_ack", (jid, messageId)) + + def onVcardReceived(self, messageId, jid, name, data, receiptRequested, isBroadcast): # TODO + buddy = jid.split("@")[0] + logging.info("vcard received from %s", buddy) + self.backend.handleMessage(self.user, buddy, "Received VCard (not implemented yet)") + if receiptRequested: self.call("message_ack", (jid, messageId)) + + def onContactTyping(self, jid): + buddy = jid.split("@")[0] + logging.info("started typing: %s", buddy) + self.backend.handleBuddyTyping(self.user, buddy) + if (self.timer != None): self.timer.cancel() + + def onContactPaused(self, jid): + buddy = jid.split("@")[0] + logging.info("paused typing: %s", buddy) + self.backend.handleBuddyTyped(self.user, jid.split("@")[0]) + self.timer = Timer(3, self.backend.handleBuddyStoppedTyping, (self.user, buddy)).start() + + def onPrecenceUpdated(self, jid, lastseen): + buddy = jid.split("@")[0] + logging.info("lastseen: %s %d secs ago", buddy, lastseen) + if (lastseen < 60): self.onPrecenceAvailable(jid) + else: self.onPrecenceUnavailable(jid) + + def onPrecenceAvailable(self, jid): + buddy = jid.split("@")[0] + if (self.roster.buddies.has_key(buddy)): + buddy = self.roster.buddies[buddy] + logging.info("is available: %s", buddy) + self.backend.handleBuddyChanged(self.user, buddy.number.number, buddy.nick, [], protocol_pb2.STATUS_ONLINE) + + def onPrecenceUnavailable(self, jid): + buddy = jid.split("@")[0] + if (self.roster.buddies.has_key(buddy)): + buddy = self.roster.buddies[buddy] + logging.info("is unavailable: %s", buddy) + self.backend.handleBuddyChanged(self.user, buddy.number.number, buddy.nick, [], protocol_pb2.STATUS_XA) + + def onGroupGotInfo(self, gjid, owner, subject, subjectOwner, subjectTimestamp, creationTimestamp): + room = gjid.split("@")[0] + + if self.groups.has_key(room): + room = self.groups[room] + room.owner = owner + room.subject = subject + else: + self.groups = Group(room, subject, owner) + + self.backend.handleRoomList([[room, subject]]) + + def onGroupGotParticipants(self, gjid, jids): + room = gjid.split("@")[0] + + for jid in jids: + buddy = jid.split("@")[0] + logging.info("added %s to room %s", buddy, room) + self.backend.handleParticipantChanged(self.user, buddy, room, protocol_pb2.PARTICIPANT_FLAG_NONE, protocol_pb2.STATUS_ONLINE) + + self.backend.handleParticipantChanged(self.user, self.legacyName, room, protocol_pb2.PARTICIPANT_FLAG_ME, protocol_pb2.STATUS_ONLINE) + # TODO check status and moderator + + def onGroupMessageReceived(self, messageId, gjid, jid, messageContent, timestamp, receiptRequested, pushName): + buddy = jid.split("@")[0] + room = gjid.split("@")[0] + + logging.info("group message received in %s from %s: %s", room, buddy, messageContent) + self.backend.handleMessage(self.user, room, self._softToUni(messageContent), buddy, timestamp=timestamp) + if receiptRequested: self.call("message_ack", (gjid, messageId)) + + def onGroupSubjectReceived(self, messageId, gjid, jid, subject, timestamp, receiptRequested): + room = gjid.split("@")[0] + buddy = jid.split("@")[0] + + self.backend.handleSubject(self.user, room, subject, buddy) + if receiptRequested: self.call("subject_ack", (gjid, messageId)) + + def onGroupParticipantAdded(self, gjid, jid, author, timestamp, messageId, receiptRequested): + room = gjid.split("@")[0] + buddy = jid.split("@")[0] + + self.backend.handleParticipantChanged(self.user, buddy, room, protocol_pb2.PARTICIPANT_FLAG_NONE, protocol_pb2.STATUS_ONLINE) +# if receiptRequested: self.call("message_ack", (gjid, messageId)) + + def onGroupParticipantRemoved(gjid, jid, author, timestamp, messageId, receiptRequested): + self.backend.handleParticipantChanged(self.user, buddy, room, protocol_pb2.PARTICIPANT_FLAG_NONE, protocol_pb2.STATUS_NONE) # TODO +# if receiptRequested: self.call("message_ack", (gjid, messageId)) diff --git a/whatsappbackend.py b/whatsappbackend.py new file mode 100644 index 0000000..827c2f5 --- /dev/null +++ b/whatsappbackend.py @@ -0,0 +1,89 @@ +from Spectrum2.backend import SpectrumBackend +from Spectrum2 import protocol_pb2 + +from session import Session + +import logging + +class WhatsAppBackend(SpectrumBackend): + def __init__(self, io, db): + SpectrumBackend.__init__(self) + self.io = io + self.db = db + self.sessions = { } + +# self.handleBackendConfig("features", "muc", "true") +# self.handleBackendConfig("features", "rawxml", "true") + + logging.info("initialized backend") + + # RequestsHandlers + def handleLoginRequest(self, user, legacyName, password, extra): + self.sessions[user] = Session(self, user, legacyName, password, extra, self.db) + + def handleLogoutRequest(self, user, legacyName): + del self.sessions[user] + + def handleMessageSendRequest(self, user, buddy, message, xhtml = ""): + self.sessions[user].sendMessage(buddy, message) + + def handleVCardRequest(self, user, buddy, ID): + # TODO + pass + + def handleVCardUpdatedRequest(self, user, photo, nickname): + # TODO + pass + + def handleJoinRoomRequest(self, user, room, nickname, pasword): + self.sessions[user].joinRoom(room) + + def handleLeaveRoomRequest(self, user, room): + pass + + def handleStatusChangeRequest(self, user, status, statusMessage): + if (len(statusMessage)): + self.sessions[user].changeStatusMessage(statusMessage) + self.sessions[user].changeStatus(status) + + def handleBuddyUpdatedRequest(self, user, buddy, nick, groups): + self.sessions[user].updateBuddy(buddy, nick, groups) + + def handleBuddyRemovedRequest(self, user, buddy, groups): + self.sessions[user].removeBuddy(buddy) + + def handleBuddyBlockToggled(self, user, buddy, blocked): + pass + + def handleTypingRequest(self, user, buddy): + self.sessions[user].sendTypingStarted(buddy) + + def handleTypedRequest(self, user, buddy): + self.sessions[user].sendTypingStopped(buddy) + + def handleStoppedTypingRequest(self, user, buddy): + self.sessions[user].sendTypingStopped(buddy) + + def handleAttentionRequest(self, user, buddy, message): + # TODO + pass + + def handleFTStartRequest(self, user, buddy, fileName, size, ftID): + pass + + def handleFTFinishRequest(self, user, buddy, fileName, size, ftID): + pass + + def handleFTPauseRequest(self, ftID): + pass + + def handleFTContinueRequest(self, ftID): + pass + + def handleRawXmlRequest(self, xml): + pass + + def sendData(self, data): + self.io.sendData(data) + +