Make Service Registration a Gtk.Assistant

- Move all xmpp Register methods into the register module
This commit is contained in:
Philipp Hörist 2018-08-04 19:47:25 +02:00
parent 99ec800856
commit 043e764896
13 changed files with 287 additions and 230 deletions

View File

@ -792,11 +792,6 @@ class Connection(CommonConnection, ConnectionHandlers):
None, dialog_name='invalid-answer',
kwargs={'name': data[0], 'error': data[3]}))
return
is_form = data[2]
conf = data[1]
app.nec.push_incoming_event(RegisterAgentInfoReceivedEvent(
None, conn=self, agent=data[0], config=conf,
is_form=is_form))
def _select_next_host(self, hosts):
"""

View File

@ -54,61 +54,6 @@ log = logging.getLogger('gajim.c.connection_handlers')
# kind of events we can wait for an answer
AGENT_REMOVED = 'agent_removed'
class ConnectionDisco:
def request_register_agent_info(self, agent):
if not self.connection or self.connected < 2:
return None
iq = nbxmpp.Iq('get', nbxmpp.NS_REGISTER, to=agent)
id_ = self.connection.getAnID()
iq.setID(id_)
# Wait the answer during 30 secondes
self.awaiting_timeouts[app.idlequeue.current_time() + 30] = (id_,
_('Registration information for transport %s has not arrived in '
'time') % agent)
self.connection.SendAndCallForResponse(iq, self._ReceivedRegInfo,
{'agent': agent})
def _agent_registered_cb(self, con, resp, agent):
if resp.getType() == 'result':
app.nec.push_incoming_event(InformationEvent(
None, dialog_name='agent-register-success', args=agent))
self.get_module('Presence').subscribe(agent, auto_auth=True)
self.agent_registrations[agent]['roster_push'] = True
if self.agent_registrations[agent]['sub_received']:
p = nbxmpp.Presence(agent, 'subscribed')
p = self.add_sha(p)
self.connection.send(p)
if resp.getType() == 'error':
app.nec.push_incoming_event(InformationEvent(
None, dialog_name='agent-register-error',
kwargs={'agent': agent,
'error': resp.getError(),
'error_msg': resp.getErrorMsg()}))
def register_agent(self, agent, info, is_form=False):
if not self.connection or self.connected < 2:
return
if is_form:
iq = nbxmpp.Iq('set', nbxmpp.NS_REGISTER, to=agent)
query = iq.setQuery()
info.setAttr('type', 'submit')
query.addChild(node=info)
self.connection.SendAndCallForResponse(iq,
self._agent_registered_cb, {'agent': agent})
else:
# fixed: blocking
nbxmpp.features_nb.register(self.connection, agent, info,
self._agent_registered_cb, {'agent': agent})
self.agent_registrations[agent] = {'roster_push': False,
'sub_received': False}
def _ReceivedRegInfo(self, con, resp, agent):
nbxmpp.features_nb._ReceivedRegInfo(con, resp, agent)
self._IqCB(con, resp)
# basic connection handlers used here and in zeroconf
class ConnectionHandlersBase:
def __init__(self):
@ -443,7 +388,7 @@ class ConnectionHandlersBase:
return sess
class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
class ConnectionHandlers(ConnectionSocks5Bytestream,
ConnectionHandlersBase,
ConnectionJingle, ConnectionIBBytestream):
def __init__(self):

View File

@ -868,10 +868,6 @@ class SignedInEvent(nec.NetworkIncomingEvent):
name = 'signed-in'
base_network_events = []
class RegisterAgentInfoReceivedEvent(nec.NetworkIncomingEvent):
name = 'register-agent-info-received'
base_network_events = []
class FileRequestReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
name = 'file-request-received'
base_network_events = []

View File

@ -31,6 +31,8 @@ class Register:
self.handlers = []
self.agent_registrations = {}
def change_password(self, password, success_cb, error_cb):
if not app.account_is_connected(self._account):
return
@ -52,11 +54,87 @@ class Register:
if not nbxmpp.isResultNode(stanza):
error = stanza.getErrorMsg()
log.info('Error: %s', error)
error_cb()(error)
if error_cb() is not None:
error_cb()(error)
else:
log.info('Password changed')
if success_cb() is not None:
success_cb()()
def register_agent(self, agent, form, is_form, success_cb, error_cb):
if not app.account_is_connected(self._account):
return
weak_success_cb = weakref.WeakMethod(success_cb)
weak_error_cb = weakref.WeakMethod(error_cb)
iq = nbxmpp.Iq('set', nbxmpp.NS_REGISTER, to=agent)
if is_form:
query = iq.setQuery()
form.setAttr('type', 'submit')
query.addChild(node=form)
else:
for field in form.keys():
iq.setTag('query').setTagData(field, form[field])
self._con.connection.SendAndCallForResponse(
iq, self._register_agent_response, {'agent': agent,
'success_cb': weak_success_cb,
'error_cb': weak_error_cb})
self.agent_registrations[agent] = {'roster_push': False,
'sub_received': False}
def _register_agent_response(self, con, stanza, agent,
success_cb, error_cb):
if not nbxmpp.isResultNode(stanza):
error = stanza.getErrorMsg()
log.info('Error: %s', error)
if error_cb() is not None:
error_cb()(error)
return
self._con.get_module('Presence').subscribe(agent, auto_auth=True)
self.agent_registrations[agent]['roster_push'] = True
if self.agent_registrations[agent]['sub_received']:
self._con.get_module('Presence').subscribed(agent)
if success_cb() is not None:
success_cb()()
def get_register_form(self, jid, success_cb, error_cb):
if not app.account_is_connected(self._account):
return
weak_success_cb = weakref.WeakMethod(success_cb)
weak_error_cb = weakref.WeakMethod(error_cb)
iq = nbxmpp.Iq('get', nbxmpp.NS_REGISTER, to=jid)
self._con.connection.SendAndCallForResponse(
iq, self._register_info_response, {'success_cb': weak_success_cb,
'error_cb': weak_error_cb})
def _register_info_response(self, con, stanza, success_cb, error_cb):
if not nbxmpp.isResultNode(stanza):
error = stanza.getErrorMsg()
log.info('Error: %s', error)
if error_cb() is not None:
error_cb()(error)
else:
log.info('Register form received')
form = stanza.getQuery().getTag('x', namespace=nbxmpp.NS_DATA)
is_form = form is not None
if not is_form:
form = {}
for field in stanza.getQueryPayload():
if not isinstance(field, nbxmpp.Node):
continue
form[field.getName()] = field.getData()
if success_cb() is not None:
success_cb()(form, is_form)
def get_instance(*args, **kwargs):
return Register(*args, **kwargs), 'Register'

View File

@ -1486,57 +1486,6 @@ class FakeDataForm(Gtk.Table, object):
self.infos[name] = self.entries[name].get_text()
return self.infos
class ServiceRegistrationWindow:
"""
Class for Service registration window. Window that appears when we want to
subscribe to a service if is_form we use dataforms_widget else we use
service_registarion_window
"""
def __init__(self, service, infos, account, is_form):
self.service = service
self.account = account
self.is_form = is_form
self.xml = gtkgui_helpers.get_gtk_builder('service_registration_window.ui')
self.window = self.xml.get_object('service_registration_window')
self.window.set_transient_for(app.interface.roster.window)
if self.is_form:
dataform = dataforms.ExtendForm(node = infos)
self.data_form_widget = dataforms_widget.DataFormWidget(dataform)
if self.data_form_widget.title:
self.window.set_title('%s - Gajim' % self.data_form_widget.title)
grid = self.xml.get_object('grid')
grid.attach(self.data_form_widget, 0, 0, 2, 1)
else:
if 'registered' in infos:
self.window.set_title(_('Edit %s') % service)
else:
self.window.set_title(_('Register to %s') % service)
self.data_form_widget = FakeDataForm(infos)
grid = self.xml.get_object('grid')
grid.attach(self.data_form_widget, 0, 0, 2, 1)
self.xml.connect_signals(self)
self.window.show_all()
def on_cancel_button_clicked(self, widget):
self.window.destroy()
def on_ok_button_clicked(self, widget):
# send registration info to the core
if self.is_form:
form = self.data_form_widget.data_form
app.connections[self.account].register_agent(self.service,
form, True) # True is for is_form
else:
infos = self.data_form_widget.get_infos()
if 'instructions' in infos:
del infos['instructions']
if 'registered' in infos:
del infos['registered']
app.connections[self.account].register_agent(self.service, infos)
self.window.destroy()
class GroupchatConfigWindow:
def __init__(self, account, room_jid, form=None):

View File

@ -1,96 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-apply</property>
</object>
<object class="GtkImage" id="image2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-cancel</property>
</object>
<object class="GtkWindow" id="service_registration_window">
<property name="can_focus">False</property>
<property name="border_width">6</property>
<property name="title" translatable="yes">Register to</property>
<property name="type_hint">dialog</property>
<child>
<object class="GtkBox" id="vbox12">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkGrid" id="grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="hbuttonbox5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">12</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="cancel_button">
<property name="label" translatable="yes">_Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="image">image2</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="on_cancel_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ok_button">
<property name="label" translatable="yes">_OK</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="receives_default">False</property>
<property name="image">image1</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="on_ok_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -59,6 +59,7 @@ from gajim import groups
from gajim import adhoc_commands
from gajim import search_window
from gajim import gui_menu_builder
from gajim.gtk import ServiceRegistration
from gajim.common import app
import nbxmpp
@ -1355,8 +1356,8 @@ class ToplevelAgentBrowser(AgentBrowser):
return
jid = model[iter_][0]
if jid:
app.connections[self.account].request_register_agent_info(jid)
self.window.destroy(chain = True)
ServiceRegistration(self.account, jid)
self.window.destroy(chain=True)
def on_join_button_clicked(self, widget):
"""

