1 /* Copyright (C) 2016-2017 Shengyu Zhang <i@silverrainz.me>
2 *
3 * This file is part of Srain.
4 *
5 * Srain is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20 * @file sui_connect_panel.c
21 * @brief Panel widget for connecting to server
22 * @author Shengyu Zhang <i@silverrainz.me>
23 * @version 0.06.2
24 * @date 2016-09-16
25 */
26
27 #include <stdlib.h>
28 #include <gtk/gtk.h>
29 #include <libsecret/secret.h>
30
31 #include "config/reader.h"
32 #include "config/password.h"
33 #include "sui/sui.h"
34 #include "srain.h"
35 #include "i18n.h"
36 #include "log.h"
37 #include "utils.h"
38
39 #include "sui_common.h"
40 #include "sui_event_hdr.h"
41 #include "sui_window.h"
42 #include "sui_connect_panel.h"
43
44 #define SERVER_LIST_STORE_COL_NAME 0
45 #define LOGIN_METHOD_LIST_STORE_COL_ID 0
46 #define LOGIN_METHOD_LIST_STORE_COL_NAME 1
47
48 #define PAGE_QUICK_MODE "quick_mode_page"
49 #define PAGE_ADVANCED_MODE "advanced_mode_page"
50
51 #define LOGIN_PAGE_NONE "none"
52 #define LOGIN_PAGE_PASSWORD "password"
53 #define LOGIN_PAGE_CERT "certificate"
54
55 struct _SuiConnectPanel {
56 GtkBox parent;
57
58 GtkStack *stack;
59
60 /* Quick mode */
61 GtkComboBox *quick_server_combo_box;
62 GtkEntry *quick_nick_entry;
63
64 /* Advance mode */
65 GtkComboBox *server_combo_box;
66 GtkEntry *host_entry;
67 GtkEntry *port_entry;
68 GtkEntry *password_entry;
69 GtkCheckButton *remember_password_check_button;
70 GtkCheckButton *tls_check_button;
71 GtkCheckButton *tls_noverify_check_button;
72
73 GtkEntry *nick_entry;
74 GtkComboBox *login_method_combo_box;
75 GtkStack *login_method_stack;
76 GtkEntry *login_password_entry;
77 GtkCheckButton *remember_login_password_check_button;
78 GtkFileChooserButton *login_cert_file_chooser_button;
79
80
81 /* Buttons */
82 GtkButton *connect_button;
83 GtkButton *cancel_button;
84
85 /* Data model */
86 GtkListStore *server_list_store;
87 GtkListStore *login_method_list_store;
88 };
89
90 struct _SuiConnectPanelClass {
91 GtkBoxClass parent_class;
92 };
93
94 static void update(SuiConnectPanel *self, const char *srv_name);
95 static void refresh_server_list(SuiConnectPanel *self);
96 static void refresh_login_method_list(SuiConnectPanel *self);
97 static void update_focus(SuiConnectPanel *self);
98
99 static void server_combo_box_on_changed(GtkComboBox *combo_box,
100 gpointer user_data);
101 static void login_method_combo_box_on_changed(GtkComboBox *combo_box,
102 gpointer user_data);
103 static void connect_button_on_click(gpointer user_data);
104 static void cancel_button_on_click(gpointer user_data);
105 static void nick_entry_on_changed(GtkEditable *editable, gpointer user_data);
106 static void on_password_lookup(GObject *source, GAsyncResult *result,
107 gpointer user_data);
108 static void stack_on_child_changed(GtkWidget *widget, GParamSpec *pspec,
109 gpointer user_data);
110
111 /*****************************************************************************
112 * GObject functions
113 *****************************************************************************/
114
115 G_DEFINE_TYPE(SuiConnectPanel, sui_connect_panel, GTK_TYPE_BOX);
116
sui_connect_panel_init(SuiConnectPanel * self)117 static void sui_connect_panel_init(SuiConnectPanel *self){
118 gtk_widget_init_template(GTK_WIDGET(self));
119
120 #if GTK_CHECK_VERSION(3, 18, 0)
121 gtk_stack_set_interpolate_size(self->stack, TRUE);
122 gtk_stack_set_interpolate_size(self->login_method_stack, TRUE);
123 #endif
124
125 /* Set server list model */
126 self->server_list_store = gtk_list_store_new(1, G_TYPE_STRING);
127 gtk_combo_box_set_model(self->quick_server_combo_box,
128 GTK_TREE_MODEL(self->server_list_store));
129 gtk_combo_box_set_id_column(self->quick_server_combo_box, 0);
130 gtk_combo_box_set_model(self->server_combo_box,
131 GTK_TREE_MODEL(self->server_list_store));
132 gtk_combo_box_set_id_column(self->server_combo_box, 0);
133 gtk_combo_box_set_entry_text_column(self->server_combo_box,
134 SERVER_LIST_STORE_COL_NAME);
135 g_object_bind_property(
136 self->quick_server_combo_box, "active",
137 self->server_combo_box, "active",
138 G_BINDING_BIDIRECTIONAL);
139
140 self->login_method_list_store = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
141 gtk_combo_box_set_model(self->login_method_combo_box,
142 GTK_TREE_MODEL(self->login_method_list_store));
143 gtk_combo_box_set_id_column(self->login_method_combo_box, 1);
144
145 g_object_bind_property(
146 self->quick_nick_entry, "text",
147 self->nick_entry, "text",
148 G_BINDING_BIDIRECTIONAL);
149
150 g_signal_connect(self->stack, "notify::visible-child",
151 G_CALLBACK(stack_on_child_changed), self);
152
153 g_signal_connect(self->quick_server_combo_box, "changed",
154 G_CALLBACK(server_combo_box_on_changed), self);
155 g_signal_connect(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(self->server_combo_box))),
156 "changed", G_CALLBACK(server_combo_box_on_changed), self);
157 g_signal_connect(self->nick_entry, "changed",
158 G_CALLBACK(nick_entry_on_changed), self);
159 g_signal_connect(self->login_method_combo_box, "changed",
160 G_CALLBACK(login_method_combo_box_on_changed), self);
161 g_signal_connect_swapped(self->connect_button, "clicked",
162 G_CALLBACK(connect_button_on_click), self);
163 g_signal_connect_swapped(self->cancel_button, "clicked",
164 G_CALLBACK(cancel_button_on_click), self);
165
166 /* Press enter to connect */
167 g_signal_connect_swapped(self->quick_nick_entry, "activate",
168 G_CALLBACK(connect_button_on_click), self);
169 g_signal_connect_swapped(self->host_entry, "activate",
170 G_CALLBACK(connect_button_on_click), self);
171 g_signal_connect_swapped(self->port_entry, "activate",
172 G_CALLBACK(connect_button_on_click), self);
173 g_signal_connect_swapped(self->password_entry, "activate",
174 G_CALLBACK(connect_button_on_click), self);
175 g_signal_connect_swapped(self->nick_entry, "activate",
176 G_CALLBACK(connect_button_on_click), self);
177 g_signal_connect_swapped(self->login_password_entry, "activate",
178 G_CALLBACK(connect_button_on_click), self);
179
180 refresh_server_list(self);
181 refresh_login_method_list(self);
182 }
183
sui_connect_panel_class_init(SuiConnectPanelClass * class)184 static void sui_connect_panel_class_init(SuiConnectPanelClass *class){
185 GtkWidgetClass *widget_class;
186
187 widget_class = GTK_WIDGET_CLASS(class);
188 gtk_widget_class_set_template_from_resource(widget_class,
189 "/im/srain/Srain/connect_panel.glade");
190
191 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, stack);
192
193 /* Quick mode */
194 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, quick_server_combo_box);
195 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, quick_nick_entry);
196
197 /* Advanced mode */
198 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, server_combo_box);
199 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, host_entry);
200 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, port_entry);
201 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, password_entry);
202 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, remember_password_check_button);
203 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, tls_check_button);
204 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, tls_noverify_check_button);
205
206 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, nick_entry);
207 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, login_method_combo_box);
208 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, login_method_stack);
209 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, login_password_entry);
210 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, remember_login_password_check_button);
211 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, login_cert_file_chooser_button);
212
213 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, connect_button);
214 gtk_widget_class_bind_template_child(widget_class, SuiConnectPanel, cancel_button);
215 }
216
217 /*****************************************************************************
218 * Expored functions
219 *****************************************************************************/
220
sui_connect_panel_new()221 SuiConnectPanel* sui_connect_panel_new(){
222 return g_object_new(SUI_TYPE_CONNECT_PANEL, NULL);
223 }
224
225 /*****************************************************************************
226 * Static functions
227 *****************************************************************************/
228
update(SuiConnectPanel * self,const char * srv_name)229 static void update(SuiConnectPanel *self, const char *srv_name){
230 if (!srv_name || !strlen(srv_name)){
231 gtk_combo_box_set_active_iter(self->server_combo_box, NULL);
232
233 gtk_entry_set_text(self->host_entry, "");
234 gtk_entry_set_text(self->port_entry, "");
235 gtk_entry_set_text(self->password_entry, "");
236 gtk_toggle_button_set_active(
237 GTK_TOGGLE_BUTTON(self->remember_password_check_button), FALSE);
238 gtk_toggle_button_set_active(
239 GTK_TOGGLE_BUTTON(self->tls_check_button), FALSE);
240 gtk_toggle_button_set_active(
241 GTK_TOGGLE_BUTTON(self->tls_noverify_check_button), FALSE);
242
243 gtk_entry_set_text(self->nick_entry, "");
244 gtk_combo_box_set_active_iter(self->login_method_combo_box, NULL);
245 gtk_entry_set_text(self->login_password_entry, "");
246 gtk_toggle_button_set_active(
247 GTK_TOGGLE_BUTTON(self->remember_login_password_check_button), FALSE);
248 gtk_file_chooser_set_filename(
249 GTK_FILE_CHOOSER(self->login_cert_file_chooser_button), "");
250 } else {
251 SrnRet ret;
252 SrnApplication *app_model;
253 SrnServerConfig *srv_cfg;
254
255 app_model = sui_application_get_ctx(sui_application_get_instance());
256 srv_cfg = srn_server_config_new();
257
258 // NOTE: this function blocks UI.
259 // pcf said this is good.
260 ret = srn_config_manager_read_server_config(
261 app_model->cfg_mgr, srv_cfg, srv_name);
262 if (!RET_IS_OK(ret)) {
263 ERR_FR("Failed to read server config: %1$s", RET_MSG(ret));
264 srn_server_config_free(srv_cfg);
265 return;
266 }
267
268 if (srv_cfg->addrs){
269 char *port;
270 SrnServerAddr *addr;
271
272 addr = srv_cfg->addrs->data;
273 port = g_strdup_printf("%d", addr->port);
274 gtk_entry_set_text(self->host_entry, addr->host);
275 gtk_entry_set_text(self->port_entry, port);
276 g_free(port);
277 }
278 if (srv_cfg->password) {
279 gtk_entry_set_text(self->password_entry, srv_cfg->password);
280 }
281 gtk_toggle_button_set_active(
282 GTK_TOGGLE_BUTTON(self->tls_check_button),
283 srv_cfg->irc->tls);
284 gtk_toggle_button_set_active(
285 GTK_TOGGLE_BUTTON(self->tls_noverify_check_button),
286 srv_cfg->irc->tls_noverify);
287
288 gtk_entry_set_text(self->nick_entry,
289 srv_cfg->user->nick? srv_cfg->user->nick: "");
290
291 gtk_combo_box_set_active_id(self->login_method_combo_box,
292 srn_login_method_to_string(srv_cfg->user->login->method));
293 gtk_entry_set_text(self->login_password_entry,
294 srv_cfg->user->login->password ?
295 srv_cfg->user->login->password : "");
296 gtk_file_chooser_set_filename(
297 GTK_FILE_CHOOSER(self->login_cert_file_chooser_button),
298 srv_cfg->user->login->cert_file ?
299 srv_cfg->user->login->cert_file : "");
300
301 srn_server_config_free(srv_cfg);
302 }
303 }
304
refresh_server_list(SuiConnectPanel * self)305 static void refresh_server_list(SuiConnectPanel *self){
306 GList *lst;
307 GList *srv_cfg_lst;
308 GtkTreeIter iter;
309 GtkListStore *store;
310 SrnRet ret;
311 SrnApplication *app_model;
312
313 app_model = sui_application_get_ctx(sui_application_get_instance());
314 store = self->server_list_store;
315 gtk_list_store_clear(store);
316
317 srv_cfg_lst = NULL;
318 ret = srn_config_manager_read_server_config_list(
319 app_model->cfg_mgr, &srv_cfg_lst);
320 if (!RET_IS_OK(ret)){
321 ERR_FR("%s", RET_MSG(ret));
322 return;
323 }
324
325 lst = srv_cfg_lst;
326 while (lst) {
327 gtk_list_store_append(store, &iter);
328 gtk_list_store_set(store, &iter,
329 SERVER_LIST_STORE_COL_NAME, lst->data,
330 -1);
331 lst = g_list_next(lst);
332 }
333
334 g_list_free_full(srv_cfg_lst, g_free);
335 }
336
refresh_login_method_list(SuiConnectPanel * self)337 static void refresh_login_method_list(SuiConnectPanel *self){
338 GtkTreeIter iter;
339 GtkListStore *store;
340
341 // Supported login methods
342 static SrnLoginMethod lms[] = {
343 SRN_LOGIN_METHOD_NONE,
344 SRN_LOGIN_METHOD_NICKSERV,
345 SRN_LOGIN_METHOD_MSG_NICKSERV,
346 SRN_LOGIN_METHOD_SASL_PLAIN,
347 SRN_LOGIN_METHOD_SASL_ECDSA_NIST256P_CHALLENGE,
348 };
349
350 store = self->login_method_list_store;
351 gtk_list_store_clear(store);
352
353 for (int i = 0; i < sizeof(lms) / sizeof(lms[0]); i++) {
354 gtk_list_store_append(store, &iter);
355 gtk_list_store_set(store, &iter,
356 LOGIN_METHOD_LIST_STORE_COL_ID, (int)lms[i],
357 LOGIN_METHOD_LIST_STORE_COL_NAME, srn_login_method_to_string(lms[i]),
358 -1);
359 }
360 }
361
server_combo_box_on_changed(GtkComboBox * combo_box,gpointer user_data)362 static void server_combo_box_on_changed(GtkComboBox *combo_box,
363 gpointer user_data){
364 const char *srv_name;
365 GtkEntry *entry;
366 SuiConnectPanel *self;
367
368 self = SUI_CONNECT_PANEL(user_data);
369 entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(self->server_combo_box)));
370 srv_name = gtk_entry_get_text(entry);
371 update(self, srv_name);
372 }
373
login_method_combo_box_on_changed(GtkComboBox * combo_box,gpointer user_data)374 static void login_method_combo_box_on_changed(GtkComboBox *combo_box,
375 gpointer user_data){
376 const char *page;
377 SrnLoginMethod lm;
378 GtkTreeModel *model;
379 GtkTreeIter iter;
380 SuiConnectPanel *self;
381
382 self = SUI_CONNECT_PANEL(user_data);
383 model = GTK_TREE_MODEL(self->login_method_list_store);
384
385 if (!gtk_combo_box_get_active_iter(combo_box, &iter)){
386 lm = SRN_LOGIN_METHOD_NONE;
387 } else {
388 // Set the login_method_stack to the corresponding page
389 gtk_tree_model_get(model, &iter,
390 LOGIN_METHOD_LIST_STORE_COL_ID, &lm,
391 -1);
392 }
393
394 switch (lm) {
395 case SRN_LOGIN_METHOD_NICKSERV:
396 case SRN_LOGIN_METHOD_MSG_NICKSERV:
397 case SRN_LOGIN_METHOD_SASL_PLAIN:
398 page = LOGIN_PAGE_PASSWORD;
399 break;
400 case SRN_LOGIN_METHOD_SASL_ECDSA_NIST256P_CHALLENGE:
401 page = LOGIN_PAGE_CERT;
402 break;
403 case SRN_LOGIN_METHOD_NONE:
404 default:
405 page = LOGIN_PAGE_NONE;
406 break;
407 }
408 gtk_stack_set_visible_child_name(self->login_method_stack, page);
409 }
410
connect_button_on_click(gpointer user_data)411 static void connect_button_on_click(gpointer user_data){
412 const char *page;
413 const char *srv_name;
414 SrnRet ret;
415 SuiConnectPanel *self;
416 SrnApplication *app_model;
417 SrnServer *srv;
418 SrnServerConfig *srv_cfg;
419
420 ret = SRN_ERR;
421 self = user_data;
422 page = gtk_stack_get_visible_child_name(self->stack);
423 app_model = sui_application_get_ctx(sui_application_get_instance());
424 srv = NULL;
425 srv_cfg = NULL;
426
427 if (g_ascii_strcasecmp(page, PAGE_QUICK_MODE) == 0){
428 const char *nick;
429
430 srv_name = gtk_combo_box_get_active_id(self->quick_server_combo_box);
431 if (!srv_name){
432 ret = RET_ERR(_("No server selected"));
433 goto FIN;
434 }
435
436 srv_cfg = srn_server_config_new();
437 ret = srn_config_manager_read_server_config(
438 app_model->cfg_mgr, srv_cfg, srv_name);
439 if (!RET_IS_OK(ret)){
440 goto FIN;
441 }
442
443 nick = gtk_entry_get_text(self->quick_nick_entry);
444
445 if (!str_is_empty(nick)) {
446 str_assign(&srv_cfg->user->nick, nick);
447 }
448 } else if (g_ascii_strcasecmp(page, PAGE_ADVANCED_MODE) == 0){
449 const char *host;
450 int port;
451 const char *passwd;
452 bool rmb_passwd;
453 bool tls;
454 bool tls_noverify;
455 const char *nick;
456 const char *method_str;
457 const char *login_passwd;
458 bool rmb_login_passwd;
459 const char *login_cert_file;
460
461 GtkEntry *entry;
462 SrnLoginMethod method;
463
464 entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(self->server_combo_box)));
465 srv_name = gtk_entry_get_text(entry);
466
467 srv_cfg = srn_server_config_new();
468 ret = srn_config_manager_read_server_config(
469 app_model->cfg_mgr, srv_cfg, srv_name);
470 if (!RET_IS_OK(ret)){
471 goto FIN;
472 }
473
474 host = gtk_entry_get_text(self->host_entry);
475 port = g_ascii_strtoll(gtk_entry_get_text(self->port_entry), NULL, 10);
476 if (!str_is_empty(host)) {
477 srn_server_config_clear_addr(srv_cfg);
478 srn_server_config_add_addr(srv_cfg, srn_server_addr_new(host, port));
479 }
480
481 passwd = gtk_entry_get_text(self->password_entry);
482 // Always overwrite password
483 str_assign(&srv_cfg->password, passwd);
484
485 rmb_passwd = gtk_toggle_button_get_active(
486 GTK_TOGGLE_BUTTON(self->remember_password_check_button));
487 if (rmb_passwd) {
488 if (strlen(passwd)) { // Reqeust to store password
489 ret = srn_config_manager_store_server_password(
490 app_model->cfg_mgr, passwd, srv_name);
491 if (!RET_IS_OK(ret)) {
492 ret = RET_ERR(_("Failed to store server password: %1$s"),
493 RET_MSG(ret));
494 sui_message_box(_("Error"), RET_MSG(ret) );
495 // No need to return
496 }
497 } else { // Reqeust to clear password
498 ret = srn_config_manager_clear_server_password(
499 app_model->cfg_mgr, srv_name);
500 if (!RET_IS_OK(ret)) {
501 ret = RET_ERR(_("Failed to clear server password: %1$s"),
502 RET_MSG(ret));
503 sui_message_box(_("Error"), RET_MSG(ret) );
504 // No need to return
505 }
506 }
507 }
508
509 tls_noverify = gtk_toggle_button_get_active(
510 GTK_TOGGLE_BUTTON(self->tls_noverify_check_button));
511 srv_cfg->irc->tls_noverify = tls_noverify;
512
513 tls = gtk_toggle_button_get_active(
514 GTK_TOGGLE_BUTTON(self->tls_check_button));
515 // TODO: Let tls_check_button to be toggled when
516 // tls_noverify_check_button is toggled.
517 srv_cfg->irc->tls = tls || tls_noverify;
518
519 nick = gtk_entry_get_text(self->nick_entry);
520 if (!str_is_empty(nick)) {
521 str_assign(&srv_cfg->user->nick, nick);
522 }
523
524 method_str = gtk_combo_box_get_active_id(self->login_method_combo_box);
525 method = srn_login_method_from_string(method_str);
526 srv_cfg->user->login->method = method;
527
528 login_passwd = gtk_entry_get_text(self->login_password_entry);
529 // Always overwrite password
530 str_assign(&srv_cfg->user->login->password, login_passwd);
531
532 rmb_login_passwd = gtk_toggle_button_get_active(
533 GTK_TOGGLE_BUTTON(self->remember_login_password_check_button));
534 if (rmb_login_passwd) {
535 if (strlen(login_passwd)) { // Reqeust to store password
536 ret = srn_config_manager_store_user_password(
537 app_model->cfg_mgr, login_passwd, srv_name, nick);
538 if (!RET_IS_OK(ret)) {
539 ret = RET_ERR(_("Failed to store user password: %1$s"),
540 RET_MSG(ret));
541 sui_message_box(_("Error"), RET_MSG(ret) );
542 // No need to return
543 }
544 } else { // Reqeust to clear password
545 ret = srn_config_manager_clear_user_password(
546 app_model->cfg_mgr, srv_name, nick);
547 if (!RET_IS_OK(ret)) {
548 ret = RET_ERR(_("Failed to clear user password: 1$%s"),
549 RET_MSG(ret));
550 sui_message_box(_("Error"), RET_MSG(ret) );
551 // No need to return
552 }
553 }
554 }
555
556 login_cert_file = gtk_file_chooser_get_filename(
557 GTK_FILE_CHOOSER(self->login_cert_file_chooser_button));
558 if (!str_is_empty(login_cert_file)) {
559 str_assign(&srv_cfg->user->login->cert_file, login_cert_file);
560 }
561 } else {
562 g_warn_if_reached();
563 goto FIN;
564 }
565
566 ret = srn_application_add_server_with_config(app_model, srv_name, srv_cfg);
567 if (!RET_IS_OK(ret)){
568 goto FIN;
569 }
570 srv_cfg = NULL; // Ownership changed to server
571
572 srv = srn_application_get_server(app_model, srv_name);
573 if (!srn_server_is_valid(srv)){
574 g_warn_if_reached();
575 goto FIN;
576 }
577
578 ret = srn_server_connect(srv);
579 LOG_FR("Server connect finished");
580 if (!RET_IS_OK(ret)){
581 goto FIN;
582 }
583
584 ret = SRN_OK;
585 FIN:
586 if (srv_cfg){
587 srn_server_config_free(srv_cfg);
588 }
589 if (RET_IS_OK(ret)){
590 sui_common_popdown_panel(GTK_WIDGET(self));
591 update(self, NULL);
592 } else {
593 if (srv){
594 srn_application_rm_server(app_model, srv);
595 }
596 sui_message_box(_("Error"), RET_MSG(ret));
597 }
598 }
599
cancel_button_on_click(gpointer user_data)600 static void cancel_button_on_click(gpointer user_data){
601 SuiConnectPanel *self;
602
603 self = user_data;
604
605 sui_common_popdown_panel(GTK_WIDGET(self));
606 update(self, NULL);
607 }
608
609
nick_entry_on_changed(GtkEditable * editable,gpointer user_data)610 static void nick_entry_on_changed(GtkEditable *editable, gpointer user_data) {
611 const char *srv_name;
612 const char *user_name;
613 GtkEntry *entry;
614 SuiConnectPanel *self;
615 SrnApplication *app_model;
616 SrnConfigManager *cfg_mgr;
617
618 entry = GTK_ENTRY(editable);
619 self = SUI_CONNECT_PANEL(user_data);
620 app_model = sui_application_get_ctx(sui_application_get_instance());
621 cfg_mgr = app_model->cfg_mgr;
622
623 srv_name = gtk_entry_get_text(
624 GTK_ENTRY(gtk_bin_get_child(GTK_BIN(self->server_combo_box))));
625 user_name = gtk_entry_get_text(entry);
626
627 // Clear login password when user name is not valid
628 if (str_is_empty(user_name)) {
629 gtk_entry_set_text(self->login_password_entry, "");
630 return;
631 }
632
633 // Lookup login password asynchronously
634 secret_password_lookup(srn_config_manager_get_user_secret_schema(cfg_mgr),
635 NULL, on_password_lookup, self->login_password_entry,
636 SRN_CONFIG_SECRET_SCHEMA_ATTR_SERVER, srv_name,
637 SRN_CONFIG_SECRET_SCHEMA_ATTR_USER, user_name,
638 NULL);
639 }
640
on_password_lookup(GObject * source,GAsyncResult * result,gpointer user_data)641 static void on_password_lookup(GObject *source, GAsyncResult *result,
642 gpointer user_data) {
643 char *passwd;
644 GtkEntry *entry;
645
646 entry = GTK_ENTRY(user_data);
647
648 passwd = secret_password_lookup_finish(result, NULL);
649 if (!passwd) {
650 return;
651 }
652
653 gtk_entry_set_text(entry, passwd);
654 secret_password_free(passwd);
655 }
656
stack_on_child_changed(GtkWidget * widget,GParamSpec * pspec,gpointer user_data)657 static void stack_on_child_changed(GtkWidget *widget, GParamSpec *pspec,
658 gpointer user_data) {
659 update_focus(SUI_CONNECT_PANEL(user_data));
660 }
661
update_focus(SuiConnectPanel * self)662 static void update_focus(SuiConnectPanel *self) {
663 const char *page = gtk_stack_get_visible_child_name(self->stack);
664
665 if (g_strcmp0(page, PAGE_QUICK_MODE) == 0){
666 gtk_widget_grab_focus(GTK_WIDGET(self->quick_server_combo_box));
667 } else if (g_strcmp0(page, PAGE_ADVANCED_MODE) == 0){
668 gtk_widget_grab_focus(GTK_WIDGET(self->server_combo_box));
669 } else {
670 g_warn_if_reached();
671 }
672 }
673