/* PureAdmin * Copyright (C) 2003 Isak Savo * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * Preferences management - the GUI-part. * * Copyright (C) 2003 - Isak Savo */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include "cfg.h" #include "prefwin.h" #include "helper.h" #include "gui_helper.h" #include "logfile.h" #include "globals.h" #include "system_accounts.h" #include "dirbrowser.h" static void prefwin_menu_gid_changed (GtkOptionMenu *optionmenu, gpointer user_data); static void prefwin_menu_uid_changed (GtkOptionMenu *optionmenu, gpointer user_data); static void prefwin_rdo_toggled (GtkToggleButton *togglebutton, gpointer user_data); static void prefwin_entry_changed (GtkEditable *editable, gpointer user_data); static void prefwin_btn_search_clicked (GtkButton *button, gpointer user_data); static void prefwin_chkbtn_toggled (GtkToggleButton *togglebutton, gpointer user_data); static void prefwin_chkencoding_toggled (GtkToggleButton *togglebutton, gpointer user_data); static void prefwin_btn_browse_clicked (GtkButton *button, GtkWidget *entry); static void prefwin_btn_browse_home_clicked (GtkButton *button, gpointer user_data); static void prefwin_btn_encoding_sel_clicked (GtkButton *button, gpointer user_data); GladeXML *pref_xml = NULL; prefwin_widgets *prefwin_get_widgets (void) { static prefwin_widgets *w = NULL; if (G_UNLIKELY (!w)) { w = g_new0 (prefwin_widgets, 1); w->menu_uid = PW("opt_menu_uid"); w->menu_gid = PW("opt_menu_gid"); w->home = PW("entry_home"); w->cmd_purepw = PW("entry_purepw_cmd"); w->pwfile = PW("entry_passwd_file"); w->pdbfile = PW("entry_pdb_file"); w->encoding = PW("entry_encoding"); w->btn_search = PW("btn_search_set_defaults"); w->rdo_syslog = PW("rdo_syslog"); w->rdo_custom = PW("rdo_custom"); w->logfile = PW("entry_logfile"); w->chk_resolve = PW("chk_resolve_hostnames"); w->btn_home_browse = PW("btn_home_dir_browse"); w->btn_encoding_sel = PW("btn_encoding_sel"); w->chk_save_window_geo = PW("chk_save_window_geo"); w->chk_use_system_encoding = PW("chk_use_system_encoding"); w->chk_use_tray_icon = PW("chk_use_tray_icon"); w->chk_always_notify = PW("chk_always_notify"); w->btn_browse_purepw = PW("btn_browse_purepw"); w->btn_browse_pw = PW("btn_browse_pw"); w->btn_browse_pdb = PW("btn_browse_pdb"); } return w; } void prefwin_close (GtkWidget *w, gpointer data) { cfg_write_settings (); } static GtkWidget *create_prefwin (void) { gchar *our_path; our_path = g_build_filename (datadir, PACKAGE, "prefwin.glade", NULL); pref_xml = glade_xml_new (our_path, NULL, NULL); g_free (our_path); /* FIXME: autoconnect? */ return PW("preferences"); } GtkWidget *pref_init_prefwindow (GtkWidget *parent) { prefwin_widgets *w; GList *id; GtkWidget *menu; static GtkWidget *prefwin = NULL; gint i; if (!prefwin) prefwin = create_prefwin (); else return prefwin; w = prefwin_get_widgets (); /* GID/UID Option menus */ id = sys_get_user_ids (); menu = gui_create_system_account_menu(id); gtk_option_menu_remove_menu (GTK_OPTION_MENU (w->menu_uid)); gtk_option_menu_set_menu (GTK_OPTION_MENU (w->menu_uid), menu); /* Keep the list attached to the menu so that it's available in the callbacks.. */ g_object_set_data (G_OBJECT (w->menu_uid), "items", id); i = 0; while (id) { if (cfg.default_uid == ((SystemAccount*) id->data)->id) break; i++; id = g_list_next (id); } gtk_option_menu_set_history (GTK_OPTION_MENU (w->menu_uid), i); id = sys_get_group_ids (); menu = gui_create_system_account_menu(id); gtk_option_menu_remove_menu (GTK_OPTION_MENU (w->menu_gid)); gtk_option_menu_set_menu (GTK_OPTION_MENU (w->menu_gid), menu); g_object_set_data_full (G_OBJECT (w->menu_gid), "items", id, (GDestroyNotify) system_account_list_free); i = 0; while (id) { if (cfg.default_gid == ((SystemAccount*) id->data)->id) break; i++; id = g_list_next (id); } gtk_option_menu_set_history (GTK_OPTION_MENU (w->menu_gid), i); if (cfg.logmethod == LOG_SYSLOG) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->rdo_syslog), TRUE); else gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->rdo_custom), TRUE); gtk_entry_set_text (GTK_ENTRY (w->home), cfg.default_home); gtk_entry_set_text (GTK_ENTRY (w->encoding), cfg.uname_encoding); gtk_entry_set_text (GTK_ENTRY (w->cmd_purepw), cfg.cmd_purepw); gtk_entry_set_text (GTK_ENTRY (w->pwfile), cfg.pwfile); gtk_entry_set_text (GTK_ENTRY (w->pdbfile), cfg.pdbfile); gtk_entry_set_text (GTK_ENTRY (w->logfile), cfg.logfile); /* Use these paths as a fallback for the fileselector */ g_object_set_data (G_OBJECT(w->cmd_purepw), "default_path", "/usr/bin/"); g_object_set_data (G_OBJECT(w->pwfile), "default_path", "/etc/"); g_object_set_data (G_OBJECT(w->pdbfile), "default_path", "/etc/"); /* Used to hint the file selector on the type of file we're selecting */ g_object_set_data (G_OBJECT(w->cmd_purepw), "whatfile", _("pure-pw executable")); g_object_set_data (G_OBJECT(w->pwfile), "whatfile", _("password file")); g_object_set_data (G_OBJECT(w->pdbfile), "whatfile", _("database file")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->chk_resolve), cfg.resolve_hostnames); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->chk_save_window_geo), cfg.save_window_geometry); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->chk_use_tray_icon), cfg.use_tray_icon); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->chk_always_notify), cfg.always_notify_activities); g_signal_connect ((gpointer) w->chk_use_system_encoding, "toggled", G_CALLBACK (prefwin_chkencoding_toggled), NULL); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->chk_use_system_encoding), cfg.use_system_encoding); /* Hookup signals for the widgets to allow 'instant-apply' */ g_signal_connect ((gpointer) w->menu_uid, "changed", G_CALLBACK (prefwin_menu_uid_changed), NULL); g_signal_connect ((gpointer) w->menu_gid, "changed", G_CALLBACK (prefwin_menu_gid_changed), NULL); g_signal_connect ((gpointer) w->home, "changed", G_CALLBACK (prefwin_entry_changed), "home"); g_signal_connect ((gpointer) w->encoding, "changed", G_CALLBACK (prefwin_entry_changed), "encoding"); g_signal_connect ((gpointer) w->cmd_purepw, "changed", G_CALLBACK (prefwin_entry_changed), "cmd_purepw"); g_signal_connect ((gpointer) w->pwfile, "changed", G_CALLBACK (prefwin_entry_changed), "pwfile"); g_signal_connect ((gpointer) w->pdbfile, "changed", G_CALLBACK (prefwin_entry_changed), "pdbfile"); g_signal_connect ((gpointer) w->rdo_syslog, "toggled", G_CALLBACK (prefwin_rdo_toggled), GINT_TO_POINTER (LOG_SYSLOG)); g_signal_connect ((gpointer) w->rdo_custom, "toggled", G_CALLBACK (prefwin_rdo_toggled), GINT_TO_POINTER (LOG_CUSTOM)); g_signal_connect ((gpointer) w->logfile, "changed", G_CALLBACK (prefwin_entry_changed), "logfile"); g_signal_connect ((gpointer) w->chk_resolve, "toggled", G_CALLBACK (prefwin_chkbtn_toggled), "resolve"); g_signal_connect ((gpointer) w->chk_use_tray_icon, "toggled", G_CALLBACK (prefwin_chkbtn_toggled), "use_tray_icon"); g_signal_connect ((gpointer) w->chk_always_notify, "toggled", G_CALLBACK (prefwin_chkbtn_toggled), "always_notify_activities"); g_signal_connect ((gpointer) w->chk_save_window_geo, "toggled", G_CALLBACK (prefwin_chkbtn_toggled), "save_window"); /* Button Callbacks */ g_signal_connect ((gpointer) w->btn_search, "clicked", G_CALLBACK (prefwin_btn_search_clicked), NULL); g_signal_connect ((gpointer) w->btn_encoding_sel, "clicked", G_CALLBACK (prefwin_btn_encoding_sel_clicked), NULL); g_signal_connect ((gpointer) w->btn_home_browse, "clicked", G_CALLBACK (prefwin_btn_browse_home_clicked), NULL); g_signal_connect ((gpointer) w->btn_browse_purepw, "clicked", G_CALLBACK (prefwin_btn_browse_clicked), (gpointer) w->cmd_purepw); g_signal_connect ((gpointer) w->btn_browse_pw, "clicked", G_CALLBACK (prefwin_btn_browse_clicked), (gpointer) w->pwfile); g_signal_connect ((gpointer) w->btn_browse_pdb, "clicked", G_CALLBACK (prefwin_btn_browse_clicked), (gpointer) w->pdbfile); /* Signals for the prefwindow actual prefwindow */ g_signal_connect_swapped (G_OBJECT (PW("btn_prefwin_close")), "clicked", G_CALLBACK (gtk_widget_hide), (gpointer) prefwin); g_signal_connect (G_OBJECT (prefwin), "delete-event", G_CALLBACK (gtk_widget_hide), NULL); g_signal_connect (G_OBJECT (prefwin), "hide", G_CALLBACK (prefwin_close), NULL); gtk_window_set_transient_for (GTK_WINDOW (prefwin), GTK_WINDOW (parent)); return prefwin; } static void prefwin_menu_gid_changed (GtkOptionMenu *optionmenu, gpointer user_data) { GList *id; gint node_no; id = (GList *) g_object_get_data (G_OBJECT (optionmenu), "items"); node_no = gtk_option_menu_get_history (optionmenu); id = g_list_nth (id, node_no); if (!id) g_print ("Gid change: Wrong history: %d\n", node_no); } static void prefwin_menu_uid_changed (GtkOptionMenu *optionmenu, gpointer user_data) { GList *id; gint node_no; id = (GList *) g_object_get_data (G_OBJECT (optionmenu), "items"); node_no = gtk_option_menu_get_history (optionmenu); id = g_list_nth (id, node_no); if (!id) g_print ("Uid change: Wrong history: %d\n", node_no); } static void prefwin_rdo_toggled (GtkToggleButton *togglebutton, gpointer user_data) { GtkWidget *entry; if (!gtk_toggle_button_get_active (togglebutton)) return; entry = PW("entry_logfile"); cfg.logmethod = GPOINTER_TO_INT (user_data); switch (GPOINTER_TO_INT (user_data)) { case LOG_SYSLOG: /* Syslog selected */ gtk_entry_set_text (GTK_ENTRY (entry), "/var/log/messages"); break; case LOG_CUSTOM: /* Custom selected */ gtk_entry_set_text (GTK_ENTRY (entry), "/var/log/pureftpd.log"); break; } } static void prefwin_chkbtn_toggled (GtkToggleButton *togglebutton, gpointer user_data) { gchar *arg = (gchar *) user_data; gboolean toggled = gtk_toggle_button_get_active (togglebutton); if (g_str_equal (arg, "resolve")) cfg.resolve_hostnames = toggled; else if (g_str_equal (arg, "save_window")) cfg.save_window_geometry = toggled; else if (g_str_equal (arg, "use_tray_icon")) { if (!toggled) /* Remove it if it's shown */ hide_status_icon (); cfg.use_tray_icon = toggled; } else if (g_str_equal (arg, "always_notify_activities")) cfg.always_notify_activities = toggled; } static void prefwin_chkencoding_toggled (GtkToggleButton *togglebutton, gpointer user_data) { prefwin_widgets *w; gboolean active; w = prefwin_get_widgets (); active = gtk_toggle_button_get_active (togglebutton); cfg.use_system_encoding = active; gtk_widget_set_sensitive (w->encoding, !active); gtk_widget_set_sensitive (w->btn_encoding_sel, !active); } static void prefwin_entry_changed (GtkEditable *editable, gpointer user_data) { gchar *tmp; gchar *ename; ename = (gchar *) user_data; tmp = gtk_editable_get_chars (GTK_EDITABLE (editable), 0, -1); /* g_print ("Entry [%s] changed into: %s\n", ename, tmp); */ if (g_str_equal (ename, "home")) { g_free (cfg.default_home); cfg.default_home = tmp; } else if (g_str_equal (ename, "cmd_purepw")) { g_free (cfg.cmd_purepw); cfg.cmd_purepw = tmp; } else if (g_str_equal (ename, "pwfile")) { g_free (cfg.pwfile); cfg.pwfile = tmp; } else if (g_str_equal (ename, "pdbfile")) { g_free (cfg.pdbfile); cfg.pdbfile = tmp; } else if (g_str_equal(ename, "logfile")) { if (g_path_is_absolute (tmp) && g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) { close_logfile (); g_free (cfg.logfile); cfg.logfile = tmp; init_logfile (); } else g_free (tmp); } else if (g_str_equal (ename, "encoding")) { g_free (cfg.uname_encoding); cfg.uname_encoding = tmp; } else g_free (tmp); } static void prefwin_btn_search_clicked (GtkButton *button, gpointer user_data) { gchar *tmp; prefwin_widgets *w; w = prefwin_get_widgets (); tmp = g_find_program_in_path ("pure-pw"); gtk_entry_set_text (GTK_ENTRY (w->cmd_purepw), tmp ? tmp : _("Not Found")); g_free (tmp); tmp = cfg_find_pwfile (); gtk_entry_set_text (GTK_ENTRY (w->pwfile), tmp ? tmp : _("Not Found")); g_free (tmp); tmp = cfg_find_pdbfile (); gtk_entry_set_text (GTK_ENTRY (w->pdbfile), tmp ? tmp : _("Not Found")); g_free (tmp); } static void store_filename (GtkWidget *widget, GtkWidget *fs) { GtkWidget *entry; const gchar *selected_filename; entry = (GtkWidget *) g_object_get_data (G_OBJECT (fs), "affected_entry"); selected_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)); gtk_entry_set_text (GTK_ENTRY (entry), selected_filename); } static GtkWidget *create_fileselector (const gchar *title, const gchar *preselected) { GtkWidget *file_selector; file_selector = gtk_file_selection_new (title); g_signal_connect (GTK_FILE_SELECTION (file_selector)->ok_button, "clicked", G_CALLBACK (store_filename), file_selector); /* Ensure that the dialog box is destroyed when the user clicks a button. */ g_signal_connect_swapped (GTK_FILE_SELECTION (file_selector)->ok_button, "clicked", G_CALLBACK (gtk_widget_destroy), file_selector); g_signal_connect_swapped (GTK_FILE_SELECTION (file_selector)->cancel_button, "clicked", G_CALLBACK (gtk_widget_destroy), file_selector); gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_selector), preselected); gtk_window_set_transient_for (GTK_WINDOW (file_selector), GTK_WINDOW (PW("preferences"))); return file_selector; } static void prefwin_btn_browse_clicked (GtkButton *button, GtkWidget *entry) { prefwin_widgets *w; GtkWidget *fs; gchar *title; w = prefwin_get_widgets (); /* Translators: %s will expand to the type of file. For instance, 'password file' or 'database file'. * This is used as title for the file selector. */ title = g_strdup_printf (_("Please select %s"), (gchar *) g_object_get_data (G_OBJECT (entry), "whatfile")); if (strlen (gtk_entry_get_text (GTK_ENTRY (entry))) > 0) fs = create_fileselector (title, gtk_entry_get_text (GTK_ENTRY (entry))); else fs = create_fileselector (title, g_object_get_data (G_OBJECT(entry), "default_path")); g_object_set_data (G_OBJECT (fs), "affected_entry", (gpointer) entry); gtk_widget_show (fs); } static void prefwin_btn_browse_home_clicked (GtkButton *button, gpointer user_data) { prefwin_widgets *w; GtkWidget *dbr; const gchar *dir; gint response; w = prefwin_get_widgets (); dbr = dirbrowser_new (_("Select Default Home Directory")); if (g_file_test (cfg.default_home, G_FILE_TEST_IS_DIR)) dirbrowser_set_directory (DIRBROWSER (dbr), cfg.default_home); response = gtk_dialog_run (GTK_DIALOG (dbr)); if (response == GTK_RESPONSE_OK) { dir = dirbrowser_get_directory (DIRBROWSER (dbr)); gtk_entry_set_text (GTK_ENTRY (w->home), dir); } gtk_widget_destroy (dbr); } static void encoding_changed_cb (GtkTreeView *tree, gpointer user_data) { GtkEntry *entry = GTK_ENTRY (user_data); GtkTreeModel *model; GtkTreeSelection *sel; GtkTreeIter iter; gchar *encoding; g_print ("encoding changed\n"); sel = gtk_tree_view_get_selection (tree); model = gtk_tree_view_get_model (tree); if (gtk_tree_selection_get_selected (sel, &model, &iter)) { gtk_tree_model_get (model, &iter, 0, &encoding, -1); gtk_entry_set_text (entry, encoding); } return; } static GList * get_available_encodings (void) { GList *retval = NULL; #define BUFSIZE 256 gchar buf[BUFSIZE], *tmp; gchar *prgm, *full_prgm; FILE *p; if (!(prgm = g_find_program_in_path ("iconv"))) { pur_log_wrn ("Couldn't find the program \"iconv\". Unable to fetch list of encodings"); return NULL; } full_prgm = g_strdup_printf ("%s --list", prgm); g_free (prgm); if ((p = popen (full_prgm, "r")) == NULL) { pur_log_wrn ("popen %s: %s", full_prgm, strerror(errno)); return NULL; } g_free (full_prgm); while (fgets (buf, BUFSIZE, p)) { if (!strstr (buf, "//")) continue; tmp = buf; while (tmp){ if (*tmp == '/' && *(tmp +1) == '/') { *tmp = '\0'; break; } tmp++; } g_strstrip (buf); retval = g_list_append (retval, g_strdup (buf)); } pclose (p); return retval; } static void free_encoding_list (GtkWidget *w, gpointer list) { g_list_free ((GList *) list); } static void filter_encoding_list (GtkWidget *entry, gpointer data) { GtkTreeView *tree = GTK_TREE_VIEW (data); GtkTreeIter iter, iter_sel; GtkListStore *model; GList *list; gint handler_id; const gchar *filter_str, *encoding; gboolean sel = FALSE; filter_str = gtk_entry_get_text (GTK_ENTRY(entry)); handler_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree), "callback_handler_id")); list = g_object_get_data (G_OBJECT (tree), "encoding_list"); model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tree))); g_signal_handler_block (G_OBJECT (tree), handler_id); gtk_list_store_clear (GTK_LIST_STORE (model)); while (list) { encoding = (const gchar *) list->data; if (misc_str_isearch (encoding, filter_str)) { gtk_list_store_append (GTK_LIST_STORE (model), &iter); gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, encoding, -1); if (g_str_equal (encoding, cfg.uname_encoding)) { memcpy (&iter_sel, &iter, sizeof (GtkTreeIter)); sel = TRUE; } } list = g_list_next (list); } if (sel) gui_select_treeview_row (&iter_sel, tree); g_signal_handler_unblock (G_OBJECT (tree), handler_id); return; } static void prefwin_btn_encoding_sel_clicked (GtkButton *button, gpointer user_data) { prefwin_widgets *w; static GtkWidget *dlg = NULL; GList *list, *head; GtkListStore *model; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeIter iter, iter_sel; GtkTreeView *tree; GtkWidget *entry; guint handler_id; gboolean sel = FALSE; if (dlg) { gtk_window_present (GTK_WINDOW (dlg)); return; } w = prefwin_get_widgets (); dlg = PW("dlg_encoding"); tree = GTK_TREE_VIEW (PW("tree_encoding")); model = gtk_list_store_new (1, G_TYPE_STRING); gtk_tree_view_set_model (GTK_TREE_VIEW (tree), GTK_TREE_MODEL (model)); gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree)), GTK_SELECTION_SINGLE); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "text", 0, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column); head = list = get_available_encodings (); while (list) { gtk_list_store_append (GTK_LIST_STORE (model), &iter); gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, (gchar *) list->data, -1); if (g_str_equal ((gchar*) list->data, cfg.uname_encoding)) { memcpy (&iter_sel, &iter, sizeof (GtkTreeIter)); sel = TRUE; } list = g_list_next (list); } if (sel) gui_select_treeview_row (&iter_sel, tree); entry = PW("entry_filter"); g_signal_connect (G_OBJECT (entry), "changed", G_CALLBACK (filter_encoding_list), (gpointer) tree); handler_id = g_signal_connect (G_OBJECT (tree), "cursor-changed", G_CALLBACK (encoding_changed_cb), w->encoding); g_object_set_data (G_OBJECT (tree), "callback_handler_id", GINT_TO_POINTER (handler_id)); g_object_set_data (G_OBJECT (tree), "encoding_list", head); g_signal_connect (G_OBJECT (dlg), "destroy", G_CALLBACK (free_encoding_list), (gpointer) head); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); dlg = NULL; }