View File

@ -66,3 +66,4 @@ from gajim.gtk.bookmarks import ManageBookmarksWindow
from gajim.gtk.profile import ProfileWindow
from gajim.gtk.features import FeaturesDialog
from gajim.gtk.account_wizard import AccountCreationWizard
from gajim.gtk.service_registration import ServiceRegistration

View File

@ -209,7 +209,8 @@ class AddNewContactWindow(Gtk.ApplicationWindow):
model = self.protocol_jid_combobox.get_model()
row = self.protocol_jid_combobox.get_active()
jid = model[row][0]
app.connections[self.account].request_register_agent_info(jid)
from gajim.gtk import ServiceRegistration
ServiceRegistration(self.account, jid)
def _on_key_press(self, widget, event):
if event.keyval == Gdk.KEY_Escape:

View File

@ -13,10 +13,10 @@
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
from gi.repository import Gtk
from gi.repository import Gdk
from gajim.common import app
from gajim.common import helpers
from gajim.common.modules import dataforms
from gajim.gtk.util import get_builder
from gajim.gtk.util import load_icon

View File

@ -0,0 +1,198 @@
# This file is part of Gajim.
#
# Gajim is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; version 3 only.
#
# Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
import logging
from enum import IntEnum
from gi.repository import Gtk
from gajim.common import app
from gajim.common.modules import dataforms
log = logging.getLogger('gajim.gtk.registration')
class Page(IntEnum):
REQUEST = 0
FORM = 1
SENDING = 2
SUCCESS = 3
ERROR = 4
class ServiceRegistration(Gtk.Assistant):
def __init__(self, account, agent):
Gtk.Assistant.__init__(self)
self._con = app.connections[account]
self._agent = agent
self._account = account
self._data_form_widget = None
self._is_form = None
self.set_application(app.app)
self.set_resizable(True)
self.set_position(Gtk.WindowPosition.CENTER)
self.set_default_size(500, 300)
self.get_style_context().add_class('dialog-margin')
request = RequestPage()
self.append_page(request)
self.set_page_type(request, Gtk.AssistantPageType.INTRO)
form = FormPage()
self.append_page(form)
self.set_page_type(form, Gtk.AssistantPageType.INTRO)
self.set_page_complete(form, True)
sending = SendingPage()
self.append_page(sending)
self.set_page_type(sending, Gtk.AssistantPageType.PROGRESS)
success = SuccessfulPage()
self.append_page(success)
self.set_page_type(success, Gtk.AssistantPageType.SUMMARY)
self.set_page_complete(success, True)
error = ErrorPage()
self.append_page(error)
self.set_page_type(error, Gtk.AssistantPageType.SUMMARY)
self.set_page_complete(error, True)
self.connect('prepare', self._on_page_change)
self.connect('cancel', self._on_cancel)
self.connect('close', self._on_cancel)
self.show_all()
def _on_page_change(self, assistant, page):
if self.get_current_page() == Page.REQUEST:
self._con.get_module('Register').get_register_form(
self._agent, self._on_get_success, self._on_error)
elif self.get_current_page() == Page.SENDING:
self._register()
self.commit()
pass
def _on_get_success(self, form, is_form):
log.info('Show Form page')
self._is_form = is_form
if is_form:
from gajim import dataforms_widget
dataform = dataforms.ExtendForm(node=form)
self._data_form_widget = dataforms_widget.DataFormWidget(dataform)
if self._data_form_widget.title:
self.set_title('%s - Gajim' % self._data_form_widget.title)
else:
if 'registered' in form:
self.set_title(_('Edit %s') % self._agent)
else:
self.set_title(_('Register to %s') % self._agent)
from gajim import config
self._data_form_widget = config.FakeDataForm(form)
page = self.get_nth_page(Page.FORM)
page.pack_start(self._data_form_widget, True, True, 0)
self._data_form_widget.show()
self.set_current_page(Page.FORM)
def _on_error(self, error_text):
log.info('Show Error page')
page = self.get_nth_page(Page.ERROR)
page.set_text(error_text)
self.set_current_page(Page.ERROR)
def _on_cancel(self, widget):
self.destroy()
def _register(self):
log.info('Show Sending page')
if self._is_form:
form = self._data_form_widget.data_form
else:
form = self._data_form_widget.get_infos()
if 'instructions' in form:
del form['instructions']
if 'registered' in form:
del form['registered']
self._con.get_module('Register').register_agent(
self._agent,
form,
self._is_form,
self._on_register_success,
self._on_error)
def _on_register_success(self):
log.info('Show Success page')
self.set_current_page(Page.SUCCESS)
class RequestPage(Gtk.Box):
def __init__(self):
super().__init__(orientation=Gtk.Orientation.VERTICAL)
self.set_spacing(18)
spinner = Gtk.Spinner()
self.pack_start(spinner, True, True, 0)
spinner.start()
class SendingPage(RequestPage):
def __init__(self):
super().__init__()
class FormPage(Gtk.Box):
def __init__(self):
super().__init__(orientation=Gtk.Orientation.VERTICAL)
class SuccessfulPage(Gtk.Box):
def __init__(self):
super().__init__(orientation=Gtk.Orientation.VERTICAL)
self.set_spacing(12)
self.set_homogeneous(True)
icon = Gtk.Image.new_from_icon_name('object-select-symbolic',
Gtk.IconSize.DIALOG)
icon.get_style_context().add_class('success-color')
icon.set_valign(Gtk.Align.END)
label = Gtk.Label(label=_('Registration successful'))
label.get_style_context().add_class('bold16')
label.set_valign(Gtk.Align.START)
self.add(icon)
self.add(label)
class ErrorPage(Gtk.Box):
def __init__(self):
super().__init__(orientation=Gtk.Orientation.VERTICAL)
self.set_spacing(12)
self.set_homogeneous(True)
icon = Gtk.Image.new_from_icon_name('dialog-error-symbolic',
Gtk.IconSize.DIALOG)
icon.get_style_context().add_class('error-color')
icon.set_valign(Gtk.Align.END)
self._label = Gtk.Label()
self._label.get_style_context().add_class('bold16')
self._label.set_valign(Gtk.Align.START)
self.add(icon)
self.add(self._label)
def set_text(self, text):
self._label.set_text(text)

