/* 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. */ /* * Main: Initiates the GUI and spawns timeout-functions. * * Copyright (C) 2003 Isak Savo */ #ifdef HAVE_CONFIG_H # include #endif #include #ifdef HAVE_LIBDL #include #endif #include #include #include #include #include #include #include "binreloc.h" #include "gui_helper.h" #include "globals.h" #include "cfg.h" #include "logfile.h" #include "helper.h" #include "famwrap.h" #include "debugging.h" #include "suexec.h" #include "mainwin.h" #include "helpview.h" #include "eggstatusicon.h" gboolean timeout_update_activity (gpointer data); gboolean timeout_check_for_availability (gpointer data); static ftp_runmode_t get_ftp_runmode (void); static void activity_show_error_message (const gchar *errmsg); static void activity_show_welcome_message (void); static gboolean create_remaining_xmls (gpointer data); gboolean debug = FALSE; gboolean prog_exiting = FALSE; GladeXML *mwin_xml = NULL; GladeXML *dlgs_xml = NULL; gchar *datadir = NULL; gchar *selfname = NULL; gchar *pixmapdir = NULL; gchar *docdir = NULL; /* Clean exit of the program. This should be called whenever we should terminate! */ void exit_program (void) { prog_exiting = TRUE; #ifdef HAVE_LIBFAM close_logfile (); fam_terminate (); #endif hlp_terminate (); gui_terminate (); srv_terminate (); /* Last of all, save settings */ cfg_write_settings (); cfg_terminate (); g_free (datadir); g_free (selfname); g_free (pixmapdir); g_free (docdir); } /* Will be called before main() */ static void locate_dirs () { gbr_init(NULL); datadir = gbr_find_data_dir(DATADIR); selfname = gbr_find_exe(BINDIR G_DIR_SEPARATOR_S "pureadmin"); pixmapdir = g_build_filename (datadir, PACKAGE, NULL); docdir = g_build_filename (datadir, PACKAGE, "docs", NULL); } int main (int argc, char *argv[]) { gchar *our_path = NULL; const gchar *startup_id; guint loghandler_id; gboolean srv_comm_have_access = FALSE; GError *err = NULL; if (g_getenv ("PUREADMIN_DEBUG") && *g_getenv ("PUREADMIN_DEBUG") != '0') debug = TRUE; locate_dirs(); pur_log_dbg ("Binary: %s", selfname); pur_log_dbg ("Datadir: %s", datadir); pur_log_dbg ("Pixmaps: %s", pixmapdir); pur_log_dbg ("Documents: %s", docdir); #ifdef ENABLE_NLS our_path = gbr_find_locale_dir(LOCALEDIR); bindtextdomain (GETTEXT_PACKAGE, our_path); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); g_free (our_path); #endif startup_id = g_getenv ("DESKTOP_STARTUP_ID"); gtk_init (&argc, &argv); /* Restore DESKTOP_STARTUP_ID since, appearently, gtk_init() sometimes clears it */ // FIXME: Do we need to check if setenv() is available? if (startup_id) setenv ("DESKTOP_STARTUP_ID", startup_id, TRUE); if (getuid() != 0) { /* FIXME: Does it matter that gtk_init() changes argv? Or will values be inherited? */ if (run_as_root (argv)) { /* Fork/exec successful! Shut down and let the root process continue! */ suexec_shutdown(); return 0; } } #ifndef G_THREADS_ENABLED g_error ("Threading is not enabled, this will not work!"); #endif g_thread_init (NULL); our_path = g_build_filename (datadir, PACKAGE, "mainwindow.glade", NULL); mwin_xml = glade_xml_new (our_path, NULL, NULL); if (!mwin_xml) { g_warning ("Couldn't load glade file '%s', please make sure it is installed correctly.", our_path); g_print ("PureAdmin will now terminate since the graphical interface couldn't be created\n"); return -1; } g_free (our_path); our_path = g_build_filename (datadir, PACKAGE, NULL); set_pixmap_directory (our_path); g_free (our_path); init_dbg_console (); loghandler_id = g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, (GLogFunc) pur_debug_handler, NULL); /* This may happen if the user canceled the password dialog */ if (getuid () != 0) pur_log_wrn ("Warning, running without root access. This may not work!"); cfg_set_defaults (); cfg_read_settings (); cfg_fill_missing (); /* FIXME: Can perhaps be called automatically from cfg_read_settings()? */ init_gui_activities (); init_gui_online_users (); init_gui_logwindow (); init_gui_mainwindow (); ftp_runmode = get_ftp_runmode (); #ifdef HAVE_LIBFAM pur_log_dbg ("HAVE_LIBFAM is defined"); init_logfile (); #else pur_log_dbg ("HAVE_LIBFAM is *not* defined!"); #endif gtk_widget_show (MW("main_window")); /* Update statusbar with status of PureFTPd */ gui_update_server_status (); err = NULL; srv_comm_have_access = srv_try_get_activities (&err); if (srv_comm_have_access) { activity_show_welcome_message (); g_timeout_add (1000, (GSourceFunc) timeout_update_activity, NULL); pur_log_dbg ("Access to server activites granted!"); } else { activity_show_error_message (err->message); pur_log_wrn ("Don't have access to server activities: %s", err->message); pur_log_wrn ("Will re-check every 3 seconds if activities are available again"); g_timeout_add (3000, (GSourceFunc) timeout_check_for_availability, NULL); g_error_free (err); err = NULL; } pur_log_nfo ("PureAdmin started!"); g_thread_create ((GThreadFunc) srv_activity_thread, NULL, FALSE, &err); /* Add this anyway, since the functionality to get activities could recover */ if (err){ pur_log_err ("Couldn't create activity thread: %s", err->message); g_error_free (err); err = NULL; } else pur_log_dbg ("Activity thread created successfully"); glade_xml_signal_autoconnect (mwin_xml); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (MW("chk_show_hide_info")), cfg.show_advinfo); /* Need to call this manually, since the event handler will only be called if the button state changes */ gui_update_info_frame (NULL); g_idle_add ((GSourceFunc) create_remaining_xmls, NULL); //create_remaining_xmls(NULL); gtk_widget_show (MW("main_window")); gtk_main (); /* make the last messages go to stderr */ g_log_remove_handler (NULL, loghandler_id); suexec_shutdown(); return 0; } static ftp_runmode_t get_ftp_runmode (void) { gchar *s = misc_get_line_beginning_with ("/etc/inetd.conf", "ftp"); gchar *output = NULL; if (s && strstr (s, "pure-ftp")) { g_free (s); return RUNMODE_INETD; } g_free (s); if ((output = misc_spawn_command ("pgrep pure-ftpd")) != NULL) { gchar **pids = g_strsplit (output, "\n", -1); gint i = 0; while (pids && pids[i]) { gchar *pid_cmdline = misc_get_process_info (pids[i], "cmdline"); if (strncmp (pid_cmdline, "pure-ftpd (SERVER)", strlen("pure-ftpd (SERVER)")) == 0) { g_free (pid_cmdline); return RUNMODE_STANDALONE; } i++; } } return RUNMODE_STOPPED; } void activity_show_welcome_message (void) { GtkTreeIter iter; GtkWidget *tree_activities = NULL; GtkTreeModel *model = NULL; //GtkTreeSelection *sel; GdkPixbuf *icon; tree_activities = MW("tree_activity"); model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_activities)); //sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_activities)); //gtk_tree_selection_set_mode (sel, GTK_SELECTION_NONE); gui_clear_activity_list (); icon = gtk_widget_render_icon (tree_activities, "gtk-dialog-info", GTK_ICON_SIZE_MENU, ""); gtk_list_store_append (GTK_LIST_STORE (model), &iter); gtk_list_store_set (GTK_LIST_STORE (model), &iter, COL_ACT_ICON, icon, COL_ACT_TEXT, _("Fetching information about server activity, please wait..."), COL_ACT_ID, 666, -1); } static void activity_show_error_message (const gchar *errmsg) { GtkTreeIter iter; GtkWidget *tree_activities = NULL; GtkTreeModel *model = NULL; GtkTreeSelection *sel; GdkPixbuf *icon; gchar *msg; tree_activities = MW("tree_activity"); model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_activities)); sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_activities)); gtk_tree_selection_set_mode (sel, GTK_SELECTION_NONE); icon = gtk_widget_render_icon (tree_activities, "gtk-dialog-error",GTK_ICON_SIZE_MENU, ""); msg = g_strconcat (_("Unable to retreive information about server activities."), "\n", errmsg, NULL); gtk_list_store_append (GTK_LIST_STORE (model), &iter); gtk_list_store_set (GTK_LIST_STORE (model), &iter, COL_ACT_ICON, icon, COL_ACT_TEXT, msg, COL_ACT_ID, 666, -1); } /* This is run as an idle function, after the program has started. * It is used to parse all remaining glade XML-files (currently one) and * create the widgets */ static gboolean create_remaining_xmls (gpointer data) { gchar *our_path; our_path = g_build_filename (datadir, PACKAGE, "dialogs.glade", NULL); dlgs_xml = glade_xml_new (our_path, NULL, NULL); g_free (our_path); glade_xml_signal_autoconnect (dlgs_xml); /* We're done, don't call us again! */ return FALSE; } gboolean timeout_check_for_availability (gpointer data) { if (srv_try_get_activities (NULL)) { activity_show_welcome_message (); g_timeout_add (1000, (GSourceFunc) timeout_update_activity, NULL); pur_log_nfo ("Access to server activites finally granted!"); /* Our work is done, remove this function from the calling list */ return FALSE; } /* Re-try again in a couple of seconds */ return TRUE; }