root/branches/gajim_0.8/scripts/gajim-remote.py

Revision 3111, 13.6 kB (checked in by nk, 3 years ago)

more fixes by nebulum [ru transl]. Dimitur plz have a look. thanks in advance

  • Property svn:executable set to *
Line 
1#!/bin/sh
2''':'
3exec python -OOt "$0" ${1+"$@"}
4' '''
5##      scripts/gajim-remote.py
6##
7## Gajim Team:
8##      - Yann Le Boulanger <asterix@lagaule.org>
9##      - Vincent Hanquez <tab@snarc.org>
10##      - Nikos Kouremenos <kourem@gmail.com>
11##      - Dimitur Kirov <dkirov@gmail.com>
12##
13##      Copyright (C) 2003-2005 Gajim Team
14##
15## This program is free software; you can redistribute it and/or modify
16## it under the terms of the GNU General Public License as published
17## by the Free Software Foundation; version 2 only.
18##
19## This program is distributed in the hope that it will be useful,
20## but WITHOUT ANY WARRANTY; without even the implied warranty of
21## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22## GNU General Public License for more details.
23##
24
25# gajim-remote help will show you the DBUS API of Gajim
26
27import sys
28import gtk
29import gobject
30
31import signal
32
33signal.signal(signal.SIGINT, signal.SIG_DFL) # ^C exits the application
34
35import i18n
36
37_ = i18n._
38i18n.init()
39
40
41try:
42        import dbus
43except:
44        send_error('Dbus is not supported.\n')
45
46_version = getattr(dbus, 'version', (0, 20, 0))
47if _version[1] >= 41:
48        import dbus.service
49        import dbus.glib
50
51OBJ_PATH = '/org/gajim/dbus/RemoteObject'
52INTERFACE = 'org.gajim.dbus.RemoteInterface'
53SERVICE = 'org.gajim.dbus'
54BASENAME = 'gajim-remote'
55
56class GajimRemote:
57       
58        def __init__(self):
59                self.argv_len = len(sys.argv) 
60                # define commands dict. Prototype :
61                # {
62                #       'command': [comment, [list of arguments] ]
63                # }
64                #
65                # each argument is defined as a tuple:
66                #    (argument name, help on argument, is mandatory)
67                #
68                self.commands = {
69                        'help':[
70                                        _('show a help on specific command'),
71                                        [
72                                                #parameter, named "on_command". User gets help for the command, specified by this parameter
73                                                (_('on_command'), 
74                                                _('show help on command'), False)
75                                        ]
76                                ], 
77                        'toggle_roster_appearance' : [
78                                        _('Shows or hides the roster window'),
79                                        []
80                                ], 
81                        'show_next_unread': [
82                                        _('Popup a window with the next unread message'),
83                                        []
84                                ],
85                        'list_contacts': [
86                                        _('Print a list of all contacts in the roster. \
87Each contact appear on a separate line'),
88                                        [
89                                                (_('account'), _('show only contacts of the \
90given account'), False)
91                                        ]
92                                       
93                                ],     
94                        'list_accounts': [
95                                        _('Print a list of registered accounts'),
96                                        []
97                                ], 
98                        'change_status': [
99                                        _('Change the status of account or accounts'),
100                                        [
101                                                (_('status'), _('one of: offline, online, chat, away, \
102xa, dnd, invisible '), True), 
103                                                (_('message'), _('status message'), False), 
104                                                (_('account'), _('change status of account "account". \
105If not specified, try to change status of all accounts that \
106have "sync with global status" option set'), False)
107                                        ]
108                                ],
109                        'open_chat': [ 
110                                        _('Show the chat dialog so that you can send message to a \
111contact'), 
112                                        [
113                                                #tell nkour that should be JID of the contact
114                                                ('jid', _('jid of the contact that you want to chat \
115with'),
116                                                        True), 
117                                                (_('account'), _('if specified, contact is taken from \
118the contact list of this account'), False)
119                                        ]
120                                ],
121                        'send_message':[
122                                        #OpenPGP key here too (tlel that to nkour)
123                                        _('Send new message to a contact in the roster. Both OpenPGP \
124key and account are optional. If you want to set only \'account\', without \
125\'pgp key\', just set \'pgp key\' to \'\'.'), 
126                                        [
127                                                #tell nkour that should be JID of the contact
128                                                ('jid', _('jid of the contact that will receive the \
129message'), True),
130                                                (_('message'), _('message contents'), True),
131                                                #tell to nkour it should be OpenPGP key
132                                                (_('pgp key'), _('if specified, the message will be \
133encrypted using this public key'), False),
134                                                (_('account'), _('if specified, the message will be \
135sent using this account'), False),
136                                        ]
137                                ], 
138                        'contact_info': [
139                                        _('Get detailed info on a contact'), 
140                                        [
141                                                #JID of the contact (tell that to nkour)
142                                                ('jid', _('jid of the contact'), True)
143                                        ]
144                                ]
145                        }
146                if self.argv_len  < 2 or \
147                        sys.argv[1] not in self.commands.keys(): # no args or bad args
148                        self.send_error(self.compose_help())
149                self.command = sys.argv[1]
150               
151                if self.command == 'help':
152                        if self.argv_len == 3:
153                                print self.help_on_command(sys.argv[2])
154                        else:
155                                print self.compose_help()
156                        sys.exit()
157               
158                self.init_connection()
159                self.check_arguments()
160               
161                if self.command == 'contact_info':
162                        if self.argv_len < 3:
163                                self.send_error(_('Missing argument "contact_jid"'))
164                        try:
165                                id = self.sbus.add_signal_receiver(self.show_vcard_info, 
166                                        'VcardInfo', INTERFACE, SERVICE, OBJ_PATH)
167                        except:
168                                self.send_error(_('Service not available'))
169               
170                res = self.call_remote_method()
171                self.print_result(res)
172               
173                if self.command == 'contact_info':
174                        gobject.timeout_add(10000, self.gtk_quit) # wait 10 sec for response
175                        gtk.main()
176       
177        def print_result(self, res):
178                ''' Print retrieved result to the output '''
179                if res is not None:
180                        if self.command in ['open_chat', 'send_message']:
181                                if self.command == 'send_message':
182                                        self.argv_len -= 2
183                               
184                                if res == False:
185                                        if self.argv_len < 4:
186                                                self.send_error(_('\'%s\' is not in your roster.\n\
187Please specify account for sending the message.') % sys.argv[2])
188                                        else:
189                                                self.send_error(_('You have no active account'))
190                        elif self.command == 'list_accounts':
191                                if type(res) == list:
192                                        for account in res:
193                                                print account
194                        elif self.command == 'list_contacts':
195                                for single_res in res:
196                                        accounts = self.unrepr(single_res)
197                                        for account_dict in accounts:
198                                                print self.print_info(0, account_dict)
199                        elif res:
200                                print res
201       
202        def init_connection(self):
203                ''' create the onnection to the session dbus,
204                or exit if it is not possible '''
205                try:
206                        self.sbus = dbus.SessionBus()
207                except:
208                        self.send_error(_('Session bus is not available.'))
209               
210                if _version[1] >= 30 and _version[1] <= 42:
211                        obj = self.sbus.get_object(SERVICE, OBJ_PATH)
212                        interface = dbus.Interface(obj, INTERFACE)
213                elif _version[1] < 30:
214                        self.service = self.sbus.get_service(SERVICE)
215                        interface = self.service.get_object(OBJ_PATH, INTERFACE)
216                else:
217                        #say to nkour that this should be Unknown D-Bus version: %s (thanks nebulam)
218                        send_error(_('Unknown dbus version: %s') % _version)
219                       
220                # get the function asked
221                self.method = interface.__getattr__(self.command)
222               
223        def make_arguments_row(self, args):
224                ''' return arguments list. Mandatory arguments are enclosed with:
225                '<', '>', optional arguments - with '[', ']' '''
226                str = ''
227                for argument in args:
228                        str += ' '
229                        if argument[2]:
230                                str += '<'
231                        else:
232                                str += '['
233                        str += argument[0]
234                        if argument[2]:
235                                str += '>'
236                        else:
237                                str += ']'
238                return str
239               
240        def help_on_command(self, command):
241                ''' return help message for a given command '''
242                if command in self.commands:
243                        command_props = self.commands[command]
244                        arguments_str = self.make_arguments_row(command_props[1])
245                        str = _('Usage: %s %s %s \n\t') % (BASENAME, command, 
246                                        arguments_str)
247                        str += command_props[0] + '\n\n' + _('Arguments:') + '\n'
248                        for argument in command_props[1]:
249                                str += ' ' +  argument[0] + ' - ' + argument[1] + '\n'
250                        return str
251                self.send_error(_('%s not found') % command)
252                       
253        def compose_help(self):
254                ''' print usage, and list available commands '''
255                str = _('Usage: %s command [arguments]\nCommand is one of:\n' ) % BASENAME
256                for command in self.commands.keys():
257                        str += '  ' + command
258                        for argument in self.commands[command][1]:
259                                str += ' '
260                                if argument[2]:
261                                        str += '<'
262                                else:
263                                        str += '['
264                                str += argument[0]
265                                if argument[2]:
266                                        str += '>'
267                                else:
268                                        str += ']'
269                        str += '\n'
270                return str
271               
272        def print_info(self, level, prop_dict):
273                ''' return formated string from serialized vcard data '''
274                if prop_dict is None or type(prop_dict) \
275                        not in [dict, list, tuple]:
276                        return ''
277                ret_str = ''
278                if type(prop_dict) in [list, tuple]:
279                        ret_str = ''
280                        spacing = ' ' * level * 4
281                        for val in prop_dict:
282                                if val is None:
283                                        ret_str +='\t'
284                                elif type(val) == unicode or type(val) == int or \
285                                        type(val) == str:
286                                        ret_str +='\t' + str(val)
287                                elif type(val) == list or type(val) == tuple:
288                                        res = ''
289                                        for items in val:
290                                                res += self.print_info(level+1, items)
291                                        if res != '':
292                                                ret_str += '\t' + res
293                        ret_str = '%s(%s)\n' % (spacing, ret_str[1:])
294                elif type(prop_dict) is dict:
295                        for key in prop_dict.keys():
296                                val = prop_dict[key]
297                                spacing = ' ' * level * 4
298                                if type(val) == unicode or type(val) == int or \
299                                        type(val) == str:
300                                        if val is not None:
301                                                val = val.strip()
302                                                ret_str += '%s%-10s: %s\n' % (spacing, key, val)
303                                elif type(val) == list or type(val) == tuple:
304                                        res = ''
305                                        for items in val:
306                                                res += self.print_info(level+1, items)
307                                        if res != '':
308                                                ret_str += '%s%s: \n%s' % (spacing, key, res)
309                                elif type(val) == dict:
310                                        res = self.print_info(level+1, val)
311                                        if res != '':
312                                                ret_str += '%s%s: \n%s' % (spacing, key, res)
313                                else:
314                                        self.send_warning(_('Unknown type %s ') % type(val))
315                return ret_str
316               
317        def unrepr(self, serialized_data):
318                ''' works the same as eval, but only for structural values,
319                not functions! e.g. dicts, lists, strings, tuples '''
320                if not serialized_data:
321                        return (None, '') 
322                value = serialized_data.strip()
323                first_char = value[0]
324                is_unicode  = False
325                is_int  = False
326               
327                if first_char == 'u':
328                        is_unicode = True
329                        value = value[1:]
330                        first_char = value[0]
331                elif '0123456789.'.find(first_char) != -1:
332                        is_int = True
333                        _str = first_char
334                        if first_char == '.':
335                                is_float = True
336                        else:
337                                is_float =  False
338                        for i in range(len(value) - 1):
339                                chr = value[i+1]
340                                if chr == '.':
341                                        is_float = True
342                                elif '0123456789'.find(chr) == -1:
343                                        break
344                                _str += chr
345                        if is_float:
346                                return (float(_str), value[len(_str):])
347                        else:
348                                return (int(_str), value[len(_str):])
349                elif first_char == 'N':
350                        if value[1:4] == 'one':
351                                return (None, value[4:])
352                        else:
353                                return (None, '')
354                if first_char == "'" or first_char == '"': # handle strings and unicode
355                        if len(value) < 2:
356                                return ('',value[1:])
357                        _str = ''
358                        previous_slash = False
359                        for i in range(len(value) - 1):
360                                chr = value[i+1]
361                                if previous_slash:
362                                        previous_slash = False
363                                        if chr == '\\':
364                                                _str += '\\'
365                                        elif chr == 'n':
366                                                _str += '\n'
367                                        elif chr == 't':
368                                                _str += '\t'
369                                        elif chr == 'r':
370                                                _str += '\r'
371                                        elif chr == 'b':
372                                                _str += '\b'
373                                        elif chr == '\'':
374                                                _str += '\''
375                                        elif chr == '\"':
376                                                _str += '\"'
377                                        elif chr == 'u' and is_unicode:
378                                                _str += '\\u'
379                                elif chr == first_char:
380                                        break
381                                elif chr == '\\':
382                                        previous_slash = True
383                                else:
384                                        _str += chr
385                        substr_len = len(_str)+2
386                        if is_unicode and _str:
387                                _str = _str.decode('unicode-escape').encode('utf-8')
388                        return (_str, value[substr_len :])
389                elif first_char == '{': # dict
390                        _dict = {}
391                        while True:
392                                if value[1] == '}':
393                                        break
394                                key, next = self.unrepr(value[1:])
395                                if type(key) != str and type(key) != unicode:
396                                        send_error('Wrong string: %s' % value)
397                                next = next.strip()
398                                if not next or next[0] != ':':
399                                        send_error('Wrong string: %s' % (value))
400                                val, next = self.unrepr(next[1:])
401                                _dict[key] = val
402                                next = next.strip()
403                                if not next:
404                                        break
405                                if next[0] == ',':
406                                        value = next
407                                elif next[0] == '}':
408                                        break
409                                else:
410                                        break
411                        return (_dict, next[1:])
412                elif first_char in ['[', '(']: # return list
413                        _tuple = []
414                        while True:
415                                if value[1] == ']':
416                                        break
417                                val, next = self.unrepr(value[1:])
418                                next = next.strip()
419                                if not next:
420                                        send_error('Wrong string: %s' % val)
421                                _tuple.append(val)
422                                next = next.strip()
423                                if not next:
424                                        break
425                                if next[0] == ',':
426                                        value = next
427                                elif next[0] in [']', ')']:
428                                        break
429                        return (_tuple, next[1:])
430               
431        def show_vcard_info(self, *args, **keyword):
432                ''' write user vcart in a formated output '''
433                props_dict = None
434                if _version[1] >= 30:
435                        props_dict = self.unrepr(args[0])
436                else:
437                        if args and len(args) >= 5:
438                                props_dict = self.unrepr(args[4].get_args_list()[0])
439
440                if props_dict:
441                        print self.print_info(0,props_dict[0])
442                # remove_signal_receiver is broken in lower versions (< 0.35),
443                # so we leave the leak - nothing can be done
444                if _version[1] >= 41:
445                        self.sbus.remove_signal_receiver(show_vcard_info, 'VcardInfo', 
446                                INTERFACE, SERVICE, OBJ_PATH)
447       
448                gtk.main_quit()
449               
450        def check_arguments(self):
451                ''' Make check if all necessary arguments are given '''
452                argv_len = self.argv_len - 2
453                args = self.commands[self.command][1]
454                if len(args) > argv_len:
455                        if args[argv_len][2]:
456                                self.send_error(_('Argument "%s" is not specified. \n\
457Type "%s help %s" for more info') % (args[argv_len][0], BASENAME, self.command))
458
459        def gtk_quit(self):
460                if _version[1] >= 41:
461                        self.sbus.remove_signal_receiver(show_vcard_info, 'VcardInfo', 
462                                INTERFACE, SERVICE, OBJ_PATH)
463                gtk.main_quit()
464       
465        # FIXME - didn't find more clever way for the below method.
466        # method(sys.argv[2:]) doesn't work, cos sys.argv[2:] is a tuple
467        def call_remote_method(self):
468                ''' calls self.method with arguments from sys.argv[2:] '''
469                try:
470                        if self.argv_len == 2:
471                                res = self.method()
472                        elif self.argv_len == 3:
473                                res = self.method(sys.argv[2])
474                        elif self.argv_len == 4:
475                                res = self.method(sys.argv[2], sys.argv[3])
476                        elif self.argv_len == 5:
477                                res = self.method(sys.argv[2], sys.argv[3], sys.argv[4])
478                        elif argv_len == 6:
479                                res = self.method(sys.argv[2], sys.argv[3], sys.argv[4], 
480                                        sys.argv[5])
481                        return res
482                except:
483                        self.send_error(_('Service not available'))
484                return None
485
486        def send_error(self, error_message):
487                '''  Writes error message to stderr and exits '''
488                sys.stderr.write(error_message + '\n')
489                sys.stderr.flush()
490                sys.exit(1)
491
492if __name__ == '__main__':
493        GajimRemote()
Note: See TracBrowser for help on using the browser.