View File

@ -580,17 +580,6 @@ class Interface:
'unsubscribed', 'gajim-unsubscribed',
event_type, obj.jid)
@staticmethod
def handle_event_register_agent_info(obj):
# ('REGISTER_AGENT_INFO', account, (agent, infos, is_form))
# info in a dataform if is_form is True
if obj.is_form or 'instructions' in obj.config:
config.ServiceRegistrationWindow(obj.agent, obj.config,
obj.conn.name, obj.is_form)
else:
ErrorDialog(_('Contact with "%s" cannot be established') % \
obj.agent, _('Check your connection or try again later.'))
def handle_event_gc_config(self, obj):
#('GC_CONFIG', account, (jid, form_node)) config is a dict
account = obj.conn.name
@ -1565,7 +1554,6 @@ class Interface:
'password-required': [self.handle_event_password_required],
'plain-connection': [self.handle_event_plain_connection],
'presence-received': [self.handle_event_presence],
'register-agent-info-received': [self.handle_event_register_agent_info],
'roster-info': [self.handle_event_roster_info],
'roster-item-exchange-received': \
[self.handle_event_roster_item_exchange],

View File

@ -71,6 +71,7 @@ from gajim.gtk import AddNewContactWindow
from gajim.gtk import ManagePEPServicesWindow
from gajim.gtk import ManageBookmarksWindow
from gajim.gtk import AccountCreationWizard
from gajim.gtk import ServiceRegistration
from gajim.common.const import AvatarSize
@ -2790,7 +2791,7 @@ class RosterWindow:
"""
When we want to modify the agent registration
"""
app.connections[account].request_register_agent_info(contact.jid)
ServiceRegistration(account, contact.jid)
def on_remove_agent(self, widget, list_):
"""