[commit-gajim] r11230 - branches/plugin-system/plugins/dbus_plugin

vardo at gajim.org vardo at gajim.org
Thu Apr 16 10:37:17 CEST 2009


Author: vardo
Date: 2009-04-16 10:37:16 +0200 (Thu, 16 Apr 2009)
New Revision: 11230

Modified:
   branches/plugin-system/plugins/dbus_plugin/plugin.py
Log:
Moved DBus type related instructions to scope which is executed only when there's a DBus support. No NameError exceptions are thrown anymore.

Makes debugging of plugins easier under WingIDE (which does not remember - at least it looks like that - the "ignore exception at this location" option when module is imported 'manually').

This could also be applied to src/remote_control.py .

Modified: branches/plugin-system/plugins/dbus_plugin/plugin.py
===================================================================
--- branches/plugin-system/plugins/dbus_plugin/plugin.py	2009-04-13 21:00:33 UTC (rev 11229)
+++ branches/plugin-system/plugins/dbus_plugin/plugin.py	2009-04-16 08:37:16 UTC (rev 11230)
@@ -45,7 +45,627 @@
 	if dbus_support:
 		import dbus.service
 		import dbus.glib
+		# type mapping
 
+		# in most cases it is a utf-8 string
+		DBUS_STRING = dbus.String
+		
+		# general type (for use in dicts, where all values should have the same type)
+		DBUS_BOOLEAN = dbus.Boolean
+		DBUS_DOUBLE = dbus.Double
+		DBUS_INT32 = dbus.Int32
+		# dictionary with string key and binary value
+		DBUS_DICT_SV = lambda : dbus.Dictionary({}, signature="sv")
+		# dictionary with string key and value
+		DBUS_DICT_SS = lambda : dbus.Dictionary({}, signature="ss")
+		# empty type (there is no equivalent of None on D-Bus, but historically gajim
+		# used 0 instead)
+		DBUS_NONE = lambda : dbus.Int32(0)
+		
+		def get_dbus_struct(obj):
+			''' recursively go through all the items and replace
+			them with their casted dbus equivalents
+			'''
+			if obj is None:
+				return DBUS_NONE()
+			if isinstance(obj, (unicode, str)):
+				return DBUS_STRING(obj)
+			if isinstance(obj, int):
+				return DBUS_INT32(obj)
+			if isinstance(obj, float):
+				return DBUS_DOUBLE(obj)
+			if isinstance(obj, bool):
+				return DBUS_BOOLEAN(obj)
+			if isinstance(obj, (list, tuple)):
+				result = dbus.Array([get_dbus_struct(i) for i in obj],
+					signature='v')
+				if result == []:
+					return DBUS_NONE()
+				return result
+			if isinstance(obj, dict):
+				result = DBUS_DICT_SV()
+				for key, value in obj.items():
+					result[DBUS_STRING(key)] = get_dbus_struct(value)
+				if result == {}:
+					return DBUS_NONE()
+				return result
+			# unknown type
+			return DBUS_NONE() 
+			
+		class SignalObject(dbus.service.Object):
+			''' Local object definition for /org/gajim/dbus/RemoteObject.
+			(This docstring is not be visible, because the clients can access only the remote object.)'''
+		
+			def __init__(self, bus_name):
+				self.first_show = True
+				self.vcard_account = None
+		
+				# register our dbus API
+				dbus.service.Object.__init__(self, bus_name, OBJ_PATH)
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def Roster(self, account_and_data):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def AccountPresence(self, status_and_account):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def ContactPresence(self, account_and_array):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def ContactAbsence(self, account_and_array):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def ContactStatus(self, account_and_array):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def NewMessage(self, account_and_array):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def Subscribe(self, account_and_array):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def Subscribed(self, account_and_array):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def Unsubscribed(self, account_and_jid):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def NewAccount(self, account_and_array):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def VcardInfo(self, account_and_vcard):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def LastStatusTime(self, account_and_array):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def OsInfo(self, account_and_array):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def GCPresence(self, account_and_array):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def GCMessage(self, account_and_array):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def RosterInfo(self, account_and_array):
+				pass
+		
+			@dbus.service.signal(INTERFACE, signature='av')
+			def NewGmail(self, account_and_array):
+				pass
+		
+			def raise_signal(self, signal, arg):
+				'''raise a signal, with a single argument of unspecified type
+				Instead of obj.raise_signal("Foo", bar), use obj.Foo(bar).'''
+				getattr(self, signal)(arg)
+		
+			@dbus.service.method(INTERFACE, in_signature='s', out_signature='s')
+			def get_status(self, account):
+				'''Returns status (show to be exact) which is the global one
+				unless account is given'''
+				if not account:
+					# If user did not ask for account, returns the global status
+					return DBUS_STRING(helpers.get_global_show())
+				# return show for the given account
+				index = gajim.connections[account].connected
+				return DBUS_STRING(gajim.SHOW_LIST[index])
+		
+			@dbus.service.method(INTERFACE, in_signature='s', out_signature='s')
+			def get_status_message(self, account):
+				'''Returns status which is the global one
+				unless account is given'''
+				if not account:
+					# If user did not ask for account, returns the global status
+					return DBUS_STRING(str(helpers.get_global_status()))
+				# return show for the given account
+				status = gajim.connections[account].status
+				return DBUS_STRING(status)
+		
+			def _get_account_and_contact(self, account, jid):
+				'''get the account (if not given) and contact instance from jid'''
+				connected_account = None
+				contact = None
+				accounts = gajim.contacts.get_accounts()
+				# if there is only one account in roster, take it as default
+				# if user did not ask for account
+				if not account and len(accounts) == 1:
+					account = accounts[0]
+				if account:
+					if gajim.connections[account].connected > 1: # account is connected
+						connected_account = account
+						contact = gajim.contacts.get_contact_with_highest_priority(account,
+							jid)
+				else:
+					for account in accounts:
+						contact = gajim.contacts.get_contact_with_highest_priority(account,
+							jid)
+						if contact and gajim.connections[account].connected > 1:
+							# account is connected
+							connected_account = account
+							break
+				if not contact:
+					contact = jid
+		
+				return connected_account, contact
+		
+			def _get_account_for_groupchat(self, account, room_jid):
+				'''get the account which is connected to groupchat (if not given)
+				or check if the given account is connected to the groupchat'''
+				connected_account = None
+				accounts = gajim.contacts.get_accounts()
+				# if there is only one account in roster, take it as default
+				# if user did not ask for account
+				if not account and len(accounts) == 1:
+					account = accounts[0]
+				if account:
+					if gajim.connections[account].connected > 1 and \
+					room_jid in gajim.gc_connected[account] and \
+					gajim.gc_connected[account][room_jid]:
+						# account and groupchat are connected
+						connected_account = account
+				else:
+					for account in accounts:
+						if gajim.connections[account].connected > 1 and \
+						room_jid in gajim.gc_connected[account] and \
+						gajim.gc_connected[account][room_jid]:
+							# account and groupchat are connected
+							connected_account = account
+							break
+				return connected_account
+		
+			@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
+			def send_file(self, file_path, jid, account):
+				'''send file, located at 'file_path' to 'jid', using account 
+				(optional) 'account' '''
+				jid = self._get_real_jid(jid, account)
+				connected_account, contact = self._get_account_and_contact(account, jid)
+		
+				if connected_account:
+					if file_path[:7] == 'file://':
+						file_path=file_path[7:]
+					if os.path.isfile(file_path): # is it file?
+						gajim.interface.instances['file_transfers'].send_file(
+							connected_account, contact, file_path)
+						return DBUS_BOOLEAN(True)
+				return DBUS_BOOLEAN(False)
+		
+			def _send_message(self, jid, message, keyID, account, type = 'chat',
+			subject = None):
+				'''can be called from send_chat_message (default when send_message)
+				or send_single_message'''
+				if not jid or not message:
+					return DBUS_BOOLEAN(False)
+				if not keyID:
+					keyID = ''
+		
+				connected_account, contact = self._get_account_and_contact(account, jid)
+				if connected_account:
+					connection = gajim.connections[connected_account]
+					connection.send_message(jid, message, keyID, type, subject)
+					return DBUS_BOOLEAN(True)
+				return DBUS_BOOLEAN(False)
+		
+			@dbus.service.method(INTERFACE, in_signature='ssss', out_signature='b')
+			def send_chat_message(self, jid, message, keyID, account):
+				'''Send chat 'message' to 'jid', using account (optional) 'account'.
+				if keyID is specified, encrypt the message with the pgp key '''
+				jid = self._get_real_jid(jid, account)
+				return self._send_message(jid, message, keyID, account)
+		
+			@dbus.service.method(INTERFACE, in_signature='sssss', out_signature='b')
+			def send_single_message(self, jid, subject, message, keyID, account):
+				'''Send single 'message' to 'jid', using account (optional) 'account'.
+				if keyID is specified, encrypt the message with the pgp key '''
+				jid = self._get_real_jid(jid, account)
+				return self._send_message(jid, message, keyID, account, type, subject)
+		
+			@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
+			def send_groupchat_message(self, room_jid, message, account):
+				'''Send 'message' to groupchat 'room_jid',
+				using account (optional) 'account'.'''
+				if not room_jid or not message:
+					return DBUS_BOOLEAN(False)
+				connected_account = self._get_account_for_groupchat(account, room_jid)
+				if connected_account:
+					connection = gajim.connections[connected_account]
+					connection.send_gc_message(room_jid, message)
+					return DBUS_BOOLEAN(True)
+				return DBUS_BOOLEAN(False)
+		
+			@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
+			def open_chat(self, jid, account):
+				'''Shows the tabbed window for new message to 'jid', using account
+				(optional) 'account' '''
+				if not jid:
+					raise MissingArgument
+					return DBUS_BOOLEAN(False)
+				jid = self._get_real_jid(jid, account)
+				try:
+					jid = helpers.parse_jid(jid)
+				except:
+					# Jid is not conform, ignore it
+					return DBUS_BOOLEAN(False)
+		
+				if account:
+					accounts = [account]
+				else:
+					accounts = gajim.connections.keys()
+					if len(accounts) == 1:
+						account = accounts[0]
+				connected_account = None
+				first_connected_acct = None
+				for acct in accounts:
+					if gajim.connections[acct].connected > 1: # account is  online
+						contact = gajim.contacts.get_first_contact_from_jid(acct, jid)
+						if gajim.interface.msg_win_mgr.has_window(jid, acct):
+							connected_account = acct
+							break
+						# jid is in roster
+						elif contact:
+							connected_account = acct
+							break
+						# we send the message to jid not in roster, because account is
+						# specified, or there is only one account
+						elif account: 
+							connected_account = acct
+						elif first_connected_acct is None:
+							first_connected_acct = acct
+		
+				# if jid is not a conntact, open-chat with first connected account
+				if connected_account is None and first_connected_acct:
+					connected_account = first_connected_acct
+		
+				if connected_account:
+					gajim.interface.new_chat_from_jid(connected_account, jid)
+					# preserve the 'steal focus preservation'
+					win = gajim.interface.msg_win_mgr.get_window(jid,
+						connected_account).window
+					if win.get_property('visible'):
+						win.window.focus()
+					return DBUS_BOOLEAN(True)
+				return DBUS_BOOLEAN(False)
+		
+			@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
+			def change_status(self, status, message, account):
+				''' change_status(status, message, account). account is optional -
+				if not specified status is changed for all accounts. '''
+				if status not in ('offline', 'online', 'chat', 
+					'away', 'xa', 'dnd', 'invisible'):
+					return DBUS_BOOLEAN(False)
+				if account:
+					gobject.idle_add(gajim.interface.roster.send_status, account,
+						status, message)
+				else:
+					# account not specified, so change the status of all accounts
+					for acc in gajim.contacts.get_accounts():
+						if not gajim.config.get_per('accounts', acc,
+						'sync_with_global_status'):
+							continue
+						gobject.idle_add(gajim.interface.roster.send_status, acc,
+							status, message)
+				return DBUS_BOOLEAN(False)
+		
+			@dbus.service.method(INTERFACE, in_signature='', out_signature='')
+			def show_next_pending_event(self):
+				'''Show the window(s) with next pending event in tabbed/group chats.'''
+				if gajim.events.get_nb_events():
+					gajim.interface.systray.handle_first_event()
+		
+			@dbus.service.method(INTERFACE, in_signature='s', out_signature='a{sv}')
+			def contact_info(self, jid):
+				'''get vcard info for a contact. Return cached value of the vcard.
+				'''
+				if not isinstance(jid, unicode):
+					jid = unicode(jid)
+				if not jid:
+					raise MissingArgument
+					return DBUS_DICT_SV()
+				jid = self._get_real_jid(jid)
+		
+				cached_vcard = gajim.connections.values()[0].get_cached_vcard(jid)
+				if cached_vcard:
+					return get_dbus_struct(cached_vcard)
+		
+				# return empty dict
+				return DBUS_DICT_SV()
+		
+			@dbus.service.method(INTERFACE, in_signature='', out_signature='as')
+			def list_accounts(self):
+				'''list register accounts'''
+				result = gajim.contacts.get_accounts()
+				result_array = dbus.Array([], signature='s')
+				if result and len(result) > 0:
+					for account in result:
+						result_array.append(DBUS_STRING(account))
+				return result_array
+		
+			@dbus.service.method(INTERFACE, in_signature='s', out_signature='a{ss}')
+			def account_info(self, account):
+				'''show info on account: resource, jid, nick, prio, message'''
+				result = DBUS_DICT_SS()
+				if gajim.connections.has_key(account):
+					# account is valid
+					con = gajim.connections[account]
+					index = con.connected
+					result['status'] = DBUS_STRING(gajim.SHOW_LIST[index])
+					result['name'] = DBUS_STRING(con.name)
+					result['jid'] = DBUS_STRING(gajim.get_jid_from_account(con.name))
+					result['message'] = DBUS_STRING(con.status)
+					result['priority'] = DBUS_STRING(unicode(con.priority))
+					result['resource'] = DBUS_STRING(unicode(gajim.config.get_per(
+						'accounts', con.name, 'resource')))
+				return result
+		
+			@dbus.service.method(INTERFACE, in_signature='s', out_signature='aa{sv}')
+			def list_contacts(self, account):
+				'''list all contacts in the roster. If the first argument is specified,
+				then return the contacts for the specified account'''
+				result = dbus.Array([], signature='aa{sv}')
+				accounts = gajim.contacts.get_accounts()
+				if len(accounts) == 0:
+					return result
+				if account:
+					accounts_to_search = [account]
+				else:
+					accounts_to_search = accounts
+				for acct in accounts_to_search:
+					if acct in accounts:
+						for jid in gajim.contacts.get_jid_list(acct):
+							item = self._contacts_as_dbus_structure(
+								gajim.contacts.get_contacts(acct, jid))
+							if item:
+								result.append(item)
+				return result
+		
+			@dbus.service.method(INTERFACE, in_signature='', out_signature='')
+			def toggle_roster_appearance(self):
+				''' shows/hides the roster window '''
+				win = gajim.interface.roster.window
+				if win.get_property('visible'):
+					gobject.idle_add(win.hide)
+				else:
+					win.present()
+					# preserve the 'steal focus preservation'
+					if self._is_first():
+						win.window.focus()
+					else:
+						win.window.focus(long(time()))
+		
+			@dbus.service.method(INTERFACE, in_signature='', out_signature='')
+			def toggle_ipython(self):
+				''' shows/hides the ipython window '''
+				win = gajim.ipython_window
+				if win:
+					if win.window.is_visible():
+						gobject.idle_add(win.hide)
+					else:
+						win.show_all()
+						win.present()
+				else:
+					gajim.interface.create_ipython_window()
+		
+			@dbus.service.method(INTERFACE, in_signature='', out_signature='a{ss}')
+			def prefs_list(self):
+				prefs_dict = DBUS_DICT_SS()
+				def get_prefs(data, name, path, value):
+					if value is None:
+						return
+					key = ''
+					if path is not None:
+						for node in path:
+							key += node + '#'
+					key += name
+					prefs_dict[DBUS_STRING(key)] = DBUS_STRING(value[1])
+				gajim.config.foreach(get_prefs)
+				return prefs_dict
+		
+			@dbus.service.method(INTERFACE, in_signature='', out_signature='b')
+			def prefs_store(self):
+				try:
+					gajim.interface.save_config()
+				except Exception, e:
+					return DBUS_BOOLEAN(False)
+				return DBUS_BOOLEAN(True)
+		
+			@dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
+			def prefs_del(self, key):
+				if not key:
+					return DBUS_BOOLEAN(False)
+				key_path = key.split('#', 2)
+				if len(key_path) != 3:
+					return DBUS_BOOLEAN(False)
+				if key_path[2] == '*':
+					gajim.config.del_per(key_path[0], key_path[1])
+				else:
+					gajim.config.del_per(key_path[0], key_path[1], key_path[2])
+				return DBUS_BOOLEAN(True)
+		
+			@dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
+			def prefs_put(self, key):
+				if not key:
+					return DBUS_BOOLEAN(False)
+				key_path = key.split('#', 2)
+				if len(key_path) < 3:
+					subname, value = key.split('=', 1)
+					gajim.config.set(subname, value)
+					return DBUS_BOOLEAN(True)
+				subname, value = key_path[2].split('=', 1)
+				gajim.config.set_per(key_path[0], key_path[1], subname, value)
+				return DBUS_BOOLEAN(True)
+		
+			@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
+			def add_contact(self, jid, account):
+				if account:
+					if account in gajim.connections and \
+						gajim.connections[account].connected > 1:
+						# if given account is active, use it 
+						AddNewContactWindow(account = account, jid = jid)
+					else:
+						# wrong account
+						return DBUS_BOOLEAN(False)
+				else:
+					# if account is not given, show account combobox
+					AddNewContactWindow(account = None, jid = jid)
+				return DBUS_BOOLEAN(True)
+		
+			@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
+			def remove_contact(self, jid, account):
+				jid = self._get_real_jid(jid, account)
+				accounts = gajim.contacts.get_accounts()
+		
+				# if there is only one account in roster, take it as default
+				if account:
+					accounts = [account]
+				contact_exists = False
+				for account in accounts:
+					contacts = gajim.contacts.get_contacts(account, jid)
+					if contacts:
+						gajim.connections[account].unsubscribe(jid)
+						for contact in contacts:
+							gajim.interface.roster.remove_contact(contact, account)
+						gajim.contacts.remove_jid(account, jid)
+						contact_exists = True
+				return DBUS_BOOLEAN(contact_exists)
+		
+			def _is_first(self):
+				if self.first_show:
+					self.first_show = False
+					return True
+				return False
+		
+			def _get_real_jid(self, jid, account = None):
+				'''get the real jid from the given one: removes xmpp: or get jid from nick
+				if account is specified, search only in this account
+				'''
+				if account:
+					accounts = [account]
+				else:
+					accounts = gajim.connections.keys()
+				if jid.startswith('xmpp:'):
+					return jid[5:] # len('xmpp:') = 5
+				nick_in_roster = None # Is jid a nick ?
+				for account in accounts:
+					# Does jid exists in roster of one account ?
+					if gajim.contacts.get_contacts(account, jid):
+						return jid
+					if not nick_in_roster:
+						# look in all contact if one has jid as nick
+						for jid_ in gajim.contacts.get_jid_list(account):
+							c = gajim.contacts.get_contacts(account, jid_)
+							if c[0].name == jid:
+								nick_in_roster = jid_
+								break
+				if nick_in_roster:
+					# We have not found jid in roster, but we found is as a nick
+					return nick_in_roster
+				# We have not found it as jid nor as nick, probably a not in roster jid
+				return jid
+		
+			def _contacts_as_dbus_structure(self, contacts):
+				''' get info from list of Contact objects and create dbus dict '''
+				if not contacts:
+					return None
+				prim_contact = None # primary contact
+				for contact in contacts:
+					if prim_contact is None or contact.priority > prim_contact.priority:
+						prim_contact = contact
+				contact_dict = DBUS_DICT_SV()
+				contact_dict['name'] = DBUS_STRING(prim_contact.name)
+				contact_dict['show'] = DBUS_STRING(prim_contact.show)
+				contact_dict['jid'] = DBUS_STRING(prim_contact.jid)
+				if prim_contact.keyID:
+					keyID = None
+					if len(prim_contact.keyID) == 8:
+						keyID = prim_contact.keyID
+					elif len(prim_contact.keyID) == 16:
+						keyID = prim_contact.keyID[8:]
+					if keyID:
+						contact_dict['openpgp'] = keyID
+				contact_dict['resources'] = dbus.Array([], signature='(sis)')
+				for contact in contacts:
+					resource_props = dbus.Struct((DBUS_STRING(contact.resource),
+						dbus.Int32(contact.priority), DBUS_STRING(contact.status)))
+					contact_dict['resources'].append(resource_props)
+				contact_dict['groups'] = dbus.Array([], signature='(s)')
+				for group in prim_contact.groups:
+					contact_dict['groups'].append((DBUS_STRING(group),))
+				return contact_dict
+		
+			@dbus.service.method(INTERFACE, in_signature='', out_signature='s')
+			def get_unread_msgs_number(self):
+				return DBUS_STRING(str(gajim.events.get_nb_events()))
+		
+			@dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
+			def start_chat(self, account):
+				if not account:
+					# error is shown in gajim-remote check_arguments(..)
+					return DBUS_BOOLEAN(False)
+				NewChatDialog(account)
+				return DBUS_BOOLEAN(True)
+		
+			@dbus.service.method(INTERFACE, in_signature='ss', out_signature='')
+			def send_xml(self, xml, account):
+				if account:
+					gajim.connections[account].send_stanza(xml)
+				else:
+					for acc in gajim.contacts.get_accounts():
+						gajim.connections[acc].send_stanza(xml)
+		
+			@dbus.service.method(INTERFACE, in_signature='ssss', out_signature='')
+			def join_room(self, room_jid, nick, password, account):
+				if not account:
+					# get the first connected account
+					accounts = gajim.connections.keys()
+					for acct in accounts:
+						if gajim.account_is_connected(acct):
+							account = acct
+							break
+					if not account:
+						return
+				if not nick:
+					nick = ''
+					gajim.interface.instances[account]['join_gc'] = \
+							JoinGroupchatWindow(account, room_jid, nick)
+				else:
+					gajim.interface.join_gc_room(account, room_jid, nick, password)
+
 INTERFACE = 'org.gajim.dbusplugin.RemoteInterface'
 OBJ_PATH = '/org/gajim/dbusplugin/RemoteObject'
 SERVICE = 'org.gajim.dbusplugin'
@@ -115,624 +735,5 @@
 		
 		return handler
 	
-# type mapping
 
-# in most cases it is a utf-8 string
-DBUS_STRING = dbus.String
-
-# general type (for use in dicts, where all values should have the same type)
-DBUS_BOOLEAN = dbus.Boolean
-DBUS_DOUBLE = dbus.Double
-DBUS_INT32 = dbus.Int32
-# dictionary with string key and binary value
-DBUS_DICT_SV = lambda : dbus.Dictionary({}, signature="sv")
-# dictionary with string key and value
-DBUS_DICT_SS = lambda : dbus.Dictionary({}, signature="ss")
-# empty type (there is no equivalent of None on D-Bus, but historically gajim
-# used 0 instead)
-DBUS_NONE = lambda : dbus.Int32(0)
-
-def get_dbus_struct(obj):
-	''' recursively go through all the items and replace
-	them with their casted dbus equivalents
-	'''
-	if obj is None:
-		return DBUS_NONE()
-	if isinstance(obj, (unicode, str)):
-		return DBUS_STRING(obj)
-	if isinstance(obj, int):
-		return DBUS_INT32(obj)
-	if isinstance(obj, float):
-		return DBUS_DOUBLE(obj)
-	if isinstance(obj, bool):
-		return DBUS_BOOLEAN(obj)
-	if isinstance(obj, (list, tuple)):
-		result = dbus.Array([get_dbus_struct(i) for i in obj],
-			signature='v')
-		if result == []:
-			return DBUS_NONE()
-		return result
-	if isinstance(obj, dict):
-		result = DBUS_DICT_SV()
-		for key, value in obj.items():
-			result[DBUS_STRING(key)] = get_dbus_struct(value)
-		if result == {}:
-			return DBUS_NONE()
-		return result
-	# unknown type
-	return DBUS_NONE() 
-	
-class SignalObject(dbus.service.Object):
-	''' Local object definition for /org/gajim/dbus/RemoteObject.
-	(This docstring is not be visible, because the clients can access only the remote object.)'''
-
-	def __init__(self, bus_name):
-		self.first_show = True
-		self.vcard_account = None
-
-		# register our dbus API
-		dbus.service.Object.__init__(self, bus_name, OBJ_PATH)
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def Roster(self, account_and_data):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def AccountPresence(self, status_and_account):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def ContactPresence(self, account_and_array):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def ContactAbsence(self, account_and_array):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def ContactStatus(self, account_and_array):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def NewMessage(self, account_and_array):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def Subscribe(self, account_and_array):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def Subscribed(self, account_and_array):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def Unsubscribed(self, account_and_jid):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def NewAccount(self, account_and_array):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def VcardInfo(self, account_and_vcard):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def LastStatusTime(self, account_and_array):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def OsInfo(self, account_and_array):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def GCPresence(self, account_and_array):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def GCMessage(self, account_and_array):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def RosterInfo(self, account_and_array):
-		pass
-
-	@dbus.service.signal(INTERFACE, signature='av')
-	def NewGmail(self, account_and_array):
-		pass
-
-	def raise_signal(self, signal, arg):
-		'''raise a signal, with a single argument of unspecified type
-		Instead of obj.raise_signal("Foo", bar), use obj.Foo(bar).'''
-		getattr(self, signal)(arg)
-
-	@dbus.service.method(INTERFACE, in_signature='s', out_signature='s')
-	def get_status(self, account):
-		'''Returns status (show to be exact) which is the global one
-		unless account is given'''
-		if not account:
-			# If user did not ask for account, returns the global status
-			return DBUS_STRING(helpers.get_global_show())
-		# return show for the given account
-		index = gajim.connections[account].connected
-		return DBUS_STRING(gajim.SHOW_LIST[index])
-
-	@dbus.service.method(INTERFACE, in_signature='s', out_signature='s')
-	def get_status_message(self, account):
-		'''Returns status which is the global one
-		unless account is given'''
-		if not account:
-			# If user did not ask for account, returns the global status
-			return DBUS_STRING(str(helpers.get_global_status()))
-		# return show for the given account
-		status = gajim.connections[account].status
-		return DBUS_STRING(status)
-
-	def _get_account_and_contact(self, account, jid):
-		'''get the account (if not given) and contact instance from jid'''
-		connected_account = None
-		contact = None
-		accounts = gajim.contacts.get_accounts()
-		# if there is only one account in roster, take it as default
-		# if user did not ask for account
-		if not account and len(accounts) == 1:
-			account = accounts[0]
-		if account:
-			if gajim.connections[account].connected > 1: # account is connected
-				connected_account = account
-				contact = gajim.contacts.get_contact_with_highest_priority(account,
-					jid)
-		else:
-			for account in accounts:
-				contact = gajim.contacts.get_contact_with_highest_priority(account,
-					jid)
-				if contact and gajim.connections[account].connected > 1:
-					# account is connected
-					connected_account = account
-					break
-		if not contact:
-			contact = jid
-
-		return connected_account, contact
-
-	def _get_account_for_groupchat(self, account, room_jid):
-		'''get the account which is connected to groupchat (if not given)
-		or check if the given account is connected to the groupchat'''
-		connected_account = None
-		accounts = gajim.contacts.get_accounts()
-		# if there is only one account in roster, take it as default
-		# if user did not ask for account
-		if not account and len(accounts) == 1:
-			account = accounts[0]
-		if account:
-			if gajim.connections[account].connected > 1 and \
-			room_jid in gajim.gc_connected[account] and \
-			gajim.gc_connected[account][room_jid]:
-				# account and groupchat are connected
-				connected_account = account
-		else:
-			for account in accounts:
-				if gajim.connections[account].connected > 1 and \
-				room_jid in gajim.gc_connected[account] and \
-				gajim.gc_connected[account][room_jid]:
-					# account and groupchat are connected
-					connected_account = account
-					break
-		return connected_account
-
-	@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
-	def send_file(self, file_path, jid, account):
-		'''send file, located at 'file_path' to 'jid', using account 
-		(optional) 'account' '''
-		jid = self._get_real_jid(jid, account)
-		connected_account, contact = self._get_account_and_contact(account, jid)
-
-		if connected_account:
-			if file_path[:7] == 'file://':
-				file_path=file_path[7:]
-			if os.path.isfile(file_path): # is it file?
-				gajim.interface.instances['file_transfers'].send_file(
-					connected_account, contact, file_path)
-				return DBUS_BOOLEAN(True)
-		return DBUS_BOOLEAN(False)
-
-	def _send_message(self, jid, message, keyID, account, type = 'chat',
-	subject = None):
-		'''can be called from send_chat_message (default when send_message)
-		or send_single_message'''
-		if not jid or not message:
-			return DBUS_BOOLEAN(False)
-		if not keyID:
-			keyID = ''
-
-		connected_account, contact = self._get_account_and_contact(account, jid)
-		if connected_account:
-			connection = gajim.connections[connected_account]
-			connection.send_message(jid, message, keyID, type, subject)
-			return DBUS_BOOLEAN(True)
-		return DBUS_BOOLEAN(False)
-
-	@dbus.service.method(INTERFACE, in_signature='ssss', out_signature='b')
-	def send_chat_message(self, jid, message, keyID, account):
-		'''Send chat 'message' to 'jid', using account (optional) 'account'.
-		if keyID is specified, encrypt the message with the pgp key '''
-		jid = self._get_real_jid(jid, account)
-		return self._send_message(jid, message, keyID, account)
-
-	@dbus.service.method(INTERFACE, in_signature='sssss', out_signature='b')
-	def send_single_message(self, jid, subject, message, keyID, account):
-		'''Send single 'message' to 'jid', using account (optional) 'account'.
-		if keyID is specified, encrypt the message with the pgp key '''
-		jid = self._get_real_jid(jid, account)
-		return self._send_message(jid, message, keyID, account, type, subject)
-
-	@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
-	def send_groupchat_message(self, room_jid, message, account):
-		'''Send 'message' to groupchat 'room_jid',
-		using account (optional) 'account'.'''
-		if not room_jid or not message:
-			return DBUS_BOOLEAN(False)
-		connected_account = self._get_account_for_groupchat(account, room_jid)
-		if connected_account:
-			connection = gajim.connections[connected_account]
-			connection.send_gc_message(room_jid, message)
-			return DBUS_BOOLEAN(True)
-		return DBUS_BOOLEAN(False)
-
-	@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
-	def open_chat(self, jid, account):
-		'''Shows the tabbed window for new message to 'jid', using account
-		(optional) 'account' '''
-		if not jid:
-			raise MissingArgument
-			return DBUS_BOOLEAN(False)
-		jid = self._get_real_jid(jid, account)
-		try:
-			jid = helpers.parse_jid(jid)
-		except:
-			# Jid is not conform, ignore it
-			return DBUS_BOOLEAN(False)
-
-		if account:
-			accounts = [account]
-		else:
-			accounts = gajim.connections.keys()
-			if len(accounts) == 1:
-				account = accounts[0]
-		connected_account = None
-		first_connected_acct = None
-		for acct in accounts:
-			if gajim.connections[acct].connected > 1: # account is  online
-				contact = gajim.contacts.get_first_contact_from_jid(acct, jid)
-				if gajim.interface.msg_win_mgr.has_window(jid, acct):
-					connected_account = acct
-					break
-				# jid is in roster
-				elif contact:
-					connected_account = acct
-					break
-				# we send the message to jid not in roster, because account is
-				# specified, or there is only one account
-				elif account: 
-					connected_account = acct
-				elif first_connected_acct is None:
-					first_connected_acct = acct
-
-		# if jid is not a conntact, open-chat with first connected account
-		if connected_account is None and first_connected_acct:
-			connected_account = first_connected_acct
-
-		if connected_account:
-			gajim.interface.new_chat_from_jid(connected_account, jid)
-			# preserve the 'steal focus preservation'
-			win = gajim.interface.msg_win_mgr.get_window(jid,
-				connected_account).window
-			if win.get_property('visible'):
-				win.window.focus()
-			return DBUS_BOOLEAN(True)
-		return DBUS_BOOLEAN(False)
-
-	@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
-	def change_status(self, status, message, account):
-		''' change_status(status, message, account). account is optional -
-		if not specified status is changed for all accounts. '''
-		if status not in ('offline', 'online', 'chat', 
-			'away', 'xa', 'dnd', 'invisible'):
-			return DBUS_BOOLEAN(False)
-		if account:
-			gobject.idle_add(gajim.interface.roster.send_status, account,
-				status, message)
-		else:
-			# account not specified, so change the status of all accounts
-			for acc in gajim.contacts.get_accounts():
-				if not gajim.config.get_per('accounts', acc,
-				'sync_with_global_status'):
-					continue
-				gobject.idle_add(gajim.interface.roster.send_status, acc,
-					status, message)
-		return DBUS_BOOLEAN(False)
-
-	@dbus.service.method(INTERFACE, in_signature='', out_signature='')
-	def show_next_pending_event(self):
-		'''Show the window(s) with next pending event in tabbed/group chats.'''
-		if gajim.events.get_nb_events():
-			gajim.interface.systray.handle_first_event()
-
-	@dbus.service.method(INTERFACE, in_signature='s', out_signature='a{sv}')
-	def contact_info(self, jid):
-		'''get vcard info for a contact. Return cached value of the vcard.
-		'''
-		if not isinstance(jid, unicode):
-			jid = unicode(jid)
-		if not jid:
-			raise MissingArgument
-			return DBUS_DICT_SV()
-		jid = self._get_real_jid(jid)
-
-		cached_vcard = gajim.connections.values()[0].get_cached_vcard(jid)
-		if cached_vcard:
-			return get_dbus_struct(cached_vcard)
-
-		# return empty dict
-		return DBUS_DICT_SV()
-
-	@dbus.service.method(INTERFACE, in_signature='', out_signature='as')
-	def list_accounts(self):
-		'''list register accounts'''
-		result = gajim.contacts.get_accounts()
-		result_array = dbus.Array([], signature='s')
-		if result and len(result) > 0:
-			for account in result:
-				result_array.append(DBUS_STRING(account))
-		return result_array
-
-	@dbus.service.method(INTERFACE, in_signature='s', out_signature='a{ss}')
-	def account_info(self, account):
-		'''show info on account: resource, jid, nick, prio, message'''
-		result = DBUS_DICT_SS()
-		if gajim.connections.has_key(account):
-			# account is valid
-			con = gajim.connections[account]
-			index = con.connected
-			result['status'] = DBUS_STRING(gajim.SHOW_LIST[index])
-			result['name'] = DBUS_STRING(con.name)
-			result['jid'] = DBUS_STRING(gajim.get_jid_from_account(con.name))
-			result['message'] = DBUS_STRING(con.status)
-			result['priority'] = DBUS_STRING(unicode(con.priority))
-			result['resource'] = DBUS_STRING(unicode(gajim.config.get_per(
-				'accounts', con.name, 'resource')))
-		return result
-
-	@dbus.service.method(INTERFACE, in_signature='s', out_signature='aa{sv}')
-	def list_contacts(self, account):
-		'''list all contacts in the roster. If the first argument is specified,
-		then return the contacts for the specified account'''
-		result = dbus.Array([], signature='aa{sv}')
-		accounts = gajim.contacts.get_accounts()
-		if len(accounts) == 0:
-			return result
-		if account:
-			accounts_to_search = [account]
-		else:
-			accounts_to_search = accounts
-		for acct in accounts_to_search:
-			if acct in accounts:
-				for jid in gajim.contacts.get_jid_list(acct):
-					item = self._contacts_as_dbus_structure(
-						gajim.contacts.get_contacts(acct, jid))
-					if item:
-						result.append(item)
-		return result
-
-	@dbus.service.method(INTERFACE, in_signature='', out_signature='')
-	def toggle_roster_appearance(self):
-		''' shows/hides the roster window '''
-		win = gajim.interface.roster.window
-		if win.get_property('visible'):
-			gobject.idle_add(win.hide)
-		else:
-			win.present()
-			# preserve the 'steal focus preservation'
-			if self._is_first():
-				win.window.focus()
-			else:
-				win.window.focus(long(time()))
-
-	@dbus.service.method(INTERFACE, in_signature='', out_signature='')
-	def toggle_ipython(self):
-		''' shows/hides the ipython window '''
-		win = gajim.ipython_window
-		if win:
-			if win.window.is_visible():
-				gobject.idle_add(win.hide)
-			else:
-				win.show_all()
-				win.present()
-		else:
-			gajim.interface.create_ipython_window()
-
-	@dbus.service.method(INTERFACE, in_signature='', out_signature='a{ss}')
-	def prefs_list(self):
-		prefs_dict = DBUS_DICT_SS()
-		def get_prefs(data, name, path, value):
-			if value is None:
-				return
-			key = ''
-			if path is not None:
-				for node in path:
-					key += node + '#'
-			key += name
-			prefs_dict[DBUS_STRING(key)] = DBUS_STRING(value[1])
-		gajim.config.foreach(get_prefs)
-		return prefs_dict
-
-	@dbus.service.method(INTERFACE, in_signature='', out_signature='b')
-	def prefs_store(self):
-		try:
-			gajim.interface.save_config()
-		except Exception, e:
-			return DBUS_BOOLEAN(False)
-		return DBUS_BOOLEAN(True)
-
-	@dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
-	def prefs_del(self, key):
-		if not key:
-			return DBUS_BOOLEAN(False)
-		key_path = key.split('#', 2)
-		if len(key_path) != 3:
-			return DBUS_BOOLEAN(False)
-		if key_path[2] == '*':
-			gajim.config.del_per(key_path[0], key_path[1])
-		else:
-			gajim.config.del_per(key_path[0], key_path[1], key_path[2])
-		return DBUS_BOOLEAN(True)
-
-	@dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
-	def prefs_put(self, key):
-		if not key:
-			return DBUS_BOOLEAN(False)
-		key_path = key.split('#', 2)
-		if len(key_path) < 3:
-			subname, value = key.split('=', 1)
-			gajim.config.set(subname, value)
-			return DBUS_BOOLEAN(True)
-		subname, value = key_path[2].split('=', 1)
-		gajim.config.set_per(key_path[0], key_path[1], subname, value)
-		return DBUS_BOOLEAN(True)
-
-	@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
-	def add_contact(self, jid, account):
-		if account:
-			if account in gajim.connections and \
-				gajim.connections[account].connected > 1:
-				# if given account is active, use it 
-				AddNewContactWindow(account = account, jid = jid)
-			else:
-				# wrong account
-				return DBUS_BOOLEAN(False)
-		else:
-			# if account is not given, show account combobox
-			AddNewContactWindow(account = None, jid = jid)
-		return DBUS_BOOLEAN(True)
-
-	@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
-	def remove_contact(self, jid, account):
-		jid = self._get_real_jid(jid, account)
-		accounts = gajim.contacts.get_accounts()
-
-		# if there is only one account in roster, take it as default
-		if account:
-			accounts = [account]
-		contact_exists = False
-		for account in accounts:
-			contacts = gajim.contacts.get_contacts(account, jid)
-			if contacts:
-				gajim.connections[account].unsubscribe(jid)
-				for contact in contacts:
-					gajim.interface.roster.remove_contact(contact, account)
-				gajim.contacts.remove_jid(account, jid)
-				contact_exists = True
-		return DBUS_BOOLEAN(contact_exists)
-
-	def _is_first(self):
-		if self.first_show:
-			self.first_show = False
-			return True
-		return False
-
-	def _get_real_jid(self, jid, account = None):
-		'''get the real jid from the given one: removes xmpp: or get jid from nick
-		if account is specified, search only in this account
-		'''
-		if account:
-			accounts = [account]
-		else:
-			accounts = gajim.connections.keys()
-		if jid.startswith('xmpp:'):
-			return jid[5:] # len('xmpp:') = 5
-		nick_in_roster = None # Is jid a nick ?
-		for account in accounts:
-			# Does jid exists in roster of one account ?
-			if gajim.contacts.get_contacts(account, jid):
-				return jid
-			if not nick_in_roster:
-				# look in all contact if one has jid as nick
-				for jid_ in gajim.contacts.get_jid_list(account):
-					c = gajim.contacts.get_contacts(account, jid_)
-					if c[0].name == jid:
-						nick_in_roster = jid_
-						break
-		if nick_in_roster:
-			# We have not found jid in roster, but we found is as a nick
-			return nick_in_roster
-		# We have not found it as jid nor as nick, probably a not in roster jid
-		return jid
-
-	def _contacts_as_dbus_structure(self, contacts):
-		''' get info from list of Contact objects and create dbus dict '''
-		if not contacts:
-			return None
-		prim_contact = None # primary contact
-		for contact in contacts:
-			if prim_contact is None or contact.priority > prim_contact.priority:
-				prim_contact = contact
-		contact_dict = DBUS_DICT_SV()
-		contact_dict['name'] = DBUS_STRING(prim_contact.name)
-		contact_dict['show'] = DBUS_STRING(prim_contact.show)
-		contact_dict['jid'] = DBUS_STRING(prim_contact.jid)
-		if prim_contact.keyID:
-			keyID = None
-			if len(prim_contact.keyID) == 8:
-				keyID = prim_contact.keyID
-			elif len(prim_contact.keyID) == 16:
-				keyID = prim_contact.keyID[8:]
-			if keyID:
-				contact_dict['openpgp'] = keyID
-		contact_dict['resources'] = dbus.Array([], signature='(sis)')
-		for contact in contacts:
-			resource_props = dbus.Struct((DBUS_STRING(contact.resource),
-				dbus.Int32(contact.priority), DBUS_STRING(contact.status)))
-			contact_dict['resources'].append(resource_props)
-		contact_dict['groups'] = dbus.Array([], signature='(s)')
-		for group in prim_contact.groups:
-			contact_dict['groups'].append((DBUS_STRING(group),))
-		return contact_dict
-
-	@dbus.service.method(INTERFACE, in_signature='', out_signature='s')
-	def get_unread_msgs_number(self):
-		return DBUS_STRING(str(gajim.events.get_nb_events()))
-
-	@dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
-	def start_chat(self, account):
-		if not account:
-			# error is shown in gajim-remote check_arguments(..)
-			return DBUS_BOOLEAN(False)
-		NewChatDialog(account)
-		return DBUS_BOOLEAN(True)
-
-	@dbus.service.method(INTERFACE, in_signature='ss', out_signature='')
-	def send_xml(self, xml, account):
-		if account:
-			gajim.connections[account].send_stanza(xml)
-		else:
-			for acc in gajim.contacts.get_accounts():
-				gajim.connections[acc].send_stanza(xml)
-
-	@dbus.service.method(INTERFACE, in_signature='ssss', out_signature='')
-	def join_room(self, room_jid, nick, password, account):
-		if not account:
-			# get the first connected account
-			accounts = gajim.connections.keys()
-			for acct in accounts:
-				if gajim.account_is_connected(acct):
-					account = acct
-					break
-			if not account:
-				return
-		if not nick:
-			nick = ''
-			gajim.interface.instances[account]['join_gc'] = \
-					JoinGroupchatWindow(account, room_jid, nick)
-		else:
-			gajim.interface.join_gc_room(account, room_jid, nick, password)
 		
\ No newline at end of file



More information about the Commits mailing list