/* * 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(self, name) ((gpointer) gtk_builder_get_object (self, name)) typedef struct { VnLogin * self; gchar * user; gchar * pass; gchar * plugin; gchar * host; gchar * schema; gchar * ssl_ca; DbConn * conn; GThread * thread; gboolean connected; GError * error; } ConnectData; void vn_login_on_gui_logout (VnGui * gui, VnLogin * self); void vn_login_on_gui_exit (VnGui * gui, VnLogin * self); 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 (GtkApplication * application) { return g_object_new (VN_TYPE_LOGIN, "application", application, 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_free (connect_data->plugin); g_free (connect_data->host); g_free (connect_data->schema); g_free (connect_data->ssl_ca); g_object_unref (connect_data->conn); g_object_unref (connect_data->self); g_thread_unref (connect_data->thread); g_free (connect_data); } /* * Loads the resources used by the login. */ static void vn_login_load (VnLogin * self) { GError * err = NULL; GtkBuilder * builder; gchar * cfg_file; // Initializing SQLite connection cfg_file = g_build_filename (g_get_user_config_dir (), "config.db", NULL); self->cfg_conn = db_conn_new (); if (!db_conn_load_plugin (self->cfg_conn, "sqlite", &err) || !db_conn_open (self->cfg_conn, NULL, cfg_file, NULL, NULL, &err)) goto exit; // Loading interface builder = gtk_builder_new (); if (gtk_builder_add_from_file (builder, LOGIN_UI, &err)) { GSList * i; VnSet * models; models = BUILDER_GET (self->builder, "models"); if (models) for (i = vn_set_get_objects (models); i; i = i->next) db_model_set_conn (i->data, self->cfg_conn); self->window = BUILDER_GET (builder, "window"); self->user = BUILDER_GET (builder, "user"); self->pass = BUILDER_GET (builder, "password"); self->remember = BUILDER_GET (builder, "remember"); self->connect = BUILDER_GET (builder, "connect"); self->settings_button = BUILDER_GET (builder, "settings"); self->spinner = BUILDER_GET (builder, "spinner"); self->settings_dialog = BUILDER_GET (builder, "settings-dialog"); gtk_builder_connect_signals (builder, self); gtk_application_add_window (self->app, self->window); } g_object_unref (builder); // Freeing resources exit: if (err) { g_warning ("VnLogin: %s", err->message); g_clear_error (&err); } g_free (cfg_file); } /* * Shows the login window to the user. */ static void vn_login_show (VnLogin * self) { gboolean autologin = FALSE; if (!self->window) { vn_login_load (self); autologin = TRUE; } if (self->window) { gtk_widget_show_all (GTK_WIDGET (self->window)); gtk_widget_grab_focus (GTK_WIDGET (self->user)); if (autologin) gtk_button_clicked (self->connect); } } /* * Enables/disables the spinner at login dialog. */ static void vn_login_set_loading (VnLogin * self, gboolean loading) { gtk_widget_set_sensitive (GTK_WIDGET (self->connect), !loading); gtk_widget_set_sensitive (GTK_WIDGET (self->settings_button), !loading); gtk_widget_set_sensitive (GTK_WIDGET (self->user), !loading); gtk_widget_set_sensitive (GTK_WIDGET (self->pass), !loading); gtk_widget_set_sensitive (GTK_WIDGET (self->remember), !loading); if (loading) { gtk_widget_show (self->spinner); gtk_widget_hide (GTK_WIDGET (self->connect)); } else { gtk_widget_hide (self->spinner); gtk_widget_show (GTK_WIDGET (self->connect)); } } /* * Frees the GUI object. */ static void vn_login_free_gui (VnLogin * self) { if (self->gui) { g_object_disconnect (self->gui ,"any_signal", vn_login_on_gui_exit, self ,"any_signal", vn_login_on_gui_logout, self ,NULL ); g_clear_object (&self->gui); } } /* * Shows the settings dialog. */ void vn_login_on_settings_clicked (GtkButton * button, VnLogin * self) { gtk_dialog_run (self->settings_dialog); } /* * Hides the settings dialog. */ void vn_login_on_settings_cancel_clicked (GtkButton * button, VnLogin * self) { gtk_widget_hide (GTK_WIDGET (self->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_on_settings_apply_clicked (GtkButton * button, VnLogin * self) { gtk_widget_hide (GTK_WIDGET (self->settings_dialog)); } /* * Shows the login dialog when user logout from GUI. */ void vn_login_on_gui_logout (VnGui * gui, VnLogin * self) { g_settings_set_string (self->settings, "pass", ""); vn_login_free_gui (self); vn_login_show (self); } /* * Destroys the login dialog when user exits from GUI. */ void vn_login_on_gui_exit (VnGui * gui, VnLogin * self) { vn_login_free_gui (self); gtk_widget_destroy (GTK_WIDGET (self->window)); } /* * Saves the login information and opens the main GUI. */ static gboolean vn_login_done (ConnectData * connect_data) { VnLogin * self = connect_data->self; if (connect_data->connected) { db_iterator_set_value (self->config, "user", gvn_param_get_value (self->user), NULL); db_iterator_set_value (self->config, "remember", gvn_param_get_value (self->remember), NULL); if (gvn_param_get_boolean (self->remember)) { GValue encoded = G_VALUE_INIT; g_value_take_string (&encoded, gvn_encode (gvn_param_get_string (self->pass))); db_iterator_set_value (self->config, "password", &encoded, NULL); g_value_unset (&encoded); } gvn_param_set_null (self->pass); gtk_widget_hide (GTK_WIDGET (self->window)); self->gui = vn_gui_new (self->app, connect_data->conn); g_object_connect (self->gui ,"signal::logout", vn_login_on_gui_logout, self ,"signal::exit", vn_login_on_gui_exit, self ,NULL ); vn_gui_open (self->gui); } else { GtkWidget * dialog; dialog = gtk_message_dialog_new (self->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 (self->pass, ""); } gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog)); vn_login_show (self); } vn_login_set_loading (self, FALSE); return G_SOURCE_REMOVE; } /* * Thread function that tries to open the connection asynchronously. */ static void vn_login_thread (ConnectData * connect_data) { VnLogin * self = connect_data->self; if (IS_DEFINED (connect_data->plugin) && IS_DEFINED (connect_data->schema)) { if (db_conn_load_plugin (connect_data->conn, connect_data->plugin, &connect_data->error)) { if (IS_DEFINED (connect_data->ssl_ca)) db_conn_set_ssl (connect_data->conn, connect_data->ssl_ca); connect_data->connected = db_conn_open (connect_data->conn ,connect_data->host ,connect_data->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_idle_add_full (G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) vn_login_done, connect_data, (GDestroyNotify) connect_data_free); } /* * Opens the connection. */ void vn_login_on_connect_clicked (GtkButton * button, VnLogin * self) { ConnectData * connect_data; vn_login_set_loading (self, TRUE); connect_data = g_new (ConnectData, 1); connect_data->self = g_object_ref (self); connect_data->user = g_strdup (gvn_param_get_string (self->user)); connect_data->pass = g_strdup (gvn_param_get_string (self->pass)); connect_data->plugin = g_strdup (db_iterator_get_string (self->config, "plugin")); connect_data->host = g_strdup (db_iterator_get_string (self->config, "host")); connect_data->schema = g_strdup (db_iterator_get_string (self->config, "schema")); connect_data->ssl_ca = g_strdup (db_iterator_get_string (self->config, "ssl_ca")); 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); } /* * Sets the default user and password for selected configuration. */ static void vn_login_on_server_changed (VnLogin * self) { const GValue * pass = db_iterator_get_value (self->config, "password"); gvn_param_set_value (self->user, db_iterator_get_value (self->config, "user")); gvn_param_set_value (self->remember, db_iterator_get_value (self->config, "remember")); if (!gvn_value_is_null (pass)) { GValue decoded = G_VALUE_INIT; g_value_take_string (&decoded, gvn_decode (g_value_get_string (pass))); gvn_param_set_value (self->pass, &decoded); g_value_unset (&decoded); } else gvn_param_set_value (self->pass, pass); } /* * Closes the application when login window is destroyed. */ void vn_login_on_destroyed (GtkWidget * window, VnLogin * self) { self->window = NULL; gtk_main_quit (); } void vn_login_on_pass_show (GtkEntry * entry, GtkEntryIconPosition * pos, GdkEvent * event, VnLogin * self) { gtk_entry_set_visibility (entry, TRUE); } void vn_login_on_pass_hide (GtkEntry * entry, GtkEntryIconPosition * pos, GdkEvent * event, VnLogin * self) { gtk_entry_set_visibility (entry, FALSE); } static void vn_login_on_startup (GApplication * app, VnLogin * self) { g_object_set (gtk_settings_get_default (), "gtk-button-images", TRUE, NULL); } static void vn_login_on_activate (GApplication * app, VnLogin * self) { if (gtk_main_level () == 0) { vn_login_show (self); gtk_main (); } else if (!self->gui) gtk_window_present (self->window); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties enum { PROP_APPLICATION = 1 }; static void vn_login_set_property (VnLogin * self, guint id, const GValue * value, GParamSpec * pspec) { switch (id) { case PROP_APPLICATION: { self->app = g_value_dup_object (value); g_object_connect (self->app ,"signal::startup", vn_login_on_startup, self ,"signal::activate", vn_login_on_activate, self ,NULL ); self->settings = g_settings_new ( g_application_get_application_id (G_APPLICATION (self->app))); break; } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (self, id, pspec); } } static void vn_login_get_property (VnLogin * self, guint id, GValue * value, GParamSpec * pspec) { switch (id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (self, id, pspec); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Class static void vn_login_init (VnLogin * self) { self->gui = NULL; self->window = NULL; self->settings = NULL; self->app = NULL; self->cfg_conn = NULL; } static void vn_login_finalize (VnLogin * self) { vn_login_free_gui (self); g_object_disconnect (self->app ,"any_signal", vn_login_on_startup, self ,"any_signal", vn_login_on_activate, self ,NULL ); g_clear_object (&self->cfg_conn); g_clear_object (&self->settings); g_clear_object (&self->app); G_OBJECT_CLASS (vn_login_parent_class)->finalize (G_OBJECT (self)); } 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, g_param_spec_object ("application" ,_("Application") ,_("The application") ,GTK_TYPE_APPLICATION ,G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY )); }