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