/* 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 <config.h>
#endif
#include <gtk/gtk.h>
#ifdef HAVE_LIBDL
#include <dlfcn.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <glade/glade.h>
#include <errno.h>
#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;
}
syntax highlighted by Code2HTML, v. 0.9.1