2 ## src/remote_control.py
4 ## Copyright (C) 2005-2006 Andrew Sayman <lorien420 AT myrealbox.com>
5 ## Dimitur Kirov <dkirov AT gmail.com>
6 ## Nikos Kouremenos <kourem AT gmail.com>
7 ## Copyright (C) 2005-2010 Yann Leboulanger <asterix AT lagaule.org>
8 ## Copyright (C) 2006-2007 Travis Shirk <travis AT pobox.com>
9 ## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
10 ## Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
11 ## Julien Pivotto <roidelapluie AT gmail.com>
12 ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
14 ## This file is part of Gajim.
16 ## Gajim is free software; you can redistribute it and/or modify
17 ## it under the terms of the GNU General Public License as published
18 ## by the Free Software Foundation; version 3 only.
20 ## Gajim is distributed in the hope that it will be useful,
21 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 ## GNU General Public License for more details.
25 ## You should have received a copy of the GNU General Public License
26 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
35 from common
import gajim
36 from common
import helpers
38 from dialogs
import AddNewContactWindow
, NewChatDialog
, JoinGroupchatWindow
39 from common
import ged
41 from common
import dbus_support
42 if dbus_support
.supported
:
48 INTERFACE
= 'org.gajim.dbus.RemoteInterface'
49 OBJ_PATH
= '/org/gajim/dbus/RemoteObject'
50 SERVICE
= 'org.gajim.dbus'
54 # in most cases it is a utf-8 string
55 DBUS_STRING
= dbus
.String
57 # general type (for use in dicts, where all values should have the same type)
58 DBUS_BOOLEAN
= dbus
.Boolean
59 DBUS_DOUBLE
= dbus
.Double
60 DBUS_INT32
= dbus
.Int32
61 # dictionary with string key and binary value
62 DBUS_DICT_SV
= lambda : dbus
.Dictionary({}, signature
="sv")
63 # dictionary with string key and value
64 DBUS_DICT_SS
= lambda : dbus
.Dictionary({}, signature
="ss")
65 # empty type (there is no equivalent of None on D-Bus, but historically gajim
67 DBUS_NONE
= lambda : dbus
.Int32(0)
69 def get_dbus_struct(obj
):
71 Recursively go through all the items and replace them with their casted dbus
76 if isinstance(obj
, (unicode, str)):
77 return DBUS_STRING(obj
)
78 if isinstance(obj
, int):
79 return DBUS_INT32(obj
)
80 if isinstance(obj
, float):
81 return DBUS_DOUBLE(obj
)
82 if isinstance(obj
, bool):
83 return DBUS_BOOLEAN(obj
)
84 if isinstance(obj
, (list, tuple)):
85 result
= dbus
.Array([get_dbus_struct(i
) for i
in obj
],
90 if isinstance(obj
, dict):
91 result
= DBUS_DICT_SV()
92 for key
, value
in obj
.items():
93 result
[DBUS_STRING(key
)] = get_dbus_struct(value
)
102 self
.signal_object
= None
103 session_bus
= dbus_support
.session_bus
.SessionBus()
105 bus_name
= dbus
.service
.BusName(SERVICE
, bus
=session_bus
)
106 self
.signal_object
= SignalObject(bus_name
)
108 gajim
.ged
.register_event_handler('last-result-received', ged
.POSTGUI
,
109 self
.on_last_status_time
)
110 gajim
.ged
.register_event_handler('version-result-received', ged
.POSTGUI
,
112 gajim
.ged
.register_event_handler('time-result-received', ged
.POSTGUI
,
114 gajim
.ged
.register_event_handler('gmail-nofify', ged
.POSTGUI
,
115 self
.on_gmail_notify
)
116 gajim
.ged
.register_event_handler('roster-info', ged
.POSTGUI
,
118 gajim
.ged
.register_event_handler('presence-received', ged
.POSTGUI
,
119 self
.on_presence_received
)
120 gajim
.ged
.register_event_handler('subscribe-presence-received',
121 ged
.POSTGUI
, self
.on_subscribe_presence_received
)
122 gajim
.ged
.register_event_handler('subscribed-presence-received',
123 ged
.POSTGUI
, self
.on_subscribed_presence_received
)
124 gajim
.ged
.register_event_handler('unsubscribed-presence-received',
125 ged
.POSTGUI
, self
.on_unsubscribed_presence_received
)
126 gajim
.ged
.register_event_handler('gc-message-received',
127 ged
.POSTGUI
, self
.on_gc_message_received
)
128 gajim
.ged
.register_event_handler('our-show', ged
.POSTGUI
,
130 gajim
.ged
.register_event_handler('account-created', ged
.POSTGUI
,
131 self
.on_account_created
)
132 gajim
.ged
.register_event_handler('vcard-received', ged
.POSTGUI
,
133 self
.on_vcard_received
)
135 def on_last_status_time(self
, obj
):
136 self
.raise_signal('LastStatusTime', (obj
.conn
.name
, [
137 obj
.jid
, obj
.resource
, obj
.seconds
, obj
.status
]))
139 def on_os_info(self
, obj
):
140 self
.raise_signal('OsInfo', (obj
.conn
.name
, [obj
.jid
, obj
.resource
,
141 obj
.client_info
, obj
.os_info
]))
143 def on_time(self
, obj
):
144 self
.raise_signal('EntityTime', (obj
.conn
.name
, [obj
.jid
, obj
.resource
,
147 def on_gmail_notify(self
, obj
):
148 self
.raise_signal('NewGmail', (obj
.conn
.name
, [obj
.jid
, obj
.newmsgs
,
149 obj
.gmail_messages_list
]))
151 def on_roster_info(self
, obj
):
152 self
.raise_signal('RosterInfo', (obj
.conn
.name
, [obj
.jid
, obj
.nickname
,
153 obj
.sub
, obj
.ask
, obj
.groups
]))
155 def on_presence_received(self
, obj
):
157 if obj
.old_show
< 2 and obj
.new_show
> 1:
158 event
= 'ContactPresence'
159 elif obj
.old_show
> 1 and obj
.new_show
< 2:
160 event
= 'ContactAbsence'
161 elif obj
.new_show
> 1:
162 event
= 'ContactStatus'
164 self
.raise_signal(event
, (obj
.conn
.name
, [obj
.jid
, obj
.show
,
165 obj
.status
, obj
.resource
, obj
.prio
, obj
.keyID
, obj
.timestamp
,
166 obj
.contact_nickname
]))
168 def on_subscribe_presence_received(self
, obj
):
169 self
.raise_signal('Subscribe', (obj
.conn
.name
, [obj
.jid
, obj
.status
,
172 def on_subscribed_presence_received(self
, obj
):
173 self
.raise_signal('Subscribed', (obj
.conn
.name
, [obj
.jid
,
176 def on_unsubscribed_presence_received(self
, obj
):
177 self
.raise_signal('Unsubscribed', (obj
.conn
.name
, obj
.jid
))
179 def on_gc_message_received(self
, obj
):
180 if not hasattr(obj
, 'needs_highlight'):
181 # event has not been handled at GUI level
183 self
.raise_signal('GCMessage', (obj
.conn
.name
, [obj
.fjid
, obj
.msgtxt
,
184 obj
.timestamp
, obj
.has_timestamp
, obj
.xhtml_msgtxt
, obj
.status_code
,
185 obj
.displaymarking
, obj
.captcha_form
, obj
.needs_highlight
]))
187 def on_our_status(self
, obj
):
188 self
.raise_signal('AccountPresence', (obj
.show
, obj
.conn
.name
))
190 def on_account_created(self
, obj
):
191 self
.raise_signal('NewAccount', (obj
.conn
.name
, obj
.account_info
))
193 def on_vcard_received(self
, obj
):
194 self
.raise_signal('VcardInfo', (obj
.conn
.name
, obj
.vcard_dict
))
196 def raise_signal(self
, signal
, arg
):
197 if self
.signal_object
:
199 getattr(self
.signal_object
, signal
)(get_dbus_struct(arg
))
200 except UnicodeDecodeError:
201 pass # ignore error when we fail to announce on dbus
204 class SignalObject(dbus
.service
.Object
):
206 Local object definition for /org/gajim/dbus/RemoteObject
208 This docstring is not be visible, because the clients can access only the
212 def __init__(self
, bus_name
):
213 self
.first_show
= True
214 self
.vcard_account
= None
216 # register our dbus API
217 dbus
.service
.Object
.__init
__(self
, bus_name
, OBJ_PATH
)
219 @dbus.service
.signal(INTERFACE
, signature
='av')
220 def Roster(self
, account_and_data
):
223 @dbus.service
.signal(INTERFACE
, signature
='av')
224 def AccountPresence(self
, status_and_account
):
227 @dbus.service
.signal(INTERFACE
, signature
='av')
228 def ContactPresence(self
, account_and_array
):
231 @dbus.service
.signal(INTERFACE
, signature
='av')
232 def ContactAbsence(self
, account_and_array
):
235 @dbus.service
.signal(INTERFACE
, signature
='av')
236 def ContactStatus(self
, account_and_array
):
239 @dbus.service
.signal(INTERFACE
, signature
='av')
240 def NewMessage(self
, account_and_array
):
243 @dbus.service
.signal(INTERFACE
, signature
='av')
244 def Subscribe(self
, account_and_array
):
247 @dbus.service
.signal(INTERFACE
, signature
='av')
248 def Subscribed(self
, account_and_array
):
251 @dbus.service
.signal(INTERFACE
, signature
='av')
252 def Unsubscribed(self
, account_and_jid
):
255 @dbus.service
.signal(INTERFACE
, signature
='av')
256 def NewAccount(self
, account_and_array
):
259 @dbus.service
.signal(INTERFACE
, signature
='av')
260 def VcardInfo(self
, account_and_vcard
):
263 @dbus.service
.signal(INTERFACE
, signature
='av')
264 def LastStatusTime(self
, account_and_array
):
267 @dbus.service
.signal(INTERFACE
, signature
='av')
268 def OsInfo(self
, account_and_array
):
271 @dbus.service
.signal(INTERFACE
, signature
='av')
272 def EntityTime(self
, account_and_array
):
275 @dbus.service
.signal(INTERFACE
, signature
='av')
276 def GCPresence(self
, account_and_array
):
279 @dbus.service
.signal(INTERFACE
, signature
='av')
280 def GCMessage(self
, account_and_array
):
283 @dbus.service
.signal(INTERFACE
, signature
='av')
284 def RosterInfo(self
, account_and_array
):
287 @dbus.service
.signal(INTERFACE
, signature
='av')
288 def NewGmail(self
, account_and_array
):
291 def raise_signal(self
, signal
, arg
):
293 Raise a signal, with a single argument of unspecified type Instead of
294 obj.raise_signal("Foo", bar), use obj.Foo(bar)
296 getattr(self
, signal
)(arg
)
298 @dbus.service
.method(INTERFACE
, in_signature
='s', out_signature
='s')
299 def get_status(self
, account
):
301 Return status (show to be exact) which is the global one unless account is
305 # If user did not ask for account, returns the global status
306 return DBUS_STRING(helpers
.get_global_show())
307 # return show for the given account
308 index
= gajim
.connections
[account
].connected
309 return DBUS_STRING(gajim
.SHOW_LIST
[index
])
311 @dbus.service
.method(INTERFACE
, in_signature
='s', out_signature
='s')
312 def get_status_message(self
, account
):
314 Return status which is the global one unless account is given
317 # If user did not ask for account, returns the global status
318 return DBUS_STRING(str(helpers
.get_global_status()))
319 # return show for the given account
320 status
= gajim
.connections
[account
].status
321 return DBUS_STRING(status
)
323 def _get_account_and_contact(self
, account
, jid
):
325 Get the account (if not given) and contact instance from jid
327 connected_account
= None
329 accounts
= gajim
.contacts
.get_accounts()
330 # if there is only one account in roster, take it as default
331 # if user did not ask for account
332 if not account
and len(accounts
) == 1:
333 account
= accounts
[0]
335 if gajim
.connections
[account
].connected
> 1: # account is connected
336 connected_account
= account
337 contact
= gajim
.contacts
.get_contact_with_highest_priority(account
,
340 for account
in accounts
:
341 contact
= gajim
.contacts
.get_contact_with_highest_priority(account
,
343 if contact
and gajim
.connections
[account
].connected
> 1:
344 # account is connected
345 connected_account
= account
350 return connected_account
, contact
352 def _get_account_for_groupchat(self
, account
, room_jid
):
354 Get the account which is connected to groupchat (if not given)
355 or check if the given account is connected to the groupchat
357 connected_account
= None
358 accounts
= gajim
.contacts
.get_accounts()
359 # if there is only one account in roster, take it as default
360 # if user did not ask for account
361 if not account
and len(accounts
) == 1:
362 account
= accounts
[0]
364 if gajim
.connections
[account
].connected
> 1 and \
365 room_jid
in gajim
.gc_connected
[account
] and \
366 gajim
.gc_connected
[account
][room_jid
]:
367 # account and groupchat are connected
368 connected_account
= account
370 for account
in accounts
:
371 if gajim
.connections
[account
].connected
> 1 and \
372 room_jid
in gajim
.gc_connected
[account
] and \
373 gajim
.gc_connected
[account
][room_jid
]:
374 # account and groupchat are connected
375 connected_account
= account
377 return connected_account
379 @dbus.service
.method(INTERFACE
, in_signature
='sss', out_signature
='b')
380 def send_file(self
, file_path
, jid
, account
):
382 Send file, located at 'file_path' to 'jid', using account (optional)
385 jid
= self
._get
_real
_jid
(jid
, account
)
386 connected_account
, contact
= self
._get
_account
_and
_contact
(account
, jid
)
388 if connected_account
:
389 if file_path
.startswith('file://'):
390 file_path
=file_path
[7:]
391 if os
.path
.isfile(file_path
): # is it file?
392 gajim
.interface
.instances
['file_transfers'].send_file(
393 connected_account
, contact
, file_path
)
394 return DBUS_BOOLEAN(True)
395 return DBUS_BOOLEAN(False)
397 def _send_message(self
, jid
, message
, keyID
, account
, type_
= 'chat',
400 Can be called from send_chat_message (default when send_message) or
403 if not jid
or not message
:
404 return DBUS_BOOLEAN(False)
408 connected_account
, contact
= self
._get
_account
_and
_contact
(account
, jid
)
409 if connected_account
:
410 connection
= gajim
.connections
[connected_account
]
411 connection
.send_message(jid
, message
, keyID
, type_
, subject
)
412 return DBUS_BOOLEAN(True)
413 return DBUS_BOOLEAN(False)
415 @dbus.service
.method(INTERFACE
, in_signature
='ssss', out_signature
='b')
416 def send_chat_message(self
, jid
, message
, keyID
, account
):
418 Send chat 'message' to 'jid', using account (optional) 'account'. If keyID
419 is specified, encrypt the message with the pgp key
421 jid
= self
._get
_real
_jid
(jid
, account
)
422 return self
._send
_message
(jid
, message
, keyID
, account
)
424 @dbus.service
.method(INTERFACE
, in_signature
='sssss', out_signature
='b')
425 def send_single_message(self
, jid
, subject
, message
, keyID
, account
):
427 Send single 'message' to 'jid', using account (optional) 'account'. If
428 keyID is specified, encrypt the message with the pgp key
430 jid
= self
._get
_real
_jid
(jid
, account
)
431 return self
._send
_message
(jid
, message
, keyID
, account
, type, subject
)
433 @dbus.service
.method(INTERFACE
, in_signature
='sss', out_signature
='b')
434 def send_groupchat_message(self
, room_jid
, message
, account
):
436 Send 'message' to groupchat 'room_jid', using account (optional) 'account'
438 if not room_jid
or not message
:
439 return DBUS_BOOLEAN(False)
440 connected_account
= self
._get
_account
_for
_groupchat
(account
, room_jid
)
441 if connected_account
:
442 connection
= gajim
.connections
[connected_account
]
443 connection
.send_gc_message(room_jid
, message
)
444 return DBUS_BOOLEAN(True)
445 return DBUS_BOOLEAN(False)
447 @dbus.service
.method(INTERFACE
, in_signature
='sss', out_signature
='b')
448 def open_chat(self
, jid
, account
, message
):
450 Shows the tabbed window for new message to 'jid', using account (optional)
454 raise dbus_support
.MissingArgument()
455 jid
= self
._get
_real
_jid
(jid
, account
)
457 jid
= helpers
.parse_jid(jid
)
459 # Jid is not conform, ignore it
460 return DBUS_BOOLEAN(False)
465 accounts
= gajim
.connections
.keys()
466 if len(accounts
) == 1:
467 account
= accounts
[0]
468 connected_account
= None
469 first_connected_acct
= None
470 for acct
in accounts
:
471 if gajim
.connections
[acct
].connected
> 1: # account is online
472 contact
= gajim
.contacts
.get_first_contact_from_jid(acct
, jid
)
473 if gajim
.interface
.msg_win_mgr
.has_window(jid
, acct
):
474 connected_account
= acct
478 connected_account
= acct
480 # we send the message to jid not in roster, because account is
481 # specified, or there is only one account
483 connected_account
= acct
484 elif first_connected_acct
is None:
485 first_connected_acct
= acct
487 # if jid is not a conntact, open-chat with first connected account
488 if connected_account
is None and first_connected_acct
:
489 connected_account
= first_connected_acct
491 if connected_account
:
492 gajim
.interface
.new_chat_from_jid(connected_account
, jid
, message
)
493 # preserve the 'steal focus preservation'
494 win
= gajim
.interface
.msg_win_mgr
.get_window(jid
,
495 connected_account
).window
496 if win
.get_property('visible'):
497 win
.window
.focus(gtk
.get_current_event_time())
498 return DBUS_BOOLEAN(True)
499 return DBUS_BOOLEAN(False)
501 @dbus.service
.method(INTERFACE
, in_signature
='sss', out_signature
='b')
502 def change_status(self
, status
, message
, account
):
504 change_status(status, message, account). Account is optional - if not
505 specified status is changed for all accounts
507 if status
not in ('offline', 'online', 'chat',
508 'away', 'xa', 'dnd', 'invisible'):
512 if account
not in gajim
.connections
:
513 return DBUS_BOOLEAN(False)
514 status
= gajim
.SHOW_LIST
[gajim
.connections
[account
].connected
]
515 gobject
.idle_add(gajim
.interface
.roster
.send_status
, account
,
518 # account not specified, so change the status of all accounts
519 for acc
in gajim
.contacts
.get_accounts():
520 if not gajim
.config
.get_per('accounts', acc
,
521 'sync_with_global_status'):
526 if acc
not in gajim
.connections
:
528 status_
= gajim
.SHOW_LIST
[gajim
.connections
[acc
].connected
]
529 gobject
.idle_add(gajim
.interface
.roster
.send_status
, acc
,
531 return DBUS_BOOLEAN(False)
533 @dbus.service
.method(INTERFACE
, in_signature
='ss', out_signature
='')
534 def set_priority(self
, prio
, account
):
536 set_priority(prio, account). Account is optional - if not specified
537 priority is changed for all accounts. That are synced with global status
540 gajim
.config
.set_per('accounts', account
, 'priority', prio
)
541 show
= gajim
.SHOW_LIST
[gajim
.connections
[account
].connected
]
542 status
= gajim
.connections
[account
].status
543 gobject
.idle_add(gajim
.connections
[account
].change_status
, show
,
546 # account not specified, so change prio of all accounts
547 for acc
in gajim
.contacts
.get_accounts():
548 if not gajim
.account_is_connected(acc
):
550 if not gajim
.config
.get_per('accounts', acc
,
551 'sync_with_global_status'):
553 gajim
.config
.set_per('accounts', acc
, 'priority', prio
)
554 show
= gajim
.SHOW_LIST
[gajim
.connections
[acc
].connected
]
555 status
= gajim
.connections
[acc
].status
556 gobject
.idle_add(gajim
.connections
[acc
].change_status
, show
,
559 @dbus.service
.method(INTERFACE
, in_signature
='', out_signature
='')
560 def show_next_pending_event(self
):
562 Show the window(s) with next pending event in tabbed/group chats
564 if gajim
.events
.get_nb_events():
565 gajim
.interface
.systray
.handle_first_event()
567 @dbus.service
.method(INTERFACE
, in_signature
='s', out_signature
='a{sv}')
568 def contact_info(self
, jid
):
570 Get vcard info for a contact. Return cached value of the vcard
572 if not isinstance(jid
, unicode):
575 raise dbus_support
.MissingArgument()
576 jid
= self
._get
_real
_jid
(jid
)
578 cached_vcard
= gajim
.connections
.values()[0].get_cached_vcard(jid
)
580 return get_dbus_struct(cached_vcard
)
583 return DBUS_DICT_SV()
585 @dbus.service
.method(INTERFACE
, in_signature
='', out_signature
='as')
586 def list_accounts(self
):
588 List register accounts
590 result
= gajim
.contacts
.get_accounts()
591 result_array
= dbus
.Array([], signature
='s')
592 if result
and len(result
) > 0:
593 for account
in result
:
594 result_array
.append(DBUS_STRING(account
))
597 @dbus.service
.method(INTERFACE
, in_signature
='s', out_signature
='a{ss}')
598 def account_info(self
, account
):
600 Show info on account: resource, jid, nick, prio, message
602 result
= DBUS_DICT_SS()
603 if account
in gajim
.connections
:
605 con
= gajim
.connections
[account
]
606 index
= con
.connected
607 result
['status'] = DBUS_STRING(gajim
.SHOW_LIST
[index
])
608 result
['name'] = DBUS_STRING(con
.name
)
609 result
['jid'] = DBUS_STRING(gajim
.get_jid_from_account(con
.name
))
610 result
['message'] = DBUS_STRING(con
.status
)
611 result
['priority'] = DBUS_STRING(unicode(con
.priority
))
612 result
['resource'] = DBUS_STRING(unicode(gajim
.config
.get_per(
613 'accounts', con
.name
, 'resource')))
616 @dbus.service
.method(INTERFACE
, in_signature
='s', out_signature
='aa{sv}')
617 def list_contacts(self
, account
):
619 List all contacts in the roster. If the first argument is specified, then
620 return the contacts for the specified account
622 result
= dbus
.Array([], signature
='aa{sv}')
623 accounts
= gajim
.contacts
.get_accounts()
624 if len(accounts
) == 0:
627 accounts_to_search
= [account
]
629 accounts_to_search
= accounts
630 for acct
in accounts_to_search
:
632 for jid
in gajim
.contacts
.get_jid_list(acct
):
633 item
= self
._contacts
_as
_dbus
_structure
(
634 gajim
.contacts
.get_contacts(acct
, jid
))
639 @dbus.service
.method(INTERFACE
, in_signature
='', out_signature
='')
640 def toggle_roster_appearance(self
):
642 Show/hide the roster window
644 win
= gajim
.interface
.roster
.window
645 if win
.get_property('visible'):
646 gobject
.idle_add(win
.hide
)
649 # preserve the 'steal focus preservation'
651 win
.window
.focus(gtk
.get_current_event_time())
653 win
.window
.focus(long(time()))
655 @dbus.service
.method(INTERFACE
, in_signature
='', out_signature
='')
656 def toggle_ipython(self
):
658 Show/hide the ipython window
660 win
= gajim
.ipython_window
662 if win
.window
.is_visible():
663 gobject
.idle_add(win
.hide
)
668 gajim
.interface
.create_ipython_window()
670 @dbus.service
.method(INTERFACE
, in_signature
='', out_signature
='a{ss}')
671 def prefs_list(self
):
672 prefs_dict
= DBUS_DICT_SS()
673 def get_prefs(data
, name
, path
, value
):
681 prefs_dict
[DBUS_STRING(key
)] = DBUS_STRING(value
[1])
682 gajim
.config
.foreach(get_prefs
)
685 @dbus.service
.method(INTERFACE
, in_signature
='', out_signature
='b')
686 def prefs_store(self
):
688 gajim
.interface
.save_config()
690 return DBUS_BOOLEAN(False)
691 return DBUS_BOOLEAN(True)
693 @dbus.service
.method(INTERFACE
, in_signature
='s', out_signature
='b')
694 def prefs_del(self
, key
):
696 return DBUS_BOOLEAN(False)
697 key_path
= key
.split('#', 2)
698 if len(key_path
) != 3:
699 return DBUS_BOOLEAN(False)
700 if key_path
[2] == '*':
701 gajim
.config
.del_per(key_path
[0], key_path
[1])
703 gajim
.config
.del_per(key_path
[0], key_path
[1], key_path
[2])
704 return DBUS_BOOLEAN(True)
706 @dbus.service
.method(INTERFACE
, in_signature
='s', out_signature
='b')
707 def prefs_put(self
, key
):
709 return DBUS_BOOLEAN(False)
710 key_path
= key
.split('#', 2)
711 if len(key_path
) < 3:
712 subname
, value
= key
.split('=', 1)
713 gajim
.config
.set(subname
, value
)
714 return DBUS_BOOLEAN(True)
715 subname
, value
= key_path
[2].split('=', 1)
716 gajim
.config
.set_per(key_path
[0], key_path
[1], subname
, value
)
717 return DBUS_BOOLEAN(True)
719 @dbus.service
.method(INTERFACE
, in_signature
='ss', out_signature
='b')
720 def add_contact(self
, jid
, account
):
722 if account
in gajim
.connections
and \
723 gajim
.connections
[account
].connected
> 1:
724 # if given account is active, use it
725 AddNewContactWindow(account
= account
, jid
= jid
)
728 return DBUS_BOOLEAN(False)
730 # if account is not given, show account combobox
731 AddNewContactWindow(account
= None, jid
= jid
)
732 return DBUS_BOOLEAN(True)
734 @dbus.service
.method(INTERFACE
, in_signature
='ss', out_signature
='b')
735 def remove_contact(self
, jid
, account
):
736 jid
= self
._get
_real
_jid
(jid
, account
)
737 accounts
= gajim
.contacts
.get_accounts()
739 # if there is only one account in roster, take it as default
742 contact_exists
= False
743 for account
in accounts
:
744 contacts
= gajim
.contacts
.get_contacts(account
, jid
)
746 gajim
.connections
[account
].unsubscribe(jid
)
747 for contact
in contacts
:
748 gajim
.interface
.roster
.remove_contact(contact
, account
)
749 gajim
.contacts
.remove_jid(account
, jid
)
750 contact_exists
= True
751 return DBUS_BOOLEAN(contact_exists
)
755 self
.first_show
= False
759 def _get_real_jid(self
, jid
, account
= None):
761 Get the real jid from the given one: removes xmpp: or get jid from nick if
762 account is specified, search only in this account
767 accounts
= gajim
.connections
.keys()
768 if jid
.startswith('xmpp:'):
769 return jid
[5:] # len('xmpp:') = 5
770 nick_in_roster
= None # Is jid a nick ?
771 for account
in accounts
:
772 # Does jid exists in roster of one account ?
773 if gajim
.contacts
.get_contacts(account
, jid
):
775 if not nick_in_roster
:
776 # look in all contact if one has jid as nick
777 for jid_
in gajim
.contacts
.get_jid_list(account
):
778 c
= gajim
.contacts
.get_contacts(account
, jid_
)
780 nick_in_roster
= jid_
783 # We have not found jid in roster, but we found is as a nick
784 return nick_in_roster
785 # We have not found it as jid nor as nick, probably a not in roster jid
788 def _contacts_as_dbus_structure(self
, contacts
):
790 Get info from list of Contact objects and create dbus dict
794 prim_contact
= None # primary contact
795 for contact
in contacts
:
796 if prim_contact
is None or contact
.priority
> prim_contact
.priority
:
797 prim_contact
= contact
798 contact_dict
= DBUS_DICT_SV()
799 contact_dict
['name'] = DBUS_STRING(prim_contact
.name
)
800 contact_dict
['show'] = DBUS_STRING(prim_contact
.show
)
801 contact_dict
['jid'] = DBUS_STRING(prim_contact
.jid
)
802 if prim_contact
.keyID
:
804 if len(prim_contact
.keyID
) == 8:
805 keyID
= prim_contact
.keyID
806 elif len(prim_contact
.keyID
) == 16:
807 keyID
= prim_contact
.keyID
[8:]
809 contact_dict
['openpgp'] = keyID
810 contact_dict
['resources'] = dbus
.Array([], signature
='(sis)')
811 for contact
in contacts
:
812 resource_props
= dbus
.Struct((DBUS_STRING(contact
.resource
),
813 dbus
.Int32(contact
.priority
), DBUS_STRING(contact
.status
)))
814 contact_dict
['resources'].append(resource_props
)
815 contact_dict
['groups'] = dbus
.Array([], signature
='(s)')
816 for group
in prim_contact
.groups
:
817 contact_dict
['groups'].append((DBUS_STRING(group
),))
820 @dbus.service
.method(INTERFACE
, in_signature
='', out_signature
='s')
821 def get_unread_msgs_number(self
):
822 return DBUS_STRING(str(gajim
.events
.get_nb_events()))
824 @dbus.service
.method(INTERFACE
, in_signature
='s', out_signature
='b')
825 def start_chat(self
, account
):
827 # error is shown in gajim-remote check_arguments(..)
828 return DBUS_BOOLEAN(False)
829 NewChatDialog(account
)
830 return DBUS_BOOLEAN(True)
832 @dbus.service
.method(INTERFACE
, in_signature
='ss', out_signature
='')
833 def send_xml(self
, xml
, account
):
835 gajim
.connections
[account
].send_stanza(str(xml
))
837 for acc
in gajim
.contacts
.get_accounts():
838 gajim
.connections
[acc
].send_stanza(str(xml
))
840 @dbus.service
.method(INTERFACE
, in_signature
='ss', out_signature
='')
841 def change_avatar(self
, picture
, account
):
842 filesize
= os
.path
.getsize(picture
)
844 if os
.path
.isfile(picture
):
845 stat
= os
.stat(picture
)
850 if not invalid_file
and filesize
< 16384:
851 fd
= open(picture
, 'rb')
853 avatar
= base64
.encodestring(data
)
854 avatar_mime_type
= mimetypes
.guess_type(picture
)[0]
856 vcard
['PHOTO'] = {'BINVAL': avatar
}
858 vcard
['PHOTO']['TYPE'] = avatar_mime_type
860 gajim
.connections
[account
].send_vcard(vcard
)
862 for acc
in gajim
.connections
:
863 gajim
.connections
[acc
].send_vcard(vcard
)
865 @dbus.service
.method(INTERFACE
, in_signature
='ssss', out_signature
='')
866 def join_room(self
, room_jid
, nick
, password
, account
):
868 # get the first connected account
869 accounts
= gajim
.connections
.keys()
870 for acct
in accounts
:
871 if gajim
.account_is_connected(acct
):
878 gajim
.interface
.instances
[account
]['join_gc'] = \
879 JoinGroupchatWindow(account
, room_jid
, nick
)
881 gajim
.interface
.join_gc_room(account
, room_jid
, nick
, password
)