In-Band Registration
This commit is contained in:
parent
ee5c838a6b
commit
4be8c92a2c
|
@ -40,6 +40,7 @@ SOURCES
|
|||
src/service/muc_manager.vala
|
||||
src/service/notification_events.vala
|
||||
src/service/presence_manager.vala
|
||||
src/service/registration.vala
|
||||
src/service/roster_manager.vala
|
||||
src/service/stream_interactor.vala
|
||||
src/service/util.vala
|
||||
|
|
|
@ -76,6 +76,7 @@ public class ModuleManager {
|
|||
module_map[account].add(new Xep.Ping.Module());
|
||||
module_map[account].add(new Xep.DelayedDelivery.Module());
|
||||
module_map[account].add(new StreamError.Module());
|
||||
module_map[account].add(new Xep.InBandRegistration.Module());
|
||||
initialize_account_modules(account, module_map[account]);
|
||||
}
|
||||
}
|
||||
|
|
42
libdino/src/service/registration.vala
Normal file
42
libdino/src/service/registration.vala
Normal file
|
@ -0,0 +1,42 @@
|
|||
using Gee;
|
||||
|
||||
using Xmpp;
|
||||
using Dino.Entities;
|
||||
|
||||
namespace Dino {
|
||||
|
||||
public class Register {
|
||||
|
||||
public static async Xep.InBandRegistration.Form get_registration_form(Jid jid) {
|
||||
XmppStream stream = new XmppStream();
|
||||
stream.add_module(new Tls.Module());
|
||||
stream.add_module(new Iq.Module());
|
||||
stream.add_module(new Xep.InBandRegistration.Module());
|
||||
stream.connect.begin(jid.bare_jid.to_string());
|
||||
|
||||
Xep.InBandRegistration.Form? form = null;
|
||||
SourceFunc callback = get_registration_form.callback;
|
||||
stream.stream_negotiated.connect(() => {
|
||||
if (callback != null) {
|
||||
Idle.add((owned)callback);
|
||||
}
|
||||
});
|
||||
Timeout.add_seconds(5, () => {
|
||||
if (callback != null) {
|
||||
Idle.add((owned)callback);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
yield;
|
||||
if (stream.negotiation_complete) {
|
||||
form = yield stream.get_module(Xep.InBandRegistration.Module.IDENTITY).get_from_server(stream, jid);
|
||||
}
|
||||
return form;
|
||||
}
|
||||
|
||||
public static async string submit_form(Jid jid, Xep.InBandRegistration.Form form) {
|
||||
return yield form.stream.get_module(Xep.InBandRegistration.Module.IDENTITY).submit_to_server(form.stream, jid, form);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -124,6 +124,7 @@ SOURCES
|
|||
src/ui/settings_dialog.vala
|
||||
src/ui/unified_window.vala
|
||||
src/ui/util/accounts_combo_box.vala
|
||||
src/ui/util/data_forms.vala
|
||||
src/ui/util/helper.vala
|
||||
src/ui/util/label_hybrid.vala
|
||||
src/ui/util/preview_file_chooser_native.vala
|
||||
|
|
|
@ -1,14 +1,112 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="DinoUiManageAccountsAddAccountDialog">
|
||||
<property name="default_width">300</property>
|
||||
<property name="default_width">400</property>
|
||||
<property name="modal">True</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="cancel_button">
|
||||
<property name="label" translatable="yes">Cancel</property>
|
||||
<object class="GtkOverlay">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="expand">True</property>
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="transition_type">slide-left</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="sign_in_box">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="margin">20</property>
|
||||
<property name="margin-start">50</property>
|
||||
<property name="margin-end">50</property>
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Sign in</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="visible">True</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="1.3"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="info_grid">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">JID</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="visible">True</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="0.9"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="jid_entry">
|
||||
<property name="activates_default">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="width_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Password</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="margin-top">7</property>
|
||||
<property name="visible">True</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="0.9"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="password_entry">
|
||||
<property name="activates_default">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="input_purpose">password</property>
|
||||
<property name="width_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="visibility">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Local alias</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="margin-top">7</property>
|
||||
<property name="visible">True</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="0.9"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="alias_entry">
|
||||
<property name="activates_default">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="width_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="margin-top">20</property>
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="serverlist_button">
|
||||
<property name="label" translatable="yes">Create account</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
|
@ -16,7 +114,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="ok_button">
|
||||
<object class="GtkButton" id="sign_in_continue">
|
||||
<property name="can_default">True</property>
|
||||
<property name="label" translatable="yes">Save</property>
|
||||
<property name="sensitive">False</property>
|
||||
|
@ -31,106 +129,262 @@
|
|||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">login</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="info_grid">
|
||||
<object class="GtkBox" id="create_account_box">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="margin">20</property>
|
||||
<property name="column-spacing">10</property>
|
||||
<property name="row-spacing">7</property>
|
||||
<property name="margin-start">50</property>
|
||||
<property name="margin-end">50</property>
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">JID</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="label" translatable="yes">Create Account</property>
|
||||
<property name="margin-bottom">20</property>
|
||||
<property name="visible">True</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="1.3"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="jid_entry">
|
||||
<property name="activates_default">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="width_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Password</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Choose a public server</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="PANGO_WEIGHT_BOLD"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="password_entry">
|
||||
<property name="activates_default">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="input_purpose">password</property>
|
||||
<property name="width_request">200</property>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="max_content_height">300</property>
|
||||
<property name="propagate_natural_height">True</property>
|
||||
<property name="hscrollbar_policy">never</property>
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="server_list_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="visibility">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Local alias</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="margin-top">20</property>
|
||||
<property name="label" translatable="yes">Or specify a server address</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="PANGO_WEIGHT_BOLD"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="server_entry">
|
||||
<property name="activates_default">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="margin-top">30</property>
|
||||
<property name="orientation">horizontal</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="login_button">
|
||||
<property name="label" translatable="yes">Sign in instead</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
<property name="pack_type">start</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="alias_entry">
|
||||
<property name="activates_default">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="width_request">200</property>
|
||||
<object class="GtkButton" id="select_server_continue">
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="visible">True</property>
|
||||
<style>
|
||||
<class name="text-button"/>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkStack" id="select_server_continue_stack">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Next</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
<property name="name">label</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinner">
|
||||
<property name="active">True</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">spinner</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">server</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="register_box">
|
||||
<property name="margin">20</property>
|
||||
<property name="margin-start">50</property>
|
||||
<property name="margin-end">50</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="register_title">
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="visible">True</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="1.3"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="form_box">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="margin-top">30</property>
|
||||
<property name="orientation">horizontal</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="register_form_back">
|
||||
<property name="label" translatable="yes">Pick another server</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">start</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="register_form_continue">
|
||||
<property name="can_default">True</property>
|
||||
<property name="visible">True</property>
|
||||
<style>
|
||||
<class name="text-button"/>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkStack" id="register_form_continue_stack">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="register_form_continue_label">
|
||||
<property name="label" translatable="yes">Next</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">label</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinner">
|
||||
<property name="active">True</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">spinner</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">form</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="index">-1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="overlay">
|
||||
<object class="GtkRevealer" id="notification_revealer">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GtkFrame" id="frame2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<style>
|
||||
<class name="app-notification"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkBox" id="box2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">20</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="notification_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<action-widgets>
|
||||
<action-widget response="cancel">cancel_button</action-widget>
|
||||
<action-widget response="ok" default="true">ok_button</action-widget>
|
||||
</action-widgets>
|
||||
</template>
|
||||
</interface>
|
||||
|
|
|
@ -74,57 +74,9 @@ public class MucConfigFormProvider : Plugins.ContactDetailsProvider, Object {
|
|||
}
|
||||
}
|
||||
|
||||
Widget? widget = get_widget(field);
|
||||
Widget? widget = Util.get_data_form_fild_widget(field);
|
||||
if (widget != null) contact_details.add(_("Room Configuration"), label, desc, widget);
|
||||
}
|
||||
|
||||
private static Widget? get_widget(DataForms.DataForm.Field field) {
|
||||
if (field.type_ == null) return null;
|
||||
switch (field.type_) {
|
||||
case DataForms.DataForm.Type.BOOLEAN:
|
||||
DataForms.DataForm.BooleanField boolean_field = field as DataForms.DataForm.BooleanField;
|
||||
Switch sw = new Switch() { active=boolean_field.value, valign=Align.CENTER, visible=true };
|
||||
sw.state_set.connect((state) => {
|
||||
boolean_field.value = state;
|
||||
return false;
|
||||
});
|
||||
return sw;
|
||||
case DataForms.DataForm.Type.JID_MULTI:
|
||||
return null;
|
||||
case DataForms.DataForm.Type.LIST_SINGLE:
|
||||
DataForms.DataForm.ListSingleField list_single_field = field as DataForms.DataForm.ListSingleField;
|
||||
ComboBoxText combobox = new ComboBoxText() { valign=Align.CENTER, visible=true };
|
||||
for (int i = 0; i < list_single_field.options.size; i++) {
|
||||
DataForms.DataForm.Option option = list_single_field.options[i];
|
||||
combobox.append(option.value, option.label);
|
||||
if (option.value == list_single_field.value) combobox.active = i;
|
||||
}
|
||||
combobox.changed.connect(() => {
|
||||
list_single_field.value = combobox.get_active_id();
|
||||
});
|
||||
return combobox;
|
||||
case DataForms.DataForm.Type.LIST_MULTI:
|
||||
return null;
|
||||
case DataForms.DataForm.Type.TEXT_PRIVATE:
|
||||
DataForms.DataForm.TextPrivateField text_private_field = field as DataForms.DataForm.TextPrivateField;
|
||||
Entry entry = new Entry() { text=text_private_field.value ?? "", valign=Align.CENTER, visible=true, visibility=false };
|
||||
entry.key_release_event.connect(() => {
|
||||
text_private_field.value = entry.text;
|
||||
return false;
|
||||
});
|
||||
return entry;
|
||||
case DataForms.DataForm.Type.TEXT_SINGLE:
|
||||
DataForms.DataForm.TextSingleField text_single_field = field as DataForms.DataForm.TextSingleField;
|
||||
Entry entry = new Entry() { text=text_single_field.value ?? "", valign=Align.CENTER, visible=true };
|
||||
entry.key_release_event.connect(() => {
|
||||
text_single_field.value = entry.text;
|
||||
return false;
|
||||
});
|
||||
return entry;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,29 +11,120 @@ public class AddAccountDialog : Gtk.Dialog {
|
|||
|
||||
public signal void added(Account account);
|
||||
|
||||
[GtkChild] private Button cancel_button;
|
||||
[GtkChild] private Button ok_button;
|
||||
[GtkChild] private Entry alias_entry;
|
||||
[GtkChild] private Stack stack;
|
||||
|
||||
[GtkChild] private Revealer notification_revealer;
|
||||
[GtkChild] private Label notification_label;
|
||||
|
||||
// Sign in
|
||||
[GtkChild] private Box sign_in_box;
|
||||
[GtkChild] private Entry jid_entry;
|
||||
[GtkChild] private Entry alias_entry;
|
||||
[GtkChild] private Entry password_entry;
|
||||
[GtkChild] private Button sign_in_continue;
|
||||
[GtkChild] private Button serverlist_button;
|
||||
|
||||
// Select Server
|
||||
[GtkChild] private Box create_account_box;
|
||||
[GtkChild] private Button login_button;
|
||||
[GtkChild] private Stack select_server_continue_stack;
|
||||
[GtkChild] private Button select_server_continue;
|
||||
[GtkChild] private Label register_form_continue_label;
|
||||
[GtkChild] private ListBox server_list_box;
|
||||
[GtkChild] private Entry server_entry;
|
||||
|
||||
// Register Form
|
||||
[GtkChild] private Box register_box;
|
||||
[GtkChild] private Label register_title;
|
||||
[GtkChild] private Box form_box;
|
||||
[GtkChild] private Button register_form_back;
|
||||
[GtkChild] private Stack register_form_continue_stack;
|
||||
[GtkChild] private Button register_form_continue;
|
||||
|
||||
private static string[] server_list = new string[]{
|
||||
"5222.de",
|
||||
"jabber.fr",
|
||||
"movim.eu",
|
||||
"yax.im"
|
||||
};
|
||||
private HashMap<ListBoxRow, string> list_box_jids = new HashMap<ListBoxRow, string>();
|
||||
private Jid? server_jid = null;
|
||||
private Xep.InBandRegistration.Form? form = null;
|
||||
|
||||
public AddAccountDialog(StreamInteractor stream_interactor) {
|
||||
Object(use_header_bar : 1);
|
||||
this.title = _("Add Account");
|
||||
|
||||
cancel_button.clicked.connect(() => { close(); });
|
||||
ok_button.clicked.connect(on_ok_button_clicked);
|
||||
// Sign in
|
||||
jid_entry.changed.connect(on_jid_entry_changed);
|
||||
jid_entry.focus_out_event.connect(on_jid_entry_focus_out_event);
|
||||
sign_in_continue.clicked.connect(on_sign_in_continue_clicked);
|
||||
serverlist_button.clicked.connect(show_select_server);
|
||||
|
||||
// Select Server
|
||||
server_entry.changed.connect(() => {
|
||||
Jid? jid = Jid.parse(server_entry.text);
|
||||
select_server_continue.sensitive = jid != null && jid.localpart == null && jid.resourcepart == null;
|
||||
});
|
||||
select_server_continue.clicked.connect(on_select_server_continue);
|
||||
login_button.clicked.connect(show_sign_in);
|
||||
|
||||
foreach (string server in server_list) {
|
||||
ListBoxRow list_box_row = new ListBoxRow() { visible=true };
|
||||
list_box_row.add(new Label(server) { xalign=0, margin=3, margin_start=7, margin_end=7, visible=true });
|
||||
list_box_jids[list_box_row] = server;
|
||||
server_list_box.add(list_box_row);
|
||||
}
|
||||
|
||||
// Register Form
|
||||
register_form_continue.clicked.connect(on_register_form_continue_clicked);
|
||||
register_form_back.clicked.connect(show_select_server);
|
||||
|
||||
show_sign_in();
|
||||
}
|
||||
|
||||
private void show_sign_in() {
|
||||
sign_in_box.visible = true;
|
||||
stack.visible_child_name = "login";
|
||||
create_account_box.visible = false;
|
||||
register_box.visible = false;
|
||||
set_default(sign_in_continue);
|
||||
animate_window_resize(sign_in_box);
|
||||
}
|
||||
|
||||
private void show_select_server() {
|
||||
server_entry.text = "";
|
||||
server_entry.grab_focus();
|
||||
set_default(select_server_continue);
|
||||
|
||||
server_list_box.row_selected.disconnect(on_server_list_row_selected);
|
||||
server_list_box.unselect_all();
|
||||
server_list_box.row_selected.connect(on_server_list_row_selected);
|
||||
|
||||
create_account_box.visible = true;
|
||||
stack.visible_child_name = "server";
|
||||
sign_in_box.visible = false;
|
||||
register_box.visible = false;
|
||||
|
||||
animate_window_resize(create_account_box);
|
||||
}
|
||||
|
||||
private void show_register_form() {
|
||||
register_box.visible = true;
|
||||
stack.visible_child_name = "form";
|
||||
sign_in_box.visible = false;
|
||||
create_account_box.visible = false;
|
||||
|
||||
set_default(register_form_continue);
|
||||
animate_window_resize(register_box);
|
||||
}
|
||||
|
||||
private void on_jid_entry_changed() {
|
||||
Jid? jid = Jid.parse(jid_entry.text);
|
||||
if (jid != null && jid.localpart != null && jid.resourcepart == null) {
|
||||
ok_button.set_sensitive(true);
|
||||
sign_in_continue.set_sensitive(true);
|
||||
jid_entry.secondary_icon_name = null;
|
||||
} else {
|
||||
ok_button.set_sensitive(false);
|
||||
sign_in_continue.set_sensitive(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +132,6 @@ public class AddAccountDialog : Gtk.Dialog {
|
|||
Jid? jid = Jid.parse(jid_entry.text);
|
||||
if (jid == null || jid.localpart == null || jid.resourcepart != null) {
|
||||
jid_entry.secondary_icon_name = "dialog-warning-symbolic";
|
||||
// TODO why doesn't the tooltip work
|
||||
jid_entry.set_icon_tooltip_text(EntryIconPosition.SECONDARY, _("JID should be of the form “user@example.com”"));
|
||||
} else {
|
||||
jid_entry.secondary_icon_name = null;
|
||||
|
@ -49,13 +139,131 @@ public class AddAccountDialog : Gtk.Dialog {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void on_ok_button_clicked() {
|
||||
private void on_sign_in_continue_clicked() {
|
||||
Jid jid = new Jid(jid_entry.get_text());
|
||||
string password = password_entry.get_text();
|
||||
string alias = alias_entry.get_text();
|
||||
store_account(jid, password, alias);
|
||||
close();
|
||||
}
|
||||
|
||||
private void on_select_server_continue() {
|
||||
server_jid = new Jid(server_entry.text);
|
||||
request_show_register_form.begin();
|
||||
}
|
||||
|
||||
private void on_server_list_row_selected(ListBox box, ListBoxRow? row) {
|
||||
server_jid = new Jid(list_box_jids[row]);
|
||||
request_show_register_form.begin();
|
||||
}
|
||||
|
||||
private async void request_show_register_form() {
|
||||
select_server_continue_stack.visible_child_name = "spinner";
|
||||
form = yield Register.get_registration_form(server_jid);
|
||||
if (select_server_continue_stack == null) {
|
||||
return;
|
||||
}
|
||||
select_server_continue_stack.visible_child_name = "label";
|
||||
if (form != null) {
|
||||
set_register_form(server_jid, form);
|
||||
show_register_form();
|
||||
} else {
|
||||
display_notification(_("No response from server"));
|
||||
}
|
||||
}
|
||||
|
||||
private void set_register_form(Jid server, Xep.InBandRegistration.Form form) {
|
||||
form_box.foreach((widget) => { widget.destroy(); });
|
||||
register_title.label = _("Register on %s").printf(server.to_string());
|
||||
|
||||
if (form.oob != null) {
|
||||
form_box.add(new Label(_("The server requires to sign up through a website")){ use_markup=true, visible=true } );
|
||||
form_box.add(new Label(@"<a href=\"$(form.oob)\">$(form.oob)</a>") { use_markup=true, visible=true });
|
||||
register_form_continue_label.label = _("Open Registration");
|
||||
register_form_continue.visible = true;
|
||||
register_form_continue.grab_focus();
|
||||
} else if (form.fields.size > 0) {
|
||||
int i = 0;
|
||||
foreach (Xep.DataForms.DataForm.Field field in form.fields) {
|
||||
if (field.label != null && field.label != "") {
|
||||
form_box.add(new Label(field.label) { xalign=0, margin_top=7, visible=true });
|
||||
}
|
||||
Widget field_widget = Util.get_data_form_fild_widget(field);
|
||||
if (field_widget != null) {
|
||||
form_box.add(field_widget);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
register_form_continue.visible = true;
|
||||
register_form_continue_label.label = _("Register");
|
||||
} else {
|
||||
form_box.add(new Label(_("Check %s for information on how to sign up").printf(@"<a href=\"http://$(server)\">$(server)</a>")) { use_markup=true, visible=true });
|
||||
register_form_continue.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async void on_register_form_continue_clicked() {
|
||||
notification_revealer.set_reveal_child(false);
|
||||
// Button is opening a registration website
|
||||
if (form.oob != null) {
|
||||
try {
|
||||
AppInfo.launch_default_for_uri(form.oob, null);
|
||||
} catch (Error e) { }
|
||||
show_sign_in();
|
||||
return;
|
||||
}
|
||||
|
||||
register_form_continue_stack.visible_child_name = "spinner";
|
||||
string? error = yield Register.submit_form(server_jid, form);
|
||||
if (register_form_continue_stack == null) {
|
||||
return;
|
||||
}
|
||||
register_form_continue_stack.visible_child_name = "label";
|
||||
if (error == null) {
|
||||
string? username = null, password = null;
|
||||
foreach (Xep.DataForms.DataForm.Field field in form.fields) {
|
||||
switch (field.var) {
|
||||
case "username": username = field.get_value_string(); break;
|
||||
case "password": password = field.get_value_string(); break;
|
||||
}
|
||||
}
|
||||
store_account(new Jid(username + "@" + server_jid.domainpart), password, "");
|
||||
close();
|
||||
} else {
|
||||
display_notification(error);
|
||||
}
|
||||
}
|
||||
|
||||
private void store_account(Jid jid, string password, string? alias) {
|
||||
Account account = new Account(jid, null, password, alias);
|
||||
added(account);
|
||||
close();
|
||||
}
|
||||
|
||||
private void display_notification(string text) {
|
||||
notification_label.label = text;
|
||||
notification_revealer.set_reveal_child(true);
|
||||
Timeout.add_seconds(5, () => {
|
||||
notification_revealer.set_reveal_child(false);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private void animate_window_resize(Widget widget) { // TODO code duplication
|
||||
int def_height, curr_width, curr_height;
|
||||
get_size(out curr_width, out curr_height);
|
||||
widget.get_preferred_height(null, out def_height);
|
||||
def_height += 5;
|
||||
int difference = def_height - curr_height;
|
||||
Timer timer = new Timer();
|
||||
Timeout.add((int) (stack.transition_duration / 30),
|
||||
() => {
|
||||
ulong microsec;
|
||||
timer.elapsed(out microsec);
|
||||
ulong millisec = microsec / 1000;
|
||||
double partial = double.min(1, (double) millisec / stack.transition_duration);
|
||||
resize(curr_width, (int) (curr_height + difference * partial));
|
||||
return millisec < stack.transition_duration;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
57
main/src/ui/util/data_forms.vala
Normal file
57
main/src/ui/util/data_forms.vala
Normal file
|
@ -0,0 +1,57 @@
|
|||
using Gee;
|
||||
using Gtk;
|
||||
|
||||
using Dino.Entities;
|
||||
using Xmpp.Xep;
|
||||
|
||||
namespace Dino.Ui.Util {
|
||||
|
||||
public static Widget? get_data_form_fild_widget(DataForms.DataForm.Field field) {
|
||||
if (field.type_ == null) return null;
|
||||
switch (field.type_) {
|
||||
case DataForms.DataForm.Type.BOOLEAN:
|
||||
DataForms.DataForm.BooleanField boolean_field = field as DataForms.DataForm.BooleanField;
|
||||
Switch sw = new Switch() { active=boolean_field.value, valign=Align.CENTER, visible=true };
|
||||
sw.state_set.connect((state) => {
|
||||
boolean_field.value = state;
|
||||
return false;
|
||||
});
|
||||
return sw;
|
||||
case DataForms.DataForm.Type.JID_MULTI:
|
||||
return null;
|
||||
case DataForms.DataForm.Type.LIST_SINGLE:
|
||||
DataForms.DataForm.ListSingleField list_single_field = field as DataForms.DataForm.ListSingleField;
|
||||
ComboBoxText combobox = new ComboBoxText() { valign=Align.CENTER, visible=true };
|
||||
for (int i = 0; i < list_single_field.options.size; i++) {
|
||||
DataForms.DataForm.Option option = list_single_field.options[i];
|
||||
combobox.append(option.value, option.label);
|
||||
if (option.value == list_single_field.value) combobox.active = i;
|
||||
}
|
||||
combobox.changed.connect(() => {
|
||||
list_single_field.value = combobox.get_active_id();
|
||||
});
|
||||
return combobox;
|
||||
case DataForms.DataForm.Type.LIST_MULTI:
|
||||
return null;
|
||||
case DataForms.DataForm.Type.TEXT_PRIVATE:
|
||||
DataForms.DataForm.TextPrivateField text_private_field = field as DataForms.DataForm.TextPrivateField;
|
||||
Entry entry = new Entry() { text=text_private_field.value ?? "", valign=Align.CENTER, visible=true, visibility=false };
|
||||
entry.key_release_event.connect(() => {
|
||||
text_private_field.value = entry.text;
|
||||
return false;
|
||||
});
|
||||
return entry;
|
||||
case DataForms.DataForm.Type.TEXT_SINGLE:
|
||||
DataForms.DataForm.TextSingleField text_single_field = field as DataForms.DataForm.TextSingleField;
|
||||
Entry entry = new Entry() { text=text_single_field.value ?? "", valign=Align.CENTER, visible=true };
|
||||
entry.key_release_event.connect(() => {
|
||||
text_single_field.value = entry.text;
|
||||
return false;
|
||||
});
|
||||
return entry;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -55,6 +55,7 @@ SOURCES
|
|||
"src/module/xep/0054_vcard/module.vala"
|
||||
"src/module/xep/0060_pubsub.vala"
|
||||
"src/module/xep/0066_out_of_band_data.vala"
|
||||
"src/module/xep/0077_in_band_registration.vala"
|
||||
"src/module/xep/0082_date_time_profiles.vala"
|
||||
"src/module/xep/0084_user_avatars.vala"
|
||||
"src/module/xep/0085_chat_state_notifications.vala"
|
||||
|
|
|
@ -36,6 +36,10 @@ namespace Xmpp {
|
|||
get { return error_node.get_attribute("by"); }
|
||||
}
|
||||
|
||||
public string? text {
|
||||
get { return error_node.get_deep_string_content("urn:ietf:params:xml:ns:xmpp-stanzas:text"); }
|
||||
}
|
||||
|
||||
public string condition {
|
||||
get {
|
||||
Gee.List<StanzaNode> subnodes = error_node.sub_nodes;
|
||||
|
@ -57,7 +61,7 @@ namespace Xmpp {
|
|||
}
|
||||
|
||||
public StanzaNode stanza;
|
||||
private StanzaNode error_node;
|
||||
public StanzaNode error_node;
|
||||
|
||||
public ErrorStanza.from_stanza(StanzaNode stanza) {
|
||||
this.stanza = stanza;
|
||||
|
|
|
@ -78,7 +78,7 @@ public class DataForm {
|
|||
return ret;
|
||||
}
|
||||
|
||||
internal string get_value_string() {
|
||||
public string get_value_string() {
|
||||
Gee.List<string> values = get_values();
|
||||
return values.size > 0 ? values[0] : "";
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ public class DataForm {
|
|||
|
||||
// TODO text-multi
|
||||
|
||||
internal DataForm.from_node(StanzaNode node, XmppStream stream, owned OnResult listener) {
|
||||
internal DataForm.from_node(StanzaNode node, XmppStream stream, owned OnResult? listener = null) {
|
||||
this.stanza_node = node;
|
||||
this.stream = stream;
|
||||
this.on_result = (owned)listener;
|
||||
|
|
64
xmpp-vala/src/module/xep/0077_in_band_registration.vala
Normal file
64
xmpp-vala/src/module/xep/0077_in_band_registration.vala
Normal file
|
@ -0,0 +1,64 @@
|
|||
using Gee;
|
||||
|
||||
namespace Xmpp.Xep.InBandRegistration {
|
||||
|
||||
public const string NS_URI = "jabber:iq:register";
|
||||
|
||||
public class Module : XmppStreamNegotiationModule {
|
||||
public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0077_in_band_registration");
|
||||
|
||||
public async Form? get_from_server(XmppStream stream, Jid jid) {
|
||||
Iq.Stanza request_form_iq = new Iq.Stanza.get(new StanzaNode.build("query", NS_URI).add_self_xmlns());
|
||||
request_form_iq.to = jid;
|
||||
SourceFunc callback = get_from_server.callback;
|
||||
Form? form = null;
|
||||
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, request_form_iq, (stream, response_iq) => {
|
||||
form = new Form.from_node(stream, response_iq);
|
||||
Idle.add((owned)callback);
|
||||
});
|
||||
yield;
|
||||
return form;
|
||||
}
|
||||
|
||||
public async string submit_to_server(XmppStream stream, Jid jid, Form form) {
|
||||
StanzaNode query_node = new StanzaNode.build("query", NS_URI).add_self_xmlns();
|
||||
query_node.put_node(form.get_submit_node());
|
||||
Iq.Stanza iq = new Iq.Stanza.set(query_node);
|
||||
iq.to = jid;
|
||||
string? error_message = null;
|
||||
SourceFunc callback = submit_to_server.callback;
|
||||
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, response_iq) => {
|
||||
if (response_iq.is_error()) {
|
||||
ErrorStanza? error_stanza = response_iq.get_error();
|
||||
error_message = error_stanza.text ?? "Error";
|
||||
}
|
||||
Idle.add((owned)callback);
|
||||
});
|
||||
yield;
|
||||
return error_message;
|
||||
}
|
||||
|
||||
public override bool mandatory_outstanding(XmppStream stream) { return false; }
|
||||
|
||||
public override bool negotiation_active(XmppStream stream) { return false; }
|
||||
|
||||
public override void attach(XmppStream stream) { }
|
||||
|
||||
public override void detach(XmppStream stream) { }
|
||||
|
||||
public override string get_ns() { return NS_URI; }
|
||||
public override string get_id() { return IDENTITY.id; }
|
||||
}
|
||||
|
||||
public class Form : DataForms.DataForm {
|
||||
public string? oob = null;
|
||||
|
||||
internal Form.from_node(XmppStream stream, Iq.Stanza iq) {
|
||||
StanzaNode? x_node = iq.stanza.get_deep_subnode(NS_URI + ":query", DataForms.NS_URI + ":x");
|
||||
base.from_node(x_node ?? new StanzaNode.build("x", NS_URI).add_self_xmlns(), stream);
|
||||
|
||||
oob = iq.stanza.get_deep_string_content(NS_URI + ":query", "jabber:x:oob:x", "url");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue