aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@frugalware.org>2010-12-29 01:40:21 +0100
committerMiklos Vajna <vmiklos@frugalware.org>2010-12-29 01:40:21 +0100
commitae8cc50eac47c3ff71000ca4b819fc5d238c5031 (patch)
tree671bcc21e3df6cb6154b257460fe03784a1c5baf
parent988d75c36aac56a8a5c4b4530b50cf0c5211a502 (diff)
parentf85837a655ba1ba169e272e5929242b1bd47f51f (diff)
Merge remote branch 'pcrama/windows-skyped2'
-rw-r--r--skype/skyped.py165
1 files changed, 129 insertions, 36 deletions
diff --git a/skype/skyped.py b/skype/skyped.py
index f15245ed..bf35b9ce 100644
--- a/skype/skyped.py
+++ b/skype/skyped.py
@@ -25,7 +25,6 @@ import os
import signal
import locale
import time
-import gobject
import socket
import getopt
import Skype4Py
@@ -33,6 +32,8 @@ import hashlib
from ConfigParser import ConfigParser, NoOptionError
from traceback import print_exception
import ssl
+import select
+import threading
__version__ = "0.1.1"
@@ -41,8 +42,7 @@ def eh(type, value, tb):
if type != KeyboardInterrupt:
print_exception(type, value, tb)
- gobject.MainLoop().quit()
- options.conn.close()
+ if options.conn: options.conn.close()
# shut down client if it's running
try:
skype.skype.Client.Shutdown()
@@ -52,66 +52,104 @@ def eh(type, value, tb):
sys.excepthook = eh
-def input_handler(fd, io_condition):
+def wait_for_lock(lock, timeout_to_print, timeout, msg):
+ start = time.time()
+ locked = lock.acquire(0)
+ while not(locked):
+ time.sleep(0.5)
+ if timeout_to_print and (time.time() - timeout_to_print > start):
+ dprint("%s: Waited %f seconds" % \
+ (msg, time.time() - start))
+ timeout_to_print = False
+ if timeout and (time.time() - timeout > start):
+ dprint("%s: Waited %f seconds, giving up" % \
+ (msg, time.time() - start))
+ return False
+ locked = lock.acquire(0)
+ return True
+
+def input_handler(fd):
global options
+ global skype
if options.buf:
for i in options.buf:
skype.send(i.strip())
options.buf = None
- else:
- try:
- input = fd.recv(1024)
- except Exception, s:
- dprint("Warning, receiving 1024 bytes failed (%s)." % s)
- fd.close()
- return False
- for i in input.split("\n"):
- skype.send(i.strip())
return True
+ else:
+ close_socket = False
+ if wait_for_lock(options.lock, 3, 10, "input_handler"):
+ try:
+ input = fd.recv(1024)
+ options.lock.release()
+ except Exception, s:
+ dprint("Warning, receiving 1024 bytes failed (%s)." % s)
+ fd.close()
+ options.conn = False
+ options.lock.release()
+ return False
+ for i in input.split("\n"):
+ if i.strip() == "SET USERSTATUS OFFLINE":
+ close_socket = True
+ skype.send(i.strip())
+ return not(close_socket)
def skype_idle_handler(skype):
try:
c = skype.skype.Command("PING", Block=True)
skype.skype.SendCommand(c)
+ dprint("... skype pinged")
except Skype4Py.SkypeAPIError, s:
dprint("Warning, pinging Skype failed (%s)." % (s))
return True
def send(sock, txt):
- from time import sleep
+ global options
count = 1
done = False
- while (not done) and (count < 10):
- try:
- sock.send(txt)
- done = True
- except Exception, s:
- count += 1
- dprint("Warning, sending '%s' failed (%s). count=%d" % (txt, s, count))
- sleep(1)
+ while (not done) and (count < 10) and options.conn:
+ if wait_for_lock(options.lock, 3, 10, "socket send"):
+ try:
+ if options.conn: sock.send(txt)
+ options.lock.release()
+ done = True
+ except Exception, s:
+ options.lock.release()
+ count += 1
+ dprint("Warning, sending '%s' failed (%s). count=%d" % (txt, s, count))
+ time.sleep(1)
if not done:
- options.conn.close()
+ if options.conn: options.conn.close()
+ options.conn = False
+ return done
def bitlbee_idle_handler(skype):
+ global options
+ done = False
if options.conn:
try:
e = "PING"
- send(options.conn, "%s\n" % e)
+ done = send(options.conn, "%s\n" % e)
+ dprint("... pinged Bitlbee")
except Exception, s:
dprint("Warning, sending '%s' failed (%s)." % (e, s))
- options.conn.close()
- return True
+ if options.conn: options.conn.close()
+ options.conn = False
+ done = False
+ return done
-def server(host, port):
+def server(host, port, skype):
global options
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((host, port))
sock.listen(1)
- gobject.io_add_watch(sock, gobject.IO_IN, listener)
+ dprint("Waiting for connection...")
+ listener(sock, skype)
-def listener(sock, *args):
+def listener(sock, skype):
global options
+ if not(wait_for_lock(options.lock, 3, 10, "listener")): return False
rawsock, addr = sock.accept()
options.conn = ssl.wrap_socket(rawsock,
server_side=True,
@@ -122,6 +160,7 @@ def listener(sock, *args):
try:
options.conn.handshake()
except Exception:
+ options.lock.release()
dprint("Warning, handshake failed, closing connection.")
return False
ret = 0
@@ -135,15 +174,21 @@ def listener(sock, *args):
except Exception, s:
dprint("Warning, receiving 1024 bytes failed (%s)." % s)
options.conn.close()
+ options.conn = False
+ options.lock.release()
return False
if ret == 2:
dprint("Username and password OK.")
options.conn.send("PASSWORD OK\n")
- gobject.io_add_watch(options.conn, gobject.IO_IN, input_handler)
+ options.lock.release()
+ serverloop(options, skype)
return True
else:
dprint("Username and/or password WRONG.")
options.conn.send("PASSWORD KO\n")
+ options.conn.close()
+ options.conn = False
+ options.lock.release()
return False
def dprint(msg):
@@ -187,16 +232,21 @@ class SkypeApi:
# messages.. so here it is: always use utf-8 then
# everybody will be happy
e = i.encode('UTF-8')
- dprint('<< ' + e)
if options.conn:
+ dprint('<< ' + e)
try:
+ # I called the send function really_send
send(options.conn, e + "\n")
except Exception, s:
dprint("Warning, sending '%s' failed (%s)." % (e, s))
- options.conn.close()
+ if options.conn: options.conn.close()
+ options.conn = False
+ else:
+ dprint('---' + e)
def send(self, msg_text):
if not len(msg_text) or msg_text == "PONG":
+ if msg_text == "PONG": options.last_bitlbee_pong = time.time()
return
try:
encoding = locale.getdefaultlocale()[1]
@@ -252,6 +302,49 @@ Options:
-v --version display version information""" % (self.cfgpath, self.host, self.port)
sys.exit(ret)
+def serverloop(options, skype):
+ timeout = 1; # in seconds
+ skype_ping_period = 5
+ bitlbee_ping_period = 10
+ bitlbee_pong_timeout = 30
+ now = time.time()
+ skype_ping_start_time = now
+ bitlbee_ping_start_time = now
+ options.last_bitlbee_pong = now
+ in_error = []
+ handler_ok = True
+ while (len(in_error) == 0) and handler_ok and options.conn:
+ ready_to_read, ready_to_write, in_error = \
+ select.select([options.conn], [], [options.conn], \
+ timeout)
+ now = time.time()
+ handler_ok = len(in_error) == 0
+ if (len(ready_to_read) == 1) and handler_ok:
+ handler_ok = input_handler(ready_to_read.pop())
+ # don't ping bitlbee/skype if they already received data
+ now = time.time() # allow for the input_handler to take some time
+ bitlbee_ping_start_time = now
+ skype_ping_start_time = now
+ options.last_bitlbee_pong = now
+ if (now - skype_ping_period > skype_ping_start_time) and handler_ok:
+ handler_ok = skype_idle_handler(skype)
+ skype_ping_start_time = now
+ if now - bitlbee_ping_period > bitlbee_ping_start_time:
+ handler_ok = bitlbee_idle_handler(skype)
+ bitlbee_ping_start_time = now
+ if options.last_bitlbee_pong:
+ if (now - options.last_bitlbee_pong) > bitlbee_pong_timeout:
+ dprint("Bitlbee pong timeout")
+ # TODO is following line necessary? Should there be a options.conn.unwrap() somewhere?
+ # options.conn.shutdown()
+ if options.conn: options.conn.close()
+ options.conn = False
+ else:
+ dprint("%f seconds since last PONG" % (now - options.last_bitlbee_pong))
+ else:
+ options.last_bitlbee_pong = now
+ dprint("Serverloop done")
+
if __name__=='__main__':
options = Options()
try:
@@ -316,11 +409,11 @@ if __name__=='__main__':
sys.exit(0)
else:
dprint('skyped is started on port %s' % options.port)
- server(options.host, options.port)
try:
skype = SkypeApi()
except Skype4Py.SkypeAPIError, s:
sys.exit("%s. Are you sure you have started Skype?" % s)
- gobject.timeout_add(2000, skype_idle_handler, skype)
- gobject.timeout_add(60000, bitlbee_idle_handler, skype)
- gobject.MainLoop().run()
+ while 1:
+ options.conn = False
+ options.lock = threading.Lock()
+ server(options.host, options.port, skype)