root/branches/gajim_0.10.1/src/gajim-remote.py

Revision 5927, 12.3 kB (checked in by nicfit, 3 years ago)

Since gajim-remote is a user script and the output of which is often parsed I think
it unwise to include the "inconsistent use of tabs and spaces in indentation" warning.
Filtering stderr works, but may also filter out useful info.

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
Line 
1#!/bin/sh
2''':'
3exec python -OOt "$0" ${1+"$@"}
4' '''
5##      scripts/gajim-remote.py
6##
7## Contributors for this file:
8##      - Yann Le Boulanger <asterix@lagaule.org>
9##      - Nikos Kouremenos <kourem@gmail.com>
10##      - Dimitur Kirov <dkirov@gmail.com>
11##
12## Copyright (C) 2003-2004 Yann Le Boulanger <asterix@lagaule.org>
13##                         Vincent Hanquez <tab@snarc.org>
14## Copyright (C) 2005 Yann Le Boulanger <asterix@lagaule.org>
15##                    Vincent Hanquez <tab@snarc.org>
16##                    Nikos Kouremenos <nkour@jabber.org>
17##                    Dimitur Kirov <dkirov@gmail.com>
18##                    Travis Shirk <travis@pobox.com>
19##                    Norman Rasmussen <norman@rasmussen.co.za>
20##
21## This program is free software; you can redistribute it and/or modify
22## it under the terms of the GNU General Public License as published
23## by the Free Software Foundation; version 2 only.
24##
25## This program is distributed in the hope that it will be useful,
26## but WITHOUT ANY WARRANTY; without even the implied warranty of
27## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28## GNU General Public License for more details.
29##
30
31# gajim-remote help will show you the DBUS API of Gajim
32
33import sys
34import locale
35import signal
36signal.signal(signal.SIGINT, signal.SIG_DFL) # ^C exits the application
37
38from common import exceptions
39from common import i18n
40
41_ = i18n._
42i18n.init()
43try:
44        PREFERRED_ENCODING = locale.getpreferredencoding()
45except:
46        sys.exc_clear()
47        PREFERRED_ENCODING = 'UTF-8'
48
49def send_error(error_message):
50        '''Writes error message to stderr and exits'''
51        print >> sys.stderr, error_message.encode(PREFERRED_ENCODING)
52        sys.exit(1)
53
54try:
55        import dbus
56except:
57        raise exceptions.DbusNotSupported
58
59_version = getattr(dbus, 'version', (0, 20, 0))
60if _version[1] >= 41:
61        import dbus.service
62        import dbus.glib
63
64OBJ_PATH = '/org/gajim/dbus/RemoteObject'
65INTERFACE = 'org.gajim.dbus.RemoteInterface'
66SERVICE = 'org.gajim.dbus'
67BASENAME = 'gajim-remote'
68
69
70class GajimRemote:
71       
72        def __init__(self):
73                self.argv_len = len(sys.argv) 
74                # define commands dict. Prototype :
75                # {
76                #       'command': [comment, [list of arguments] ]
77                # }
78                #
79                # each argument is defined as a tuple:
80                #    (argument name, help on argument, is mandatory)
81                #
82                self.commands = {
83                        'help':[
84                                        _('shows a help on specific command'),
85                                        [
86                                                #User gets help for the command, specified by this parameter
87                                                (_('command'), 
88                                                _('show help on command'), False)
89                                        ]
90                                ], 
91                        'toggle_roster_appearance' : [
92                                        _('Shows or hides the roster window'),
93                                        []
94                                ], 
95                        'show_next_unread': [
96                                        _('Popups a window with the next unread message'),
97                                        []
98                                ],
99                        'list_contacts': [
100                                        _('Prints a list of all contacts in the roster. Each contact appear on a separate line'),
101                                        [
102                                                (_('account'), _('show only contacts of the given account'), False)
103                                        ]
104                                       
105                                ],     
106                        'list_accounts': [
107                                        _('Prints a list of registered accounts'),
108                                        []
109                                ], 
110                        'change_status': [
111                                        _('Changes the status of account or accounts'),
112                                        [
113                                                (_('status'), _('one of: offline, online, chat, away, xa, dnd, invisible '), True), 
114                                                (_('message'), _('status message'), False), 
115                                                (_('account'), _('change status of account "account". '
116                'If not specified, try to change status of all accounts that have '
117                '"sync with global status" option set'), False)
118                                        ]
119                                ],
120                        'open_chat': [ 
121                                        _('Shows the chat dialog so that you can send messages to a contact'), 
122                                        [
123                                                ('jid', _('JID of the contact that you want to chat with'),
124                                                        True), 
125                                                (_('account'), _('if specified, contact is taken from the '
126                                                'contact list of this account'), False)
127                                        ]
128                                ],
129                        'send_message':[
130                                        _('Sends new message to a contact in the roster. Both OpenPGP key '
131                                        'and account are optional. If you want to set only \'account\', '
132                                        'without \'OpenPGP key\', just set \'OpenPGP key\' to \'\'.'), 
133                                        [
134                                                ('jid', _('JID of the contact that will receive the message'), True),
135                                                (_('message'), _('message contents'), True),
136                                                (_('pgp key'), _('if specified, the message will be encrypted '
137                                                        'using this public key'), False),
138                                                (_('account'), _('if specified, the message will be sent '
139                                                        'using this account'), False),
140                                        ]
141                                ], 
142                        'contact_info': [
143                                        _('Gets detailed info on a contact'), 
144                                        [
145                                                ('jid', _('JID of the contact'), True)
146                                        ]
147                                ],
148                        'account_info': [
149                                        _('Gets detailed info on a account'), 
150                                        [
151                                                ('account', _('Name of the account'), True)
152                                        ]
153                                ],
154                        'send_file': [
155                                        _('Sends file to a contact'),
156                                        [
157                                                (_('file'), _('File path'), True),
158                                                ('jid', _('JID of the contact'), True),
159                                                (_('account'), _('if specified, file will be sent using this '
160                                                        'account'), False)
161                                        ]
162                                ],
163                        'prefs_list': [
164                                        _('Lists all preferences and their values'),
165                                        [ ]
166                                ],
167                        'prefs_put': [
168                                        _('Sets value of \'key\' to \'value\'.'),
169                                        [
170                                                (_('key=value'), _('\'key\' is the name of the preference, '
171                                                        '\'value\' is the value to set it to'), True)
172                                        ]
173                                ],
174                        'prefs_del': [
175                                        _('Deletes a preference item'),
176                                        [ 
177                                                (_('key'), _('name of the preference to be deleted'), True) 
178                                        ]
179                                ],
180                        'prefs_store': [
181                                        _('Writes the current state of Gajim preferences to the .config '
182                                                'file'),
183                                        [ ]
184                                ],
185                        'remove_contact': [
186                                        _('Removes contact from roster'),
187                                        [ 
188                                                ('jid', _('JID of the contact'), True),
189                                                (_('account'), _('if specified, contact is taken from the '
190                                                        'contact list of this account'), False)
191                                               
192                                        ]
193                                ],
194                        'add_contact': [
195                                        _('Adds contact to roster'),
196                                        [ 
197                                                (_('account'), _('Adds new contact to this account.'), True)
198                                        ]
199                                ],
200                       
201                        'get_status': [
202                                _('Returns current status (the global one unless account is specified)'),
203                                        [
204                                                (_('account'), _(''), False)
205                                        ]
206                                ],
207                       
208                        'get_status_message': [
209                                _('Returns current status message(the global one unless account is specified)'),
210                                        [
211                                                (_('account'), _(''), False)
212                                        ]
213                                ],                             
214
215                        'get_unread_msgs_number': [
216                                _('Returns number of unreaded messages'),
217                                        [ ]
218                                ],
219                        }
220                if self.argv_len  < 2 or \
221                        sys.argv[1] not in self.commands.keys(): # no args or bad args
222                        send_error(self.compose_help())
223                self.command = sys.argv[1]
224                if self.command == 'help':
225                        if self.argv_len == 3:
226                                print self.help_on_command(sys.argv[2]).encode(PREFERRED_ENCODING)
227                        else:
228                                print self.compose_help().encode(PREFERRED_ENCODING)
229                        sys.exit(0)
230               
231                self.init_connection()
232                self.check_arguments()
233               
234                if self.command == 'contact_info':
235                        if self.argv_len < 3:
236                                send_error(_('Missing argument "contact_jid"'))
237               
238                try:
239                        res = self.call_remote_method()
240                except exceptions.ServiceNotAvailable:
241                        # At this point an error message has already been displayed
242                        sys.exit(1)
243                else:
244                        self.print_result(res)
245               
246        def print_result(self, res):
247                ''' Print retrieved result to the output '''
248                if res is not None:
249                        if self.command in ('open_chat', 'send_message'):
250                                if self.command == 'send_message':
251                                        self.argv_len -= 2
252                               
253                                if res is False:
254                                        if self.argv_len < 4:
255                                                send_error(_('\'%s\' is not in your roster.\n'
256                                        'Please specify account for sending the message.') % sys.argv[2])
257                                        else:
258                                                send_error(_('You have no active account'))
259                        elif self.command == 'list_accounts':
260                                if isinstance(res, list):
261                                        for account in res:
262                                                if isinstance(account, unicode):
263                                                        print account.encode(PREFERRED_ENCODING)
264                                                else:
265                                                        print account
266                        elif self.command == 'account_info':
267                                if res:
268                                        print self.print_info(0, res, True)
269                        elif self.command == 'list_contacts':
270                                for account_dict in res:
271                                        print self.print_info(0, account_dict, True)
272                        elif self.command == 'prefs_list':
273                                pref_keys = res.keys()
274                                pref_keys.sort()
275                                for pref_key in pref_keys:
276                                        result = '%s = %s' % (pref_key, res[pref_key])
277                                        if isinstance(result, unicode): 
278                                                print result.encode(PREFERRED_ENCODING)
279                                        else:
280                                                print result
281                        elif self.command == 'contact_info':
282                                print self.print_info(0, res, True)
283                        elif res:
284                                print unicode(res).encode(PREFERRED_ENCODING)
285       
286        def init_connection(self):
287                ''' create the onnection to the session dbus,
288                or exit if it is not possible '''
289                try:
290                        self.sbus = dbus.SessionBus()
291                except:
292                        raise exceptions.SessionBusNotPresent
293               
294                if _version[1] >= 30:
295                        obj = self.sbus.get_object(SERVICE, OBJ_PATH)
296                        interface = dbus.Interface(obj, INTERFACE)
297                elif _version[1] < 30:
298                        self.service = self.sbus.get_service(SERVICE)
299                        interface = self.service.get_object(OBJ_PATH, INTERFACE)
300                else:
301                        send_error(_('Unknown D-Bus version: %s') % _version[1])
302                       
303                # get the function asked
304                self.method = interface.__getattr__(self.command)
305               
306        def make_arguments_row(self, args):
307                ''' return arguments list. Mandatory arguments are enclosed with:
308                '<', '>', optional arguments - with '[', ']' '''
309                str = ''
310                for argument in args:
311                        str += ' '
312                        if argument[2]:
313                                str += '<'
314                        else:
315                                str += '['
316                        str += argument[0]
317                        if argument[2]:
318                                str += '>'
319                        else:
320                                str += ']'
321                return str
322               
323        def help_on_command(self, command):
324                ''' return help message for a given command '''
325                if command in self.commands:
326                        command_props = self.commands[command]
327                        arguments_str = self.make_arguments_row(command_props[1])
328                        str = _('Usage: %s %s %s \n\t %s') % (BASENAME, command, 
329                                        arguments_str, command_props[0])
330                        if len(command_props[1]) > 0:
331                                str += '\n\n' + _('Arguments:') + '\n'
332                                for argument in command_props[1]:
333                                        str += ' ' +  argument[0] + ' - ' + argument[1] + '\n'
334                        return str
335                send_error(_('%s not found') % command)
336                       
337        def compose_help(self):
338                ''' print usage, and list available commands '''
339                str = _('Usage: %s command [arguments]\nCommand is one of:\n' ) % BASENAME
340                commands = self.commands.keys()
341                commands.sort()
342                for command in commands:
343                        str += '  ' + command
344                        for argument in self.commands[command][1]:
345                                str += ' '
346                                if argument[2]:
347                                        str += '<'
348                                else:
349                                        str += '['
350                                str += argument[0]
351                                if argument[2]:
352                                        str += '>'
353                                else:
354                                        str += ']'
355                        str += '\n'
356                return str
357               
358        def print_info(self, level, prop_dict, encode_return = False):
359                ''' return formated string from data structure '''
360                if prop_dict is None or not isinstance(prop_dict, (dict, list, tuple)):
361                        return ''
362                ret_str = ''
363                if isinstance(prop_dict, (list, tuple)):
364                        ret_str = ''
365                        spacing = ' ' * level * 4
366                        for val in prop_dict:
367                                if val is None:
368                                        ret_str +='\t'
369                                elif isinstance(val, int):
370                                        ret_str +='\t' + str(val)
371                                elif isinstance(val, (str, unicode)):
372                                        ret_str +='\t' + val
373                                elif isinstance(val, (list, tuple)):
374                                        res = ''
375                                        for items in val:
376                                                res += self.print_info(level+1, items)
377                                        if res != '':
378                                                ret_str += '\t' + res
379                                elif isinstance(val, dict):
380                                        ret_str += self.print_info(level+1, val)
381                        ret_str = '%s(%s)\n' % (spacing, ret_str[1:])
382                elif isinstance(prop_dict, dict):
383                        for key in prop_dict.keys():
384                                val = prop_dict[key]
385                                spacing = ' ' * level * 4
386                                if isinstance(val, (unicode, int, str)):
387                                        if val is not None:
388                                                val = val.strip()
389                                                ret_str += '%s%-10s: %s\n' % (spacing, key, val)
390                                elif isinstance(val, (list, tuple)):
391                                        res = ''
392                                        for items in val:
393                                                res += self.print_info(level+1, items)
394                                        if res != '':
395                                                ret_str += '%s%s: \n%s' % (spacing, key, res)
396                                elif isinstance(val, dict):
397                                        res = self.print_info(level+1, val)
398                                        if res != '':
399                                                ret_str += '%s%s: \n%s' % (spacing, key, res)
400                if (encode_return):
401                        try:
402                                ret_str = ret_str.encode(PREFERRED_ENCODING)
403                        except:
404                                pass
405                return ret_str
406       
407        def check_arguments(self):
408                ''' Make check if all necessary arguments are given '''
409                argv_len = self.argv_len - 2
410                args = self.commands[self.command][1]
411                if len(args) > argv_len:
412                        if args[argv_len][2]:
413                                send_error(_('Argument "%s" is not specified. \n'
414                                        'Type "%s help %s" for more info') % 
415                                        (args[argv_len][0], BASENAME, self.command))
416       
417        def call_remote_method(self):
418                ''' calls self.method with arguments from sys.argv[2:] '''
419                args = sys.argv[2:]
420                args = [i.decode(PREFERRED_ENCODING) for i in sys.argv[2:]]
421                if _version[1] >= 41:
422                        args = [dbus.String(i) for i in args]
423                else:
424                        args = [i.encode('UTF-8') for i in sys.argv[2:]]
425                try:
426                        res = self.method(*args)
427                        return res
428                except Exception:
429                        raise exceptions.ServiceNotAvailable
430                return None
431
432if __name__ == '__main__':
433        GajimRemote()
Note: See TracBrowser for help on using the browser.