don't prevent removing a sevret key when none in available. Fixes #1210
[gajim.git] / src / remote_control.py
blobf9c6d5947e5d62c820481019d0d530a2ab9410fe
1 # -*- coding:utf-8 -*-
2 ## src/remote_control.py
3 ##
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-2008 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/>.
29 import gobject
30 import os
32 from common import gajim
33 from common import helpers
34 from time import time
35 from dialogs import AddNewContactWindow, NewChatDialog, JoinGroupchatWindow
37 from common import dbus_support
38 if dbus_support.supported:
39 import dbus
40 if dbus_support:
41 import dbus.service
42 import dbus.glib
44 INTERFACE = 'org.gajim.dbus.RemoteInterface'
45 OBJ_PATH = '/org/gajim/dbus/RemoteObject'
46 SERVICE = 'org.gajim.dbus'
48 # type mapping
50 # in most cases it is a utf-8 string
51 DBUS_STRING = dbus.String
53 # general type (for use in dicts, where all values should have the same type)
54 DBUS_BOOLEAN = dbus.Boolean
55 DBUS_DOUBLE = dbus.Double
56 DBUS_INT32 = dbus.Int32
57 # dictionary with string key and binary value
58 DBUS_DICT_SV = lambda : dbus.Dictionary({}, signature="sv")
59 # dictionary with string key and value
60 DBUS_DICT_SS = lambda : dbus.Dictionary({}, signature="ss")
61 # empty type (there is no equivalent of None on D-Bus, but historically gajim
62 # used 0 instead)
63 DBUS_NONE = lambda : dbus.Int32(0)
65 def get_dbus_struct(obj):
66 ''' recursively go through all the items and replace
67 them with their casted dbus equivalents
68 '''
69 if obj is None:
70 return DBUS_NONE()
71 if isinstance(obj, (unicode, str)):
72 return DBUS_STRING(obj)
73 if isinstance(obj, int):
74 return DBUS_INT32(obj)
75 if isinstance(obj, float):
76 return DBUS_DOUBLE(obj)
77 if isinstance(obj, bool):
78 return DBUS_BOOLEAN(obj)
79 if isinstance(obj, (list, tuple)):
80 result = dbus.Array([get_dbus_struct(i) for i in obj],
81 signature='v')
82 if result == []:
83 return DBUS_NONE()
84 return result
85 if isinstance(obj, dict):
86 result = DBUS_DICT_SV()
87 for key, value in obj.items():
88 result[DBUS_STRING(key)] = get_dbus_struct(value)
89 if result == {}:
90 return DBUS_NONE()
91 return result
92 # unknown type
93 return DBUS_NONE()
95 class Remote:
96 def __init__(self):
97 self.signal_object = None
98 session_bus = dbus_support.session_bus.SessionBus()
100 bus_name = dbus.service.BusName(SERVICE, bus=session_bus)
101 self.signal_object = SignalObject(bus_name)
103 def raise_signal(self, signal, arg):
104 if self.signal_object:
105 try:
106 getattr(self.signal_object, signal)(get_dbus_struct(arg))
107 except UnicodeDecodeError:
108 pass # ignore error when we fail to announce on dbus
111 class SignalObject(dbus.service.Object):
112 ''' Local object definition for /org/gajim/dbus/RemoteObject.
113 (This docstring is not be visible, because the clients can access only the remote object.)'''
115 def __init__(self, bus_name):
116 self.first_show = True
117 self.vcard_account = None
119 # register our dbus API
120 dbus.service.Object.__init__(self, bus_name, OBJ_PATH)
122 @dbus.service.signal(INTERFACE, signature='av')
123 def Roster(self, account_and_data):
124 pass
126 @dbus.service.signal(INTERFACE, signature='av')
127 def AccountPresence(self, status_and_account):
128 pass
130 @dbus.service.signal(INTERFACE, signature='av')
131 def ContactPresence(self, account_and_array):
132 pass
134 @dbus.service.signal(INTERFACE, signature='av')
135 def ContactAbsence(self, account_and_array):
136 pass
138 @dbus.service.signal(INTERFACE, signature='av')
139 def ContactStatus(self, account_and_array):
140 pass
142 @dbus.service.signal(INTERFACE, signature='av')
143 def NewMessage(self, account_and_array):
144 pass
146 @dbus.service.signal(INTERFACE, signature='av')
147 def Subscribe(self, account_and_array):
148 pass
150 @dbus.service.signal(INTERFACE, signature='av')
151 def Subscribed(self, account_and_array):
152 pass
154 @dbus.service.signal(INTERFACE, signature='av')
155 def Unsubscribed(self, account_and_jid):
156 pass
158 @dbus.service.signal(INTERFACE, signature='av')
159 def NewAccount(self, account_and_array):
160 pass
162 @dbus.service.signal(INTERFACE, signature='av')
163 def VcardInfo(self, account_and_vcard):
164 pass
166 @dbus.service.signal(INTERFACE, signature='av')
167 def LastStatusTime(self, account_and_array):
168 pass
170 @dbus.service.signal(INTERFACE, signature='av')
171 def OsInfo(self, account_and_array):
172 pass
174 @dbus.service.signal(INTERFACE, signature='av')
175 def EntityTime(self, account_and_array):
176 pass
178 @dbus.service.signal(INTERFACE, signature='av')
179 def GCPresence(self, account_and_array):
180 pass
182 @dbus.service.signal(INTERFACE, signature='av')
183 def GCMessage(self, account_and_array):
184 pass
186 @dbus.service.signal(INTERFACE, signature='av')
187 def RosterInfo(self, account_and_array):
188 pass
190 @dbus.service.signal(INTERFACE, signature='av')
191 def NewGmail(self, account_and_array):
192 pass
194 def raise_signal(self, signal, arg):
195 '''raise a signal, with a single argument of unspecified type
196 Instead of obj.raise_signal("Foo", bar), use obj.Foo(bar).'''
197 getattr(self, signal)(arg)
199 @dbus.service.method(INTERFACE, in_signature='s', out_signature='s')
200 def get_status(self, account):
201 '''Returns status (show to be exact) which is the global one
202 unless account is given'''
203 if not account:
204 # If user did not ask for account, returns the global status
205 return DBUS_STRING(helpers.get_global_show())
206 # return show for the given account
207 index = gajim.connections[account].connected
208 return DBUS_STRING(gajim.SHOW_LIST[index])
210 @dbus.service.method(INTERFACE, in_signature='s', out_signature='s')
211 def get_status_message(self, account):
212 '''Returns status which is the global one
213 unless account is given'''
214 if not account:
215 # If user did not ask for account, returns the global status
216 return DBUS_STRING(str(helpers.get_global_status()))
217 # return show for the given account
218 status = gajim.connections[account].status
219 return DBUS_STRING(status)
221 def _get_account_and_contact(self, account, jid):
222 '''get the account (if not given) and contact instance from jid'''
223 connected_account = None
224 contact = None
225 accounts = gajim.contacts.get_accounts()
226 # if there is only one account in roster, take it as default
227 # if user did not ask for account
228 if not account and len(accounts) == 1:
229 account = accounts[0]
230 if account:
231 if gajim.connections[account].connected > 1: # account is connected
232 connected_account = account
233 contact = gajim.contacts.get_contact_with_highest_priority(account,
234 jid)
235 else:
236 for account in accounts:
237 contact = gajim.contacts.get_contact_with_highest_priority(account,
238 jid)
239 if contact and gajim.connections[account].connected > 1:
240 # account is connected
241 connected_account = account
242 break
243 if not contact:
244 contact = jid
246 return connected_account, contact
248 def _get_account_for_groupchat(self, account, room_jid):
249 '''get the account which is connected to groupchat (if not given)
250 or check if the given account is connected to the groupchat'''
251 connected_account = None
252 accounts = gajim.contacts.get_accounts()
253 # if there is only one account in roster, take it as default
254 # if user did not ask for account
255 if not account and len(accounts) == 1:
256 account = accounts[0]
257 if account:
258 if gajim.connections[account].connected > 1 and \
259 room_jid in gajim.gc_connected[account] and \
260 gajim.gc_connected[account][room_jid]:
261 # account and groupchat are connected
262 connected_account = account
263 else:
264 for account in accounts:
265 if gajim.connections[account].connected > 1 and \
266 room_jid in gajim.gc_connected[account] and \
267 gajim.gc_connected[account][room_jid]:
268 # account and groupchat are connected
269 connected_account = account
270 break
271 return connected_account
273 @dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
274 def send_file(self, file_path, jid, account):
275 '''send file, located at 'file_path' to 'jid', using account
276 (optional) 'account' '''
277 jid = self._get_real_jid(jid, account)
278 connected_account, contact = self._get_account_and_contact(account, jid)
280 if connected_account:
281 if file_path.startswith('file://'):
282 file_path=file_path[7:]
283 if os.path.isfile(file_path): # is it file?
284 gajim.interface.instances['file_transfers'].send_file(
285 connected_account, contact, file_path)
286 return DBUS_BOOLEAN(True)
287 return DBUS_BOOLEAN(False)
289 def _send_message(self, jid, message, keyID, account, type_ = 'chat',
290 subject = None):
291 '''can be called from send_chat_message (default when send_message)
292 or send_single_message'''
293 if not jid or not message:
294 return DBUS_BOOLEAN(False)
295 if not keyID:
296 keyID = ''
298 connected_account, contact = self._get_account_and_contact(account, jid)
299 if connected_account:
300 connection = gajim.connections[connected_account]
301 connection.send_message(jid, message, keyID, type_, subject)
302 return DBUS_BOOLEAN(True)
303 return DBUS_BOOLEAN(False)
305 @dbus.service.method(INTERFACE, in_signature='ssss', out_signature='b')
306 def send_chat_message(self, jid, message, keyID, account):
307 '''Send chat 'message' to 'jid', using account (optional) 'account'.
308 if keyID is specified, encrypt the message with the pgp key '''
309 jid = self._get_real_jid(jid, account)
310 return self._send_message(jid, message, keyID, account)
312 @dbus.service.method(INTERFACE, in_signature='sssss', out_signature='b')
313 def send_single_message(self, jid, subject, message, keyID, account):
314 '''Send single 'message' to 'jid', using account (optional) 'account'.
315 if keyID is specified, encrypt the message with the pgp key '''
316 jid = self._get_real_jid(jid, account)
317 return self._send_message(jid, message, keyID, account, type, subject)
319 @dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
320 def send_groupchat_message(self, room_jid, message, account):
321 '''Send 'message' to groupchat 'room_jid',
322 using account (optional) 'account'.'''
323 if not room_jid or not message:
324 return DBUS_BOOLEAN(False)
325 connected_account = self._get_account_for_groupchat(account, room_jid)
326 if connected_account:
327 connection = gajim.connections[connected_account]
328 connection.send_gc_message(room_jid, message)
329 return DBUS_BOOLEAN(True)
330 return DBUS_BOOLEAN(False)
332 @dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
333 def open_chat(self, jid, account, message):
334 '''Shows the tabbed window for new message to 'jid', using account
335 (optional) 'account' '''
336 if not jid:
337 raise dbus_support.MissingArgument()
338 jid = self._get_real_jid(jid, account)
339 try:
340 jid = helpers.parse_jid(jid)
341 except Exception:
342 # Jid is not conform, ignore it
343 return DBUS_BOOLEAN(False)
345 if account:
346 accounts = [account]
347 else:
348 accounts = gajim.connections.keys()
349 if len(accounts) == 1:
350 account = accounts[0]
351 connected_account = None
352 first_connected_acct = None
353 for acct in accounts:
354 if gajim.connections[acct].connected > 1: # account is online
355 contact = gajim.contacts.get_first_contact_from_jid(acct, jid)
356 if gajim.interface.msg_win_mgr.has_window(jid, acct):
357 connected_account = acct
358 break
359 # jid is in roster
360 elif contact:
361 connected_account = acct
362 break
363 # we send the message to jid not in roster, because account is
364 # specified, or there is only one account
365 elif account:
366 connected_account = acct
367 elif first_connected_acct is None:
368 first_connected_acct = acct
370 # if jid is not a conntact, open-chat with first connected account
371 if connected_account is None and first_connected_acct:
372 connected_account = first_connected_acct
374 if connected_account:
375 gajim.interface.new_chat_from_jid(connected_account, jid, message)
376 # preserve the 'steal focus preservation'
377 win = gajim.interface.msg_win_mgr.get_window(jid,
378 connected_account).window
379 if win.get_property('visible'):
380 win.window.focus()
381 return DBUS_BOOLEAN(True)
382 return DBUS_BOOLEAN(False)
384 @dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
385 def change_status(self, status, message, account):
386 ''' change_status(status, message, account). account is optional -
387 if not specified status is changed for all accounts. '''
388 if status not in ('offline', 'online', 'chat',
389 'away', 'xa', 'dnd', 'invisible'):
390 return DBUS_BOOLEAN(False)
391 if account:
392 gobject.idle_add(gajim.interface.roster.send_status, account,
393 status, message)
394 else:
395 # account not specified, so change the status of all accounts
396 for acc in gajim.contacts.get_accounts():
397 if not gajim.config.get_per('accounts', acc,
398 'sync_with_global_status'):
399 continue
400 gobject.idle_add(gajim.interface.roster.send_status, acc,
401 status, message)
402 return DBUS_BOOLEAN(False)
404 @dbus.service.method(INTERFACE, in_signature='', out_signature='')
405 def show_next_pending_event(self):
406 '''Show the window(s) with next pending event in tabbed/group chats.'''
407 if gajim.events.get_nb_events():
408 gajim.interface.systray.handle_first_event()
410 @dbus.service.method(INTERFACE, in_signature='s', out_signature='a{sv}')
411 def contact_info(self, jid):
412 '''get vcard info for a contact. Return cached value of the vcard.
414 if not isinstance(jid, unicode):
415 jid = unicode(jid)
416 if not jid:
417 raise dbus_support.MissingArgument()
418 jid = self._get_real_jid(jid)
420 cached_vcard = gajim.connections.values()[0].get_cached_vcard(jid)
421 if cached_vcard:
422 return get_dbus_struct(cached_vcard)
424 # return empty dict
425 return DBUS_DICT_SV()
427 @dbus.service.method(INTERFACE, in_signature='', out_signature='as')
428 def list_accounts(self):
429 '''list register accounts'''
430 result = gajim.contacts.get_accounts()
431 result_array = dbus.Array([], signature='s')
432 if result and len(result) > 0:
433 for account in result:
434 result_array.append(DBUS_STRING(account))
435 return result_array
437 @dbus.service.method(INTERFACE, in_signature='s', out_signature='a{ss}')
438 def account_info(self, account):
439 '''show info on account: resource, jid, nick, prio, message'''
440 result = DBUS_DICT_SS()
441 if account in gajim.connections:
442 # account is valid
443 con = gajim.connections[account]
444 index = con.connected
445 result['status'] = DBUS_STRING(gajim.SHOW_LIST[index])
446 result['name'] = DBUS_STRING(con.name)
447 result['jid'] = DBUS_STRING(gajim.get_jid_from_account(con.name))
448 result['message'] = DBUS_STRING(con.status)
449 result['priority'] = DBUS_STRING(unicode(con.priority))
450 result['resource'] = DBUS_STRING(unicode(gajim.config.get_per(
451 'accounts', con.name, 'resource')))
452 return result
454 @dbus.service.method(INTERFACE, in_signature='s', out_signature='aa{sv}')
455 def list_contacts(self, account):
456 '''list all contacts in the roster. If the first argument is specified,
457 then return the contacts for the specified account'''
458 result = dbus.Array([], signature='aa{sv}')
459 accounts = gajim.contacts.get_accounts()
460 if len(accounts) == 0:
461 return result
462 if account:
463 accounts_to_search = [account]
464 else:
465 accounts_to_search = accounts
466 for acct in accounts_to_search:
467 if acct in accounts:
468 for jid in gajim.contacts.get_jid_list(acct):
469 item = self._contacts_as_dbus_structure(
470 gajim.contacts.get_contacts(acct, jid))
471 if item:
472 result.append(item)
473 return result
475 @dbus.service.method(INTERFACE, in_signature='', out_signature='')
476 def toggle_roster_appearance(self):
477 ''' shows/hides the roster window '''
478 win = gajim.interface.roster.window
479 if win.get_property('visible'):
480 gobject.idle_add(win.hide)
481 else:
482 win.present()
483 # preserve the 'steal focus preservation'
484 if self._is_first():
485 win.window.focus()
486 else:
487 win.window.focus(long(time()))
489 @dbus.service.method(INTERFACE, in_signature='', out_signature='')
490 def toggle_ipython(self):
491 ''' shows/hides the ipython window '''
492 win = gajim.ipython_window
493 if win:
494 if win.window.is_visible():
495 gobject.idle_add(win.hide)
496 else:
497 win.show_all()
498 win.present()
499 else:
500 gajim.interface.create_ipython_window()
502 @dbus.service.method(INTERFACE, in_signature='', out_signature='a{ss}')
503 def prefs_list(self):
504 prefs_dict = DBUS_DICT_SS()
505 def get_prefs(data, name, path, value):
506 if value is None:
507 return
508 key = ''
509 if path is not None:
510 for node in path:
511 key += node + '#'
512 key += name
513 prefs_dict[DBUS_STRING(key)] = DBUS_STRING(value[1])
514 gajim.config.foreach(get_prefs)
515 return prefs_dict
517 @dbus.service.method(INTERFACE, in_signature='', out_signature='b')
518 def prefs_store(self):
519 try:
520 gajim.interface.save_config()
521 except Exception, e:
522 return DBUS_BOOLEAN(False)
523 return DBUS_BOOLEAN(True)
525 @dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
526 def prefs_del(self, key):
527 if not key:
528 return DBUS_BOOLEAN(False)
529 key_path = key.split('#', 2)
530 if len(key_path) != 3:
531 return DBUS_BOOLEAN(False)
532 if key_path[2] == '*':
533 gajim.config.del_per(key_path[0], key_path[1])
534 else:
535 gajim.config.del_per(key_path[0], key_path[1], key_path[2])
536 return DBUS_BOOLEAN(True)
538 @dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
539 def prefs_put(self, key):
540 if not key:
541 return DBUS_BOOLEAN(False)
542 key_path = key.split('#', 2)
543 if len(key_path) < 3:
544 subname, value = key.split('=', 1)
545 gajim.config.set(subname, value)
546 return DBUS_BOOLEAN(True)
547 subname, value = key_path[2].split('=', 1)
548 gajim.config.set_per(key_path[0], key_path[1], subname, value)
549 return DBUS_BOOLEAN(True)
551 @dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
552 def add_contact(self, jid, account):
553 if account:
554 if account in gajim.connections and \
555 gajim.connections[account].connected > 1:
556 # if given account is active, use it
557 AddNewContactWindow(account = account, jid = jid)
558 else:
559 # wrong account
560 return DBUS_BOOLEAN(False)
561 else:
562 # if account is not given, show account combobox
563 AddNewContactWindow(account = None, jid = jid)
564 return DBUS_BOOLEAN(True)
566 @dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
567 def remove_contact(self, jid, account):
568 jid = self._get_real_jid(jid, account)
569 accounts = gajim.contacts.get_accounts()
571 # if there is only one account in roster, take it as default
572 if account:
573 accounts = [account]
574 contact_exists = False
575 for account in accounts:
576 contacts = gajim.contacts.get_contacts(account, jid)
577 if contacts:
578 gajim.connections[account].unsubscribe(jid)
579 for contact in contacts:
580 gajim.interface.roster.remove_contact(contact, account)
581 gajim.contacts.remove_jid(account, jid)
582 contact_exists = True
583 return DBUS_BOOLEAN(contact_exists)
585 def _is_first(self):
586 if self.first_show:
587 self.first_show = False
588 return True
589 return False
591 def _get_real_jid(self, jid, account = None):
592 '''get the real jid from the given one: removes xmpp: or get jid from nick
593 if account is specified, search only in this account
595 if account:
596 accounts = [account]
597 else:
598 accounts = gajim.connections.keys()
599 if jid.startswith('xmpp:'):
600 return jid[5:] # len('xmpp:') = 5
601 nick_in_roster = None # Is jid a nick ?
602 for account in accounts:
603 # Does jid exists in roster of one account ?
604 if gajim.contacts.get_contacts(account, jid):
605 return jid
606 if not nick_in_roster:
607 # look in all contact if one has jid as nick
608 for jid_ in gajim.contacts.get_jid_list(account):
609 c = gajim.contacts.get_contacts(account, jid_)
610 if c[0].name == jid:
611 nick_in_roster = jid_
612 break
613 if nick_in_roster:
614 # We have not found jid in roster, but we found is as a nick
615 return nick_in_roster
616 # We have not found it as jid nor as nick, probably a not in roster jid
617 return jid
619 def _contacts_as_dbus_structure(self, contacts):
620 ''' get info from list of Contact objects and create dbus dict '''
621 if not contacts:
622 return None
623 prim_contact = None # primary contact
624 for contact in contacts:
625 if prim_contact is None or contact.priority > prim_contact.priority:
626 prim_contact = contact
627 contact_dict = DBUS_DICT_SV()
628 contact_dict['name'] = DBUS_STRING(prim_contact.name)
629 contact_dict['show'] = DBUS_STRING(prim_contact.show)
630 contact_dict['jid'] = DBUS_STRING(prim_contact.jid)
631 if prim_contact.keyID:
632 keyID = None
633 if len(prim_contact.keyID) == 8:
634 keyID = prim_contact.keyID
635 elif len(prim_contact.keyID) == 16:
636 keyID = prim_contact.keyID[8:]
637 if keyID:
638 contact_dict['openpgp'] = keyID
639 contact_dict['resources'] = dbus.Array([], signature='(sis)')
640 for contact in contacts:
641 resource_props = dbus.Struct((DBUS_STRING(contact.resource),
642 dbus.Int32(contact.priority), DBUS_STRING(contact.status)))
643 contact_dict['resources'].append(resource_props)
644 contact_dict['groups'] = dbus.Array([], signature='(s)')
645 for group in prim_contact.groups:
646 contact_dict['groups'].append((DBUS_STRING(group),))
647 return contact_dict
649 @dbus.service.method(INTERFACE, in_signature='', out_signature='s')
650 def get_unread_msgs_number(self):
651 return DBUS_STRING(str(gajim.events.get_nb_events()))
653 @dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
654 def start_chat(self, account):
655 if not account:
656 # error is shown in gajim-remote check_arguments(..)
657 return DBUS_BOOLEAN(False)
658 NewChatDialog(account)
659 return DBUS_BOOLEAN(True)
661 @dbus.service.method(INTERFACE, in_signature='ss', out_signature='')
662 def send_xml(self, xml, account):
663 if account:
664 gajim.connections[account].send_stanza(str(xml))
665 else:
666 for acc in gajim.contacts.get_accounts():
667 gajim.connections[acc].send_stanza(str(xml))
669 @dbus.service.method(INTERFACE, in_signature='ssss', out_signature='')
670 def join_room(self, room_jid, nick, password, account):
671 if not account:
672 # get the first connected account
673 accounts = gajim.connections.keys()
674 for acct in accounts:
675 if gajim.account_is_connected(acct):
676 account = acct
677 break
678 if not account:
679 return
680 if not nick:
681 nick = ''
682 gajim.interface.instances[account]['join_gc'] = \
683 JoinGroupchatWindow(account, room_jid, nick)
684 else:
685 gajim.interface.join_gc_room(account, room_jid, nick, password)
687 # vim: se ts=3: