root/branches/gajim_0.9/src/remote_control.py

Revision 4768, 15.4 kB (checked in by asterix, 3 years ago)

gajim-remote get_status without account now return global status

  • Property svn:eol-style set to LF
Line 
1##      remote_control.py
2##
3## Contributors for this file:
4##      - Yann Le Boulanger <asterix@lagaule.org>
5##      - Nikos Kouremenos <kourem@gmail.com>
6##      - Dimitur Kirov <dkirov@gmail.com>
7##      - Andrew Sayman <lorien420@myrealbox.com>
8##
9## Copyright (C) 2003-2004 Yann Le Boulanger <asterix@lagaule.org>
10##                         Vincent Hanquez <tab@snarc.org>
11## Copyright (C) 2005 Yann Le Boulanger <asterix@lagaule.org>
12##                    Vincent Hanquez <tab@snarc.org>
13##                    Nikos Kouremenos <nkour@jabber.org>
14##                    Dimitur Kirov <dkirov@gmail.com>
15##                    Travis Shirk <travis@pobox.com>
16##                    Norman Rasmussen <norman@rasmussen.co.za>
17##
18## This program is free software; you can redistribute it and/or modify
19## it under the terms of the GNU General Public License as published
20## by the Free Software Foundation; version 2 only.
21##
22## This program is distributed in the hope that it will be useful,
23## but WITHOUT ANY WARRANTY; without even the implied warranty of
24## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25## GNU General Public License for more details.
26##
27
28import gobject
29import gtk
30import os
31import sys
32
33import systray
34
35from common import exceptions
36from common import gajim
37from common import helpers
38from time import time
39from common import i18n
40from dialogs import AddNewContactWindow
41_ = i18n._
42
43import dbus_support
44if dbus_support.supported:
45        import dbus
46        if dbus_support.version >= (0, 41, 0):
47                import dbus.service
48                import dbus.glib # cause dbus 0.35+ doesn't return signal replies without it
49                DbusPrototype = dbus.service.Object
50        elif dbus_support.version >= (0, 20, 0):
51                DbusPrototype = dbus.Object
52        else: #dbus is not defined
53                DbusPrototype = str 
54
55INTERFACE = 'org.gajim.dbus.RemoteInterface'
56OBJ_PATH = '/org/gajim/dbus/RemoteObject'
57SERVICE = 'org.gajim.dbus'
58
59STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
60        'invisible']
61
62class Remote:
63        def __init__(self):
64                self.signal_object = None
65                session_bus = dbus_support.session_bus.SessionBus()
66               
67                if dbus_support.version[1] >= 41:
68                        service = dbus.service.BusName(SERVICE, bus=session_bus)
69                        self.signal_object = SignalObject(service)
70                elif dbus_support.version[1] <= 40 and dbus_support.version[1] >= 20:
71                        service=dbus.Service(SERVICE, session_bus)
72                        self.signal_object = SignalObject(service)
73
74        def raise_signal(self, signal, arg):
75                if self.signal_object:
76                        self.signal_object.raise_signal(signal, repr(arg))
77               
78
79class SignalObject(DbusPrototype):
80        ''' Local object definition for /org/gajim/dbus/RemoteObject. This doc must
81        not be visible, because the clients can access only the remote object. '''
82       
83        def __init__(self, service):
84                self.first_show = True
85                self.vcard_account = None
86
87                # register our dbus API
88                if dbus_support.version[1] >= 41:
89                        DbusPrototype.__init__(self, service, OBJ_PATH)
90                elif dbus_support.version[1] >= 30:
91                        DbusPrototype.__init__(self, OBJ_PATH, service)
92                else:
93                        DbusPrototype.__init__(self, OBJ_PATH, service, 
94                        [       self.toggle_roster_appearance,
95                                self.show_next_unread,
96                                self.list_contacts,
97                                self.list_accounts,
98                                self.change_status,
99                                self.open_chat,
100                                self.send_message,
101                                self.contact_info,
102                                self.send_file,
103                                self.prefs_list,
104                                self.prefs_store,
105                                self.prefs_del,
106                                self.prefs_put,
107                                self.add_contact,
108                                self.remove_contact,
109                                self.get_status,
110                        ])
111
112        def raise_signal(self, signal, arg):
113                ''' raise a signal, with a single string message '''
114                if dbus_support.version[1] >= 30:
115                        from dbus import dbus_bindings
116                        message = dbus_bindings.Signal(OBJ_PATH, INTERFACE, signal)
117                        i = message.get_iter(True)
118                        i.append(arg)
119                        self._connection.send(message)
120                else:
121                        self.emit_signal(INTERFACE, signal, arg)
122
123       
124        # signals
125        def VcardInfo(self, *vcard):
126                pass
127
128        def get_status(self, *args):
129                '''get_status(account = None)
130                returns status (show to be exact) which is the global one
131                unless account is given'''
132                account = self._get_real_arguments(args, 1)[0]
133                accounts = gajim.contacts.keys()
134                if not account:
135                        # If user did not ask for account, returns the global status
136                        return helpers.get_global_show()
137                # return show for the given account
138                index = gajim.connections[account].connected
139                return STATUS_LIST[index]
140
141        def send_file(self, *args):
142                '''send_file(file_path, jid, account=None)
143                send file, located at 'file_path' to 'jid', using account
144                (optional) 'account' '''
145                file_path, jid, account = self._get_real_arguments(args, 3)
146                accounts = gajim.contacts.keys()
147               
148                # if there is only one account in roster, take it as default
149                # if user did not ask for account
150                if not account and len(accounts) == 1:
151                        account = accounts[0]
152                if account:
153                        if gajim.connections[account].connected > 1: # account is  online
154                                connected_account = gajim.connections[account]
155                else:
156                        for account in accounts:
157                                if gajim.contacts[account].has_key(jid) and \
158                                        gajim.connections[account].connected > 1: # account is  online
159                                        connected_account = gajim.connections[account]
160                                        break
161                if gajim.contacts.has_key(account) and \
162                        gajim.contacts[account].has_key(jid):
163                        contact = gajim.get_highest_prio_contact_from_contacts(
164                                gajim.contacts[account][jid])
165                else:
166                        contact = jid
167               
168                if connected_account:
169                        if os.path.isfile(file_path): # is it file?
170                                gajim.interface.instances['file_transfers'].send_file(account, 
171                                        contact, file_path)
172                                return True
173                return False
174               
175        def send_message(self, *args):
176                ''' send_message(jid, message, keyID=None, account=None)
177                send 'message' to 'jid', using account (optional) 'account'.
178                if keyID is specified, encrypt the message with the pgp key '''
179                jid, message, keyID, account = self._get_real_arguments(args, 4)
180                if not jid or not message:
181                        return None # or raise error
182                if not keyID:
183                        keyID = ''
184                connected_account = None
185                accounts = gajim.contacts.keys()
186               
187                # if there is only one account in roster, take it as default
188                if not account and len(accounts) == 1:
189                        account = accounts[0]
190                if account:
191                        if gajim.connections[account].connected > 1: # account is  online
192                                connected_account = gajim.connections[account]
193                else:
194                        for account in accounts:
195                                if gajim.contacts[account].has_key(jid) and \
196                                        gajim.connections[account].connected > 1: # account is  online
197                                        connected_account = gajim.connections[account]
198                                        break
199                if connected_account:
200                        res = connected_account.send_message(jid, message, keyID)
201                        return True
202                return False
203
204        def open_chat(self, *args):
205                ''' start_chat(jid, account=None) -> shows the tabbed window for new
206                message to 'jid', using account(optional) 'account' '''
207                jid, account = self._get_real_arguments(args, 2)
208                if not jid:
209                        # FIXME: raise exception for missing argument (dbus0.35+)
210                        return None
211                if jid.startswith('xmpp:'):
212                        jid = jid[5:] # len('xmpp:') = 5
213
214                if account:
215                        accounts = [account]
216                else:
217                        accounts = gajim.connections.keys()
218                        if len(accounts) == 1:
219                                account = accounts[0]
220                connected_account = None
221                first_connected_acct = None
222                for acct in accounts:
223                        if gajim.connections[acct].connected > 1: # account is  online
224                                if gajim.interface.instances[acct]['chats'].has_key(jid):
225                                        connected_account = acct
226                                        break
227                                # jid is in roster
228                                elif gajim.contacts[acct].has_key(jid):
229                                        connected_account = acct
230                                        break
231                                # we send the message to jid not in roster, because account is specified,
232                                # or there is only one account
233                                elif account: 
234                                        connected_account = acct
235                                elif first_connected_acct is None:
236                                        first_connected_acct = acct
237               
238                # if jid is not a conntact, open-chat with first connected account
239                if connected_account is None and first_connected_acct:
240                        connected_account = first_connected_acct
241               
242                if connected_account:
243                        gajim.interface.roster.new_chat_from_jid(connected_account, jid)
244                        # preserve the 'steal focus preservation'
245                        win = gajim.interface.instances[connected_account]['chats'][jid].window
246                        if win.get_property('visible'):
247                                win.window.focus()
248                        return True
249                return False
250       
251        def change_status(self, *args, **keywords):
252                ''' change_status(status, message, account). account is optional -
253                if not specified status is changed for all accounts. '''
254                status, message, account = self._get_real_arguments(args, 3)
255                if status not in ('offline', 'online', 'chat', 
256                        'away', 'xa', 'dnd', 'invisible'):
257                        # FIXME: raise exception for bad status (dbus0.35)
258                        return None
259                if account:
260                        gobject.idle_add(gajim.interface.roster.send_status, account, 
261                                status, message)
262                else:
263                        # account not specified, so change the status of all accounts
264                        for acc in gajim.contacts.keys():
265                                gobject.idle_add(gajim.interface.roster.send_status, acc, 
266                                        status, message)
267                return None
268
269        def show_next_unread(self, *args):
270                ''' Show the window(s) with next waiting messages in tabbed/group chats. '''
271                #FIXME: when systray is disabled this method does nothing.
272                if len(gajim.interface.systray.jids) != 0:
273                        gajim.interface.systray.handle_first_event()
274
275        def contact_info(self, *args):
276                ''' get vcard info for a contact. This method returns nothing.
277                You have to register the 'VcardInfo' signal to get the real vcard. '''
278                [jid] = self._get_real_arguments(args, 1)
279                if not isinstance(jid, unicode):
280                        jid = unicode(jid)
281                if not jid:
282                        # FIXME: raise exception for missing argument (0.3+)
283                        return None
284
285                accounts = gajim.contacts.keys()
286               
287                for account in accounts:
288                        if gajim.contacts[account].__contains__(jid):
289                                self.vcard_account =  account
290                                gajim.connections[account].request_vcard(jid)
291                                break
292                return None
293
294        def list_accounts(self, *args):
295                ''' list register accounts '''
296                if gajim.contacts:
297                        result = gajim.contacts.keys()
298                        if result and len(result) > 0:
299                                result_array = []
300                                for account in result:
301                                        result_array.append(account.encode('utf-8'))
302                                return result_array
303                return None
304
305        def list_contacts(self, *args):
306                ''' list all contacts in the roster. If the first argument is specified,
307                then return the contacts for the specified account '''
308                [for_account] = self._get_real_arguments(args, 1)
309                result = []
310                if not gajim.contacts or len(gajim.contacts) == 0:
311                        return None
312                if for_account:
313                        if gajim.contacts.has_key(for_account):
314                                for jid in gajim.contacts[for_account]:
315                                        item = self._serialized_contacts(
316                                                gajim.contacts[for_account][jid])
317                                        if item:
318                                                result.append(item)
319                        else:
320                                # 'for_account: is not recognised:',
321                                return None
322                else:
323                        for account in gajim.contacts:
324                                for jid in gajim.contacts[account]:
325                                        item = self._serialized_contacts(gajim.contacts[account][jid])
326                                        if item:
327                                                result.append(item)
328                # dbus 0.40 does not support return result as empty list
329                if result == []:
330                        return None
331                return result
332
333        def toggle_roster_appearance(self, *args):
334                ''' shows/hides the roster window '''
335                win = gajim.interface.roster.window
336                if win.get_property('visible'):
337                        gobject.idle_add(win.hide)
338                else:
339                        win.present()
340                        # preserve the 'steal focus preservation'
341                        if self._is_first():
342                                win.window.focus()
343                        else:
344                                win.window.focus(long(time()))
345
346        def prefs_list(self, *args):
347                prefs_dict = {}
348                def get_prefs(data, name, path, value):
349                        if value is None:
350                                return
351                        key = ""
352                        if path is not None:
353                                for node in path:
354                                        key += node + "#"
355                        key += name
356                        prefs_dict[key] = unicode(value[1])
357                gajim.config.foreach(get_prefs)
358                return repr(prefs_dict)
359               
360        def prefs_store(self, *args):
361                try:
362                        gajim.interface.save_config()
363                except Exception, e:
364                        return False
365                return True
366       
367        def prefs_del(self, *args):
368                [key] = self._get_real_arguments(args, 1)
369                if not key:
370                        return False
371                key_path = key.split('#', 2)
372                if len(key_path) != 3:
373                        return False
374                if key_path[2] == '*':
375                        gajim.config.del_per(key_path[0], key_path[1])
376                else:
377                        gajim.config.del_per(key_path[0], key_path[1], key_path[2])
378                return True
379               
380        def prefs_put(self, *args):
381                [key] = self._get_real_arguments(args, 1)
382                if not key:
383                        return False
384                key_path = key.split('#', 2)
385                if len(key_path) < 3:
386                        subname, value = key.split('=', 1)
387                        gajim.config.set(subname, value)
388                        return True
389                subname, value = key_path[2].split('=', 1)
390                gajim.config.set_per(key_path[0], key_path[1], subname, value)
391                return True
392               
393        def add_contact(self, *args):
394                [account] = self._get_real_arguments(args, 1)
395                if gajim.contacts.has_key(account):
396                        AddNewContactWindow(account)
397                        return True
398                return False
399       
400        def remove_contact(self, *args):
401                [jid, account] = self._get_real_arguments(args, 2)
402                accounts = gajim.contacts.keys()
403               
404                # if there is only one account in roster, take it as default
405                if account:
406                        accounts = [account]
407                else:
408                        accounts = gajim.contacts.keys()
409                contact_exists = False
410                for account in accounts:
411                        if gajim.contacts[account].has_key(jid):
412                                gajim.connections[account].unsubscribe(jid)
413                                for contact in gajim.contacts[account][jid]:
414                                        gajim.interface.roster.remove_contact(contact, account)
415                                del gajim.contacts[account][jid]
416                                contact_exists = True
417                return contact_exists
418               
419        def _is_first(self):
420                if self.first_show:
421                        self.first_show = False
422                        return True
423                return False
424
425        def _get_real_arguments(self, args, desired_length):
426                # supresses the first 'message' argument, which is set in dbus 0.23
427                if dbus_support.version[1] == 20:
428                        args=args[1:]
429                if desired_length > 0:
430                        args = list(args)
431                        args.extend([None] * (desired_length - len(args)))
432                        args = args[:desired_length]
433                return args
434
435        def _serialized_contacts(self, contacts):
436                ''' get info from list of Contact objects and create a serialized
437                dict for sending it over dbus '''
438                if not contacts:
439                        return None
440                prim_contact = None # primary contact
441                for contact in contacts:
442                        if prim_contact == None or contact.priority > prim_contact.priority:
443                                prim_contact = contact
444                contact_dict = {}
445                contact_dict['name'] = prim_contact.name
446                contact_dict['show'] = prim_contact.show
447                contact_dict['jid'] = prim_contact.jid
448                if prim_contact.keyID:
449                        keyID = None
450                        if len(prim_contact.keyID) == 8:
451                                keyID = prim_contact.keyID
452                        elif len(prim_contact.keyID) == 16:
453                                keyID = prim_contact.keyID[8:]
454                        if keyID:
455                                contact_dict['openpgp'] = keyID
456                contact_dict['resources'] = []
457                for contact in contacts:
458                        contact_dict['resources'].append(tuple([contact.resource, 
459                                contact.priority, contact.status]))
460                return repr(contact_dict)
461       
462       
463        if dbus_support.version[1] >= 30 and dbus_support.version[1] <= 40:
464                method = dbus.method
465                signal = dbus.signal
466        elif dbus_support.version[1] >= 41:
467                method = dbus.service.method
468                signal = dbus.service.signal
469
470        if dbus_support.version[1] >= 30:
471                # prevent using decorators, because they are not supported
472                # on python < 2.4
473                # FIXME: use decorators when python2.3 (and dbus 0.23) is OOOOOOLD
474                toggle_roster_appearance = method(INTERFACE)(toggle_roster_appearance)
475                list_contacts = method(INTERFACE)(list_contacts)
476                list_accounts = method(INTERFACE)(list_accounts)
477                show_next_unread = method(INTERFACE)(show_next_unread)
478                change_status = method(INTERFACE)(change_status)
479                open_chat = method(INTERFACE)(open_chat)
480                contact_info = method(INTERFACE)(contact_info)
481                send_message = method(INTERFACE)(send_message)
482                send_file = method(INTERFACE)(send_file)
483                VcardInfo = signal(INTERFACE)(VcardInfo)
484                prefs_list = method(INTERFACE)(prefs_list)
485                prefs_put = method(INTERFACE)(prefs_put)
486                prefs_del = method(INTERFACE)(prefs_del)
487                prefs_store = method(INTERFACE)(prefs_store)
488                remove_contact = method(INTERFACE)(remove_contact)
489                add_contact = method(INTERFACE)(add_contact)
490                get_status = method(INTERFACE)(get_status)
Note: See TracBrowser for help on using the browser.