Package Skype4Py :: Package API :: Module posix_dbus
[frames] | no frames]

Source Code for Module Skype4Py.API.posix_dbus

  1  ''' 
  2  Low level Skype for Linux interface implemented 
  3  using python-dbus package. 
  4   
  5  This module handles the options that you can pass to L{ISkype.__init__<skype.ISkype.__init__>} 
  6  for Linux machines when the transport is set to DBus. See below. 
  7   
  8  @newfield option: Option, Options 
  9   
 10  @option: C{Bus} DBus bus object as returned by python-dbus package. 
 11  If not specified, private session bus is created and used. See also C{MainLoop}. 
 12  @option: C{MainLoop} DBus mainloop object. Use only without specifying the C{Bus} 
 13  (if you use C{Bus}, pass the mainloop to the bus constructor). If neither C{Bus} or 
 14  C{MainLoop} is specified, glib mainloop is used. In such case, the mainloop is 
 15  also run on a separate thread upon attaching to Skype. If you want to use glib 
 16  mainloop but you want to run the loop yourself (for example because your GUI toolkit 
 17  does it for you), pass C{dbus.mainloop.glib.DBusGMainLoop()} object as C{MainLoop} 
 18  parameter. 
 19   
 20  @requires: Skype for Linux 2.0 (beta) or newer. 
 21  ''' 
 22   
 23  import threading 
 24  import time 
 25  import weakref 
 26  from Skype4Py.API import ICommand, _ISkypeAPIBase 
 27  from Skype4Py.enums import * 
 28  from Skype4Py.errors import ISkypeAPIError 
 29  from Skype4Py.utils import cndexp 
 30   
 31   
 32  try: 
 33      import dbus, dbus.service 
 34  except ImportError: 
 35      import sys 
 36      if sys.argv == ['(imported)']: 
 37          # we get here if we're building docs on windows, to let the module 
 38          # import without exceptions, we import our faked dbus module 
 39          from faked_dbus import dbus 
 40      else: 
 41          raise 
