示例#1
0
    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
示例#2
0
    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
示例#3
0
 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
示例#4
0
 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
示例#5
0
 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)
示例#6
0
 def enable_ping(self):
     cmd = msnp.Command()
     cmd.build("PNG", None)
     self.send_command(cmd, False)
     self.__png_timeout = None
     return False
示例#7
0
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 []
示例#8
0
 def enable_ping(self):
     cmd = msnp.Command()
     cmd.build("PNG", None)
     self.send_command(cmd, False)