Ejemplo n.º 1
0
    def __init__(self, on_message_callback, skypename, password):
        """

        :param callable on_message_callback:
        :return:
        """
        self.on_message_callback = on_message_callback

        self.skypename = skypename
        self.login_instance = PyLogin(skypename, password)  # TODO: @kuptsov - maybe move to the top of `connect` method
Ejemplo n.º 2
0
class Connection(object):
    """
    Connection to Skype server.
    """

    registration = ''

    on_message_callback = None
    login_instance = None
    skypename = None

    def __init__(self, on_message_callback, skypename, password):
        """

        :param callable on_message_callback:
        :return:
        """
        self.on_message_callback = on_message_callback

        self.skypename = skypename
        self.login_instance = PyLogin(skypename, password)  # TODO: @kuptsov - maybe move to the top of `connect` method

    def connect(self, host='s.gateway.messenger.live.com', port=443):
        print "Connecting to %s:%d" % (host, port)
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        self.ssl_sock = ssl.wrap_socket(s)
        self.ssl_sock.connect((host, port))
        self.sock_file = self.ssl_sock.makefile()

        self.cnt = 0
        self.queue = Queue.Queue(-1)
        self.pending_requests = { }

        self.sender = threading.Thread(target=self.sender_loop)
        self.sender.setDaemon(True)
        self.sender.start()

        self.receiver = threading.Thread(target=self.receiver_loop)
        self.receiver.setDaemon(True)
        self.receiver.start()

        self.start_handshake()

    def shutdown(self):
        self.ssl_sock.close()
        self.send(None, None, None, None)

    def send(self, cmd, url, body, callback=None):
        if callback == None:
            callback = self.nop
        self.queue.put((cmd, url, body, callback))

    def sender_loop(self):
        global cnt
        while True:
            try:
                cmd, url, body, callback = self.queue.get(True, 500)
                if cmd == None:
                    break
                self.cnt = self.cnt + 1
                self.pending_requests[self.cnt] = callback
                p = "%s %d %s %d\r\n%s" % (cmd, self.cnt, url, len(body), body)
                print ">>>>>>> %d pending requests" % len(self.pending_requests)
                print p
                self.ssl_sock.send(p)
            except Queue.Empty:
                self.send("PNG", "CON", self._reg())

    def handle(self, cmd, cnt, url, hdr, body):
        print '\n\n\ngot MESSAGE\n\n\n'
        print "inbound " + cmd
        if cmd == 'SDG':
            self.on_message_callback(body)

    def receiver_loop(self):
        while True:
            l = self.sock_file.readline()
            print "<<<<<<<"
            print l
            cmd, cnt, url, bsz = l.split()
            cnt = int(cnt)
            body = self.sock_file.read(int(bsz))
            print body, '-|||||||||'
            if body[:2] == "\r\n":
                hdr = dict()
                body = body[2:]
            else:
                cut_here = body.find("\r\n\r\n")
                hdr = body[:cut_here]
                body = body[cut_here+4:]
                hdr = hdr.split("\r\n")
                if hdr[0] == "":
                    hdr = hdr[1:]
                hdr = dict(x.split(": ") for x in hdr)

            if "Set-Registration" in hdr:
                self.registration = hdr["Set-Registration"]

            if cmd == "XFR":
                self.handle_XFR(cmd, url, hdr, body)
                break

            if cnt:
                callback = self.pending_requests[cnt]
                callback(cmd, url, hdr, body)
                del self.pending_requests[cnt]
            else:
                self.handle(cmd, cnt, url, hdr, body)

    def nop(self, cmd, url, hdr, body):
        print "ignoring reply " + cmd

    def handle_XFR(self, cmd, url, hdr, body):
        self.shutdown()

        root = etree.parse(StringIO(body))
        target = root.xpath("/xfr/target")[0].text
        target = target.split(':')
        self.connect(target[0], int(target[1]))

    def handle_CNT_reply(self, cmd, url, hdr, body):
        assert cmd == "CNT"

        root=etree.parse(StringIO(body))
        nonce=root.xpath("/connect-response/nonce")[0].text

        self.send("ATH", "CON\USER", "\r\n<user><uic>" + self.login_instance.uic(nonce, "WS-SecureConversationSESSION KEY TOKEN") + "</uic><id>" + self.skypename + "</id></user>\r\n", self.handle_ATH_reply);

    def handle_ATH_reply(self, cmd, url, hdr, body):
        assert cmd == "ATH"

        self.send("BND", "CON\MSGR", "\r\n<msgr><ver>2</ver><altVersions><ver>1</ver></altVersions><client><name>Skype</name><ver>2/4.3.0.37/172</ver></client><epid>" + EPID + "</epid></msgr>\r\n", self.handle_BND_reply)


    def handle_BND_reply(self, cmd, url, hdr, body):
        assert cmd == "BND"

        root=etree.parse(StringIO(body))
        nonce=root.xpath("/msgr-response/nonce")[0].text

        rsp=funnydigest(nonce)

        self.send("PUT", "MSGR\CHALLENGE", self._reg() + "<challenge><appId>PROD0090YUAUV{2B</appId><response>" + rsp + "</response></challenge>\r\n")

        self.send("PUT", "MSGR\PRESENCE", self._reg() + self._routing(self.skypename) + RELIABILITY + self._publication())

        self.send("PUT", "MSGR\SUBSCRIPTIONS", self._reg() + "<subscribe><presence><buddies><all /></buddies></presence><messaging><im /><conversations /></messaging></subscribe>")

        self.send("GET", "MSGR\RECENTCONVERSATIONS", self._reg() + "<recentconversations><pagesize>100</pagesize></recentconversations>")

    def start_handshake(self):
        self.send("CNT", "CON", "\r\n<connect><ver>2</ver><agent><os>Linux</os><osVer>Linux 3.11.0-12-gene</osVer><proc>2 1800 I-586-6-15-13 Intel Core2</proc><lcid>en-US</lcid><country>nz</country></agent></connect>\r\n", self.handle_CNT_reply)

    def msgr(self, body):
        self.send("SDG", "MSGR", self._reg() + body)

    def wrapped_send(self, target_skypename, message):
        self.msgr( self._routing(target_skypename) + RELIABILITY + messaging_rich(message) )

    def _reg(self):
        return "Registration: " + self.registration + "\r\n\r\n"

    def _publication(self, hdr={}):
        defaults = {
            'Uri': '/user',
            'Content-Type': 'application/user+xml'
        }
        defaults.update(hdr)
        body='<user><sep n="PE" epid="{' + EPID + '}"><VER>2/4.3.0.37/172</VER><TYP>14</TYP><Capabilities>0:0</Capabilities></sep><s n="IM"><Status>NLN</Status></s><sep n="IM" epid="{' + EPID + '}"><Capabilities>0:4194560</Capabilities></sep><sep n="PD" epid="{' + EPID + '}"><EpName>ubuntu</EpName><ClientType>14</ClientType></sep><s n="SKP"><Mood/><Skypename>' + self.skypename + '</Skypename></s><sep n="SKP" epid="{' + EPID + '}"><NodeInfo>x8b24a10d59cbd00e01c0a80137d4126fdd4d8f9c4cb6308989d4120801</NodeInfo><Version>24</Version><Seamless>true</Seamless></sep></user>'
        return entity("Publication: 1.0", defaults, body)

    def _routing(self, to, hdr={}):
        """

        :param to:
        :param hdr:
        :return:
        """
        defaults = {
            'To': '8:' + to,
            'From': "8:" + self.skypename + ";epid={" + EPID + "}"
        }
        defaults.update(hdr)
        return entity("Routing: 1.0", defaults)