42 43 44 -class _SkypeNotifyCallback(dbus.service.Object):
45 '''DBus object which exports a Notify method. This will be called by Skype for all 46 notifications with the notification string as a parameter. The Notify method of this 47 class calls in turn the callable passed to the constructor. 48 ''' 49
50 - def __init__(self, bus, notify):
51 dbus.service.Object.__init__(self, bus, '/com/Skype/Client') 52 self.notify = notify
53 54 @dbus.service.method(dbus_interface='com.Skype.API.Client')
55 - def Notify(self, com):
56 self.notify(unicode(com))
57
58 59 -class _ISkypeAPI(_ISkypeAPIBase):
60 - def __init__(self, handler, opts):
61 _ISkypeAPIBase.__init__(self, opts) 62 self.RegisterHandler(handler) 63 self.skype_in = self.skype_out = self.dbus_name_owner_watch = None 64 self.bus = opts.pop('Bus', None) 65 try: 66 mainloop = opts.pop('MainLoop') 67 if self.bus != None: 68 raise TypeError('Bus and MainLoop cannot be used at the same time!') 69 except KeyError: 70 if self.bus == None: 71 import dbus.mainloop.glib 72 import gobject 73 gobject.threads_init() 74 dbus.mainloop.glib.threads_init() 75 mainloop = dbus.mainloop.glib.DBusGMainLoop() 76 self.mainloop = gobject.MainLoop() 77 if self.bus == None: 78 from dbus import SessionBus 79 self.bus = SessionBus(private=True, mainloop=mainloop) 80 if opts: 81 raise TypeError('Unexpected parameter(s): %s' % ', '.join(opts.keys()))
82
83 - def run(self):
84 self.DebugPrint('thread started') 85 if hasattr(self, 'mainloop'): 86 self.mainloop.run() 87 self.DebugPrint('thread finished')
88
89 - def Close(self):
90 if hasattr(self, 'mainloop'): 91 self.mainloop.quit() 92 self.skype_in = self.skype_out = None 93 if self.dbus_name_owner_watch != None: 94 self.bus.remove_signal_receiver(self.dbus_name_owner_watch) 95 self.dbus_name_owner_watch = None 96 self.DebugPrint('closed')
97
98 - def SetFriendlyName(self, FriendlyName):
99 self.FriendlyName = FriendlyName 100 if self.skype_out: 101 self.SendCommand(ICommand(-1, 'NAME %s' % FriendlyName))
102
103 - def StartWatcher(self):
104 self.dbus_name_owner_watch = self.bus.add_signal_receiver(self.dbus_name_owner_changed, 105 'NameOwnerChanged', 106 'org.freedesktop.DBus', 107 'org.freedesktop.DBus', 108 '/org/freedesktop/DBus', 109 arg0='com.Skype.API')
110
111 - def __Attach_ftimeout(self):
112 self.wait = False
113
114 - def Attach(self, Timeout=30000, Wait=True):
115 try: 116 if not self.isAlive(): 117 self.StartWatcher() 118 self.start() 119 except AssertionError: 120 pass 121 try: 122 self.wait = True 123 t = threading.Timer(Timeout / 1000.0, self.__Attach_ftimeout) 124 if Wait: 125 t.start() 126 while self.wait: 127 if not Wait: 128 self.wait = False 129 try: 130 if not self.skype_out: 131 self.skype_out = self.bus.get_object('com.Skype.API', '/com/Skype') 132 if not self.skype_in: 133 self.skype_in = _SkypeNotifyCallback(self.bus, self.notify) 134 except dbus.DBusException: 135 if not Wait: 136 break 137 time.sleep(1.0) 138 else: 139 break 140 else: 141 raise ISkypeAPIError('Skype attach timeout') 142 finally: 143 t.cancel() 144 c = ICommand(-1, 'NAME %s' % self.FriendlyName, '', True, Timeout) 145 if self.skype_out: 146 self.SendCommand(c) 147 if c.Reply != 'OK': 148 self.skype_out = None 149 self.SetAttachmentStatus(apiAttachRefused) 150 return 151 self.SendCommand(ICommand(-1, 'PROTOCOL %s' % self.Protocol)) 152 self.SetAttachmentStatus(apiAttachSuccess)
153
154 - def IsRunning(self):
155 try: 156 self.bus.get_object('com.Skype.API', '/com/Skype') 157 return True 158 except dbus.DBusException: 159 return False
160
161 - def Start(self, Minimized=False, Nosplash=False):
162 # options are not supported as of Skype 1.4 Beta for Linux 163 if not self.IsRunning(): 164 import os 165 if os.fork() == 0: # we're child 166 os.setsid() 167 os.execlp('skype')
168
169 - def Shutdown(self):
170 import os 171 from signal import SIGINT 172 fh = os.popen('ps -o %p --no-heading -C skype') 173 pid = fh.readline().strip() 174 fh.close() 175 if pid: 176 os.kill(int(pid), SIGINT) 177 self.skype_in = self.skype_out = None
178
179 - def SendCommand(self, Command):
180 if not self.skype_out: 181 self.Attach(Command.Timeout) 182 self.CommandsStackPush(Command) 183 self.CallHandler('send', Command) 184 com = u'#%d %s' % (Command.Id, Command.Command) 185 self.DebugPrint('->', repr(com)) 186 if Command.Blocking: 187 Command._event = event = threading.Event() 188 else: 189 Command._timer = timer = threading.Timer(Command.Timeout / 1000.0, self.CommandsStackPop, (Command.Id,)) 190 try: 191 result = self.skype_out.Invoke(com) 192 except dbus.DBusException, err: 193 raise ISkypeAPIError(str(err)) 194 if result.startswith(u'#%d ' % Command.Id): 195 self.notify(result) 196 if Command.Blocking: 197 event.wait(Command.Timeout / 1000.0) 198 if not event.isSet(): 199 raise ISkypeAPIError('Skype command timeout') 200 else: 201 timer.start()
202
203 - def notify(self, com):
204 self.DebugPrint('<-', repr(com)) 205 if com.startswith(u'#'): 206 p = com.find(u' ') 207 Command = self.CommandsStackPop(int(com[1:p])) 208 if Command: 209 Command.Reply = com[p + 1:] 210 if Command.Blocking: 211 Command._event.set() 212 del Command._event 213 else: 214 Command._timer.cancel() 215 del Command._timer 216 self.CallHandler('rece', Command) 217 else: 218 self.CallHandler('rece_api', com[p + 1:]) 219 else: 220 self.CallHandler('rece_api', com)
221
222 - def dbus_name_owner_changed(self, owned, old_owner, new_owner):
223 self.DebugPrint('<-', 'dbus_name_owner_changed') 224 if new_owner == '': 225 self.skype_out = None 226 self.SetAttachmentStatus(cndexp(new_owner == '', 227 apiAttachNotAvailable, 228 apiAttachAvailable))
229