Changes in / [ae8cc50:988d75c]


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • skype/skyped.py

    rae8cc50 r988d75c  
    2626import locale
    2727import time
     28import gobject
    2829import socket
    2930import getopt
     
    3334from traceback import print_exception
    3435import ssl
    35 import select
    36 import threading
    3736
    3837__version__ = "0.1.1"
     
    4342        if type != KeyboardInterrupt:
    4443                print_exception(type, value, tb)
    45         if options.conn: options.conn.close()
     44        gobject.MainLoop().quit()
     45        options.conn.close()
    4646        # shut down client if it's running
    4747        try:
     
    5353sys.excepthook = eh
    5454
    55 def wait_for_lock(lock, timeout_to_print, timeout, msg):
    56         start = time.time()
    57         locked = lock.acquire(0)
    58         while not(locked):
    59                 time.sleep(0.5)
    60                 if timeout_to_print and (time.time() - timeout_to_print > start):
    61                         dprint("%s: Waited %f seconds" % \
    62                                         (msg, time.time() - start))
    63                         timeout_to_print = False
    64                 if timeout and (time.time() - timeout > start):
    65                         dprint("%s: Waited %f seconds, giving up" % \
    66                                         (msg, time.time() - start))
    67                         return False
    68                 locked = lock.acquire(0)
    69         return True
    70 
    71 def input_handler(fd):
    72         global options
    73         global skype
     55def input_handler(fd, io_condition):
     56        global options
    7457        if options.buf:
    7558                for i in options.buf:
    7659                        skype.send(i.strip())
    7760                options.buf = None
     61        else:
     62                try:
     63                        input = fd.recv(1024)
     64                except Exception, s:
     65                        dprint("Warning, receiving 1024 bytes failed (%s)." % s)
     66                        fd.close()
     67                        return False
     68                for i in input.split("\n"):
     69                        skype.send(i.strip())
    7870                return True
    79         else:
    80                 close_socket = False
    81                 if wait_for_lock(options.lock, 3, 10, "input_handler"):
    82                         try:
    83                                         input = fd.recv(1024)
    84                                         options.lock.release()
    85                         except Exception, s:
    86                                 dprint("Warning, receiving 1024 bytes failed (%s)." % s)
    87                                 fd.close()
    88                                 options.conn = False
    89                                 options.lock.release()
    90                                 return False
    91                         for i in input.split("\n"):
    92                                 if i.strip() == "SET USERSTATUS OFFLINE":
    93                                         close_socket = True
    94                                 skype.send(i.strip())
    95                 return not(close_socket)
    9671
    9772def skype_idle_handler(skype):
     
    9974                c = skype.skype.Command("PING", Block=True)
    10075                skype.skype.SendCommand(c)
    101                 dprint("... skype pinged")
    10276        except Skype4Py.SkypeAPIError, s:
    10377                dprint("Warning, pinging Skype failed (%s)." % (s))
     
    10579
    10680def send(sock, txt):
    107         global options
     81        from time import sleep
    10882        count = 1
    10983        done = False
    110         while (not done) and (count < 10) and options.conn:
    111                 if wait_for_lock(options.lock, 3, 10, "socket send"):
    112                         try:
    113                                 if options.conn: sock.send(txt)
    114                                 options.lock.release()
    115                                 done = True
    116                         except Exception, s:
    117                                 options.lock.release()
    118                                 count += 1
    119                                 dprint("Warning, sending '%s' failed (%s). count=%d" % (txt, s, count))
    120                                 time.sleep(1)
     84        while (not done) and (count < 10):
     85                try:
     86                        sock.send(txt)
     87                        done = True
     88                except Exception, s:
     89                        count += 1
     90                        dprint("Warning, sending '%s' failed (%s). count=%d" % (txt, s, count))
     91                        sleep(1)
    12192        if not done:
    122                 if options.conn: options.conn.close()
    123                 options.conn = False
    124         return done
     93                options.conn.close()
    12594
    12695def bitlbee_idle_handler(skype):
    127         global options
    128         done = False
    12996        if options.conn:
    13097                try:
    13198                        e = "PING"
    132                         done = send(options.conn, "%s\n" % e)
    133                         dprint("... pinged Bitlbee")
     99                        send(options.conn, "%s\n" % e)
    134100                except Exception, s:
    135101                        dprint("Warning, sending '%s' failed (%s)." % (e, s))
    136                         if options.conn: options.conn.close()
    137                         options.conn = False
    138                         done = False
    139         return done
    140 
    141 def server(host, port, skype):
     102                        options.conn.close()
     103        return True
     104
     105def server(host, port):
    142106        global options
    143107        sock = socket.socket()
     
    145109        sock.bind((host, port))
    146110        sock.listen(1)
    147         dprint("Waiting for connection...")
    148         listener(sock, skype)
    149 
    150 def listener(sock, skype):
    151         global options
    152         if not(wait_for_lock(options.lock, 3, 10, "listener")): return False
     111        gobject.io_add_watch(sock, gobject.IO_IN, listener)
     112
     113def listener(sock, *args):
     114        global options
    153115        rawsock, addr = sock.accept()
    154116        options.conn = ssl.wrap_socket(rawsock,
     
    161123                        options.conn.handshake()
    162124                except Exception:
    163                         options.lock.release()
    164125                        dprint("Warning, handshake failed, closing connection.")
    165126                        return False
     
    175136                dprint("Warning, receiving 1024 bytes failed (%s)." % s)
    176137                options.conn.close()
    177                 options.conn = False
    178                 options.lock.release()
    179138                return False
    180139        if ret == 2:
    181140                dprint("Username and password OK.")
    182141                options.conn.send("PASSWORD OK\n")
    183                 options.lock.release()
    184                 serverloop(options, skype)
     142                gobject.io_add_watch(options.conn, gobject.IO_IN, input_handler)
    185143                return True
    186144        else:
    187145                dprint("Username and/or password WRONG.")
    188146                options.conn.send("PASSWORD KO\n")
    189                 options.conn.close()
    190                 options.conn = False
    191                 options.lock.release()
    192147                return False
    193148
     
    233188                        # everybody will be happy
    234189                        e = i.encode('UTF-8')
     190                        dprint('<< ' + e)
    235191                        if options.conn:
    236                                 dprint('<< ' + e)
    237192                                try:
    238                                         # I called the send function really_send
    239193                                        send(options.conn, e + "\n")
    240194                                except Exception, s:
    241195                                        dprint("Warning, sending '%s' failed (%s)." % (e, s))
    242                                         if options.conn: options.conn.close()
    243                                         options.conn = False
    244                         else:
    245                                 dprint('---' + e)
     196                                        options.conn.close()
    246197
    247198        def send(self, msg_text):
    248199                if not len(msg_text) or msg_text == "PONG":
    249                         if msg_text == "PONG": options.last_bitlbee_pong = time.time()
    250200                        return
    251201                try:
     
    302252        -v      --version       display version information""" % (self.cfgpath, self.host, self.port)
    303253                sys.exit(ret)
    304 
    305 def serverloop(options, skype):
    306         timeout = 1; # in seconds
    307         skype_ping_period = 5
    308         bitlbee_ping_period = 10
    309         bitlbee_pong_timeout = 30
    310         now = time.time()
    311         skype_ping_start_time = now
    312         bitlbee_ping_start_time = now
    313         options.last_bitlbee_pong = now
    314         in_error = []
    315         handler_ok = True
    316         while (len(in_error) == 0) and handler_ok and options.conn:
    317                 ready_to_read, ready_to_write, in_error = \
    318                         select.select([options.conn], [], [options.conn], \
    319                                 timeout)
    320                 now = time.time()
    321                 handler_ok = len(in_error) == 0
    322                 if (len(ready_to_read) == 1) and handler_ok:
    323                         handler_ok = input_handler(ready_to_read.pop())
    324                         # don't ping bitlbee/skype if they already received data
    325                         now = time.time() # allow for the input_handler to take some time
    326                         bitlbee_ping_start_time = now
    327                         skype_ping_start_time = now
    328                         options.last_bitlbee_pong = now
    329                 if (now - skype_ping_period > skype_ping_start_time) and handler_ok:
    330                         handler_ok = skype_idle_handler(skype)
    331                         skype_ping_start_time = now
    332                 if now - bitlbee_ping_period > bitlbee_ping_start_time:
    333                         handler_ok = bitlbee_idle_handler(skype)
    334                         bitlbee_ping_start_time = now
    335                         if options.last_bitlbee_pong:
    336                                 if (now - options.last_bitlbee_pong) > bitlbee_pong_timeout:
    337                                         dprint("Bitlbee pong timeout")
    338                                         # TODO is following line necessary? Should there be a options.conn.unwrap() somewhere?
    339                                         # options.conn.shutdown()
    340                                         if options.conn: options.conn.close()
    341                                         options.conn = False
    342                                 else:
    343                                         dprint("%f seconds since last PONG" % (now - options.last_bitlbee_pong))
    344                         else:
    345                                 options.last_bitlbee_pong = now
    346         dprint("Serverloop done")
    347254
    348255if __name__=='__main__':
     
    410317        else:
    411318                dprint('skyped is started on port %s' % options.port)
     319        server(options.host, options.port)
    412320        try:
    413321                skype = SkypeApi()
    414322        except Skype4Py.SkypeAPIError, s:
    415323                sys.exit("%s. Are you sure you have started Skype?" % s)
    416         while 1:
    417                 options.conn = False
    418                 options.lock = threading.Lock()
    419                 server(options.host, options.port, skype)
     324        gobject.timeout_add(2000, skype_idle_handler, skype)
     325        gobject.timeout_add(60000, bitlbee_idle_handler, skype)
     326        gobject.MainLoop().run()
Note: See TracChangeset for help on using the changeset viewer.