1 /*
2 * Copyright (C) 2009 - 2012 Vivien Malerba <malerba@gnome-db.org>
3 * Copyright (C) 2010 David King <davidk@openismus.com>
4 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include <glib/gi18n-lib.h>
22 #include <string.h>
23 #include <libgda/binreloc/gda-binreloc.h>
24 #include "auth-dialog.h"
25 #include "browser-spinner.h"
26 #include "support.h"
27 #include <libgda/thread-wrapper/gda-thread-wrapper.h>
28
29 /*
30 * Main static functions
31 */
32 static void auth_dialog_class_init (AuthDialogClass * class);
33 static void auth_dialog_init (AuthDialog *dialog);
34 static void auth_dialog_dispose (GObject *object);
35
36 /* get a pointer to the parents to be able to call their destructor */
37 static GObjectClass *parent_class = NULL;
38
39 typedef struct {
40 AuthDialogConnection ext;
41 GdaDsnInfo cncinfo;
42 GtkWidget *auth_widget;
43 GString *auth_string;
44
45 GdaThreadWrapper *wrapper;
46 guint jobid;
47 } AuthData;
48
49 static void
auth_data_free(AuthData * ad)50 auth_data_free (AuthData *ad)
51 {
52 g_free (ad->cncinfo.name);
53 g_free (ad->cncinfo.description);
54 g_free (ad->cncinfo.provider);
55 g_free (ad->cncinfo.cnc_string);
56 g_free (ad->cncinfo.auth_string);
57 g_free (ad->ext.cnc_string);
58 if (ad->auth_string)
59 g_string_free (ad->auth_string, TRUE);
60
61 g_object_unref (ad->wrapper);
62 if (ad->ext.cnc_open_error)
63 g_error_free (ad->ext.cnc_open_error);
64 if (ad->ext.cnc)
65 g_object_unref (ad->ext.cnc);
66 g_free (ad);
67 }
68
69 struct _AuthDialogPrivate
70 {
71 GSList *auth_list; /* list of AuthData pointers */
72 GtkWidget *spinner;
73 guint source_id; /* timer to check if connections have been opened */
74 GMainLoop *loop; /* waiting loop */
75 };
76
77 /* module error */
auth_dialog_error_quark(void)78 GQuark auth_dialog_error_quark (void)
79 {
80 static GQuark quark;
81 if (!quark)
82 quark = g_quark_from_static_string ("auth_dialog_error");
83 return quark;
84 }
85
86 GType
auth_dialog_get_type(void)87 auth_dialog_get_type (void)
88 {
89 static GType type = 0;
90
91 if (G_UNLIKELY (type == 0)) {
92 static GMutex registering;
93 static const GTypeInfo info = {
94 sizeof (AuthDialogClass),
95 (GBaseInitFunc) NULL,
96 (GBaseFinalizeFunc) NULL,
97 (GClassInitFunc) auth_dialog_class_init,
98 NULL,
99 NULL,
100 sizeof (AuthDialog),
101 0,
102 (GInstanceInitFunc) auth_dialog_init,
103 0
104 };
105
106 g_mutex_lock (®istering);
107 if (type == 0)
108 type = g_type_register_static (GTK_TYPE_DIALOG, "AuthDialog", &info, 0);
109 g_mutex_unlock (®istering);
110 }
111
112 return type;
113 }
114
115
116 static void
auth_dialog_class_init(AuthDialogClass * class)117 auth_dialog_class_init (AuthDialogClass *class)
118 {
119 GObjectClass *object_class = G_OBJECT_CLASS (class);
120
121 parent_class = g_type_class_peek_parent (class);
122
123 /* virtual functions */
124 object_class->dispose = auth_dialog_dispose;
125 }
126
127 /*
128 static void
129 auth_contents_changed_cb (GdauiAuth *auth, gboolean is_valid, AuthDialog *dialog)
130 {
131 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT, is_valid);
132 if (is_valid)
133 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
134 }
135 */
136
137 static void
update_ad_auth(AuthData * ad)138 update_ad_auth (AuthData *ad)
139 {
140 if (ad->auth_widget && ad->cncinfo.auth_string) {
141 /* split array in a list of named parameters, and for each parameter value,
142 * set the correcponding parameter in @dset */
143 GdaSet *dset;
144 dset = gdaui_basic_form_get_data_set (GDAUI_BASIC_FORM (ad->auth_widget));
145 gchar **array = NULL;
146 array = g_strsplit (ad->cncinfo.auth_string, ";", 0);
147 if (array) {
148 gint index = 0;
149 gchar *tok;
150 gchar *value;
151 gchar *name;
152
153 for (index = 0; array[index]; index++) {
154 name = strtok_r (array [index], "=", &tok);
155 if (name)
156 value = strtok_r (NULL, "=", &tok);
157 else
158 value = NULL;
159 if (name && value) {
160 GdaHolder *param;
161 gda_rfc1738_decode (name);
162 gda_rfc1738_decode (value);
163
164 param = gda_set_get_holder (dset, name);
165 if (param)
166 g_assert (gda_holder_set_value_str (param, NULL, value, NULL));
167 }
168 }
169
170 g_strfreev (array);
171 }
172 gdaui_basic_form_entry_grab_focus (GDAUI_BASIC_FORM (ad->auth_widget), NULL);
173 }
174 }
175
176 /*
177 * Update the auth part
178 */
179 static void
dsn_changed_cb(G_GNUC_UNUSED GdaConfig * config,GdaDsnInfo * info,AuthDialog * dialog)180 dsn_changed_cb (G_GNUC_UNUSED GdaConfig *config, GdaDsnInfo *info, AuthDialog *dialog)
181 {
182 GSList *list;
183 if (!info || !info->name) /* should not happen */
184 return;
185 for (list = dialog->priv->auth_list; list; list = list->next) {
186 AuthData *ad = (AuthData*) list->data;
187 if (! ad->cncinfo.name || strcmp (info->name, ad->cncinfo.name))
188 continue;
189 g_free (ad->cncinfo.auth_string);
190 ad->cncinfo.auth_string = NULL;
191 if (info->auth_string)
192 ad->cncinfo.auth_string = g_strdup (info->auth_string);
193 update_ad_auth (ad);
194 }
195 }
196
197 static void
auth_dialog_init(AuthDialog * dialog)198 auth_dialog_init (AuthDialog *dialog)
199 {
200 GtkWidget *label, *hbox, *wid;
201 char *markup, *str;
202 GtkWidget *dcontents;
203
204 dialog->priv = g_new0 (AuthDialogPrivate, 1);
205
206 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
207 GTK_STOCK_CONNECT,
208 GTK_RESPONSE_ACCEPT,
209 GTK_STOCK_CANCEL,
210 GTK_RESPONSE_REJECT, NULL);
211
212 dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
213 gtk_box_set_spacing (GTK_BOX (dcontents), 5);
214 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT, TRUE);
215
216 str = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "pixmaps", "gda-browser-auth.png", NULL);
217 gtk_window_set_icon_from_file (GTK_WINDOW (dialog), str, NULL);
218 g_free (str);
219
220 /* label and spinner */
221 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
222 gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
223 gtk_box_pack_start (GTK_BOX (dcontents), hbox, FALSE, FALSE, 0);
224
225 str = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "pixmaps", "gda-browser-auth-big.png", NULL);
226 wid = gtk_image_new_from_file (str);
227 g_free (str);
228 gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 0);
229
230 label = gtk_label_new ("");
231 markup = g_markup_printf_escaped ("<big><b>%s\n</b></big>\n",
232 _("Connection opening"));
233 gtk_label_set_markup (GTK_LABEL (label), markup);
234 g_free (markup);
235 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
236 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 12);
237
238 dialog->priv->spinner = browser_spinner_new ();
239 gtk_box_pack_start (GTK_BOX (hbox), dialog->priv->spinner, FALSE, FALSE, 0);
240
241 gtk_widget_show_all (hbox);
242 gtk_widget_hide (dialog->priv->spinner);
243
244 GdaConfig *conf = gda_config_get ();
245 g_signal_connect (conf, "dsn-changed",
246 G_CALLBACK (dsn_changed_cb), dialog);
247 g_object_unref (conf);
248 }
249
250 static void
auth_dialog_dispose(GObject * object)251 auth_dialog_dispose (GObject *object)
252 {
253 AuthDialog *dialog;
254 dialog = AUTH_DIALOG (object);
255 if (dialog->priv) {
256 GdaConfig *conf = gda_config_get ();
257 g_signal_handlers_disconnect_by_func (conf,
258 G_CALLBACK (dsn_changed_cb), dialog);
259 g_object_unref (conf);
260 if (dialog->priv->auth_list) {
261 g_slist_foreach (dialog->priv->auth_list, (GFunc) auth_data_free, NULL);
262 g_slist_free (dialog->priv->auth_list);
263 }
264 if (dialog->priv->source_id)
265 g_source_remove (dialog->priv->source_id);
266 if (dialog->priv->loop)
267 g_main_loop_quit (dialog->priv->loop);
268 g_free (dialog->priv);
269 dialog->priv = NULL;
270 }
271
272 /* parent class */
273 parent_class->dispose (object);
274 }
275
276 /**
277 * auth_dialog_new
278 *
279 * Creates a new dialog dialog
280 *
281 * Returns: a new #AuthDialog object
282 */
283 AuthDialog *
auth_dialog_new(GtkWindow * parent)284 auth_dialog_new (GtkWindow *parent)
285 {
286 return (AuthDialog*) g_object_new (AUTH_TYPE_DIALOG, "title", _("Authentication"),
287 "transient-for", parent,
288 "resizable", FALSE,
289 "border-width", 10, NULL);
290 }
291
292 /*
293 * executed in a sub thread
294 */
295 static GdaConnection *
sub_thread_open_cnc(AuthData * ad,GError ** error)296 sub_thread_open_cnc (AuthData *ad, GError **error)
297 {
298 #ifndef DUMMY
299 GdaConnection *cnc;
300 GdaDsnInfo *info = &(ad->cncinfo);
301 if (info->name)
302 cnc = gda_connection_open_from_dsn (info->name, ad->auth_string ? ad->auth_string->str : NULL,
303 GDA_CONNECTION_OPTIONS_THREAD_SAFE |
304 GDA_CONNECTION_OPTIONS_AUTO_META_DATA,
305 error);
306 else
307 cnc = gda_connection_open_from_string (info->provider, info->cnc_string,
308 ad->auth_string ? ad->auth_string->str : NULL,
309 GDA_CONNECTION_OPTIONS_THREAD_SAFE |
310 GDA_CONNECTION_OPTIONS_AUTO_META_DATA,
311 error);
312 #ifdef HAVE_LDAP
313 if (cnc && GDA_IS_LDAP_CONNECTION (cnc)) {
314 /* force classes init */
315 gda_ldap_get_class_info (GDA_LDAP_CONNECTION (cnc), "top");
316 }
317 #endif
318 return cnc;
319 #else /* DUMMY defined */
320 sleep (5);
321 g_set_error (error, GDA_TOOLS_ERROR, TOOLS_INTERNAL_COMMAND_ERROR, "%s", "Dummy error!");
322 return NULL;
323 #endif
324 }
325
326 static gboolean
check_for_cnc(AuthDialog * dialog)327 check_for_cnc (AuthDialog *dialog)
328 {
329 GSList *list;
330 gboolean finished = TRUE;
331 for (list = dialog->priv->auth_list; list; list = list->next) {
332 AuthData *ad = (AuthData*) list->data;
333
334 if (ad->jobid) {
335 GError *lerror = NULL;
336 ad->ext.cnc = gda_thread_wrapper_fetch_result (ad->wrapper, FALSE, ad->jobid, &lerror);
337 if (ad->ext.cnc || (!ad->ext.cnc && lerror)) {
338 /* waiting is finished! */
339 if (ad->ext.cnc)
340 g_object_set (ad->ext.cnc, "monitor-wrapped-in-mainloop", TRUE, NULL);
341 if (lerror)
342 ad->ext.cnc_open_error = lerror;
343 ad->jobid = 0;
344 }
345 else
346 finished = FALSE;
347 }
348 }
349
350 if (finished) {
351 dialog->priv->source_id = 0;
352 if (dialog->priv->loop)
353 g_main_loop_quit (dialog->priv->loop);
354 }
355 return !finished;
356 }
357
358 static void
update_dialog_focus(AuthDialog * dialog)359 update_dialog_focus (AuthDialog *dialog)
360 {
361 GSList *list;
362 gboolean allvalid = TRUE;
363 for (list = dialog->priv->auth_list; list; list = list->next) {
364 AuthData *ad;
365 ad = (AuthData*) list->data;
366 if (ad->auth_widget && !ad->ext.cnc &&
367 ! gdaui_basic_form_is_valid (GDAUI_BASIC_FORM (ad->auth_widget))) {
368 allvalid = FALSE;
369 gtk_widget_grab_focus (ad->auth_widget);
370 break;
371 }
372 }
373
374 if (allvalid) {
375 GtkWidget *wid;
376 wid = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
377 gtk_widget_grab_focus (wid);
378 }
379 }
380
381 static void
auth_form_activated_cb(G_GNUC_UNUSED GdauiBasicForm * form,AuthDialog * dialog)382 auth_form_activated_cb (G_GNUC_UNUSED GdauiBasicForm *form, AuthDialog *dialog)
383 {
384 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
385 }
386
387 static void
auth_contents_changed_cb(GdauiBasicForm * form,GdaHolder * h,gboolean is_user_modif,AuthDialog * dialog)388 auth_contents_changed_cb (GdauiBasicForm *form, GdaHolder *h, gboolean is_user_modif, AuthDialog *dialog)
389 {
390 GSList *list;
391 for (list = dialog->priv->auth_list; list; list = list->next) {
392 AuthData *ad = (AuthData*) list->data;
393 if (! gdaui_basic_form_is_valid (GDAUI_BASIC_FORM (ad->auth_widget)))
394 break;
395 }
396
397 gboolean is_valid;
398 is_valid = list ? FALSE : TRUE;
399 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT, is_valid);
400 if (is_valid)
401 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
402 }
403
404 /**
405 * auth_dialog_add_cnc_string
406 */
407 gboolean
auth_dialog_add_cnc_string(AuthDialog * dialog,const gchar * cnc_string,GError ** error)408 auth_dialog_add_cnc_string (AuthDialog *dialog, const gchar *cnc_string, GError **error)
409 {
410 g_return_val_if_fail (AUTH_IS_DIALOG (dialog), FALSE);
411 g_return_val_if_fail (cnc_string, FALSE);
412
413 gchar *real_cnc_string;
414 GdaDsnInfo *info;
415 gchar *user, *pass, *real_cnc, *real_provider, *real_auth_string = NULL;
416
417 /* if cnc string is a regular file, then use it with SQLite */
418 if (g_file_test (cnc_string, G_FILE_TEST_IS_REGULAR)) {
419 gchar *path, *file, *e1, *e2;
420 const gchar *pname = "SQLite";
421
422 path = g_path_get_dirname (cnc_string);
423 file = g_path_get_basename (cnc_string);
424 if (g_str_has_suffix (file, ".mdb")) {
425 pname = "MSAccess";
426 file [strlen (file) - 4] = 0;
427 }
428 else if (g_str_has_suffix (file, ".db"))
429 file [strlen (file) - 3] = 0;
430 e1 = gda_rfc1738_encode (path);
431 e2 = gda_rfc1738_encode (file);
432 g_free (path);
433 g_free (file);
434 real_cnc_string = g_strdup_printf ("%s://DB_DIR=%s;EXTRA_FUNCTIONS=TRUE;DB_NAME=%s", pname, e1, e2);
435 g_free (e1);
436 g_free (e2);
437 gda_connection_string_split (real_cnc_string, &real_cnc, &real_provider, &user, &pass);
438 }
439 else {
440 gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass);
441 real_cnc_string = g_strdup (cnc_string);
442 }
443 if (!real_cnc) {
444 g_free (user);
445 g_free (pass);
446 g_free (real_provider);
447 g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR,
448 _("Malformed connection string '%s'"), cnc_string);
449 g_free (real_cnc_string);
450 return FALSE;
451 }
452
453 AuthData *ad;
454 ad = g_new0 (AuthData, 1);
455 ad->wrapper = gda_thread_wrapper_new ();
456 /*g_print ("Auth dialog: new thread wrapper %p\n", ad->wrapper);*/
457 ad->ext.cnc_string = g_strdup (cnc_string);
458 ad->auth_string = NULL;
459 info = gda_config_get_dsn_info (real_cnc);
460 if (info && !real_provider) {
461 ad->cncinfo.name = g_strdup (info->name);
462 ad->cncinfo.provider = g_strdup (info->provider);
463 if (info->description)
464 ad->cncinfo.description = g_strdup (info->description);
465 if (info->cnc_string)
466 ad->cncinfo.cnc_string = g_strdup (info->cnc_string);
467 if (info->auth_string)
468 ad->cncinfo.auth_string = g_strdup (info->auth_string);
469 }
470 else {
471 ad->cncinfo.name = NULL;
472 ad->cncinfo.provider = real_provider;
473 real_provider = NULL;
474 ad->cncinfo.cnc_string = real_cnc;
475 real_cnc = NULL;
476 ad->cncinfo.auth_string = real_auth_string;
477 real_auth_string = NULL;
478 }
479
480 if (! ad->cncinfo.provider) {
481 g_free (user);
482 g_free (pass);
483 g_free (real_provider);
484 g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR,
485 _("Malformed connection string '%s'"), cnc_string);
486 g_free (real_cnc_string);
487 auth_data_free (ad);
488 return FALSE;
489 }
490
491 if (user || pass) {
492 gchar *s1;
493 s1 = gda_rfc1738_encode (user);
494 if (pass) {
495 gchar *s2;
496 s2 = gda_rfc1738_encode (pass);
497 real_auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2);
498 g_free (s2);
499 }
500 else
501 real_auth_string = g_strdup_printf ("USERNAME=%s", s1);
502 g_free (s1);
503 }
504 if (real_auth_string) {
505 if (ad->cncinfo.auth_string)
506 g_free (ad->cncinfo.auth_string);
507 ad->cncinfo.auth_string = real_auth_string;
508 real_auth_string = NULL;
509 }
510
511 dialog->priv->auth_list = g_slist_append (dialog->priv->auth_list, ad);
512
513 /* build widget */
514 gboolean auth_needed = FALSE;
515 GdaProviderInfo *pinfo;
516 pinfo = gda_config_get_provider_info (ad->cncinfo.provider);
517 if (pinfo && pinfo->auth_params && pinfo->auth_params->holders)
518 auth_needed = TRUE;
519 if (auth_needed) {
520 GdaSet *set;
521
522 set = gda_set_copy (pinfo->auth_params);
523 ad->auth_widget = gdaui_basic_form_new (set);
524 g_signal_connect (G_OBJECT (ad->auth_widget), "activated",
525 G_CALLBACK (auth_form_activated_cb), dialog);
526 g_signal_connect (G_OBJECT (ad->auth_widget), "holder-changed",
527 G_CALLBACK (auth_contents_changed_cb), dialog);
528 g_object_unref (set);
529
530 /* add widget */
531 GtkWidget *hbox, *label;
532 gchar *str, *tmp, *ptr;
533 GtkWidget *dcontents;
534
535 dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
536 label = gtk_label_new ("");
537 tmp = g_strdup (ad->ext.cnc_string);
538 for (ptr = tmp; *ptr; ptr++) {
539 if (*ptr == ':') {
540 /* remove everything up to the '@' */
541 gchar *ptr2;
542 for (ptr2 = ptr+1; *ptr2; ptr2++) {
543 if (*ptr2 == '@') {
544 memmove (ptr, ptr2, strlen (ptr2) + 1);
545 break;
546 }
547 }
548 break;
549 }
550 }
551 str = g_strdup_printf ("<b>%s: %s</b>\n%s", _("For connection"), tmp,
552 _("enter authentication information"));
553 g_free (tmp);
554 gtk_label_set_markup (GTK_LABEL (label), str);
555 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
556 g_free (str);
557 gtk_box_pack_start (GTK_BOX (dcontents), label, FALSE, FALSE, 0);
558 gtk_widget_show (label);
559
560 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); /* HIG */
561 gtk_box_pack_start (GTK_BOX (dcontents), hbox, TRUE, TRUE, 0);
562 label = gtk_label_new (" ");
563 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
564 gtk_box_pack_start (GTK_BOX (hbox), ad->auth_widget, TRUE, TRUE, 0);
565 gtk_widget_show_all (hbox);
566
567 /* set values */
568 if (ad->cncinfo.auth_string)
569 update_ad_auth (ad);
570 }
571 else {
572 /* open connection right away */
573 ad->jobid = gda_thread_wrapper_execute (ad->wrapper,
574 (GdaThreadWrapperFunc) sub_thread_open_cnc,
575 (gpointer) ad,
576 (GDestroyNotify) NULL,
577 &(ad->ext.cnc_open_error));
578 if (dialog->priv->source_id == 0) {
579 dialog->priv->source_id = g_timeout_add (200, (GSourceFunc) check_for_cnc, dialog);
580 }
581 }
582
583 g_free (real_cnc_string);
584 g_free (real_cnc);
585 g_free (user);
586 g_free (pass);
587 g_free (real_provider);
588 g_free (real_auth_string);
589
590 update_dialog_focus (dialog);
591
592 return TRUE;
593 }
594
595 /**
596 * auth_dialog_run
597 * @dialog: a #GdaAuth object
598 * @retry: if set to %TRUE, then this method returns only when either a connection has been opened or the
599 * user gave up
600 * @error: a place to store errors, or %NULL
601 *
602 * Displays the dialog and let the user open some connections. this function returns either only when
603 * all the connections have been opened, or when the user cancelled.
604 *
605 * Return: %TRUE if all the connections have been opened, and %FALSE if the user cancelled.
606 */
607 gboolean
auth_dialog_run(AuthDialog * dialog)608 auth_dialog_run (AuthDialog *dialog)
609 {
610 gboolean allopened = FALSE;
611
612 g_return_val_if_fail (AUTH_IS_DIALOG (dialog), FALSE);
613
614 gtk_widget_show (GTK_WIDGET (dialog));
615
616 while (1) {
617 gint result;
618 GSList *list;
619 gboolean needs_running = FALSE;
620
621 /* determine if we need to run the dialog */
622 for (list = dialog->priv->auth_list; list; list = list->next) {
623 AuthData *ad;
624 ad = (AuthData *) list->data;
625 if (ad->auth_widget) {
626 needs_running = TRUE;
627 break;
628 }
629 }
630
631 if (needs_running)
632 result = gtk_dialog_run (GTK_DIALOG (dialog));
633 else
634 result = GTK_RESPONSE_ACCEPT;
635
636 gtk_widget_show (dialog->priv->spinner);
637 browser_spinner_start (BROWSER_SPINNER (dialog->priv->spinner));
638
639 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT, FALSE);
640 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT, FALSE);
641
642 if (result == GTK_RESPONSE_ACCEPT) {
643 for (list = dialog->priv->auth_list; list; list = list->next) {
644 AuthData *ad;
645 ad = (AuthData *) list->data;
646 if (ad->auth_widget && !ad->jobid) {
647 GSList *plist;
648 GdaSet *set;
649 set = gdaui_basic_form_get_data_set (GDAUI_BASIC_FORM (ad->auth_widget));
650 if (ad->auth_string) {
651 g_string_free (ad->auth_string, TRUE);
652 ad->auth_string = NULL;
653 }
654 for (plist = set ? set->holders : NULL;
655 plist; plist = plist->next) {
656 GdaHolder *holder = GDA_HOLDER (plist->data);
657 const GValue *cvalue = NULL;
658 if (gda_holder_is_valid (holder))
659 cvalue = gda_holder_get_value (holder);
660 if (cvalue && (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL)) {
661 gchar *r1, *r2;
662 r1 = gda_value_stringify (cvalue);
663 r2 = gda_rfc1738_encode (r1);
664 g_free (r1);
665 if (r2) {
666 r1 = gda_rfc1738_encode (gda_holder_get_id (holder));
667 if (ad->auth_string)
668 g_string_append_c (ad->auth_string, ';');
669 else
670 ad->auth_string = g_string_new ("");
671 g_string_append (ad->auth_string, r1);
672 g_string_append_c (ad->auth_string, '=');
673 g_string_append (ad->auth_string, r2);
674
675 g_free (r1);
676 g_free (r2);
677 }
678 }
679 }
680 gtk_widget_set_sensitive (ad->auth_widget, FALSE);
681 ad->jobid = gda_thread_wrapper_execute (ad->wrapper,
682 (GdaThreadWrapperFunc) sub_thread_open_cnc,
683 (gpointer) ad,
684 (GDestroyNotify) NULL,
685 &(ad->ext.cnc_open_error));
686 if (dialog->priv->source_id == 0) {
687 dialog->priv->source_id =
688 g_timeout_add (200, (GSourceFunc) check_for_cnc, dialog);
689 }
690 }
691 }
692
693 if (dialog->priv->source_id != 0) {
694 dialog->priv->loop = g_main_loop_new (NULL, FALSE);
695 g_main_loop_run (dialog->priv->loop);
696 g_main_loop_unref (dialog->priv->loop);
697 dialog->priv->loop = NULL;
698 }
699
700 allopened = TRUE;
701 for (list = dialog->priv->auth_list; list; list = list->next) {
702 AuthData *ad;
703
704 ad = (AuthData *) list->data;
705 if (ad->auth_widget && !ad->ext.cnc) {
706 g_print ("ERROR: %s\n", ad->ext.cnc_open_error && ad->ext.cnc_open_error->message ?
707 ad->ext.cnc_open_error->message : _("No detail"));
708 browser_show_error (GTK_WINDOW (dialog), _("Could not open connection:\n%s"),
709 ad->ext.cnc_open_error && ad->ext.cnc_open_error->message ?
710 ad->ext.cnc_open_error->message : _("No detail"));
711 allopened = FALSE;
712 gtk_widget_set_sensitive (ad->auth_widget, TRUE);
713 }
714 }
715 if (allopened)
716 goto out;
717 }
718 else {
719 /* cancelled connection opening */
720 goto out;
721 }
722
723 browser_spinner_stop (BROWSER_SPINNER (dialog->priv->spinner));
724 gtk_widget_hide (dialog->priv->spinner);
725 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT, TRUE);
726 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT, TRUE);
727 }
728
729 out:
730 return allopened;
731 }
732
733
734 /**
735 * auth_dialog_get_connections
736 *
737 * Returns: a list of pointers to AuthDialogConnection structures.
738 */
739 const GSList *
auth_dialog_get_connections(AuthDialog * dialog)740 auth_dialog_get_connections (AuthDialog *dialog)
741 {
742 g_return_val_if_fail (AUTH_IS_DIALOG (dialog), NULL);
743 return dialog->priv->auth_list;
744 }
745