/* 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.
 */

/*
 * Logfile-functions incl. callbacks to manage the logfile-viewer
 *
 * Copyright (C) 2003 Isak Savo
 */
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <time.h>
#include <errno.h>

#include "globals.h"
#include "cfg.h"
#include "helper.h"
#include "gui_helper.h"
#include "logfile.h"
#include "famwrap.h"

FILE *logfile = NULL;
GtkWidget *logview = NULL;
GtkTextBuffer *viewbuffer = NULL;
GtkTextTag *logview_tags[NUM_LOGTAGS];
static gchar cur_logfile[FILEPATH_MAX];
#define LOG_BUF_LEN 1024

/* Appends a line to the logview. 'buf' must be valid UTF-8 */
static
void logview_append_line (const gchar *buf, log_textview_mode mode)
{
	GtkTextIter iter;
	static GtkTextMark *mark = NULL;
	
	gtk_text_buffer_get_end_iter (viewbuffer, &iter);
	gtk_text_buffer_insert_with_tags (viewbuffer, &iter, buf, -1, logview_tags[mode], NULL);
	
	if (!mark)
		mark = gtk_text_buffer_create_mark (viewbuffer, "last_line", &iter, FALSE);
	else
		gtk_text_buffer_move_mark (viewbuffer, mark, &iter);

	gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (logview), mark, 
				      0, TRUE, 0, 1);
}

static
log_textview_mode get_logline_mode (const gchar *line)
{
	log_textview_mode mode = LOG_INFO;

	if (strstr (line, "[NOTICE]"))
		mode = LOG_NOTICE;
	else if (strstr (line, "[WARNING]"))
		mode = LOG_WARNING;
	else if (strstr (line, "[ERROR]"))
		mode = LOG_ERROR;
	else if (strstr (line, "[DEBUG]"))
		mode = LOG_DEBUG;
   
	return mode;
}

/** GLOBAL FUNCTIONS **/

/* init_logfile:  Initializes the logwindow
 *
 * Returns: TRUE if everything is setup correctly
 *	    FALSE if something went wrong (or if FAM is disabled)
 */
gboolean init_logfile (void)
{
	static GtkWidget *lbl = NULL;
	PangoFontDescription *font_desc;
   
	if (!logview)
	{
		logview = MW("logview");
		if (!logview)
			return FALSE;
		font_desc = pango_font_description_new ();
		pango_font_description_set_family_static (font_desc, "monospace");
		gtk_widget_modify_font (logview, font_desc);
		pango_font_description_free (font_desc);
		viewbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview));
	}
	/* This shouldn't even be called when not defined, but let's check it anyway... */
#ifndef HAVE_LIBFAM
	return FALSE;
#endif

	if (!lbl)
		lbl = MW("lbl_logfilename");
   
	if (!logfile)
	{
		if (!(logfile = fopen (cfg.logfile, "r")))
		{
			pur_log_wrn ("Unable to open logfile %s: %s", cfg.logfile, strerror (errno));
			log_display_error_text (2);
			return FALSE;
		}
		/* We use a local copy of the filename, in case someone changes cfg.logfile, and we want to modify the FAM-watch */
		strncpy (cur_logfile, cfg.logfile, FILEPATH_MAX);
	}
	if (!fam_set_watch (cfg.logfile, read_logfile))
	{
		close_logfile ();
		log_display_error_text (3);
		return FALSE;
	}
	gtk_label_set_text (GTK_LABEL (lbl), cur_logfile);
	return TRUE;
}

/* close_logfile: Closes the logfile and removes any FAM watches
 *		  that are open. Also frees all resources allocated.
 */
void close_logfile (void)
{
#ifndef HAVE_LIBFAM
	return;
#endif
	if (cur_logfile && *cur_logfile)
		fam_delete_watch ();
	if (logfile)
		fclose (logfile);
	logfile = NULL;
	log_clear_logview ();
}

/* log_clear_logview: Removes all text in the logview
 *
 */
