Show account status (incl errors) in ManageAccounts.Dialog
This commit is contained in:
parent
d6e742eb61
commit
d8881c4b16
|
@ -9,6 +9,7 @@ public class ConnectionManager {
|
||||||
|
|
||||||
public signal void stream_opened(Account account, Core.XmppStream stream);
|
public signal void stream_opened(Account account, Core.XmppStream stream);
|
||||||
public signal void connection_state_changed(Account account, ConnectionState state);
|
public signal void connection_state_changed(Account account, ConnectionState state);
|
||||||
|
public signal void connection_error(Account account, ConnectionError error);
|
||||||
|
|
||||||
public enum ConnectionState {
|
public enum ConnectionState {
|
||||||
CONNECTED,
|
CONNECTED,
|
||||||
|
@ -17,12 +18,32 @@ public class ConnectionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<Account> connection_todo = new ArrayList<Account>(Account.equals_func);
|
private ArrayList<Account> connection_todo = new ArrayList<Account>(Account.equals_func);
|
||||||
private HashMap<Account, Connection> stream_states = new HashMap<Account, Connection>(Account.hash_func, Account.equals_func);
|
private HashMap<Account, Connection> connections = new HashMap<Account, Connection>(Account.hash_func, Account.equals_func);
|
||||||
|
private HashMap<Account, ConnectionError> connection_errors = new HashMap<Account, ConnectionError>(Account.hash_func, Account.equals_func);
|
||||||
|
|
||||||
private NetworkManager? network_manager;
|
private NetworkManager? network_manager;
|
||||||
private Login1Manager? login1;
|
private Login1Manager? login1;
|
||||||
private ModuleManager module_manager;
|
private ModuleManager module_manager;
|
||||||
public string? log_options;
|
public string? log_options;
|
||||||
|
|
||||||
|
public class ConnectionError {
|
||||||
|
|
||||||
|
public enum Source {
|
||||||
|
CONNECTION,
|
||||||
|
SASL,
|
||||||
|
STREAM_ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
public Source source;
|
||||||
|
public string? identifier;
|
||||||
|
public StreamError.Flag? flag;
|
||||||
|
|
||||||
|
public ConnectionError(Source source, string? identifier) {
|
||||||
|
this.source = source;
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class Connection {
|
private class Connection {
|
||||||
public Core.XmppStream stream { get; set; }
|
public Core.XmppStream stream { get; set; }
|
||||||
public ConnectionState connection_state { get; set; default = ConnectionState.DISCONNECTED; }
|
public ConnectionState connection_state { get; set; default = ConnectionState.DISCONNECTED; }
|
||||||
|
@ -46,26 +67,33 @@ public class ConnectionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Core.XmppStream? get_stream(Account account) {
|
public Core.XmppStream? get_stream(Account account) {
|
||||||
if (get_connection_state(account) == ConnectionState.CONNECTED) {
|
if (get_state(account) == ConnectionState.CONNECTED) {
|
||||||
return stream_states[account].stream;
|
return connections[account].stream;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConnectionState get_connection_state(Account account) {
|
public ConnectionState get_state(Account account) {
|
||||||
if (stream_states.has_key(account)){
|
if (connections.has_key(account)){
|
||||||
return stream_states[account].connection_state;
|
return connections[account].connection_state;
|
||||||
}
|
}
|
||||||
return ConnectionState.DISCONNECTED;
|
return ConnectionState.DISCONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConnectionError? get_error(Account account) {
|
||||||
|
if (connection_errors.has_key(account)) {
|
||||||
|
return connection_errors[account];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public ArrayList<Account> get_managed_accounts() {
|
public ArrayList<Account> get_managed_accounts() {
|
||||||
return connection_todo;
|
return connection_todo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Core.XmppStream? connect(Account account) {
|
public Core.XmppStream? connect(Account account) {
|
||||||
if (!connection_todo.contains(account)) connection_todo.add(account);
|
if (!connection_todo.contains(account)) connection_todo.add(account);
|
||||||
if (!stream_states.has_key(account)) {
|
if (!connections.has_key(account)) {
|
||||||
return connect_(account);
|
return connect_(account);
|
||||||
} else {
|
} else {
|
||||||
check_reconnect(account);
|
check_reconnect(account);
|
||||||
|
@ -76,18 +104,18 @@ public class ConnectionManager {
|
||||||
public void disconnect(Account account) {
|
public void disconnect(Account account) {
|
||||||
change_connection_state(account, ConnectionState.DISCONNECTED);
|
change_connection_state(account, ConnectionState.DISCONNECTED);
|
||||||
connection_todo.remove(account);
|
connection_todo.remove(account);
|
||||||
if (stream_states.has_key(account)) {
|
if (connections.has_key(account)) {
|
||||||
try {
|
try {
|
||||||
stream_states[account].stream.disconnect();
|
connections[account].stream.disconnect();
|
||||||
|
connections.unset(account);
|
||||||
} catch (Error e) { }
|
} catch (Error e) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Core.XmppStream? connect_(Account account, string? resource = null) {
|
private Core.XmppStream? connect_(Account account, string? resource = null) {
|
||||||
|
if (connections.has_key(account)) connections[account].stream.remove_modules();
|
||||||
|
connection_errors.unset(account);
|
||||||
if (resource == null) resource = account.resourcepart;
|
if (resource == null) resource = account.resourcepart;
|
||||||
if (stream_states.has_key(account)) {
|
|
||||||
stream_states[account].stream.remove_modules();
|
|
||||||
}
|
|
||||||
|
|
||||||
Core.XmppStream stream = new Core.XmppStream();
|
Core.XmppStream stream = new Core.XmppStream();
|
||||||
foreach (Core.XmppStreamModule module in module_manager.get_modules(account, resource)) {
|
foreach (Core.XmppStreamModule module in module_manager.get_modules(account, resource)) {
|
||||||
|
@ -96,11 +124,15 @@ public class ConnectionManager {
|
||||||
stream.log = new Core.XmppLog(account.bare_jid.to_string(), log_options);
|
stream.log = new Core.XmppLog(account.bare_jid.to_string(), log_options);
|
||||||
|
|
||||||
Connection connection = new Connection(stream, new DateTime.now_local());
|
Connection connection = new Connection(stream, new DateTime.now_local());
|
||||||
stream_states[account] = connection;
|
connections[account] = connection;
|
||||||
change_connection_state(account, ConnectionState.CONNECTING);
|
change_connection_state(account, ConnectionState.CONNECTING);
|
||||||
stream.stream_negotiated.connect((stream) => {
|
stream.stream_negotiated.connect((stream) => {
|
||||||
change_connection_state(account, ConnectionState.CONNECTED);
|
change_connection_state(account, ConnectionState.CONNECTED);
|
||||||
});
|
});
|
||||||
|
stream.get_module(PlainSasl.Module.IDENTITY).received_auth_failure.connect((stream, node) => {
|
||||||
|
set_connection_error(account, ConnectionError.Source.SASL, null);
|
||||||
|
change_connection_state(account, ConnectionState.DISCONNECTED);
|
||||||
|
});
|
||||||
new Thread<void*> (null, () => {
|
new Thread<void*> (null, () => {
|
||||||
try {
|
try {
|
||||||
stream.connect(account.domainpart);
|
stream.connect(account.domainpart);
|
||||||
|
@ -108,10 +140,13 @@ public class ConnectionManager {
|
||||||
stderr.printf("Stream Error: %s\n", e.message);
|
stderr.printf("Stream Error: %s\n", e.message);
|
||||||
change_connection_state(account, ConnectionState.DISCONNECTED);
|
change_connection_state(account, ConnectionState.DISCONNECTED);
|
||||||
if (!connection_todo.contains(account)) {
|
if (!connection_todo.contains(account)) {
|
||||||
stream_states.unset(account);
|
connections.unset(account);
|
||||||
} else {
|
} else {
|
||||||
interpret_reconnect_flags(account, stream.get_flag(StreamError.Flag.IDENTITY) ??
|
StreamError.Flag? flag = stream.get_flag(StreamError.Flag.IDENTITY);
|
||||||
new StreamError.Flag() { reconnection_recomendation = StreamError.Flag.Reconnect.NOW });
|
if (flag != null) {
|
||||||
|
set_connection_error(account, ConnectionError.Source.STREAM_ERROR, flag.error_type);
|
||||||
|
}
|
||||||
|
interpret_connection_error(account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -121,29 +156,33 @@ public class ConnectionManager {
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void interpret_reconnect_flags(Account account, StreamError.Flag stream_error_flag) {
|
private void interpret_connection_error(Account account) {
|
||||||
int wait_sec = 10;
|
ConnectionError? error = connection_errors[account];
|
||||||
if (network_manager != null && network_manager.State != NetworkManager.CONNECTED_GLOBAL) {
|
int wait_sec = 5;
|
||||||
wait_sec = 60;
|
if (error == null) {
|
||||||
|
wait_sec = 3;
|
||||||
|
} else if (error.source == ConnectionError.Source.STREAM_ERROR && error.flag != null) {
|
||||||
|
if (error.flag.resource_rejected) {
|
||||||
|
connect_(account, account.resourcepart + "-" + random_uuid());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
switch (stream_error_flag.reconnection_recomendation) {
|
switch (error.flag.reconnection_recomendation) {
|
||||||
case StreamError.Flag.Reconnect.NOW:
|
case StreamError.Flag.Reconnect.NOW:
|
||||||
wait_sec = 10;
|
wait_sec = 5; break;
|
||||||
break;
|
|
||||||
case StreamError.Flag.Reconnect.LATER:
|
case StreamError.Flag.Reconnect.LATER:
|
||||||
case StreamError.Flag.Reconnect.UNKNOWN:
|
wait_sec = 60; break;
|
||||||
wait_sec = 60;
|
|
||||||
break;
|
|
||||||
case StreamError.Flag.Reconnect.NEVER:
|
case StreamError.Flag.Reconnect.NEVER:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (error.source == ConnectionError.Source.SASL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (network_manager != null && network_manager.State != NetworkManager.CONNECTED_GLOBAL) {
|
||||||
|
wait_sec = 60;
|
||||||
|
}
|
||||||
print(@"recovering in $wait_sec\n");
|
print(@"recovering in $wait_sec\n");
|
||||||
Timeout.add_seconds(wait_sec, () => {
|
Timeout.add_seconds(wait_sec, () => {
|
||||||
if (stream_error_flag.resource_rejected) {
|
|
||||||
connect_(account, account.resourcepart + "-" + random_uuid());
|
|
||||||
} else {
|
|
||||||
connect_(account);
|
connect_(account);
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -156,16 +195,16 @@ public class ConnectionManager {
|
||||||
|
|
||||||
private void check_reconnect(Account account) {
|
private void check_reconnect(Account account) {
|
||||||
PingResponseListenerImpl ping_response_listener = new PingResponseListenerImpl(this, account);
|
PingResponseListenerImpl ping_response_listener = new PingResponseListenerImpl(this, account);
|
||||||
Core.XmppStream stream = stream_states[account].stream;
|
Core.XmppStream stream = connections[account].stream;
|
||||||
stream.get_module(Xep.Ping.Module.IDENTITY).send_ping(stream, account.domainpart, ping_response_listener);
|
stream.get_module(Xep.Ping.Module.IDENTITY).send_ping(stream, account.domainpart, ping_response_listener);
|
||||||
|
|
||||||
Timeout.add_seconds(5, () => {
|
Timeout.add_seconds(5, () => {
|
||||||
if (stream_states[account].stream != stream) return false;
|
if (connections[account].stream != stream) return false;
|
||||||
if (ping_response_listener.acked) return false;
|
if (ping_response_listener.acked) return false;
|
||||||
|
|
||||||
change_connection_state(account, ConnectionState.DISCONNECTED);
|
change_connection_state(account, ConnectionState.DISCONNECTED);
|
||||||
try {
|
try {
|
||||||
stream_states[account].stream.disconnect();
|
connections[account].stream.disconnect();
|
||||||
} catch (Error e) { }
|
} catch (Error e) { }
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -207,8 +246,8 @@ public class ConnectionManager {
|
||||||
Xmpp.Presence.Stanza presence = new Xmpp.Presence.Stanza();
|
Xmpp.Presence.Stanza presence = new Xmpp.Presence.Stanza();
|
||||||
presence.type_ = Xmpp.Presence.Stanza.TYPE_UNAVAILABLE;
|
presence.type_ = Xmpp.Presence.Stanza.TYPE_UNAVAILABLE;
|
||||||
try {
|
try {
|
||||||
stream_states[account].stream.get_module(Presence.Module.IDENTITY).send_presence(stream_states[account].stream, presence);
|
connections[account].stream.get_module(Presence.Module.IDENTITY).send_presence(connections[account].stream, presence);
|
||||||
stream_states[account].stream.disconnect();
|
connections[account].stream.disconnect();
|
||||||
} catch (Error e) { print(@"on_prepare_for_sleep error $(e.message)\n"); }
|
} catch (Error e) { print(@"on_prepare_for_sleep error $(e.message)\n"); }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -218,9 +257,17 @@ public class ConnectionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void change_connection_state(Account account, ConnectionState state) {
|
private void change_connection_state(Account account, ConnectionState state) {
|
||||||
stream_states[account].connection_state = state;
|
if (connections.has_key(account)) {
|
||||||
|
connections[account].connection_state = state;
|
||||||
connection_state_changed(account, state);
|
connection_state_changed(account, state);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void set_connection_error(Account account, ConnectionError.Source source, string? id) {
|
||||||
|
ConnectionError error = new ConnectionError(source, id);
|
||||||
|
connection_errors[account] = error;
|
||||||
|
connection_error(account, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,18 +33,11 @@ public class ModuleManager {
|
||||||
public ArrayList<Core.XmppStreamModule> get_modules(Account account, string? resource = null) {
|
public ArrayList<Core.XmppStreamModule> get_modules(Account account, string? resource = null) {
|
||||||
ArrayList<Core.XmppStreamModule> modules = new ArrayList<Core.XmppStreamModule>();
|
ArrayList<Core.XmppStreamModule> modules = new ArrayList<Core.XmppStreamModule>();
|
||||||
lock (module_map) {
|
lock (module_map) {
|
||||||
if (!module_map.has_key(account)) {
|
if (!module_map.has_key(account)) initialize(account);
|
||||||
initialize(account);
|
foreach (Core.XmppStreamModule module in module_map[account]) modules.add(module);
|
||||||
}
|
}
|
||||||
foreach (Core.XmppStreamModule module in module_map[account]) {
|
|
||||||
if (Bind.Module.IDENTITY.matches(module)) {
|
|
||||||
// TODO: argh?!
|
|
||||||
modules.add(new Bind.Module(resource == null ? account.resourcepart : resource));
|
modules.add(new Bind.Module(resource == null ? account.resourcepart : resource));
|
||||||
} else {
|
modules.add(new PlainSasl.Module(account.bare_jid.to_string(), account.password));
|
||||||
modules.add(module);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return modules;
|
return modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,8 +45,6 @@ public class ModuleManager {
|
||||||
lock(module_map) {
|
lock(module_map) {
|
||||||
module_map[account] = new ArrayList<Core.XmppStreamModule>();
|
module_map[account] = new ArrayList<Core.XmppStreamModule>();
|
||||||
module_map[account].add(new Tls.Module());
|
module_map[account].add(new Tls.Module());
|
||||||
module_map[account].add(new PlainSasl.Module(account.bare_jid.to_string(), account.password));
|
|
||||||
module_map[account].add(new Bind.Module(account.resourcepart));
|
|
||||||
module_map[account].add(new Roster.Module());
|
module_map[account].add(new Roster.Module());
|
||||||
module_map[account].add(new Xep.ServiceDiscovery.Module.with_identity("client", "pc"));
|
module_map[account].add(new Xep.ServiceDiscovery.Module.with_identity("client", "pc"));
|
||||||
module_map[account].add(new Xep.PrivateXmlStorage.Module());
|
module_map[account].add(new Xep.PrivateXmlStorage.Module());
|
||||||
|
|
|
@ -23,6 +23,11 @@
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="icon">
|
||||||
|
<property name="icon-name">dialog-warning-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -130,6 +130,21 @@
|
||||||
<property name="height">1</property>
|
<property name="height">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="state_label">
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</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>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkSwitch" id="active_switch">
|
<object class="GtkSwitch" id="active_switch">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
|
|
@ -9,13 +9,34 @@ public class AccountRow : Gtk.ListBoxRow {
|
||||||
|
|
||||||
[GtkChild] public Image image;
|
[GtkChild] public Image image;
|
||||||
[GtkChild] public Label jid_label;
|
[GtkChild] public Label jid_label;
|
||||||
|
[GtkChild] public Image icon;
|
||||||
|
|
||||||
public Account account;
|
public Account account;
|
||||||
|
private StreamInteractor stream_interactor;
|
||||||
|
|
||||||
public AccountRow(StreamInteractor stream_interactor, Account account) {
|
public AccountRow(StreamInteractor stream_interactor, Account account) {
|
||||||
|
this.stream_interactor = stream_interactor;
|
||||||
this.account = account;
|
this.account = account;
|
||||||
Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(40, 40, image.scale_factor)).draw_account(stream_interactor, account));
|
Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(40, 40, image.scale_factor)).draw_account(stream_interactor, account));
|
||||||
jid_label.set_label(account.bare_jid.to_string());
|
jid_label.set_label(account.bare_jid.to_string());
|
||||||
|
|
||||||
|
stream_interactor.connection_manager.connection_error.connect((account, error) => {
|
||||||
|
Idle.add(() => {
|
||||||
|
if (account.equals(this.account)) update_warning_icon();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
stream_interactor.connection_manager.connection_state_changed.connect((account, state) => {
|
||||||
|
Idle.add(() => {
|
||||||
|
if (account.equals(this.account)) update_warning_icon();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update_warning_icon() {
|
||||||
|
ConnectionManager.ConnectionError? error = stream_interactor.connection_manager.get_error(account);
|
||||||
|
icon.visible = (error != null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ public class Dialog : Gtk.Window {
|
||||||
[GtkChild] public Image image;
|
[GtkChild] public Image image;
|
||||||
[GtkChild] public Button image_button;
|
[GtkChild] public Button image_button;
|
||||||
[GtkChild] public Label jid_label;
|
[GtkChild] public Label jid_label;
|
||||||
|
[GtkChild] public Label state_label;
|
||||||
[GtkChild] public Switch active_switch;
|
[GtkChild] public Switch active_switch;
|
||||||
|
|
||||||
[GtkChild] public Stack password_stack;
|
[GtkChild] public Stack password_stack;
|
||||||
|
@ -39,12 +40,14 @@ public class Dialog : Gtk.Window {
|
||||||
|
|
||||||
private Database db;
|
private Database db;
|
||||||
private StreamInteractor stream_interactor;
|
private StreamInteractor stream_interactor;
|
||||||
|
private Account? selected_account;
|
||||||
|
|
||||||
construct {
|
construct {
|
||||||
account_list.row_selected.connect(account_list_row_selected);
|
Util.force_error_color(state_label, ".is_error");
|
||||||
add_button.clicked.connect(add_button_clicked);
|
account_list.row_selected.connect(on_account_list_row_selected);
|
||||||
no_accounts_add.clicked.connect(add_button_clicked);
|
add_button.clicked.connect(on_add_button_clicked);
|
||||||
remove_button.clicked.connect(remove_button_clicked);
|
no_accounts_add.clicked.connect(on_add_button_clicked);
|
||||||
|
remove_button.clicked.connect(on_remove_button_clicked);
|
||||||
password_entry.key_release_event.connect(on_password_key_release_event);
|
password_entry.key_release_event.connect(on_password_key_release_event);
|
||||||
alias_entry.key_release_event.connect(on_alias_key_release_event);
|
alias_entry.key_release_event.connect(on_alias_key_release_event);
|
||||||
image_button.clicked.connect(on_image_button_clicked);
|
image_button.clicked.connect(on_image_button_clicked);
|
||||||
|
@ -82,7 +85,20 @@ public class Dialog : Gtk.Window {
|
||||||
Idle.add(() => {
|
Idle.add(() => {
|
||||||
on_received_avatar(pixbuf, jid, account);
|
on_received_avatar(pixbuf, jid, account);
|
||||||
return false;
|
return false;
|
||||||
});});
|
});
|
||||||
|
});
|
||||||
|
stream_interactor.connection_manager.connection_error.connect((account, error) => {
|
||||||
|
Idle.add(() => {
|
||||||
|
if (account.equals(selected_account)) update_status_label(account);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
stream_interactor.connection_manager.connection_state_changed.connect((account, state) => {
|
||||||
|
Idle.add(() => {
|
||||||
|
if (account.equals(selected_account)) update_status_label(account);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if (account_list.get_row_at_index(0) != null) account_list.select_row(account_list.get_row_at_index(0));
|
if (account_list.get_row_at_index(0) != null) account_list.select_row(account_list.get_row_at_index(0));
|
||||||
}
|
}
|
||||||
|
@ -94,7 +110,7 @@ public class Dialog : Gtk.Window {
|
||||||
return account_item;
|
return account_item;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add_button_clicked() {
|
private void on_add_button_clicked() {
|
||||||
AddAccountDialog add_account_dialog = new AddAccountDialog(stream_interactor);
|
AddAccountDialog add_account_dialog = new AddAccountDialog(stream_interactor);
|
||||||
add_account_dialog.set_transient_for(this);
|
add_account_dialog.set_transient_for(this);
|
||||||
add_account_dialog.added.connect((account) => {
|
add_account_dialog.added.connect((account) => {
|
||||||
|
@ -106,7 +122,7 @@ public class Dialog : Gtk.Window {
|
||||||
add_account_dialog.show();
|
add_account_dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void remove_button_clicked() {
|
private void on_remove_button_clicked() {
|
||||||
AccountRow account_item = account_list.get_selected_row() as AccountRow;
|
AccountRow account_item = account_list.get_selected_row() as AccountRow;
|
||||||
if (account_item != null) {
|
if (account_item != null) {
|
||||||
account_list.remove(account_item);
|
account_list.remove(account_item);
|
||||||
|
@ -121,40 +137,14 @@ public class Dialog : Gtk.Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void account_list_row_selected(ListBoxRow? row) {
|
private void on_account_list_row_selected(ListBoxRow? row) {
|
||||||
AccountRow? account_item = row as AccountRow;
|
AccountRow? account_item = row as AccountRow;
|
||||||
if (account_item != null) populate_grid_data(account_item.account);
|
if (account_item != null) {
|
||||||
|
selected_account = account_item.account;
|
||||||
|
populate_grid_data(account_item.account);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populate_grid_data(Account account) {
|
|
||||||
active_switch.state_set.disconnect(on_active_switch_state_changed);
|
|
||||||
|
|
||||||
Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(50, 50, image.scale_factor)).draw_account(stream_interactor, account));
|
|
||||||
active_switch.set_active(account.enabled);
|
|
||||||
jid_label.label = account.bare_jid.to_string();
|
|
||||||
|
|
||||||
string filler = "";
|
|
||||||
for (int i = 0; i < account.password.length; i++) filler += password_entry.get_invisible_char().to_string();
|
|
||||||
password_label.label = filler;
|
|
||||||
password_stack.set_visible_child_name("label");
|
|
||||||
password_entry.text = account.password;
|
|
||||||
|
|
||||||
alias_stack.set_visible_child_name("label");
|
|
||||||
alias_label.label = account.alias;
|
|
||||||
alias_entry.text = account.alias;
|
|
||||||
|
|
||||||
password_button.clicked.connect(() => { set_active_stack(password_stack); });
|
|
||||||
alias_button.clicked.connect(() => { set_active_stack(alias_stack); });
|
|
||||||
active_switch.state_set.connect(on_active_switch_state_changed);
|
|
||||||
|
|
||||||
foreach(Plugins.AccountSettingsWidget widget in plugin_widgets) {
|
|
||||||
widget.set_account(account);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
child_activated(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void on_image_button_clicked() {
|
private void on_image_button_clicked() {
|
||||||
FileChooserDialog chooser = new FileChooserDialog (
|
FileChooserDialog chooser = new FileChooserDialog (
|
||||||
"Select avatar", this, FileChooserAction.OPEN,
|
"Select avatar", this, FileChooserAction.OPEN,
|
||||||
|
@ -175,6 +165,7 @@ public class Dialog : Gtk.Window {
|
||||||
Account account = (account_list.get_selected_row() as AccountRow).account;
|
Account account = (account_list.get_selected_row() as AccountRow).account;
|
||||||
account.enabled = state;
|
account.enabled = state;
|
||||||
if (state) {
|
if (state) {
|
||||||
|
if (account.enabled) account_disabled(account);
|
||||||
account_enabled(account);
|
account_enabled(account);
|
||||||
} else {
|
} else {
|
||||||
account_disabled(account);
|
account_disabled(account);
|
||||||
|
@ -211,6 +202,62 @@ public class Dialog : Gtk.Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void populate_grid_data(Account account) {
|
||||||
|
active_switch.state_set.disconnect(on_active_switch_state_changed);
|
||||||
|
|
||||||
|
Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(50, 50, image.scale_factor)).draw_account(stream_interactor, account));
|
||||||
|
active_switch.set_active(account.enabled);
|
||||||
|
jid_label.label = account.bare_jid.to_string();
|
||||||
|
|
||||||
|
string filler = "";
|
||||||
|
for (int i = 0; i < account.password.length; i++) filler += password_entry.get_invisible_char().to_string();
|
||||||
|
password_label.label = filler;
|
||||||
|
password_stack.set_visible_child_name("label");
|
||||||
|
password_entry.text = account.password;
|
||||||
|
|
||||||
|
alias_stack.set_visible_child_name("label");
|
||||||
|
alias_label.label = account.alias;
|
||||||
|
alias_entry.text = account.alias;
|
||||||
|
|
||||||
|
update_status_label(account);
|
||||||
|
|
||||||
|
password_button.clicked.connect(() => { set_active_stack(password_stack); });
|
||||||
|
alias_button.clicked.connect(() => { set_active_stack(alias_stack); });
|
||||||
|
active_switch.state_set.connect(on_active_switch_state_changed);
|
||||||
|
|
||||||
|
foreach(Plugins.AccountSettingsWidget widget in plugin_widgets) {
|
||||||
|
widget.set_account(account);
|
||||||
|
}
|
||||||
|
|
||||||
|
child_activated(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update_status_label(Account account) {
|
||||||
|
state_label.label = "";
|
||||||
|
ConnectionManager.ConnectionError? error = stream_interactor.connection_manager.get_error(account);
|
||||||
|
if (error != null) {
|
||||||
|
state_label.label = get_connection_error_description(error);
|
||||||
|
state_label.get_style_context().add_class("is_error");
|
||||||
|
|
||||||
|
if (error.source == ConnectionManager.ConnectionError.Source.SASL ||
|
||||||
|
(error.flag != null && error.flag.reconnection_recomendation == Xmpp.StreamError.Flag.Reconnect.NEVER)) {
|
||||||
|
active_switch.active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ConnectionManager.ConnectionState state = stream_interactor.connection_manager.get_state(account);
|
||||||
|
switch (state) {
|
||||||
|
case ConnectionManager.ConnectionState.CONNECTING:
|
||||||
|
state_label.label = "Connecting..."; break;
|
||||||
|
case ConnectionManager.ConnectionState.CONNECTED:
|
||||||
|
state_label.label = "Connected"; break;
|
||||||
|
case ConnectionManager.ConnectionState.DISCONNECTED:
|
||||||
|
state_label.label = "Disconnected"; break;
|
||||||
|
}
|
||||||
|
state_label.get_style_context().remove_class("is_error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void child_activated(Gtk.Widget? widget) {
|
private void child_activated(Gtk.Widget? widget) {
|
||||||
if (widget != password_stack) password_stack.set_visible_child_name("label");
|
if (widget != password_stack) password_stack.set_visible_child_name("label");
|
||||||
if (widget != alias_stack) alias_stack.set_visible_child_name("label");
|
if (widget != alias_stack) alias_stack.set_visible_child_name("label");
|
||||||
|
@ -224,6 +271,18 @@ public class Dialog : Gtk.Window {
|
||||||
stack.set_visible_child_name("entry");
|
stack.set_visible_child_name("entry");
|
||||||
child_activated(stack);
|
child_activated(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string get_connection_error_description(ConnectionManager.ConnectionError error) {
|
||||||
|
switch (error.source) {
|
||||||
|
case ConnectionManager.ConnectionError.Source.SASL:
|
||||||
|
return "Wrong password";
|
||||||
|
}
|
||||||
|
if (error.identifier != null) {
|
||||||
|
return "Error" + ": " + error.identifier;
|
||||||
|
} else {
|
||||||
|
return "Error";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,6 @@ public class Util : Object {
|
||||||
private const string force_background_css = "%s { background-color: %s; }";
|
private const string force_background_css = "%s { background-color: %s; }";
|
||||||
private const string force_color_css = "%s { color: %s; }";
|
private const string force_color_css = "%s { color: %s; }";
|
||||||
|
|
||||||
|
|
||||||
private static void force_css(Gtk.Widget widget, string css) {
|
private static void force_css(Gtk.Widget widget, string css) {
|
||||||
var p = new Gtk.CssProvider();
|
var p = new Gtk.CssProvider();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -80,7 +80,7 @@ private class AccountSettingsWidget : Stack, Plugins.AccountSettingsWidget {
|
||||||
list_store.set(iter, 0, build_markup_string("Key publishing disabled", "Select key"), 1, "");
|
list_store.set(iter, 0, build_markup_string("Key publishing disabled", "Select key"), 1, "");
|
||||||
for (int i = 0; i < keys.size; i++) {
|
for (int i = 0; i < keys.size; i++) {
|
||||||
list_store.append(out iter);
|
list_store.append(out iter);
|
||||||
list_store.set(iter, 0, build_markup_string(keys[i].uids[0].uid, "0x" + keys[i].fpr[0:16]));
|
list_store.set(iter, 0, @"$(Markup.escape_text(keys[i].uids[0].uid))\n<span font_family='monospace' font='8'>0x$(Markup.escape_text(keys[i].fpr[0:16]))</span>");
|
||||||
list_store.set(iter, 1, keys[i].fpr);
|
list_store.set(iter, 1, keys[i].fpr);
|
||||||
if (keys[i].fpr == plugin.db.get_account_key(current_account)) {
|
if (keys[i].fpr == plugin.db.get_account_key(current_account)) {
|
||||||
set_label_active(iter, i + 1);
|
set_label_active(iter, i + 1);
|
||||||
|
@ -95,7 +95,7 @@ private class AccountSettingsWidget : Stack, Plugins.AccountSettingsWidget {
|
||||||
list_store.clear();
|
list_store.clear();
|
||||||
list_store.append(out iter);
|
list_store.append(out iter);
|
||||||
label.set_markup(build_markup_string("Loading...", "Querying GnuPG"));
|
label.set_markup(build_markup_string("Loading...", "Querying GnuPG"));
|
||||||
new Thread<void*> (null, () => { // Querying GnuPG might take some while
|
new Thread<void*> (null, () => { // Querying GnuPG might take some time
|
||||||
try {
|
try {
|
||||||
keys = GPGHelper.get_keylist(null, true);
|
keys = GPGHelper.get_keylist(null, true);
|
||||||
Idle.add(() => {
|
Idle.add(() => {
|
||||||
|
|
Loading…
Reference in a new issue