New Service Discovery, couple of quick notes about this commit:
* src/disco.py contains all the disco stuff * registration remains in src/config.py * data/pixmaps/agents contains the icons used in the toplevel server browser and the banner. They're referenced at the top of src/disco.py.
1
README
|
@ -79,4 +79,5 @@ sounds and stellar iconstyle taken from Psi
|
|||
some emoticons taken from Psi
|
||||
the basic emoticons taken from Gossip
|
||||
gossip iconstyle taken from Gossip
|
||||
service discovery icons taken from Gaim and the GNOME hi-color theme
|
||||
If you think we're violating a license please inform us
|
||||
|
|
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.9 KiB |
|
@ -207,7 +207,7 @@ class Connection:
|
|||
|
||||
def discoverInfo(self, jid, node = None):
|
||||
'''According to JEP-0030:
|
||||
For identity: category, name is mandatory, type is optional.
|
||||
For identity: category, type is mandatory, name is optional.
|
||||
For feature: var is mandatory'''
|
||||
self._discover(common.xmpp.NS_DISCO_INFO, jid, node)
|
||||
|
||||
|
@ -1048,6 +1048,11 @@ class Connection:
|
|||
self.dispatch('ROSTER_INFO', (jid, name, sub, ask, groups))
|
||||
raise common.xmpp.NodeProcessed
|
||||
|
||||
def _DiscoverItemsErrorCB(self, con, iq_obj):
|
||||
gajim.log.debug('DiscoverItemsErrorCB')
|
||||
jid = iq_obj.getFrom()
|
||||
self.dispatch('AGENT_ERROR_ITEMS', (jid))
|
||||
|
||||
def _DiscoverItemsCB(self, con, iq_obj):
|
||||
gajim.log.debug('DiscoverItemsCB')
|
||||
q = iq_obj.getTag('query')
|
||||
|
@ -1066,12 +1071,17 @@ class Connection:
|
|||
jid = unicode(iq_obj.getFrom())
|
||||
self.dispatch('AGENT_INFO_ITEMS', (jid, node, items))
|
||||
|
||||
def _DiscoverInfoErrorCB(self, con, iq_obj):
|
||||
gajim.log.debug('DiscoverInfoErrorCB')
|
||||
jid = iq_obj.getFrom()
|
||||
self.dispatch('AGENT_ERROR_INFO', (jid))
|
||||
|
||||
def _DiscoverInfoCB(self, con, iq_obj):
|
||||
gajim.log.debug('DiscoverInfoCB')
|
||||
# According to JEP-0030:
|
||||
# For identity: category, name is mandatory, type is optional.
|
||||
# For identity: category, type is mandatory, name is optional.
|
||||
# For feature: var is mandatory
|
||||
identities, features = [], []
|
||||
identities, features, data = [], [], []
|
||||
q = iq_obj.getTag('query')
|
||||
node = q.getAttr('node')
|
||||
if not node:
|
||||
|
@ -1087,9 +1097,12 @@ class Connection:
|
|||
identities.append(attr)
|
||||
elif i.getName() == 'feature':
|
||||
features.append(i.getAttr('var'))
|
||||
elif i.getName() == 'x' and i.getAttr('xmlns') == NS_DATA:
|
||||
data.append(common.xmpp.DataForm(node=i))
|
||||
jid = unicode(iq_obj.getFrom())
|
||||
if identities: #if not: an error occured
|
||||
self.dispatch('AGENT_INFO_INFO', (jid, node, identities, features))
|
||||
self.dispatch('AGENT_INFO_INFO', (jid, node, identities,
|
||||
features, data))
|
||||
|
||||
def _VersionCB(self, con, iq_obj):
|
||||
gajim.log.debug('VersionCB')
|
||||
|
@ -1487,8 +1500,12 @@ class Connection:
|
|||
common.xmpp.NS_BYTESTREAM)
|
||||
con.RegisterHandler('iq', self._DiscoverItemsCB, 'result',
|
||||
common.xmpp.NS_DISCO_ITEMS)
|
||||
con.RegisterHandler('iq', self._DiscoverItemsErrorCB, 'error',
|
||||
common.xmpp.NS_DISCO_ITEMS)
|
||||
con.RegisterHandler('iq', self._DiscoverInfoCB, 'result',
|
||||
common.xmpp.NS_DISCO_INFO)
|
||||
con.RegisterHandler('iq', self._DiscoverInfoErrorCB, 'error',
|
||||
common.xmpp.NS_DISCO_INFO)
|
||||
con.RegisterHandler('iq', self._VersionCB, 'get',
|
||||
common.xmpp.NS_VERSION)
|
||||
con.RegisterHandler('iq', self._VersionResultCB, 'result',
|
||||
|
@ -1789,13 +1806,6 @@ class Connection:
|
|||
self.connection.getRoster().setItem(jid = jid, name = name,
|
||||
groups = groups)
|
||||
|
||||
def request_agents(self, jid, node):
|
||||
if self.connection:
|
||||
iq = common.xmpp.Iq(to = jid, typ = 'get',
|
||||
queryNS = common.xmpp.NS_DISCO_ITEMS)
|
||||
if node: iq.setQuerynode(node)
|
||||
self.to_be_sent.append(iq)
|
||||
|
||||
def request_register_agent_info(self, agent):
|
||||
if not self.connection:
|
||||
return None
|
||||
|
|
|
@ -60,7 +60,7 @@ def discoverInfo(disp,jid,node=None):
|
|||
""" Query remote object about info that it publishes. Returns identities and features lists."""
|
||||
""" According to JEP-0030:
|
||||
query MAY have node attribute
|
||||
identity: MUST HAVE category and name attributes and MAY HAVE type attribute.
|
||||
identity: MUST HAVE category and type attributes and MAY HAVE name attribute.
|
||||
feature: MUST HAVE var attribute"""
|
||||
identities , features = [] , []
|
||||
for i in _discover(disp,NS_DISCO_INFO,jid,node):
|
||||
|
|
319
src/config.py
|
@ -1282,7 +1282,7 @@ _('To change the account name, you must be disconnected.')).get_response()
|
|||
gajim.events_for_ui[name] = gajim.events_for_ui[self.account]
|
||||
|
||||
#upgrade account variable in opened windows
|
||||
for kind in ('infos', 'chats', 'gc', 'gc_config'):
|
||||
for kind in ('infos', 'disco', 'chats', 'gc', 'gc_config'):
|
||||
for j in gajim.interface.windows[name][kind]:
|
||||
gajim.interface.windows[name][kind][j].account = name
|
||||
|
||||
|
@ -1346,8 +1346,8 @@ _('To change the account name, you must be disconnected.')).get_response()
|
|||
if config['savepass']:
|
||||
gajim.connections[name].password = config['password']
|
||||
#update variables
|
||||
gajim.interface.windows[name] = {'infos': {}, 'chats': {}, 'gc': {}, \
|
||||
'gc_config': {}}
|
||||
gajim.interface.windows[name] = {'infos': {}, 'disco': {}, 'chats': {},
|
||||
'gc': {}, 'gc_config': {}}
|
||||
gajim.interface.windows[name]['xml_console'] = \
|
||||
dialogs.XMLConsoleWindow(name)
|
||||
gajim.awaiting_events[name] = {}
|
||||
|
@ -2162,315 +2162,6 @@ class ManageEmoticonsWindow:
|
|||
if event.keyval == gtk.keysyms.Delete:
|
||||
self.on_button_remove_emoticon_clicked(widget)
|
||||
|
||||
|
||||
#---------- ServiceDiscoveryWindow class -------------#
|
||||
class ServiceDiscoveryWindow:
|
||||
'''Class for Service Discovery Window:
|
||||
to know the services on a server'''
|
||||
def on_service_discovery_window_destroy(self, widget):
|
||||
del gajim.interface.windows[self.account]['disco']
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
self.window.destroy()
|
||||
|
||||
def __init__(self, account):
|
||||
self.account = account
|
||||
self.agent_infos = {}
|
||||
self.items_asked = [] #we already asked items to these jids
|
||||
if gajim.connections[account].connected < 2:
|
||||
dialogs.ErrorDialog(_('You are not connected to the server'),
|
||||
_('Without a connection, you can not browse available services')).get_response()
|
||||
raise RuntimeError, 'You must be connected to browse services'
|
||||
xml = gtk.glade.XML(GTKGUI_GLADE, 'service_discovery_window', APP)
|
||||
self.window = xml.get_widget('service_discovery_window')
|
||||
if len(gajim.connections):
|
||||
self.window.set_title(_('Service Discovery using %s account') %account)
|
||||
else:
|
||||
self.window.set_title(_('Service Discovery'))
|
||||
self.services_treeview = xml.get_widget('services_treeview')
|
||||
self.join_button = xml.get_widget('join_button')
|
||||
self.register_button = xml.get_widget('register_button')
|
||||
self.address_comboboxentry = xml.get_widget('address_comboboxentry')
|
||||
self.address_comboboxentry_entry = self.address_comboboxentry.child
|
||||
self.address_comboboxentry_entry.set_activates_default(True)
|
||||
|
||||
model = gtk.TreeStore(str, str, str)
|
||||
model.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
self.services_treeview.set_model(model)
|
||||
#columns
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.set_data('column', 0)
|
||||
col = self.services_treeview.insert_column_with_attributes(-1,
|
||||
_('Name'), renderer, text = 0)
|
||||
col.set_resizable(True)
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.set_data('column', 1)
|
||||
col = self.services_treeview.insert_column_with_attributes(-1,
|
||||
_('Service'), renderer, text = 1)
|
||||
col.set_resizable(True)
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.set_data('column', 1)
|
||||
col = self.services_treeview.insert_column_with_attributes(-1,
|
||||
_('Node'), renderer, text = 2)
|
||||
col.set_resizable(True)
|
||||
|
||||
self.address_comboboxentry = xml.get_widget('address_comboboxentry')
|
||||
liststore = gtk.ListStore(str)
|
||||
self.address_comboboxentry.set_model(liststore)
|
||||
self.address_comboboxentry.set_text_column(0)
|
||||
self.latest_addresses = gajim.config.get('latest_disco_addresses').split()
|
||||
server_address = gajim.get_hostname_from_account(self.account)
|
||||
if server_address in self.latest_addresses:
|
||||
self.latest_addresses.remove(server_address)
|
||||
self.latest_addresses.insert(0, server_address)
|
||||
if len(self.latest_addresses) > 10:
|
||||
self.latest_addresses = self.latest_addresses[0:10]
|
||||
for j in self.latest_addresses:
|
||||
self.address_comboboxentry.append_text(j)
|
||||
self.address_comboboxentry.child.set_text(server_address)
|
||||
|
||||
self.register_button.set_sensitive(False)
|
||||
self.join_button.set_sensitive(False)
|
||||
xml.signal_autoconnect(self)
|
||||
self.browse(server_address)
|
||||
self.window.show_all()
|
||||
|
||||
def browse(self, jid, node = ''):
|
||||
'''Send a request to the core to know the available services'''
|
||||
model = self.services_treeview.get_model()
|
||||
if not model.get_iter_first():
|
||||
# we begin to fill the treevier with the first line
|
||||
iter = model.append(None, (jid, jid, node))
|
||||
self.agent_infos[jid] = {'features' : []}
|
||||
gajim.connections[self.account].request_agents(jid, node)
|
||||
self.items_asked.append(jid+node)
|
||||
|
||||
def agents(self, agents):
|
||||
'''When list of available agent arrive:
|
||||
Fill the treeview with it'''
|
||||
model = self.services_treeview.get_model()
|
||||
for agent in agents:
|
||||
node = ''
|
||||
if agent.has_key('node'):
|
||||
node = agent['node']
|
||||
iter = model.append(None, (agent['name'], agent['jid'], node))
|
||||
self.agent_infos[agent['jid'] + node] = {'features' : []}
|
||||
|
||||
def iter_is_visible(self, iter):
|
||||
if not iter:
|
||||
return False
|
||||
model = self.services_treeview.get_model()
|
||||
iter = model.iter_parent(iter)
|
||||
while iter:
|
||||
if not self.services_treeview.row_expanded(model.get_path(iter)):
|
||||
return False
|
||||
iter = model.iter_parent(iter)
|
||||
return True
|
||||
|
||||
def on_services_treeview_row_expanded(self, widget, iter, path):
|
||||
model = self.services_treeview.get_model()
|
||||
if model.iter_n_children(iter) > 15:
|
||||
return
|
||||
child = model.iter_children(iter)
|
||||
while child:
|
||||
child_jid = model.get_value(child, 1).decode('utf-8')
|
||||
child_node = model.get_value(child, 2).decode('utf-8')
|
||||
# We never requested its infos
|
||||
if child_jid + child_node not in self.items_asked:
|
||||
self.browse(child_jid, child_node)
|
||||
child = model.iter_next(child)
|
||||
|
||||
def agent_info_info(self, agent, node, identities, features):
|
||||
'''When we recieve informations about an agent, but not its items'''
|
||||
model = self.services_treeview.get_model()
|
||||
iter = model.get_iter_root()
|
||||
# We look if this agent is in the treeview
|
||||
while (iter):
|
||||
if agent == model[iter][1].decode('utf-8') and\
|
||||
node == model.get_value(iter, 2).decode('utf-8'):
|
||||
break
|
||||
if model.iter_has_child(iter):
|
||||
iter = model.iter_children(iter)
|
||||
else:
|
||||
if not model.iter_next(iter):
|
||||
iter = model.iter_parent(iter)
|
||||
if iter:
|
||||
iter = model.iter_next(iter)
|
||||
if not iter: #If it is not we stop
|
||||
return
|
||||
self.agent_infos[agent + node]['features'] = features
|
||||
if len(identities):
|
||||
self.agent_infos[agent + node]['identities'] = identities
|
||||
if identities[0].has_key('name'):
|
||||
model.set_value(iter, 0, identities[0]['name'])
|
||||
self.update_buttons()
|
||||
|
||||
def agent_info_items(self, agent, node, items, do_browse = True):
|
||||
'''When we recieve items about an agent'''
|
||||
model = self.services_treeview.get_model()
|
||||
iter = model.get_iter_root()
|
||||
# We look if this agent is in the treeview
|
||||
while (iter):
|
||||
if agent == model[iter][1].decode('utf-8') and\
|
||||
node == model.get_value(iter, 2).decode('utf-8'):
|
||||
break
|
||||
if model.iter_has_child(iter):
|
||||
iter = model.iter_children(iter)
|
||||
else:
|
||||
if not model.iter_next(iter):
|
||||
iter = model.iter_parent(iter)
|
||||
if iter:
|
||||
iter = model.iter_next(iter)
|
||||
if not iter: #If it is not, we stop
|
||||
return
|
||||
expand = False
|
||||
if len(model.get_path(iter)) == 1:
|
||||
expand = True
|
||||
for item in items:
|
||||
name = ''
|
||||
if item.has_key('name'):
|
||||
name = item['name']
|
||||
node = ''
|
||||
if item.has_key('node'):
|
||||
node = item['node']
|
||||
# We look if this item is already in the treeview
|
||||
iter_child = model.iter_children(iter)
|
||||
while iter_child:
|
||||
if item['jid'] == model.get_value(iter_child, 1).decode('utf-8') and\
|
||||
node == model.get_value(iter_child, 2).decode('utf-8'):
|
||||
break
|
||||
iter_child = model.iter_next(iter_child)
|
||||
if not iter_child: # If it is not we add it
|
||||
iter_child = model.append(iter, (name, item['jid'], node))
|
||||
self.agent_infos[item['jid'] + node] = {'identities': [item]}
|
||||
else:
|
||||
self.agent_infos[item['jid'] + node]['identities'] = [item]
|
||||
if self.iter_is_visible(iter_child) and not expand and do_browse:
|
||||
self.browse(item['jid'], node)
|
||||
if expand:
|
||||
self.services_treeview.expand_row((model.get_path(iter)), False)
|
||||
|
||||
def agent_info(self, agent, identities, features, items):
|
||||
'''When we recieve informations about an agent'''
|
||||
self.agent_info_info(agent, '', identities, features)
|
||||
self.agent_info_items(agent, '', items, False)
|
||||
|
||||
def on_refresh_button_clicked(self, widget):
|
||||
'''When refresh button is clicked: refresh list: clear and rerequest it'''
|
||||
self.services_treeview.get_model().clear()
|
||||
self.items_asked = []
|
||||
jid = self.address_comboboxentry.child.get_text().decode('utf-8')
|
||||
self.browse(jid)
|
||||
|
||||
def on_address_comboboxentry_changed(self, widget):
|
||||
'is executed on each keypress'
|
||||
if self.address_comboboxentry.get_active() != -1:
|
||||
# user selected one of the entries so do auto-visit
|
||||
self.services_treeview.get_model().clear()
|
||||
self.items_asked = []
|
||||
server_address = self.address_comboboxentry.child.get_text().decode('utf-8')
|
||||
self.browse(server_address)
|
||||
|
||||
def on_services_treeview_row_activated(self, widget, path, col = 0):
|
||||
'''When a row is activated: Register or join the selected agent'''
|
||||
#if both buttons are sensitive, it will register [default]
|
||||
if self.register_button.get_property('sensitive'):
|
||||
self.on_register_button_clicked(widget)
|
||||
elif self.join_button.get_property('sensitive'):
|
||||
self.on_join_button_clicked(widget)
|
||||
|
||||
def on_join_button_clicked(self, widget):
|
||||
'''When we want to join a conference:
|
||||
Ask specific informations about the selected agent and close the window'''
|
||||
model, iter = self.services_treeview.get_selection().get_selected()
|
||||
if not iter:
|
||||
return
|
||||
service = model[iter][1].decode('utf-8')
|
||||
room = ''
|
||||
if service.find('@') != -1:
|
||||
services = service.split('@')
|
||||
room = services[0]
|
||||
service = services[1]
|
||||
if not gajim.interface.windows[self.account].has_key('join_gc'):
|
||||
dialogs.JoinGroupchatWindow(self.account, service, room)
|
||||
else:
|
||||
gajim.interface.windows[self.account]['join_gc'].window.present()
|
||||
|
||||
def on_register_button_clicked(self, widget):
|
||||
'''When we want to register an agent:
|
||||
Ask specific informations about the selected agent and close the window'''
|
||||
model, iter = self.services_treeview.get_selection().get_selected()
|
||||
if not iter :
|
||||
return
|
||||
service = model[iter][1].decode('utf-8')
|
||||
gajim.connections[self.account].request_register_agent_info(service)
|
||||
|
||||
self.window.destroy()
|
||||
|
||||
def update_buttons(self):
|
||||
self.join_button.set_sensitive(False)
|
||||
self.register_button.set_sensitive(False)
|
||||
model, iter = self.services_treeview.get_selection().get_selected()
|
||||
if not iter:
|
||||
return
|
||||
path = model.get_path(iter)
|
||||
if len(path) == 1: # we selected the jabber server
|
||||
return
|
||||
jid = model[iter][1].decode('utf-8')
|
||||
node = model[iter][2].decode('utf-8')
|
||||
registered_transports = []
|
||||
contacts = gajim.contacts[self.account]
|
||||
for j in contacts:
|
||||
if _('Transports') in contacts[j][0].groups:
|
||||
registered_transports.append(j)
|
||||
if jid in registered_transports:
|
||||
self.register_button.set_label(_('_Edit'))
|
||||
else:
|
||||
self.register_button.set_label(_('Re_gister'))
|
||||
if self.agent_infos[jid + node].has_key('features'):
|
||||
if common.xmpp.NS_REGISTER in self.agent_infos[jid + node]['features']:
|
||||
self.register_button.set_sensitive(True)
|
||||
if self.agent_infos[jid + node].has_key('identities') and \
|
||||
len(self.agent_infos[jid + node]['identities']):
|
||||
if self.agent_infos[jid + node]['identities'][0].has_key('category'):
|
||||
if self.agent_infos[jid + node]['identities'][0]['category'] == \
|
||||
'conference':
|
||||
self.join_button.set_sensitive(True)
|
||||
|
||||
def on_services_treeview_cursor_changed(self, widget):
|
||||
'''When we select a row :
|
||||
activate buttons if needed'''
|
||||
self.update_buttons()
|
||||
model, iter = self.services_treeview.get_selection().get_selected()
|
||||
if not iter:
|
||||
return
|
||||
path = model.get_path(iter)
|
||||
if len(path) == 1: # we selected the jabber server
|
||||
return
|
||||
jid = model[iter][1].decode('utf-8')
|
||||
node = model[iter][2].decode('utf-8')
|
||||
if jid+node not in self.items_asked:
|
||||
self.browse(jid, node)
|
||||
if not self.agent_infos[jid + node].has_key('features'):
|
||||
gajim.connections[self.account].discoverInfo(jid, node)
|
||||
|
||||
def on_go_button_clicked(self, widget):
|
||||
server_address = self.address_comboboxentry.child.get_text().decode('utf-8')
|
||||
if server_address in self.latest_addresses:
|
||||
self.latest_addresses.remove(server_address)
|
||||
self.latest_addresses.insert(0, server_address)
|
||||
if len(self.latest_addresses) > 10:
|
||||
self.latest_addresses = self.latest_addresses[0:10]
|
||||
self.address_comboboxentry.get_model().clear()
|
||||
for j in self.latest_addresses:
|
||||
self.address_comboboxentry.append_text(j)
|
||||
gajim.config.set('latest_disco_addresses',
|
||||
' '.join(self.latest_addresses))
|
||||
self.services_treeview.get_model().clear()
|
||||
self.items_asked = []
|
||||
self.browse(server_address)
|
||||
gajim.interface.save_config()
|
||||
|
||||
class GroupchatConfigWindow(DataFormWindow):
|
||||
'''GroupchatConfigWindow class'''
|
||||
def __init__(self, account, room_jid, config):
|
||||
|
@ -2997,8 +2688,8 @@ _('You need to enter a valid server address to continue.')).get_response()
|
|||
if config['savepass']:
|
||||
gajim.connections[name].password = config['password']
|
||||
# update variables
|
||||
gajim.interface.windows[name] = {'infos': {}, 'chats': {}, 'gc': {},
|
||||
'gc_config': {}}
|
||||
gajim.interface.windows[name] = {'infos': {}, 'disco': {}, 'chats': {},
|
||||
'gc': {}, 'gc_config': {}}
|
||||
gajim.interface.windows[name]['xml_console'] = \
|
||||
dialogs.XMLConsoleWindow(name)
|
||||
gajim.awaiting_events[name] = {}
|
||||
|
|
47
src/gajim.py
|
@ -148,6 +148,7 @@ import roster_window
|
|||
import systray
|
||||
import dialogs
|
||||
import config
|
||||
import disco
|
||||
|
||||
GTKGUI_GLADE = 'gtkgui.glade'
|
||||
|
||||
|
@ -230,7 +231,6 @@ class Interface:
|
|||
def allow_notif(self, account):
|
||||
gajim.allow_notifications[account] = True
|
||||
|
||||
|
||||
def handle_event_status(self, account, status): # OUR status
|
||||
#('STATUS', account, status)
|
||||
model = self.roster.status_combobox.get_model()
|
||||
|
@ -566,11 +566,19 @@ class Interface:
|
|||
if self.remote and self.remote.is_enabled():
|
||||
self.remote.raise_signal('Unsubscribed', (account, jid))
|
||||
|
||||
def handle_event_agent_info(self, account, array):
|
||||
#('AGENT_INFO', account, (agent, identities, features, items))
|
||||
if self.windows[account].has_key('disco'):
|
||||
self.windows[account]['disco'].agent_info(array[0], array[1], \
|
||||
array[2], array[3])
|
||||
def handle_event_agent_info_error(self, account, agent):
|
||||
#('AGENT_ERROR_INFO', account, (agent))
|
||||
try:
|
||||
gajim.connections[account].services_cache.agent_info_error(agent)
|
||||
except AttributeError:
|
||||
return
|
||||
|
||||
def handle_event_agent_items_error(self, account, agent):
|
||||
#('AGENT_ERROR_INFO', account, (agent))
|
||||
try:
|
||||
gajim.connections[account].services_cache.agent_items_error(agent)
|
||||
except AttributeError:
|
||||
return
|
||||
|
||||
def handle_event_register_agent_info(self, account, array):
|
||||
#('REGISTER_AGENT_INFO', account, (agent, infos, is_form))
|
||||
|
@ -583,15 +591,19 @@ class Interface:
|
|||
|
||||
def handle_event_agent_info_items(self, account, array):
|
||||
#('AGENT_INFO_ITEMS', account, (agent, node, items))
|
||||
if self.windows[account].has_key('disco'):
|
||||
self.windows[account]['disco'].agent_info_items(array[0], array[1],
|
||||
array[2])
|
||||
try:
|
||||
gajim.connections[account].services_cache.agent_items(array[0],
|
||||
array[1], array[2])
|
||||
except AttributeError:
|
||||
return
|
||||
|
||||
def handle_event_agent_info_info(self, account, array):
|
||||
#('AGENT_INFO_INFO', account, (agent, node, identities, features))
|
||||
if self.windows[account].has_key('disco'):
|
||||
self.windows[account]['disco'].agent_info_info(array[0], array[1], \
|
||||
array[2], array[3])
|
||||
#('AGENT_INFO_INFO', account, (agent, node, identities, features, data))
|
||||
try:
|
||||
gajim.connections[account].services_cache.agent_info(array[0],
|
||||
array[1], array[2], array[3], array[4])
|
||||
except AttributeError:
|
||||
return
|
||||
|
||||
def handle_event_acc_ok(self, account, array):
|
||||
#('ACC_OK', account, (name, config))
|
||||
|
@ -603,7 +615,8 @@ class Interface:
|
|||
gajim.config.set_per('accounts', name, opt, array[1][opt])
|
||||
if self.windows.has_key('account_modification'):
|
||||
self.windows['account_modification'].account_is_ok(array[0])
|
||||
self.windows[name] = {'infos': {}, 'chats': {}, 'gc': {}, 'gc_config': {}}
|
||||
self.windows[name] = {'infos': {}, 'disco': {}, 'chats': {},
|
||||
'gc': {}, 'gc_config': {}}
|
||||
self.windows[name]['xml_console'] = dialogs.XMLConsoleWindow(name)
|
||||
gajim.awaiting_events[name] = {}
|
||||
# disconnect from server - our status in roster is offline
|
||||
|
@ -1119,7 +1132,8 @@ class Interface:
|
|||
'SUBSCRIBED': self.handle_event_subscribed,
|
||||
'UNSUBSCRIBED': self.handle_event_unsubscribed,
|
||||
'SUBSCRIBE': self.handle_event_subscribe,
|
||||
'AGENT_INFO': self.handle_event_agent_info,
|
||||
'AGENT_ERROR_INFO': self.handle_event_agent_info_error,
|
||||
'AGENT_ERROR_ITEMS': self.handle_event_agent_items_error,
|
||||
'REGISTER_AGENT_INFO': self.handle_event_register_agent_info,
|
||||
'AGENT_INFO_ITEMS': self.handle_event_agent_info_items,
|
||||
'AGENT_INFO_INFO': self.handle_event_agent_info_info,
|
||||
|
@ -1275,7 +1289,8 @@ class Interface:
|
|||
self.avatar_pixbufs = {}
|
||||
|
||||
for a in gajim.connections:
|
||||
self.windows[a] = {'infos': {}, 'chats': {}, 'gc': {}, 'gc_config': {}}
|
||||
self.windows[a] = {'infos': {}, 'disco': {}, 'chats': {},
|
||||
'gc': {}, 'gc_config': {}}
|
||||
gajim.contacts[a] = {}
|
||||
gajim.groups[a] = {}
|
||||
gajim.gc_contacts[a] = {}
|
||||
|
|
289
src/gtkgui.glade
|
@ -2661,13 +2661,11 @@
|
|||
</widget>
|
||||
|
||||
<widget class="GtkWindow" id="service_discovery_window">
|
||||
<property name="border_width">12</property>
|
||||
<property name="border_width">13</property>
|
||||
<property name="title" translatable="yes"></property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="default_width">500</property>
|
||||
<property name="default_height">300</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
|
@ -2685,7 +2683,54 @@
|
|||
<property name="spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2942">
|
||||
<widget class="GtkEventBox" id="banner_agent_eventbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="visible_window">True</property>
|
||||
<property name="above_child">False</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="banner_agent_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="banner_agent_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label"><span weight="heavy" size="large">Agent name</span>
|
||||
Agent JID - node</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.0500000007451</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">6</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="address_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
@ -2718,6 +2763,7 @@
|
|||
|
||||
<child>
|
||||
<widget class="GtkComboBoxEntry" id="address_comboboxentry">
|
||||
<property name="width_request">250</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="add_tearoffs">False</property>
|
||||
<property name="has_frame">True</property>
|
||||
|
@ -2733,81 +2779,17 @@
|
|||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="go_button">
|
||||
<widget class="GtkButton" id="browse_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Go</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_go_button_clicked" last_modification_time="Sun, 27 Mar 2005 08:47:16 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow9">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="services_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">True</property>
|
||||
<property name="rules_hint">False</property>
|
||||
<property name="reorderable">False</property>
|
||||
<property name="enable_search">True</property>
|
||||
<property name="fixed_height_mode">False</property>
|
||||
<property name="hover_selection">False</property>
|
||||
<property name="hover_expand">False</property>
|
||||
<signal name="row_activated" handler="on_services_treeview_row_activated" last_modification_time="Mon, 28 Mar 2005 00:28:25 GMT"/>
|
||||
<signal name="cursor_changed" handler="on_services_treeview_cursor_changed" last_modification_time="Mon, 28 Mar 2005 00:28:33 GMT"/>
|
||||
<signal name="row_expanded" handler="on_services_treeview_row_expanded" last_modification_time="Mon, 28 Mar 2005 00:28:39 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox4">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="refresh_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_refresh_button_clicked" last_modification_time="Tue, 01 Mar 2005 14:17:42 GMT"/>
|
||||
<signal name="clicked" handler="on_go_button_clicked" last_modification_time="Sun, 04 Sep 2005 20:37:26 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment16">
|
||||
<widget class="GtkAlignment" id="alignment93">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
|
@ -2819,15 +2801,15 @@
|
|||
<property name="right_padding">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox20">
|
||||
<widget class="GtkHBox" id="hbox2995">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">2</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImage" id="image105">
|
||||
<widget class="GtkImage" id="image1148">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-refresh</property>
|
||||
<property name="stock">gtk-jump-to</property>
|
||||
<property name="icon_size">4</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
|
@ -2842,10 +2824,9 @@
|
|||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label29">
|
||||
<widget class="GtkLabel" id="label362">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">_Refresh</property>
|
||||
<property name="label" translatable="yes">G_o</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
|
@ -2871,44 +2852,158 @@
|
|||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="services_scrollwin">
|
||||
<property name="height_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="register_button">
|
||||
<widget class="GtkTreeView" id="services_treeview">
|
||||
<property name="height_request">150</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Re_gister</property>
|
||||
<property name="headers_visible">False</property>
|
||||
<property name="rules_hint">False</property>
|
||||
<property name="reorderable">False</property>
|
||||
<property name="enable_search">True</property>
|
||||
<property name="fixed_height_mode">False</property>
|
||||
<property name="hover_selection">False</property>
|
||||
<property name="hover_expand">False</property>
|
||||
<signal name="row_activated" handler="on_services_treeview_row_activated" last_modification_time="Mon, 28 Mar 2005 00:28:25 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="filter_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label361">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Filter:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_register_button_clicked" last_modification_time="Sat, 26 Mar 2005 15:07:31 GMT"/>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">filter_entry</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="join_button">
|
||||
<widget class="GtkEntry" id="filter_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">_Join</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_join_button_clicked" last_modification_time="Sat, 26 Mar 2005 15:08:01 GMT"/>
|
||||
<property name="editable">True</property>
|
||||
<property name="visibility">True</property>
|
||||
<property name="max_length">0</property>
|
||||
<property name="text" translatable="yes"></property>
|
||||
<property name="has_frame">True</property>
|
||||
<property name="invisible_char">*</property>
|
||||
<property name="activates_default">False</property>
|
||||
<signal name="changed" handler="on_filter_entry_changed" last_modification_time="Sun, 04 Sep 2005 11:35:21 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2994">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkProgressBar" id="services_progressbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
|
||||
<property name="fraction">0</property>
|
||||
<property name="pulse_step">0.10000000149</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<widget class="GtkHButtonBox" id="action_buttonbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="label">gtk-close</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_close_button_clicked" last_modification_time="Sat, 26 Mar 2005 15:05:59 GMT"/>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="label">gtk-close</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_close_button_clicked" last_modification_time="Sat, 26 Mar 2005 15:05:59 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
|
|
|
@ -31,6 +31,7 @@ import groupchat_window
|
|||
import history_window
|
||||
import dialogs
|
||||
import config
|
||||
import disco
|
||||
import gtkgui_helpers
|
||||
import cell_renderer_image
|
||||
import tooltips
|
||||
|
@ -1971,13 +1972,13 @@ _('If "%s" accepts this request you will know his status.') %jid)
|
|||
model.set_value(iter, 5, False)
|
||||
|
||||
def on_service_disco_menuitem_activate(self, widget, account):
|
||||
if gajim.interface.windows[account].has_key('disco'):
|
||||
gajim.interface.windows[account]['disco'].window.present()
|
||||
server_jid = gajim.config.get_per('accounts', account, 'hostname')
|
||||
if gajim.interface.windows[account]['disco'].has_key(server_jid):
|
||||
gajim.interface.windows[account]['disco'][server_jid].window.present()
|
||||
else:
|
||||
# c http://nkour.blogspot.com/2005/05/pythons-init-return-none-doesnt-return.html
|
||||
try:
|
||||
gajim.interface.windows[account]['disco'] = \
|
||||
config.ServiceDiscoveryWindow(account)
|
||||
# Object will add itself to the window dict
|
||||
disco.ServiceDiscoveryWindow(account, address_entry=True)
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
|
@ -2044,6 +2045,8 @@ _('If "%s" accepts this request you will know his status.') %jid)
|
|||
gajim.interface.windows[account]['chats'][jid].repaint_colored_widgets()
|
||||
for jid in gajim.interface.windows[account]['gc']:
|
||||
gajim.interface.windows[account]['gc'][jid].repaint_colored_widgets()
|
||||
for addr in gajim.interface.windows[account]['disco']:
|
||||
gajim.interface.windows[account]['disco'][addr].paint_banner()
|
||||
|
||||
def on_show_offline_contacts_menuitem_activate(self, widget):
|
||||
'''when show offline option is changed:
|
||||
|
|