void log_clear_logview (void)
{
	if (viewbuffer)
		gtk_text_buffer_set_text (viewbuffer, "", -1);
}

/* log_display_error_text: Display an errormessage explaining why
 *			   logfile viewer has been disabled.
 *
 * Argument: reason:
 *		0 ==> FAM isn't installed,
 *		1 ==> FAM isn't running.
 *		2 ==> Couldn't open the specified logfile
 */
void log_display_error_text (gint reason)
{
	GtkWidget *btn, *lbl;
	GtkTextIter iter;
	gchar *err_msg = NULL;

	if (!logview)
	{
		logview = MW("logview");
		if (!logview)
			return;
		viewbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview));
	}
   
	pur_log_dbg ("Displaying logfile errortext, reason: %d", reason);
	lbl = MW("lbl_logfilename");
	gtk_label_set_text (GTK_LABEL (lbl), _("[Logfile viewer Disabled]"));
	gtk_text_buffer_get_end_iter (viewbuffer, &iter);
	switch (reason)
	{
		case 0:
		  err_msg = g_strdup (_("Logfile viewer has been disabled because FAM isn't installed on this computer. "
					"If you want to use the logfile viewer you need to install FAM and then recompile PureAdmin\n\n" 
					"Check your distribution for appropriate packages or visit "
					"http://oss.sgi.com/projects/fam/ for more info about FAM."));
		  break;
		case 1:
		  err_msg = g_strdup (_("Logfile viewer has been disabled because PureAdmin couldn't connect to local FAM-service.\n"
					"FAM is installed so it should be sufficient to either start FAM as a separate server or run it\n"
					"from inetd (Internet Super Server) by adding an entry to /etc/inetd.conf.\n\n"
					"Check your configuration for FAM if you want to use the logfile viewer."));
		  break;
		case 2:
		  err_msg = g_strdup (_("Logfile viewer has been disable because PureAdmin could not open the specified logfile.\n"
					"Make sure that you are running as a user that has permission to open the logfile."));
		  break;
		case 3:
		default:
		  err_msg = g_strdup (_("Logfile viewer has been disable because PureAdmin could not watch for changes to the logfile.\n"
					"Make sure that you are running as a user that has permission to access the logfile."));
		  break;
	}
	gtk_text_buffer_insert_with_tags (viewbuffer, &iter, err_msg, -1, logview_tags[LOG_ERROR], NULL);
	g_free (err_msg);
	btn = MW("btn_logview_clear");
	gtk_widget_set_sensitive (btn, FALSE);
	btn = MW("btn_logview_reread");
	gtk_widget_set_sensitive (btn, FALSE);

}

/* read_logfile: Reads the newly added contents of the logfile
 */
void read_logfile (void)
{
	gchar buf[LOG_BUF_LEN];
	gint mode = 0;
	gchar *utf8_str;
   
	if (!logfile)
		init_logfile ();
	pur_log_dbg ("Reading logfile");
	if (fseek (logfile, 0, SEEK_CUR) != 0) 
		/* To clear an invalid EOF indicator for the stream, and to verify that
		   there is new data to be read...*/
		return;
	while (!feof (logfile))
	{
		memset (buf, '\0', LOG_BUF_LEN);
		fgets (buf, LOG_BUF_LEN, logfile);
		if (misc_str_is_only_whitespace (buf))
			continue;
		utf8_str = NULL;
		if (cfg.logmethod == LOG_SYSLOG && strstr (buf, "pure-ftpd:"))
		{
			utf8_str = string_to_utf8 (buf);
			mode = get_logline_mode (buf);
	      
			/* Eventually filter old log-messages */
			logview_append_line (utf8_str, mode);
		}
		else if (cfg.logmethod == LOG_CUSTOM)
		{
			utf8_str = string_to_utf8 (buf);
			logview_append_line (utf8_str, LOG_INFO);
		}
		g_free (utf8_str);
	}
}


syntax highlighted by Code2HTML, v. 0.9.1