[tuxdroid-svn] r5580 - in software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py
Status: Beta
Brought to you by:
ks156
|
From: jerome <c2m...@c2...> - 2009-10-01 14:31:01
|
Author: jerome
Date: 2009-10-01 14:25:22 +0200 (Thu, 01 Oct 2009)
New Revision: 5580
Added:
software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/
software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/__init__.py
software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/darwin.py
software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/faked_dbus.py
software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/posix.py
software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/posix_dbus.py
software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/posix_x11.py
software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/windows.py
Log:
* Added new api transport package.
Added: software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/__init__.py
===================================================================
--- software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/__init__.py (rev 0)
+++ software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/__init__.py 2009-10-01 12:25:22 UTC (rev 5580)
@@ -0,0 +1,240 @@
+"""
+Low-level Skype API definitions.
+
+This subpackage imports one of the:
+
+- `Skype4Py.api.darwin`
+- `Skype4Py.api.posix`
+- `Skype4Py.api.windows`
+
+modules based on the current platform.
+
+Name of the imported module in available in the `platform` variable.
+
+The modules implement the low-level Skype API and define options
+for the `Skype.__init__` constructor.
+"""
+__docformat__ = 'restructuredtext en'
+
+
+import sys
+import threading
+import logging
+
+from Skype4Py.utils import *
+from Skype4Py.enums import apiAttachUnknown
+from Skype4Py.errors import SkypeAPIError
+
+
+__all__ = ['Command', 'SkypeAPINotifier', 'SkypeAPI']
+
+
+DEFAULT_PROTOCOL = 5
+DEFAULT_FRIENDLYNAME = u'Skype4Py'
+DEFAULT_TIMEOUT = 30000
+
+
+class Command(object):
+ """Represents an API command. Use `Skype.Command` to instantiate.
+
+ To send a command to Skype, use `Skype.SendCommand`.
+ """
+
+ def __init__(self, Command, Expected=u'', Blocking=False, Timeout=DEFAULT_TIMEOUT, Id=-1):
+ """Use `Skype.Command` to instantiate the object instead of doing it directly.
+ """
+
+ self.Blocking = Blocking
+ """If set to True, `Skype.SendCommand` will block until the reply is received.
+
+ :type: bool"""
+
+ self.Command = tounicode(Command)
+ """Command string.
+
+ :type: unicode"""
+
+ self.Expected = tounicode(Expected)
+ """Expected reply.
+
+ :type: unicode"""
+
+ self.Id = Id
+ """Command Id.
+
+ :type: int"""
+
+ self.Reply = u''
+ """Reply after the command has been sent and Skype has replied.
+
+ :type: unicode"""
+
+ self.Timeout = Timeout
+ """Timeout if Blocking == True.
+
+ :type: int"""
+
+ def __repr__(self):
+ return '<%s with Command=%s, Blocking=%s, Reply=%s, Id=%s>' % \
+ (object.__repr__(self)[1:-1], repr(self.Command), self.Blocking, repr(self.Reply), self.Id)
+
+ def timeout2float(self):
+ """A wrapper for `api.timeout2float` function. Returns the converted
+ `Timeout` property.
+ """
+ return timeout2float(self.Timeout)
+
+
+class SkypeAPINotifier(object):
+ def attachment_changed(self, status):
+ pass
+
+ def notification_received(self, notification):
+ pass
+
+ def sending_command(self, command):
+ pass
+
+ def reply_received(self, command):
+ pass
+
+
+class SkypeAPIBase(threading.Thread):
+ def __init__(self):
+ threading.Thread.__init__(self, name='Skype4Py API thread')
+ self.setDaemon(True)
+ if not hasattr(self, 'logger'):
+ # Create a logger if the subclass hasn't done it already.
+ self.logger = logging.getLogger('Skype4Py.api.SkypeAPIBase')
+ self.friendly_name = DEFAULT_FRIENDLYNAME
+ self.protocol = DEFAULT_PROTOCOL
+ self.commands = {}
+ # This lock is the main mechanism to make Skype4Py thread-safe.
+ self.rlock = threading.RLock()
+ self.notifier = SkypeAPINotifier()
+ self.attachment_status = apiAttachUnknown
+ self.logger.info('opened')
+
+ def _not_implemented(self):
+ raise SkypeAPIError('Function not implemented')
+
+ def set_notifier(self, notifier):
+ self.notifier = notifier
+
+ def push_command(self, command):
+ self.acquire()
+ try:
+ if command.Id < 0:
+ command.Id = 0
+ while command.Id in self.commands:
+ command.Id += 1
+ elif command.Id in self.commands:
+ raise SkypeAPIError('Command Id conflict')
+ self.commands[command.Id] = command
+ finally:
+ self.release()
+
+ def pop_command(self, id_):
+ self.acquire()
+ try:
+ try:
+ return self.commands.pop(id_)
+ except KeyError:
+ return None
+ finally:
+ self.release()
+
+ def acquire(self):
+ self.rlock.acquire()
+
+ def release(self):
+ self.rlock.release()
+
+ def close(self):
+ self.logger.info('closed')
+
+ def set_friendly_name(self, friendly_name):
+ self.friendly_name = friendly_name
+
+ def set_attachment_status(self, attachment_status):
+ if attachment_status != self.attachment_status:
+ self.logger.info('attachment: %s', attachment_status)
+ self.attachment_status = attachment_status
+ self.notifier.attachment_changed(attachment_status)
+
+ def attach(self, timeout, wait=True):
+ self._not_implemented()
+
+ def is_running(self):
+ self._not_implemented()
+
+ def startup(self, minimized, nosplash):
+ self._not_implemented()
+
+ def shutdown(self):
+ self._not_implemented()
+
+ def send_command(self, command):
+ self._not_implemented()
+
+ def security_context_enabled(self, context):
+ self._not_implemented()
+
+ def enable_security_context(self, context):
+ self._not_implemented()
+
+ def allow_focus(self, timeout):
+ pass
+
+
+def timeout2float(timeout):
+ """Converts a timeout expressed in milliseconds or seconds into a timeout expressed
+ in seconds using a floating point number.
+
+ :Parameters:
+ timeout : int, long or float
+ The input timeout. Assumed to be expressed in number of
+ milliseconds if the type is int or long. For float, assumed
+ to be a number of seconds (or fractions thereof).
+
+ :return: The timeout expressed in number of seconds (or fractions thereof).
+ :rtype: float
+ """
+ if isinstance(timeout, float):
+ return timeout
+ return timeout / 1000.0
+
+
+def finalize_opts(opts):
+ """Convinient function called after popping all options from a dictionary.
+ If there are any items left, a TypeError exception is raised listing all
+ unexpected keys in the error message.
+ """
+ if opts:
+ raise TypeError('Unexpected option(s): %s' % ', '.join(opts.keys()))
+
+
+# Select appropriate low-level Skype API module
+if getattr(sys, 'skype4py_setup', False):
+ # dummy for the setup.py run
+ SkypeAPI = lambda **Options: None
+ platform = ''
+elif sys.platform.startswith('win'):
+ from windows import SkypeAPI
+ platform = 'windows'
+elif sys.platform == 'darwin':
+ from darwin import SkypeAPI
+ platform = 'darwin'
+else:
+ from posix import SkypeAPI
+ platform = 'posix'
+
+
+# Note. py2exe will include the darwin but not the posix module. This seems to be the case
+# solely because of the "posix" name. It might be a bug in py2exe or modulefinder caused
+# by a failed attempt to import a "posix" module by the os module. If this is encountered
+# during modulefinder scanning, the Skype4Py.api.posix is simply ignored.
+#
+# That being said ideally we would like to exclude both of them but I couldn't find a way
+# to cause py2exe to skip them. I think py2exe should expose mechanisms to cooperate with
+# extension modules aware of its existence.
Added: software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/darwin.py
===================================================================
--- software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/darwin.py (rev 0)
+++ software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/darwin.py 2009-10-01 12:25:22 UTC (rev 5580)
@@ -0,0 +1,475 @@
+"""
+Low level *Skype for Mac OS X* interface implemented using *Carbon
+distributed notifications*. Uses direct *Carbon*/*CoreFoundation*
+calls through the *ctypes* module.
+
+This module handles the options that you can pass to
+`Skype.__init__` for *Mac OS X* machines.
+
+- ``RunMainLoop`` (bool) - If set to False, Skype4Py won't start the Carbon event
+ loop. Otherwise it is started in a separate thread. The loop must be running for
+ Skype4Py events to work properly. Set this option to False if you plan to run the
+ loop yourself or if, for example, your GUI framework does it for you.
+
+Thanks to **Eion Robb** for reversing *Skype for Mac* API protocol.
+"""
+__docformat__ = 'restructuredtext en'
+
+
+import sys
+from ctypes import *
+from ctypes.util import find_library
+import threading
+import time
+import logging
+
+from Skype4Py.api import Command, SkypeAPIBase, \
+ timeout2float, finalize_opts
+from Skype4Py.errors import SkypeAPIError
+from Skype4Py.enums import *
+
+
+__all__ = ['SkypeAPI']
+
+
+class CFType(object):
+ """Fundamental type for all CoreFoundation types.
+
+ :see: http://developer.apple.com/documentation/CoreFoundation/Reference/CFTypeRef/
+ """
+
+ def __init__(self, init):
+ self.owner = True
+ if isinstance(init, CFType):
+ # copy the handle and increase the use count
+ self.handle = init.get_handle()
+ coref.CFRetain(self)
+ elif isinstance(init, c_void_p):
+ self.handle = init
+ else:
+ raise TypeError('illegal init type: %s' % type(init))
+
+ @classmethod
+ def from_handle(cls, handle):
+ if isinstance(handle, (int, long)):
+ handle = c_void_p(handle)
+ elif not isinstance(handle, c_void_p):
+ raise TypeError('illegal handle type: %s' % type(handle))
+ obj = cls(handle)
+ obj.owner = False
+ return obj
+
+ def __del__(self):
+ if not coref:
+ return
+ if self.owner:
+ coref.CFRelease(self)
+
+ def __repr__(self):
+ return '%s(handle=%s)' % (self.__class__.__name__, repr(self.handle))
+
+ def retain(self):
+ if not self.owner:
+ coref.CFRetain(self)
+ self.owner = True
+
+ def get_retain_count(self):
+ return coref.CFGetRetainCount(self)
+
+ def get_handle(self):
+ return self.handle
+
+ # allows passing CF types as ctypes function parameters
+ _as_parameter_ = property(get_handle)
+
+
+class CFString(CFType):
+ """CoreFoundation string type.
+
+ Supports Python unicode type only. String is immutable.
+
+ :see: http://developer.apple.com/documentation/CoreFoundation/Reference/CFStringRef/
+ """
+
+ def __init__(self, init=u''):
+ if isinstance(init, (str, unicode)):
+ s = unicode(init).encode('utf-8')
+ init = c_void_p(coref.CFStringCreateWithBytes(None,
+ s, len(s), 0x08000100, False))
+ CFType.__init__(self, init)
+
+ def __str__(self):
+ i = coref.CFStringGetLength(self)
+ size = c_long()
+ if coref.CFStringGetBytes(self, 0, i, 0x08000100, 0, False, None, 0, byref(size)) > 0:
+ buf = create_string_buffer(size.value)
+ coref.CFStringGetBytes(self, 0, i, 0x08000100, 0, False, buf, size, None)
+ return buf.value
+ else:
+ raise UnicodeError('CFStringGetBytes() failed')
+
+ def __unicode__(self):
+ return self.__str__().decode('utf-8')
+
+ def __len__(self):
+ return coref.CFStringGetLength(self)
+
+ def __repr__(self):
+ return 'CFString(%s)' % repr(unicode(self))
+
+
+class CFNumber(CFType):
+ """CoreFoundation number type.
+
+ Supports Python int type only. Number is immutable.
+
+ :see: http://developer.apple.com/documentation/CoreFoundation/Reference/CFNumberRef/
+ """
+
+ def __init__(self, init=0):
+ if isinstance(init, (int, long)):
+ init = c_void_p(coref.CFNumberCreate(None, 3, byref(c_int(int(init)))))
+ CFType.__init__(self, init)
+
+ def __int__(self):
+ n = c_int()
+ if coref.CFNumberGetValue(self, 3, byref(n)):
+ return n.value
+ return 0
+
+ def __repr__(self):
+ return 'CFNumber(%s)' % repr(int(self))
+
+
+class CFDictionary(CFType):
+ """CoreFoundation immutable dictionary type.
+
+ :see: http://developer.apple.com/documentation/CoreFoundation/Reference/CFDictionaryRef/
+ """
+
+ def __init__(self, init={}):
+ if isinstance(init, dict):
+ d = dict(init)
+ keys = (c_void_p * len(d))()
+ values = (c_void_p * len(d))()
+ for i, (k, v) in enumerate(d.items()):
+ keys[i] = k.get_handle()
+ values[i] = v.get_handle()
+ init = c_void_p(coref.CFDictionaryCreate(None, keys, values, len(d),
+ coref.kCFTypeDictionaryKeyCallBacks, coref.kCFTypeDictionaryValueCallBacks))
+ CFType.__init__(self, init)
+
+ def get_dict(self):
+ n = len(self)
+ keys = (c_void_p * n)()
+ values = (c_void_p * n)()
+ coref.CFDictionaryGetKeysAndValues(self, keys, values)
+ d = dict()
+ for i in xrange(n):
+ d[CFType.from_handle(keys[i])] = CFType.from_handle(values[i])
+ return d
+
+ def __getitem__(self, key):
+ return CFType.from_handle(coref.CFDictionaryGetValue(self, key))
+
+ def __len__(self):
+ return coref.CFDictionaryGetCount(self)
+
+
+class CFDistributedNotificationCenter(CFType):
+ """CoreFoundation distributed notification center type.
+
+ :see: http://developer.apple.com/documentation/CoreFoundation/Reference/CFNotificationCenterRef/
+ """
+
+ CFNOTIFICATIONCALLBACK = CFUNCTYPE(None, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p)
+
+ def __init__(self):
+ CFType.__init__(self, c_void_p(coref.CFNotificationCenterGetDistributedCenter()))
+ # there is only one distributed notification center per application
+ self.owner = False
+ self.callbacks = {}
+ self._c_callback = self.CFNOTIFICATIONCALLBACK(self._callback)
+
+ def _callback(self, center, observer, name, obj, userInfo):
+ observer = CFString.from_handle(observer)
+ name = CFString.from_handle(name)
+ if obj:
+ obj = CFString.from_handle(obj)
+ userInfo = CFDictionary.from_handle(userInfo)
+ callback = self.callbacks[(unicode(observer), unicode(name))]
+ callback(self, observer, name, obj, userInfo)
+
+ def add_observer(self, observer, callback, name=None, obj=None,
+ drop=False, coalesce=False, hold=False, immediate=False):
+ if not callable(callback):
+ raise TypeError('callback must be callable')
+ observer = CFString(observer)
+ self.callbacks[(unicode(observer), unicode(name))] = callback
+ if name is not None:
+ name = CFString(name)
+ if obj is not None:
+ obj = CFString(obj)
+ if drop:
+ behaviour = 1
+ elif coalesce:
+ behaviour = 2
+ elif hold:
+ behaviour = 3
+ elif immediate:
+ behaviour = 4
+ else:
+ behaviour = 0
+ coref.CFNotificationCenterAddObserver(self, observer,
+ self._c_callback, name, obj, behaviour)
+
+ def remove_observer(self, observer, name=None, obj=None):
+ observer = CFString(observer)
+ if name is not None:
+ name = CFString(name)
+ if obj is not None:
+ obj = CFString(obj)
+ coref.CFNotificationCenterRemoveObserver(self, observer, name, obj)
+ try:
+ del self.callbacks[(unicode(observer), unicode(name))]
+ except KeyError:
+ pass
+
+ def post_notification(self, name, obj=None, userInfo=None, immediate=False):
+ name = CFString(name)
+ if obj is not None:
+ obj = CFString(obj)
+ if userInfo is not None:
+ userInfo = CFDictionary(userInfo)
+ coref.CFNotificationCenterPostNotification(self, name, obj, userInfo, immediate)
+
+
+class EventLoop(object):
+ """Carbon event loop object for the current thread.
+
+ The Carbon reference documentation seems to be gone from developer.apple.com, the following
+ link points to a mirror I found. I don't know how long until this one is gone too.
+
+ :see: http://www.monen.nl/DevDoc/documentation/Carbon/Reference/Carbon_Event_Manager_Ref/index.html
+ """
+
+ def __init__(self):
+ self.handle = c_void_p(carbon.GetCurrentEventLoop())
+
+ @staticmethod
+ def run(timeout=-1):
+ # Timeout is expressed in seconds (float), -1 means forever.
+ # Returns True if aborted (eventLoopQuitErr).
+ return (carbon.RunCurrentEventLoop(timeout) == -9876)
+
+ def stop(self):
+ carbon.QuitEventLoop(self.handle)
+
+
+# load the Carbon and CoreFoundation frameworks
+# (only if not building the docs)
+if not getattr(sys, 'skype4py_setup', False):
+
+ path = find_library('Carbon')
+ if path is None:
+ raise ImportError('Could not find Carbon.framework')
+ carbon = cdll.LoadLibrary(path)
+ carbon.RunCurrentEventLoop.argtypes = (c_double,)
+
+ path = find_library('CoreFoundation')
+ if path is None:
+ raise ImportError('Could not find CoreFoundation.framework')
+ coref = cdll.LoadLibrary(path)
+
+
+class SkypeAPI(SkypeAPIBase):
+ """
+ :note: Code based on Pidgin Skype Plugin source
+ (http://code.google.com/p/skype4pidgin/).
+ Permission to use granted by the author.
+ """
+
+ def __init__(self, opts):
+ self.logger = logging.getLogger('Skype4Py.api.darwin.SkypeAPI')
+ SkypeAPIBase.__init__(self)
+ self.run_main_loop = opts.pop('RunMainLoop', True)
+ finalize_opts(opts)
+ self.center = CFDistributedNotificationCenter()
+ self.is_available = False
+ self.client_id = -1
+
+ def run(self):
+ self.logger.info('thread started')
+ if self.run_main_loop:
+ self.loop = EventLoop()
+ EventLoop.run()
+ self.logger.info('thread finished')
+
+ def close(self):
+ if hasattr(self, 'loop'):
+ self.loop.stop()
+ self.client_id = -1
+ SkypeAPIBase.close(self)
+
+ def set_friendly_name(self, friendly_name):
+ SkypeAPIBase.set_friendly_name(self, friendly_name)
+ if self.attachment_status == apiAttachSuccess:
+ # reattach with the new name
+ self.set_attachment_status(apiAttachUnknown)
+ self.attach()
+
+ def attach(self, timeout, wait=True):
+ if self.attachment_status in (apiAttachPendingAuthorization, apiAttachSuccess):
+ return
+ self.acquire()
+ try:
+ try:
+ self.start()
+ except AssertionError:
+ pass
+ t = threading.Timer(timeout2float(timeout), lambda: setattr(self, 'wait', False))
+ try:
+ self.init_observer()
+ self.client_id = -1
+ self.set_attachment_status(apiAttachPendingAuthorization)
+ self.post('SKSkypeAPIAttachRequest')
+ self.wait = True
+ if wait:
+ t.start()
+ while self.wait and self.attachment_status == apiAttachPendingAuthorization:
+ if self.run_main_loop:
+ time.sleep(1.0)
+ else:
+ EventLoop.run(1.0)
+ finally:
+ t.cancel()
+ if not self.wait:
+ self.set_attachment_status(apiAttachUnknown)
+ raise SkypeAPIError('Skype attach timeout')
+ finally:
+ self.release()
+ command = Command('PROTOCOL %s' % self.protocol, Blocking=True)
+ self.send_command(command)
+ self.protocol = int(command.Reply.rsplit(None, 1)[-1])
+
+ def is_running(self):
+ try:
+ self.start()
+ except AssertionError:
+ pass
+ self.init_observer()
+ self.is_available = False
+ self.post('SKSkypeAPIAvailabilityRequest')
+ time.sleep(1.0)
+ return self.is_available
+
+ def startup(self, minimized, nosplash):
+ if not self.is_running():
+ from subprocess import Popen
+ nul = file('/dev/null')
+ Popen(['/Applications/Skype.app/Contents/MacOS/Skype'], stdin=nul, stdout=nul, stderr=nul)
+
+ def send_command(self, command):
+ if not self.attachment_status == apiAttachSuccess:
+ self.attach(command.Timeout)
+ self.push_command(command)
+ self.notifier.sending_command(command)
+ cmd = u'#%d %s' % (command.Id, command.Command)
+ if command.Blocking:
+ if self.run_main_loop:
+ command._event = event = threading.Event()
+ else:
+ command._loop = EventLoop()
+ else:
+ command._timer = timer = threading.Timer(command.timeout2float(), self.pop_command, (command.Id,))
+
+ self.logger.debug('sending %s', repr(cmd))
+ userInfo = CFDictionary({CFString('SKYPE_API_COMMAND'): CFString(cmd),
+ CFString('SKYPE_API_CLIENT_ID'): CFNumber(self.client_id)})
+ self.post('SKSkypeAPICommand', userInfo)
+
+ if command.Blocking:
+ if self.run_main_loop:
+ event.wait(command.timeout2float())
+ if not event.isSet():
+ raise SkypeAPIError('Skype command timeout')
+ else:
+ if not EventLoop.run(command.timeout2float()):
+ raise SkypeAPIError('Skype command timeout')
+ else:
+ timer.start()
+
+ def init_observer(self):
+ if self.has_observer():
+ self.delete_observer()
+ self.observer = CFString(self.friendly_name)
+ self.center.add_observer(self.observer, self.SKSkypeAPINotification, 'SKSkypeAPINotification', immediate=True)
+ self.center.add_observer(self.observer, self.SKSkypeWillQuit, 'SKSkypeWillQuit', immediate=True)
+ self.center.add_observer(self.observer, self.SKSkypeBecameAvailable, 'SKSkypeBecameAvailable', immediate=True)
+ self.center.add_observer(self.observer, self.SKAvailabilityUpdate, 'SKAvailabilityUpdate', immediate=True)
+ self.center.add_observer(self.observer, self.SKSkypeAttachResponse, 'SKSkypeAttachResponse', immediate=True)
+
+ def delete_observer(self):
+ if not self.has_observer():
+ return
+ self.center.remove_observer(self.observer, 'SKSkypeAPINotification')
+ self.center.remove_observer(self.observer, 'SKSkypeWillQuit')
+ self.center.remove_observer(self.observer, 'SKSkypeBecameAvailable')
+ self.center.remove_observer(self.observer, 'SKAvailabilityUpdate')
+ self.center.remove_observer(self.observer, 'SKSkypeAttachResponse')
+ del self.observer
+
+ def has_observer(self):
+ return hasattr(self, 'observer')
+
+ def post(self, name, userInfo=None):
+ if not self.has_observer():
+ self.init_observer()
+ self.center.post_notification(name, self.observer, userInfo, immediate=True)
+
+ def SKSkypeAPINotification(self, center, observer, name, obj, userInfo):
+ client_id = int(CFNumber(userInfo[CFString('SKYPE_API_CLIENT_ID')]))
+ if client_id != 999 and (client_id == 0 or client_id != self.client_id):
+ return
+ cmd = unicode(CFString(userInfo[CFString('SKYPE_API_NOTIFICATION_STRING')]))
+ self.logger.debug('received %s', repr(cmd))
+
+ if cmd.startswith(u'#'):
+ p = cmd.find(u' ')
+ command = self.pop_command(int(cmd[1:p]))
+ if command is not None:
+ command.Reply = cmd[p + 1:]
+ if command.Blocking:
+ if self.run_main_loop:
+ command._event.set()
+ else:
+ command._loop.stop()
+ else:
+ command._timer.cancel()
+ self.notifier.reply_received(command)
+ else:
+ self.notifier.notification_received(cmd[p + 1:])
+ else:
+ self.notifier.notification_received(cmd)
+
+ def SKSkypeWillQuit(self, center, observer, name, obj, userInfo):
+ self.logger.debug('received SKSkypeWillQuit')
+ self.set_attachment_status(apiAttachNotAvailable)
+
+ def SKSkypeBecameAvailable(self, center, observer, name, obj, userInfo):
+ self.logger.debug('received SKSkypeBecameAvailable')
+ self.set_attachment_status(apiAttachAvailable)
+
+ def SKAvailabilityUpdate(self, center, observer, name, obj, userInfo):
+ self.logger.debug('received SKAvailabilityUpdate')
+ self.is_available = not not int(CFNumber(userInfo[CFString('SKYPE_API_AVAILABILITY')]))
+
+ def SKSkypeAttachResponse(self, center, observer, name, obj, userInfo):
+ self.logger.debug('received SKSkypeAttachResponse')
+ # It seems that this notification is not called if the access is refused. Therefore we can't
+ # distinguish between attach timeout and access refuse.
+ if unicode(CFString(userInfo[CFString('SKYPE_API_CLIENT_NAME')])) == self.friendly_name:
+ response = int(CFNumber(userInfo[CFString('SKYPE_API_ATTACH_RESPONSE')]))
+ if response and self.client_id == -1:
+ self.client_id = response
+ self.set_attachment_status(apiAttachSuccess)
Added: software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/faked_dbus.py
===================================================================
--- software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/faked_dbus.py (rev 0)
+++ software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/faked_dbus.py 2009-10-01 12:25:22 UTC (rev 5580)
@@ -0,0 +1,12 @@
+'''
+This faked module is used while building docs on windows
+where dbus package isn't available.
+'''
+
+class dbus(object):
+ class service(object):
+ class Object(object):
+ pass
+ @staticmethod
+ def method(*args, **kwargs):
+ return lambda *args, **kwargs: None
Added: software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/posix.py
===================================================================
--- software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/posix.py (rev 0)
+++ software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/posix.py 2009-10-01 12:25:22 UTC (rev 5580)
@@ -0,0 +1,40 @@
+"""
+Low level *Skype for Linux* interface.
+
+This module handles the options that you can pass to `Skype.__init__` for Linux machines.
+The options include:
+
+- ``Transport`` (str) - Name of a channel used to communicate with the Skype client.
+ Currently supported values:
+
+ - ``'dbus'`` (default)
+
+ Uses *DBus* thrugh *dbus-python* package.
+ This is the default if no transport is specified.
+
+ Look into `Skype4Py.api.posix_dbus` for additional options.
+
+ - ``'x11'``
+
+ Uses *X11* messaging through *Xlib*.
+
+ Look into `Skype4Py.api.posix_x11` module for additional options.
+"""
+__docformat__ = 'restructuredtext en'
+
+
+from Skype4Py.errors import SkypeAPIError
+
+
+__all__ = ['SkypeAPI']
+
+
+def SkypeAPI(opts):
+ trans = opts.pop('Transport', 'dbus')
+ if trans == 'dbus':
+ from posix_dbus import SkypeAPI
+ elif trans == 'x11':
+ from posix_x11 import SkypeAPI
+ else:
+ raise SkypeAPIError('Unknown transport: %s' % trans)
+ return SkypeAPI(opts)
Added: software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/posix_dbus.py
===================================================================
--- software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/posix_dbus.py (rev 0)
+++ software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/posix_dbus.py 2009-10-01 12:25:22 UTC (rev 5580)
@@ -0,0 +1,253 @@
+"""
+Low level *Skype for Linux* interface implemented using *dbus-python* package.
+
+This module handles the options that you can pass to `Skype.__init__`
+for Linux machines when the transport is set to *DBus*. See below.
+
+- ``RunMainLoop`` (bool) - If set to False, Skype4Py won't start the GLib main
+ loop. Otherwise it is started in a separate thread. The loop must be running for
+ Skype4Py events to work properly. Set this option to False if you plan to run the
+ loop yourself or if, for example, your GUI framework does it for you.
+
+:requires: Skype for Linux 2.0 (beta) or newer.
+"""
+__docformat__ = 'restructuredtext en'
+
+
+import sys
+import threading
+import time
+import warnings
+import logging
+
+from Skype4Py.api import Command, SkypeAPIBase, \
+ timeout2float, finalize_opts
+from Skype4Py.enums import *
+from Skype4Py.errors import SkypeAPIError
+from Skype4Py.utils import cndexp
+
+
+__all__ = ['SkypeAPI']
+
+
+if getattr(sys, 'skype4py_setup', False):
+ # we get here if we're building docs; to let the module import without
+ # exceptions, we emulate the dbus module using a class:
+ class dbus(object):
+ class service(object):
+ class Object(object):
+ pass
+ @staticmethod
+ def method(*args, **kwargs):
+ return lambda *args, **kwargs: None
+else:
+ import dbus
+ import dbus.service
+ from dbus.mainloop.glib import DBusGMainLoop
+ import gobject
+
+
+class SkypeNotify(dbus.service.Object):
+ """DBus object which exports a Notify method. This will be called by Skype for all
+ notifications with the notification string as a parameter. The Notify method of this
+ class calls in turn the callable passed to the constructor.
+ """
+
+ def __init__(self, bus, notify):
+ dbus.service.Object.__init__(self, bus, '/com/Skype/Client')
+ self.notify = notify
+
+ @dbus.service.method(dbus_interface='com.Skype.API.Client')
+ def Notify(self, com):
+ self.notify(unicode(com))
+
+
+class SkypeAPI(SkypeAPIBase):
+ def __init__(self, opts):
+ self.logger = logging.getLogger('Skype4Py.api.posix_dbus.SkypeAPI')
+ SkypeAPIBase.__init__(self)
+ self.run_main_loop = opts.pop('RunMainLoop', True)
+ finalize_opts(opts)
+ self.skype_in = self.skype_out = self.dbus_name_owner_watch = None
+
+ # initialize glib multithreading support
+ gobject.threads_init()
+
+ # dbus-python calls object.__init__() with arguments passed to SessionBus(),
+ # this throws a warning on newer Python versions; here we suppress it
+ warnings.simplefilter('ignore')
+ try:
+ self.bus = dbus.SessionBus(mainloop=DBusGMainLoop())
+ finally:
+ warnings.simplefilter('default')
+
+ if self.run_main_loop:
+ self.mainloop = gobject.MainLoop()
+
+ def run(self):
+ self.logger.info('thread started')
+ if self.run_main_loop:
+ self.mainloop.run()
+ self.logger.info('thread finished')
+
+ def close(self):
+ if self.run_main_loop:
+ self.mainloop.quit()
+ self.skype_in = self.skype_out = None
+ if self.dbus_name_owner_watch is not None:
+ self.bus.remove_signal_receiver(self.dbus_name_owner_watch)
+ self.dbus_name_owner_watch = None
+ SkypeAPIBase.close(self)
+
+ def set_friendly_name(self, friendly_name):
+ SkypeAPIBase.set_friendly_name(self, friendly_name)
+ if self.skype_out:
+ self.send_command(Command('NAME %s' % friendly_name))
+
+ def start_watcher(self):
+ # starts a signal receiver detecting Skype being closed/opened
+ self.dbus_name_owner_watch = self.bus.add_signal_receiver(self.dbus_name_owner_changed,
+ 'NameOwnerChanged',
+ 'org.freedesktop.DBus',
+ 'org.freedesktop.DBus',
+ '/org/freedesktop/DBus',
+ arg0='com.Skype.API')
+
+ def attach(self, timeout, wait=True):
+ self.acquire()
+ try:
+ try:
+ if not self.isAlive():
+ self.start_watcher()
+ self.start()
+ except AssertionError:
+ pass
+ try:
+ self.wait = True
+ t = threading.Timer(timeout2float(timeout), lambda: setattr(self, 'wait', False))
+ if wait:
+ t.start()
+ while self.wait:
+ if not wait:
+ self.wait = False
+ try:
+ if not self.skype_out:
+ self.skype_out = self.bus.get_object('com.Skype.API', '/com/Skype')
+ if not self.skype_in:
+ self.skype_in = SkypeNotify(self.bus, self.notify)
+ except dbus.DBusException:
+ if not wait:
+ break
+ time.sleep(1.0)
+ else:
+ break
+ else:
+ raise SkypeAPIError('Skype attach timeout')
+ finally:
+ t.cancel()
+ command = Command('NAME %s' % self.friendly_name, '', True, timeout)
+ if self.skype_out:
+ self.release()
+ try:
+ self.send_command(command)
+ finally:
+ self.acquire()
+ if command.Reply != 'OK':
+ self.skype_out = None
+ self.set_attachment_status(apiAttachRefused)
+ return
+ self.set_attachment_status(apiAttachSuccess)
+ finally:
+ self.release()
+ command = Command('PROTOCOL %s' % self.protocol, Blocking=True)
+ self.send_command(command)
+ self.protocol = int(command.Reply.rsplit(None, 1)[-1])
+
+ def is_running(self):
+ try:
+ self.bus.get_object('com.Skype.API', '/com/Skype')
+ return True
+ except dbus.DBusException:
+ return False
+
+ def startup(self, minimized, nosplash):
+ # options are not supported as of Skype 1.4 Beta for Linux
+ if not self.is_running():
+ import os
+ if os.fork() == 0: # we're child
+ os.setsid()
+ os.execlp('skype')
+
+ def shutdown(self):
+ import os
+ from signal import SIGINT
+ fh = os.popen('ps -o %p --no-heading -C skype')
+ pid = fh.readline().strip()
+ fh.close()
+ if pid:
+ os.kill(int(pid), SIGINT)
+ self.skype_in = self.skype_out = None
+
+ def send_command(self, command):
+ if not self.skype_out:
+ self.attach(command.Timeout)
+ self.push_command(command)
+ self.notifier.sending_command(command)
+ cmd = u'#%d %s' % (command.Id, command.Command)
+ self.logger.debug('sending %s', repr(cmd))
+ if command.Blocking:
+ if self.run_main_loop:
+ command._event = event = threading.Event()
+ else:
+ command._loop = loop = gobject.MainLoop()
+ command._set = False
+ else:
+ command._timer = timer = threading.Timer(command.timeout2float(), self.pop_command, (command.Id,))
+ try:
+ result = self.skype_out.Invoke(cmd)
+ except dbus.DBusException, err:
+ raise SkypeAPIError(str(err))
+ if result.startswith(u'#%d ' % command.Id):
+ self.notify(result)
+ if command.Blocking:
+ if self.run_main_loop:
+ event.wait(command.timeout2float())
+ if not event.isSet():
+ raise SkypeAPIError('Skype command timeout')
+ elif not command._set:
+ gobject.timeout_add_seconds(int(command.timeout2float()), loop.quit)
+ loop.run()
+ if not command._set:
+ raise SkypeAPIError('Skype command timeout')
+ else:
+ timer.start()
+
+ def notify(self, cmd):
+ cmd = unicode(cmd)
+ self.logger.debug('received %s', repr(cmd))
+ if cmd.startswith(u'#'):
+ p = cmd.find(u' ')
+ command = self.pop_command(int(cmd[1:p]))
+ if command is not None:
+ command.Reply = cmd[p + 1:]
+ if command.Blocking:
+ if self.run_main_loop:
+ command._event.set()
+ else:
+ command._set = True
+ command._loop.quit()
+ else:
+ command._timer.cancel()
+ self.notifier.reply_received(command)
+ else:
+ self.notifier.notification_received(cmd[p + 1:])
+ else:
+ self.notifier.notification_received(cmd)
+
+ def dbus_name_owner_changed(self, owned, old_owner, new_owner):
+ self.logger.debug('received dbus name owner changed')
+ if new_owner == '':
+ self.skype_out = None
+ self.set_attachment_status(cndexp((new_owner == ''),
+ apiAttachNotAvailable,
+ apiAttachAvailable))
Added: software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/posix_x11.py
===================================================================
--- software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/posix_x11.py (rev 0)
+++ software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/posix_x11.py 2009-10-01 12:25:22 UTC (rev 5580)
@@ -0,0 +1,465 @@
+"""
+Low level *Skype for Linux* interface implemented using *XWindows messaging*.
+Uses direct *Xlib* calls through *ctypes* module.
+
+This module handles the options that you can pass to `Skype.__init__`
+for Linux machines when the transport is set to *X11*.
+
+No further options are currently supported.
+
+Warning PyGTK framework users
+=============================
+
+The multithreaded architecture of Skype4Py requires a special treatment
+if the Xlib transport is combined with PyGTK GUI framework.
+
+The following code has to be called at the top of your script, before
+PyGTK is even imported.
+
+.. python::
+
+ from Skype4Py.api.posix_x11 import threads_init
+ threads_init()
+
+This function enables multithreading support in Xlib and GDK. If not done
+here, this is enabled for Xlib library when the `Skype` object is instantiated.
+If your script imports the PyGTK module, doing this so late may lead to a
+segmentation fault when the GUI is shown on the screen.
+
+A remedy is to enable the multithreading support before PyGTK is imported
+by calling the ``threads_init`` function.
+"""
+__docformat__ = 'restructuredtext en'
+
+
+import sys
+import threading
+import os
+from ctypes import *
+
+from ctypes.util import find_library
+import time
+import logging
+
+from Skype4Py.api import Command, SkypeAPIBase, \
+ timeout2float, finalize_opts
+from Skype4Py.enums import *
+from Skype4Py.errors import SkypeAPIError
+
+
+__all__ = ['SkypeAPI', 'threads_init']
+
+
+# The Xlib Programming Manual:
+# ============================
+# http://tronche.com/gui/x/xlib/
+
+
+# some Xlib constants
+PropertyChangeMask = 0x400000
+PropertyNotify = 28
+ClientMessage = 33
+PropertyNewValue = 0
+PropertyDelete = 1
+
+
+# some Xlib types
+c_ulong_p = POINTER(c_ulong)
+DisplayP = c_void_p
+Atom = c_ulong
+AtomP = c_ulong_p
+XID = c_ulong
+Window = XID
+Bool = c_int
+Status = c_int
+Time = c_ulong
+c_int_p = POINTER(c_int)
+
+
+# should the structures be aligned to 8 bytes?
+align = (sizeof(c_long) == 8 and sizeof(c_int) == 4)
+
+
+# some Xlib structures
+class XClientMessageEvent(Structure):
+ if align:
+ _fields_ = [('type', c_int),
+ ('pad0', c_int),
+ ('serial', c_ulong),
+ ('send_event', Bool),
+ ('pad1', c_int),
+ ('display', DisplayP),
+ ('window', Window),
+ ('message_type', Atom),
+ ('format', c_int),
+ ('pad2', c_int),
+ ('data', c_char * 20)]
+ else:
+ _fields_ = [('type', c_int),
+ ('serial', c_ulong),
+ ('send_event', Bool),
+ ('display', DisplayP),
+ ('window', Window),
+ ('message_type', Atom),
+ ('format', c_int),
+ ('data', c_char * 20)]
+
+class XPropertyEvent(Structure):
+ if align:
+ _fields_ = [('type', c_int),
+ ('pad0', c_int),
+ ('serial', c_ulong),
+ ('send_event', Bool),
+ ('pad1', c_int),
+ ('display', DisplayP),
+ ('window', Window),
+ ('atom', Atom),
+ ('time', Time),
+ ('state', c_int),
+ ('pad2', c_int)]
+ else:
+ _fields_ = [('type', c_int),
+ ('serial', c_ulong),
+ ('send_event', Bool),
+ ('display', DisplayP),
+ ('window', Window),
+ ('atom', Atom),
+ ('time', Time),
+ ('state', c_int)]
+
+class XErrorEvent(Structure):
+ if align:
+ _fields_ = [('type', c_int),
+ ('pad0', c_int),
+ ('display', DisplayP),
+ ('resourceid', XID),
+ ('serial', c_ulong),
+ ('error_code', c_ubyte),
+ ('request_code', c_ubyte),
+ ('minor_code', c_ubyte)]
+ else:
+ _fields_ = [('type', c_int),
+ ('display', DisplayP),
+ ('resourceid', XID),
+ ('serial', c_ulong),
+ ('error_code', c_ubyte),
+ ('request_code', c_ubyte),
+ ('minor_code', c_ubyte)]
+
+class XEvent(Union):
+ if align:
+ _fields_ = [('type', c_int),
+ ('xclient', XClientMessageEvent),
+ ('xproperty', XPropertyEvent),
+ ('xerror', XErrorEvent),
+ ('pad', c_long * 24)]
+ else:
+ _fields_ = [('type', c_int),
+ ('xclient', XClientMessageEvent),
+ ('xproperty', XPropertyEvent),
+ ('xerror', XErrorEvent),
+ ('pad', c_long * 24)]
+
+XEventP = POINTER(XEvent)
+
+
+if getattr(sys, 'skype4py_setup', False):
+ # we get here if we're building docs; to let the module import without
+ # exceptions, we emulate the X11 library using a class:
+ class X(object):
+ def __getattr__(self, name):
+ return self
+ def __setattr__(self, name, value):
+ pass
+ def __call__(self, *args, **kwargs):
+ pass
+ x11 = X()
+else:
+ # load X11 library (Xlib)
+ libpath = find_library('X11')
+ if not libpath:
+ raise ImportError('Could not find X11 library')
+ x11 = cdll.LoadLibrary(libpath)
+ del libpath
+
+
+# setup Xlib function prototypes
+x11.XCloseDisplay.argtypes = (DisplayP,)
+x11.XCloseDisplay.restype = None
+x11.XCreateSimpleWindow.argtypes = (DisplayP, Window, c_int, c_int, c_uint,
+ c_uint, c_uint, c_ulong, c_ulong)
+x11.XCreateSimpleWindow.restype = Window
+x11.XDefaultRootWindow.argtypes = (DisplayP,)
+x11.XDefaultRootWindow.restype = Window
+x11.XDeleteProperty.argtypes = (DisplayP, Window, Atom)
+x11.XDeleteProperty.restype = None
+x11.XDestroyWindow.argtypes = (DisplayP, Window)
+x11.XDestroyWindow.restype = None
+x11.XFree.argtypes = (c_void_p,)
+x11.XFree.restype = None
+x11.XGetAtomName.argtypes = (DisplayP, Atom)
+x11.XGetAtomName.restype = c_void_p
+x11.XGetErrorText.argtypes = (DisplayP, c_int, c_char_p, c_int)
+x11.XGetErrorText.restype = None
+x11.XGetWindowProperty.argtypes = (DisplayP, Window, Atom, c_long, c_long, Bool,
+ Atom, AtomP, c_int_p, c_ulong_p, c_ulong_p, POINTER(POINTER(Window)))
+x11.XGetWindowProperty.restype = c_int
+x11.XInitThreads.argtypes = ()
+x11.XInitThreads.restype = Status
+x11.XInternAtom.argtypes = (DisplayP, c_char_p, Bool)
+x11.XInternAtom.restype = Atom
+x11.XNextEvent.argtypes = (DisplayP, XEventP)
+x11.XNextEvent.restype = None
+x11.XOpenDisplay.argtypes = (c_char_p,)
+x11.XOpenDisplay.restype = DisplayP
+x11.XPending.argtypes = (DisplayP,)
+x11.XPending.restype = c_int
+x11.XSelectInput.argtypes = (DisplayP, Window, c_long)
+x11.XSelectInput.restype = None
+x11.XSendEvent.argtypes = (DisplayP, Window, Bool, c_long, XEventP)
+x11.XSendEvent.restype = Status
+x11.XLockDisplay.argtypes = (DisplayP,)
+x11.XLockDisplay.restype = None
+x11.XUnlockDisplay.argtypes = (DisplayP,)
+x11.XUnlockDisplay.restype = None
+
+
+def threads_init(gtk=True):
+ """Enables multithreading support in Xlib and PyGTK.
+ See the module docstring for more info.
+
+ :Parameters:
+ gtk : bool
+ May be set to False to skip the PyGTK module.
+ """
+ # enable X11 multithreading
+ x11.XInitThreads()
+ if gtk:
+ from gtk.gdk import threads_init
+ threads_init()
+
+
+class SkypeAPI(SkypeAPIBase):
+ def __init__(self, opts):
+ self.logger = logging.getLogger('Skype4Py.api.posix_x11.SkypeAPI')
+ SkypeAPIBase.__init__(self)
+ finalize_opts(opts)
+
+ # initialize threads if not done already by the user
+ threads_init(gtk=False)
+
+ # init Xlib display
+ self.disp = x11.XOpenDisplay(None)
+ if not self.disp:
+ raise SkypeAPIError('Could not open XDisplay')
+ self.win_root = x11.XDefaultRootWindow(self.disp)
+ self.win_self = x11.XCreateSimpleWindow(self.disp, self.win_root,
+ 100, 100, 100, 100, 1, 0, 0)
+ x11.XSelectInput(self.disp, self.win_root, PropertyChangeMask)
+ self.win_skype = self.get_skype()
+ ctrl = 'SKYPECONTROLAPI_MESSAGE'
+ self.atom_msg = x11.XInternAtom(self.disp, ctrl, False)
+ self.atom_msg_begin = x11.XInternAtom(self.disp, ctrl + '_BEGIN', False)
+
+ self.loop_event = threading.Event()
+ self.loop_timeout = 0.0001
+ self.loop_break = False
+
+ def __del__(self):
+ if x11:
+ if hasattr(self, 'disp'):
+ if hasattr(self, 'win_self'):
+ x11.XDestroyWindow(self.disp, self.win_self)
+ x11.XCloseDisplay(self.disp)
+
+ def run(self):
+ self.logger.info('thread started')
+ # main loop
+ event = XEvent()
+ data = ''
+ while not self.loop_break and x11:
+ while x11.XPending(self.disp):
+ self.loop_timeout = 0.0001
+ x11.XNextEvent(self.disp, byref(event))
+ # events we get here are already prefiltered by the predicate function
+ if event.type == ClientMessage:
+ if event.xclient.format == 8:
+ if event.xclient.message_type == self.atom_msg_begin:
+ data = str(event.xclient.data)
+ elif event.xclient.message_type == self.atom_msg:
+ if data != '':
+ data += str(event.xclient.data)
+ else:
+ self.logger.warning('Middle of Skype X11 message received with no beginning!')
+ else:
+ continue
+ if len(event.xclient.data) != 20 and data:
+ self.notify(data.decode('utf-8'))
+ data = ''
+ elif event.type == PropertyNotify:
+ namep = x11.XGetAtomName(self.disp, event.xproperty.atom)
+ is_inst = (c_char_p(namep).value == '_SKYPE_INSTANCE')
+ x11.XFree(namep)
+ if is_inst:
+ if event.xproperty.state == PropertyNewValue:
+ self.win_skype = self.get_skype()
+ # changing attachment status can cause an event handler to be fired, in
+ # turn it could try to call Attach() and doing this immediately seems to
+ # confuse Skype (command '#0 NAME xxx' returns '#0 CONNSTATUS OFFLINE' :D);
+ # to fix this, we give Skype some time to initialize itself
+ time.sleep(1.0)
+ self.set_attachment_status(apiAttachAvailable)
+ elif event.xproperty.state == PropertyDelete:
+ self.win_skype = None
+ self.set_attachment_status(apiAttachNotAvailable)
+ self.loop_event.wait(self.loop_timeout)
+ if self.loop_event.isSet():
+ self.loop_timeout = 0.0001
+ elif self.loop_timeout < 1.0:
+ self.loop_timeout *= 2
+ self.loop_event.clear()
+ self.logger.info('thread finished')
+
+ def get_skype(self):
+ """Returns Skype window ID or None if Skype not running."""
+ skype_inst = x11.XInternAtom(self.disp, '_SKYPE_INSTANCE', True)
+ if not skype_inst:
+ return
+ type_ret = Atom()
+ format_ret = c_int()
+ nitems_ret = c_ulong()
+ bytes_after_ret = c_ulong()
+ winp = pointer(Window())
+ fail = x11.XGetWindowProperty(self.disp, self.win_root, skype_inst,
+ 0, 1, False, 33, byref(type_ret), byref(format_ret),
+ byref(nitems_ret), byref(bytes_after_ret), byref(winp))
+ if not fail and format_ret.value == 32 and nitems_ret.value == 1:
+ return winp.contents.value
+
+ def close(self):
+ self.loop_break = True
+ self.loop_event.set()
+ while self.isAlive():
+ time.sleep(0.01)
+ SkypeAPIBase.close(self)
+
+ def set_friendly_name(self, friendly_name):
+ SkypeAPIBase.set_friendly_name(self, friendly_name)
+ if self.attachment_status == apiAttachSuccess:
+ # reattach with the new name
+ self.set_attachment_status(apiAttachUnknown)
+ self.attach()
+
+ def attach(self, timeout, wait=True):
+ if self.attachment_status == apiAttachSuccess:
+ return
+ self.acquire()
+ try:
+ if not self.isAlive():
+ try:
+ self.start()
+ except AssertionError:
+ raise SkypeAPIError('Skype API closed')
+ try:
+ self.wait = True
+ t = threading.Timer(timeout2float(timeout), lambda: setattr(self, 'wait', False))
+ if wait:
+ t.start()
+ while self.wait:
+ self.win_skype = self.get_skype()
+ if self.win_skype is not None:
+ break
+ else:
+ time.sleep(1.0)
+ else:
+ raise SkypeAPIError('Skype attach timeout')
+ finally:
+ t.cancel()
+ command = Command('NAME %s' % self.friendly_name, '', True, timeout)
+ self.release()
+ try:
+ self.send_command(command, True)
+ finally:
+ self.acquire()
+ if command.Reply != 'OK':
+ self.win_skype = None
+ self.set_attachment_status(apiAttachRefused)
+ return
+ self.set_attachment_status(apiAttachSuccess)
+ finally:
+ self.release()
+ command = Command('PROTOCOL %s' % self.protocol, Blocking=True)
+ self.send_command(command, True)
+ self.protocol = int(command.Reply.rsplit(None, 1)[-1])
+
+ def is_running(self):
+ return (self.get_skype() is not None)
+
+ def startup(self, minimized, nosplash):
+ # options are not supported as of Skype 1.4 Beta for Linux
+ if not self.is_running():
+ if os.fork() == 0: # we're the child
+ os.setsid()
+ os.execlp('skype')
+
+ def shutdown(self):
+ from signal import SIGINT
+ fh = os.popen('ps -o %p --no-heading -C skype')
+ pid = fh.readline().strip()
+ fh.close()
+ if pid:
+ os.kill(int(pid), SIGINT)
+ # Skype sometimes doesn't delete the '_SKYPE_INSTANCE' property
+ skype_inst = x11.XInternAtom(self.disp, '_SKYPE_INSTANCE', True)
+ if skype_inst:
+ x11.XDeleteProperty(self.disp, self.win_root, skype_inst)
+ self.win_skype = None
+ self.set_attachment_status(apiAttachNotAvailable)
+
+ def send_command(self, command, force=False):
+ if self.attachment_status != apiAttachSuccess and not force:
+ self.attach(command.Timeout)
+ self.push_command(command)
+ self.notifier.sending_command(command)
+ cmd = u'#%d %s' % (command.Id, command.Command)
+ self.logger.debug('sending %s', repr(cmd))
+ if command.Blocking:
+ command._event = bevent = threading.Event()
+ else:
+ command._timer = timer = threading.Timer(command.timeout2float(), self.pop_command, (command.Id,))
+ event = XEvent()
+ event.xclient.type = ClientMessage
+ event.xclient.display = self.disp
+ event.xclient.window = self.win_self
+ event.xclient.message_type = self.atom_msg_begin
+ event.xclient.format = 8
+ cmd = cmd.encode('utf-8') + '\x00'
+ for i in xrange(0, len(cmd), 20):
+ event.xclient.data = cmd[i:i + 20]
+ x11.XSendEvent(self.disp, self.win_skype, False, 0, byref(event))
+ event.xclient.message_type = self.atom_msg
+ self.loop_event.set()
+ if command.Blocking:
+ bevent.wait(command.timeout2float())
+ if not bevent.isSet():
+ raise SkypeAPIError('Skype command timeout')
+ else:
+ timer.start()
+
+ def notify(self, cmd):
+ self.logger.debug('received %s', repr(cmd))
+ # Called by main loop for all received Skype commands.
+ if cmd.startswith(u'#'):
+ p = cmd.find(u' ')
+ command = self.pop_command(int(cmd[1:p]))
+ if command is not None:
+ command.Reply = cmd[p + 1:]
+ if command.Blocking:
+ command._event.set()
+ else:
+ command._timer.cancel()
+ self.notifier.reply_received(command)
+ else:
+ self.notifier.notification_received(cmd[p + 1:])
+ else:
+ self.notifier.notification_received(cmd)
Added: software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/windows.py
===================================================================
--- software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/windows.py (rev 0)
+++ software_suite_v3/software/plugin/plugin-skype/trunk/executables/Skype4Py/api/windows.py 2009-10-01 12:25:22 UTC (rev 5580)
@@ -0,0 +1,352 @@
+"""
+Low level *Skype for Windows* interface implemented using *Windows messaging*.
+Uses direct *WinAPI* calls through *ctypes* module.
+
+This module handles the options that you can pass to `Skype.__init__`
+for Windows machines.
+
+No options are currently supported.
+"""
+__docformat__ = 'restructuredtext en'
+
+
+import sys
+import threading
+import time
+from ctypes import *
+import logging
+
+from Skype4Py.api import Command, SkypeAPIBase, \
+ timeout2float, finalize_opts, \
+ DEFAULT_TIMEOUT
+from Skype4Py.enums import *
+from Skype4Py.errors import SkypeAPIError
+
+
+__all__ = ['SkypeAPI']
+
+
+try:
+ WNDPROC = WINFUNCTYPE(c_long, c_int, c_uint, c_int, c_int)
+except NameError:
+ # Proceed only if our setup.py is not running.
+ if not getattr(sys, 'skype4py_setup', False):
+ raise
+ # This will allow importing of this module on non-Windows machines. It won't work
+ # of course but this will allow building documentation on any platform.
+ WNDPROC = c_void_p
+
+
+class WNDCLASS(Structure):
+ _fields_ = [('style', c_uint),
+ ('lpfnWndProc', WNDPROC),
+ ('cbClsExtra', c_int),
+ ('cbWndExtra', c_int),
+ ('hInstance', c_int),
+ ('hIcon', c_int),
+ ('hCursor', c_int),
+ ('hbrBackground', c_int),
+ ('lpszMenuName', c_char_p),
+ ('lpszClassName', c_char_p)]
+
+
+class MSG(Structure):
+ _fields_ = [('hwnd', c_int),
+ ('message', c_uint),
+ ('wParam', c_int),
+ ('lParam', c_int),
+ ('time', c_int),
+ ('pointX', c_long),
+ ('pointY', c_long)]
+
+
+class COPYDATASTRUCT(Structure):
+ _fields_ = [('dwData', POINTER(c_uint)),
+ ('cbData', c_uint),
+ ('lpData', c_char_p)]
+
+
+PCOPYDATASTRUCT = POINTER(COPYDATASTRUCT)
+
+WM_QUIT = 0x12
+WM_COPYDATA = 0x4A
+
+HWND_BROADCAST = 0xFFFF
+
+
+class SkypeAPI(SkypeAPIBase):
+ def __init__(self, opts):
+ self.logger = logging.getLogger('Skype4Py.api.windows.SkypeAPI')
+ SkypeAPIBase.__init__(self)
+ finalize_opts(opts)
+ self.window_class = None
+ self.hwnd = None
+ self.skype = None
+ self.wait = False
+ self.SkypeControlAPIDiscover = windll.user32.RegisterWindowMessageA('SkypeControlAPIDiscover')
+ self.SkypeControlAPIAttach = windll.user32.RegisterWindowMessageA('SkypeControlAPIAttach')
+ windll.user32.GetWindowLongA.restype = c_ulong
+
+ def run(self):
+ self.logger.info('thread started')
+ if not self.create_window():
+ self.hwnd = None
+ return
+
+ msg = MSG()
+ pmsg = pointer(msg)
+ while self.hwnd and windll.user32.GetMessageA(pmsg, self.hwnd, 0, 0):
+ windll.user32.TranslateMessage(pmsg)
+ windll.user32.DispatchMessageA(pmsg)
+
+ self.destroy_window()
+ self.hwnd = None
+ self.logger.info('thread finished')
+
+ def close(self):
+ if self.hwnd:
+ windll.user32.PostMessageA(self.hwnd, WM_QUIT, 0, 0)
+ while self.hwnd:
+ time.sleep(0.01)
+ self.skype = None
+ SkypeAPIBase.close(self)
+
+ def set_friendly_name(sel...
[truncated message content] |