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
38
39 from faked_dbus import dbus
40 else:
41 raise
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
53
54 @dbus.service.method(dbus_interface='com.Skype.API.Client')
56 self.notify(unicode(com))
57
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
84 self.DebugPrint('thread started')
85 if hasattr(self, 'mainloop'):
86 self.mainloop.run()
87 self.DebugPrint('thread finished')
88
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
102
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
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
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
163 if not self.IsRunning():
164 import os
165 if os.fork() == 0:
166 os.setsid()
167 os.execlp('skype')
168
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
202
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
229