/* * Copyright (C) 2012 - Juan Ferrer Toribio * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "vn-login.h" #define LOGIN_UI _GUI_DIR"/login.glade" #define IS_DEFINED(string) (string && g_strcmp0 (string, "")) #define BUILDER_GET(obj, name) ((gpointer) gtk_builder_get_object (obj, name)) typedef struct { VnLogin * obj; gchar * user; gchar * pass; DbConn * conn; GThread * thread; gboolean connected; GError * error; } ConnectData; void vn_login_cb_gui_logout (VnGui * gui, VnLogin * obj); void vn_login_cb_gui_exit (VnGui * gui, VnLogin * obj); G_DEFINE_TYPE (VnLogin, vn_login, G_TYPE_OBJECT); /** * vn_login_new: * * Creates a new Gui object. * * Return value: the created #VnLogin **/ VnLogin * vn_login_new (const gchar * application_id) { return g_object_new (VN_TYPE_LOGIN, "application-id", application_id, NULL); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Private /* * Frees the #ConnectData struct */ void connect_data_free (ConnectData * connect_data) { if (connect_data->error) g_error_free (connect_data->error); g_free (connect_data->user); g_free (connect_data->pass); g_object_unref (connect_data->conn); g_object_unref (connect_data->obj); g_thread_unref (connect_data->thread); g_free (connect_data); } /* * Shows the login window to the user. */ static void vn_login_show (VnLogin * obj) { gboolean autologin = FALSE; if (!obj->window) { gchar * user; gchar * pass; GError * err = NULL; GtkBuilder * builder = gtk_builder_new (); if (gtk_builder_add_from_file (builder, LOGIN_UI, &err)) { obj->window = BUILDER_GET (builder, "window"); obj->user = BUILDER_GET (builder, "user"); obj->pass = BUILDER_GET (builder, "password"); obj->remember = BUILDER_GET (builder, "remember"); obj->connect = BUILDER_GET (builder, "connect"); obj->settings_button = BUILDER_GET (builder, "settings"); obj->spinner = BUILDER_GET (builder, "spinner"); obj->settings_dialog = BUILDER_GET (builder, "settings-dialog"); obj->plugin = BUILDER_GET (builder, "plugin"); obj->host = BUILDER_GET (builder, "host"); obj->schema = BUILDER_GET (builder, "schema"); obj->ssl_ca = BUILDER_GET (builder, "ssl-ca"); gtk_builder_connect_signals (builder, obj); user = g_settings_get_string (obj->settings, "user"); pass = g_settings_get_string (obj->settings, "pass"); if (user && g_strcmp0 (user, "")) gtk_entry_set_text (obj->user, user); if (pass && g_strcmp0 (pass, "")) { gchar * aux = pass; pass = gvn_decode (aux); gtk_entry_set_text (obj->pass, pass); gtk_toggle_button_set_active (obj->remember, TRUE); g_free (aux); autologin = TRUE; } g_free (user); g_free (pass); } else if (err) { g_warning ("VnLogin: %s", err->message); g_clear_error (&err); } g_object_unref (builder); } gtk_widget_show_all (GTK_WIDGET (obj->window)); gtk_widget_grab_focus (GTK_WIDGET (obj->user)); if (autologin) gtk_button_clicked (obj->connect); } /* * Enables/disables the #GtkSpinner at login dialog. */ static void vn_login_set_loading (VnLogin * obj, gboolean loading) { gtk_widget_set_sensitive (GTK_WIDGET (obj->connect), !loading); gtk_widget_set_sensitive (GTK_WIDGET (obj->settings_button), !loading); gtk_widget_set_sensitive (GTK_WIDGET (obj->user), !loading); gtk_widget_set_sensitive (GTK_WIDGET (obj->pass), !loading); gtk_widget_set_sensitive (GTK_WIDGET (obj->remember), !loading); if (loading) { gtk_widget_show (obj->spinner); gtk_widget_hide (GTK_WIDGET (obj->connect)); } else { gtk_widget_hide (obj->spinner); gtk_widget_show (GTK_WIDGET (obj->connect)); } } /* * Frees the GUI object. */ static void vn_login_free_gui (VnLogin * obj) { if (obj->gui) { g_object_disconnect (obj->gui ,"any_signal", vn_login_cb_gui_exit, obj ,"any_signal", vn_login_cb_gui_logout, obj ,NULL ); g_clear_object (&obj->gui); } } /* * Shows the settings dialog. */ void vn_login_cb_settings_clicked (GtkButton * button, VnLogin * obj) { gchar * plugin = g_settings_get_string (obj->settings, "plugin"); gchar * host = g_settings_get_string (obj->settings, "host"); gchar * schema = g_settings_get_string (obj->settings, "schema"); gchar * ssl_ca = g_settings_get_string (obj->settings, "ssl-ca"); gtk_entry_set_text (obj->plugin, plugin); gtk_entry_set_text (obj->host, host); gtk_entry_set_text (obj->schema, schema); gtk_entry_set_text (obj->ssl_ca, ssl_ca); gtk_dialog_run (obj->settings_dialog); g_free (plugin); g_free (host); g_free (schema); g_free (ssl_ca); } /* * Hides the settings dialog. */ void vn_login_cb_settings_cancel_clicked (GtkButton * button, VnLogin * obj) { gtk_widget_hide (GTK_WIDGET (obj->settings_dialog)); } /* * Hides the settings dialog when escape is pressed. */ void vn_login_settings_on_delete_event (GtkWidget * settings_dialog) { gtk_widget_hide (settings_dialog); } /* * Applies the changes made on settings dialog. */ void vn_login_cb_settings_apply_clicked (GtkButton * button, VnLogin * obj) { const gchar * plugin = gtk_entry_get_text (obj->plugin); const gchar * host = gtk_entry_get_text (obj->host); const gchar * schema = gtk_entry_get_text (obj->schema); const gchar * ssl_ca = gtk_entry_get_text (obj->ssl_ca); g_settings_set_string (obj->settings, "plugin", plugin); g_settings_set_string (obj->settings, "host", host); g_settings_set_string (obj->settings, "schema", schema); g_settings_set_string (obj->settings, "ssl-ca", ssl_ca); gtk_widget_hide (GTK_WIDGET (obj->settings_dialog)); } /* * Shows the login dialog when user logout from GUI. */ void vn_login_cb_gui_logout (VnGui * gui, VnLogin * obj) { g_settings_set_string (obj->settings, "pass", ""); vn_login_free_gui (obj); vn_login_show (obj); } /* * Destroys the login dialog when user exits from GUI. */ void vn_login_cb_gui_exit (VnGui * gui, VnLogin * obj) { vn_login_free_gui (obj); gtk_widget_destroy (GTK_WIDGET (obj->window)); } /* * Saves the login information and opens the main GUI. */ static gboolean vn_login_done (ConnectData * connect_data) { VnLogin * obj = connect_data->obj; if (connect_data->connected) { const gchar * user; user = gtk_entry_get_text (obj->user); g_settings_set_string (obj->settings, "user", user); if (gtk_toggle_button_get_active (obj->remember)) { const gchar * pass = gtk_entry_get_text (obj->pass); gchar * aux = gvn_encode (pass); gtk_toggle_button_set_active (obj->remember, FALSE); g_settings_set_string (obj->settings, "pass", aux); g_free (aux); } gtk_entry_set_text (obj->pass, ""); gtk_widget_hide (GTK_WIDGET (obj->window)); obj->gui = vn_gui_new (obj->app, connect_data->conn); g_object_connect (obj->gui ,"signal::logout", vn_login_cb_gui_logout, obj ,"signal::exit", vn_login_cb_gui_exit, obj ,NULL ); vn_gui_open (obj->gui); } else { GtkWidget * dialog; dialog = gtk_message_dialog_new (obj->window ,GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT ,GTK_MESSAGE_ERROR ,GTK_BUTTONS_OK ,_("Login error") ); gtk_window_set_title (GTK_WINDOW (dialog), _("Login error")); if (connect_data->error) { gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", connect_data->error->message); if (connect_data->error->code == DB_CONN_ERROR_BAD_LOGIN) gtk_entry_set_text (obj->pass, ""); } gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog)); vn_login_show (obj); } vn_login_set_loading (obj, FALSE); return G_SOURCE_REMOVE; } /* * Thread function that tries to open the connection asynchronously. */ static void vn_login_thread (ConnectData * connect_data) { gchar * plugin; gchar * host; gchar * schema; gchar * ssl_ca; VnLogin * obj = connect_data->obj; plugin = g_settings_get_string (obj->settings, "plugin"); host = g_settings_get_string (obj->settings, "host"); schema = g_settings_get_string (obj->settings, "schema"); ssl_ca = g_settings_get_string (obj->settings, "ssl-ca"); if (IS_DEFINED (plugin) && IS_DEFINED (host) && IS_DEFINED (schema)) { if (db_conn_load_plugin (connect_data->conn, plugin, &connect_data->error)) { if (IS_DEFINED (ssl_ca)) db_conn_set_ssl (connect_data->conn, ssl_ca); connect_data->connected = db_conn_open (connect_data->conn ,host ,schema ,connect_data->user ,connect_data->pass ,&connect_data->error ); } } else connect_data->error = g_error_new ( VN_LOGIN_LOG_DOMAIN ,VN_LOGIN_ERR_BAD_SETTINGS ,_("Bad connection settings, please check it.") ); g_free (plugin); g_free (host); g_free (schema); g_free (ssl_ca); g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) vn_login_done, connect_data, (GDestroyNotify) connect_data_free); } /* * Opens the connection. */ void vn_login_cb_connect_clicked (GtkButton * button, VnLogin * obj) { ConnectData * connect_data; vn_login_set_loading (obj, TRUE); connect_data = g_new (ConnectData, 1); connect_data->obj = g_object_ref (obj); connect_data->user = g_strdup (gtk_entry_get_text (obj->user)); connect_data->pass = g_strdup (gtk_entry_get_text (obj->pass)); connect_data->conn = db_conn_new (); connect_data->connected = FALSE; connect_data->error = NULL; connect_data->thread = g_thread_new ("vn-login", (GThreadFunc) vn_login_thread, connect_data); } /* * Closes the application when login window is destroyed. */ void vn_login_cb_destroyed (GtkWidget * window, VnLogin * obj) { obj->window = NULL; gtk_main_quit (); } void vn_login_cb_pass_show (GtkEntry * entry, GtkEntryIconPosition * pos, GdkEvent * event, VnLogin * obj) { gtk_entry_set_visibility (entry, TRUE); } void vn_login_cb_pass_hide (GtkEntry * entry, GtkEntryIconPosition * pos, GdkEvent * event, VnLogin * obj) { gtk_entry_set_visibility (entry, FALSE); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public /** * vn_login_run: * @obj: a #VnLogin * * Starts the main gui application. **/ void vn_login_run (VnLogin * obj) { GApplication * app; g_return_if_fail (VN_IS_LOGIN (obj)); app = G_APPLICATION (obj->app); if (g_application_register (app, NULL, NULL) && !g_application_get_is_remote (app)) { g_object_set (gtk_settings_get_default (), "gtk-button-images", TRUE, NULL); vn_login_show (obj); gtk_main (); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties enum { PROP_APPLICATION_ID = 1 }; static void vn_login_set_property (VnLogin * obj, guint id, const GValue * value, GParamSpec * pspec) { switch (id) { case PROP_APPLICATION_ID: { const gchar * id = g_value_get_string (value); obj->app = gtk_application_new (id, G_APPLICATION_FLAGS_NONE); obj->settings = g_settings_new (id); break; } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); } } static void vn_login_get_property (VnLogin * obj, guint id, GValue * value, GParamSpec * pspec) { switch (id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Class static void vn_login_init (VnLogin * obj) { obj->gui = NULL; obj->window = NULL; obj->settings = NULL; obj->app = NULL; } static void vn_login_finalize (VnLogin * obj) { vn_login_free_gui (obj); g_clear_object (&obj->settings); g_clear_object (&obj->app); G_OBJECT_CLASS (vn_login_parent_class)->finalize (G_OBJECT (obj)); } static void vn_login_class_init (VnLoginClass * k) { GObjectClass * klass = G_OBJECT_CLASS (k); klass->finalize = (GObjectFinalizeFunc) vn_login_finalize; klass->set_property = (GObjectSetPropertyFunc) vn_login_set_property; klass->get_property = (GObjectGetPropertyFunc) vn_login_get_property; g_object_class_install_property (klass, PROP_APPLICATION_ID, g_param_spec_string ("application-id" ,_("Application id") ,_("The application identifier") ,"app.default" ,G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY )); }