def send_command_ex(self, command, arguments=(), payload=None, increment=True, callback=None, *cb_args): """ Builds a command object then send it to the server. @param command: the command name, must be a 3 letters uppercase string. @type command: string @param arguments: command arguments @type arguments: (string, ...) @param payload: payload data @type payload: string @param increment: if False, the transaction ID is not incremented @type increment: bool @param callback: callback to be used when the command has been transmitted @type callback: callable @param cb_args: callback arguments @type cb_args: tuple """ cmd = msnp.Command() cmd.build(command, self._transaction_id, payload, *arguments) self.send_command(cmd, increment, callback, *cb_args) return cmd
def send_command_ex(self, command, arguments=(), payload=None, increment=True, callback=None, errback=None): """ Builds a command object then send it to the server. @param command: the command name, must be a 3 letters uppercase string. @type command: string @param arguments: command arguments @type arguments: (string, ...) @param payload: payload data @type payload: string @param increment: if False, the transaction ID is not incremented @type increment: bool @param callback: callback once transmission of command succeeded @type callback: tuple (callable, args) @param errback: callback if transmission of command failed @type errback: tuple (callable, args) """ cmd = msnp.Command() cmd.build(command, self._transaction_id, payload, *arguments) self.send_command(cmd, increment, callback, errback) return cmd
def __on_received(self, receiver, chunk): if self.__pending_command is None: cmd = msnp.Command() try: cmd.parse(chunk) except Exception, err: logger.error("Received invalid command, closing connection") self.lose_connection(err) return if cmd.payload_len > 0: self.__pending_command = cmd self._receiver.delimiter = cmd.payload_len return # wait for payload
def __extract_command(self, data): first, rest = data.split('\r\n', 1) cmd = msnp.Command() cmd.parse(first.strip()) if cmd.name in msnp.Command.INCOMING_PAYLOAD or \ (cmd.is_error() and (cmd.arguments is not None) and len(cmd.arguments) > 0): try: payload_len = int(cmd.arguments[-1]) except: payload_len = 0 if payload_len > 0: cmd.payload = rest[:payload_len].strip() logger.debug('<<< ' + unicode(cmd)) self.emit("command-received", cmd) return rest[payload_len:] else: logger.debug('<<< ' + unicode(cmd)) self.emit("command-received", cmd) return rest
def __on_received(self, receiver, chunk): cmd = msnp.Command() if self.__pending_chunk: chunk = self.__pending_chunk + "\r\n" + chunk cmd.parse(chunk) self.__pending_chunk = None self._receiver.delimiter = "\r\n" else: cmd.parse(chunk) if cmd.name in msnp.Command.INCOMING_PAYLOAD or \ (cmd.is_error() and (cmd.arguments is not None) and len(cmd.arguments) > 0): try: payload_len = int(cmd.arguments[-1]) except: payload_len = 0 if payload_len > 0: self.__pending_chunk = chunk self._receiver.delimiter = payload_len return logger.debug('<<< ' + unicode(cmd)) if cmd.name == 'QNG': self.__handle_ping_reply(cmd) else: self.emit("command-received", cmd)
def enable_ping(self): cmd = msnp.Command() cmd.build("PNG", None) self.send_command(cmd, False) self.__png_timeout = None return False
class HTTPPollConnection(BaseTransport): """Implements an HTTP polling transport, basically it encapsulates the MSNP commands into an HTTP request, and receive responses by polling a specific url""" def __init__(self, server, server_type=ServerType.NOTIFICATION, proxies={}): self._target_server = server if server_type == ServerType.SWITCHBOARD: server = (server[0], 80) else: server = ("gateway.messenger.hotmail.com", 80) BaseTransport.__init__(self, server, server_type, proxies) self._setup_transport(server[0], server[1], proxies) self._command_queue = [] self._waiting_for_response = False # are we waiting for a response self._polling_source_id = None self._session_id = None self.__error = None def _setup_transport(self, host, port, proxies): handles = [] transport = gnet.protocol.HTTP(host, port, proxies) handles.append( transport.connect("response-received", self.__on_received)) handles.append(transport.connect("request-sent", self.__on_sent)) handles.append(transport.connect("error", self.__on_error)) self._transport_handles = handles self._transport = transport def establish_connection(self): logger.debug('<-> Connecting to %s:%d' % self.server) self._polling_source_id = gobject.timeout_add_seconds(5, self._poll) self.emit("connection-success") def lose_connection(self, error=None): if self._polling_source_id: gobject.source_remove(self._polling_source_id) self._polling_source_id = None if error is not None: self.emit("connection-failure", error) elif not self.__error: self.emit("connection-lost", None) self.__error = None def reset_connection(self, server=None): if server: self._target_server = server self.emit("connection-reset") def change_gateway(self, server): if self.server == server: return logger.debug('<-> Changing gateway to %s:%d' % server) self.server = server for handle in self._transport_handles: self._transport.disconnect(handle) self._transport.close() self._setup_transport(server[0], server[1], self.proxies) def send_command(self, command, increment=True, callback=None, errback=None): self._command_queue.append((command, increment, callback, errback)) self._send_command() def _send_command(self): if len(self._command_queue) == 0 or self._waiting_for_response: return command, increment = self._command_queue[0][0:2] resource = "/gateway/gateway.dll" headers = { "Accept": "*/*", "Accept-Language": "en-us", #"User-Agent": "MSMSGS", "Connection": "Keep-Alive", "Pragma": "no-cache", "Content-Type": "application/x-msn-messenger", "Proxy-Connection": "Keep-Alive" } str_command = str(command) if self._session_id is None: resource += "?Action=open&Server=%s&IP=%s" % ( self.server_type, self._target_server[0]) elif command == None: # Polling the server for queued messages resource += "?Action=poll&SessionID=%s" % self._session_id str_command = "" else: resource += "?SessionID=%s" % self._session_id self._transport.request(resource, headers, str_command, "POST") self._waiting_for_response = True if command is not None: logger.debug('>>> ' + unicode(command)) if increment: self._increment_transaction_id() def _poll(self): if not self._waiting_for_response: self.send_command(None) return True def __on_error(self, transport, error): self.__error = error self.emit("connection-lost", error) self.lose_connection() def __on_received(self, transport, http_response): if 'X-MSN-Messenger' in http_response.headers: data = http_response.headers['X-MSN-Messenger'].split(";") for elem in data: key, value = [p.strip() for p in elem.split('=', 1)] if key == 'SessionID': self._session_id = value elif key == 'GW-IP': self.change_gateway((value, self.server[1])) elif key == 'Session' and value == 'close': #self.lose_connection() pass self._waiting_for_response = False commands = http_response.body while len(commands) != 0: commands = self.__extract_command(commands) self._send_command() def __on_sent(self, transport, http_request): if len(self._command_queue) == 0: return command, increment, callback, errback = self._command_queue.pop(0) if command is not None: run(callback) self.emit("command-sent", command) def __extract_command(self, data): try: first, rest = data.split('\r\n', 1) except ValueError, err: logger.warning('Unable to extract a command: %s' % data) self.lose_connection(err) return [] try: cmd = msnp.Command() cmd.parse(first.strip()) if cmd.payload_len > 0: cmd.payload = rest[:cmd.payload_len].strip() rest = rest[cmd.payload_len:] except Exception, err: logger.error("Received invalid command, closing connection") self.lose_connection(err) return []
def enable_ping(self): cmd = msnp.Command() cmd.build("PNG", None) self.send_command(cmd, False)