| 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 | |
|---|
| 28 | import gobject |
|---|
| 29 | import gtk |
|---|
| 30 | import os |
|---|
| 31 | import sys |
|---|
| 32 | |
|---|
| 33 | import systray |
|---|
| 34 | |
|---|
| 35 | from common import exceptions |
|---|
| 36 | from common import gajim |
|---|
| 37 | from common import helpers |
|---|
| 38 | from time import time |
|---|
| 39 | from common import i18n |
|---|
| 40 | from dialogs import AddNewContactWindow |
|---|
| 41 | _ = i18n._ |
|---|
| 42 | |
|---|
| 43 | import dbus_support |
|---|
| 44 | if 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 | |
|---|
| 55 | INTERFACE = 'org.gajim.dbus.RemoteInterface' |
|---|
| 56 | OBJ_PATH = '/org/gajim/dbus/RemoteObject' |
|---|
| 57 | SERVICE = 'org.gajim.dbus' |
|---|
| 58 | |
|---|
| 59 | STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd', |
|---|
| 60 | 'invisible'] |
|---|
| 61 | |
|---|
| 62 | class 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 | |
|---|
| 79 | class 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) |
|---|