changeset 8573:7dcd6f26e4a7

[gaim-migrate @ 9321] " This patch reimplements the system log. It writes system log to ~/.gaim/logs/<protocol>/<username>/.system/<timestamp>.(txt|html), where <timestamp> is the time that the account <username> with <protocol> signs on. Nathan (faceprint) and LSchiere suggested this logging scheme. No code is currently written to read the old system logs. Note that if you change the logging format, you need to re-login the accounts for the change to take effect." --Ka-Hing (javabsp) Cheung who continues: "Now this one applies, also contains a rider patch that, if you enable sound for "Someone says your name in chat", it will not play a sound if the message is a system message, like if jabber chat tells you that "*** becomes available" and *** is you, it won't play a sound." committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Sat, 03 Apr 2004 18:34:29 +0000
parents f6890288bbe0
children fb1157284339
files ChangeLog src/account.c src/account.h src/connection.c src/gtkblist.c src/gtkconv.c src/gtklog.c src/gtkprefs.c src/log.c src/log.h src/prpl.h src/server.c
diffstat 12 files changed, 577 insertions(+), 139 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Apr 03 18:01:58 2004 +0000
+++ b/ChangeLog	Sat Apr 03 18:34:29 2004 +0000
@@ -1,6 +1,9 @@
 Gaim: The Pimpin' Penguin IM Client that's good for the soul!
 
 version 0.77cvs
+	New Features:
+	* The System Log returns (Ka-Hing Cheung)
+
 	Bug Fixes:
 	* Save Conversation works again (Kevin Stange)
 	* The Clear button in privacy works (Robert Mibus)
--- a/src/account.c	Sat Apr 03 18:01:58 2004 +0000
+++ b/src/account.c	Sat Apr 03 18:34:29 2004 +0000
@@ -146,6 +146,7 @@
 											  g_free, delete_setting);
 	account->ui_settings = g_hash_table_new_full(g_str_hash, g_str_equal,
 				g_free, (GDestroyNotify)g_hash_table_destroy);
+	account->system_log = NULL;
 
 	return account;
 }
@@ -183,6 +184,9 @@
 	g_hash_table_destroy(account->settings);
 	g_hash_table_destroy(account->ui_settings);
 
+	if(account->system_log)
+		gaim_log_free(account->system_log);
+
 	g_free(account);
 }
 
@@ -913,6 +917,30 @@
 	return setting->value.bool;
 }
 
+GaimLog *
+gaim_account_get_log(GaimAccount *account)
+{
+	g_return_val_if_fail(account != NULL, NULL);
+
+	if(!account->system_log){
+		account->system_log	 = gaim_log_new(GAIM_LOG_SYSTEM, account->username,
+											account, account->gc->login_time);
+	}
+
+	return account->system_log;
+}
+
+void
+gaim_account_destroy_log(GaimAccount *account)
+{
+	g_return_if_fail(account != NULL);
+
+	if(account->system_log){
+		gaim_log_free(account->system_log);
+		account->system_log = NULL;
+	}
+}
+
 /* XML Stuff */
 static void
 free_parser_data(gpointer user_data)
--- a/src/account.h	Sat Apr 03 18:01:58 2004 +0000
+++ b/src/account.h	Sat Apr 03 18:34:29 2004 +0000
@@ -37,6 +37,7 @@
 #include "connection.h"
 #include "proxy.h"
 #include "prpl.h"
+#include "log.h"
 
 struct _GaimAccountUiOps
 {
@@ -71,6 +72,7 @@
 	GSList *permit;             /**< Permit list.                         */
 	GSList *deny;               /**< Deny list.                           */
 	int perm_deny;              /**< The permit/deny setting.             */
+ 	GaimLog *system_log;        /**< The system log                       */
 };
 
 #ifdef __cplusplus
@@ -540,6 +542,24 @@
 gboolean gaim_account_get_ui_bool(const GaimAccount *account, const char *ui,
 								  const char *name, gboolean default_value);
 
+
+/**
+ * Returns the system log for an account.
+ * Create it if it doesn't already exist.
+ *
+ * @param gc The account.
+ *
+ * @return The log.
+ */
+GaimLog *gaim_account_get_log(GaimAccount *account);
+
+/**
+ * Frees the system log of an account
+ *
+ * @param gc The account.
+ */
+	void gaim_account_destroy_log(GaimAccount *account);
+
 /*@}*/
 
 /**************************************************************************/
--- a/src/connection.c	Sat Apr 03 18:01:58 2004 +0000
+++ b/src/connection.c	Sat Apr 03 18:34:29 2004 +0000
@@ -313,6 +313,7 @@
 		GaimBlistNode *gnode,*cnode,*bnode;
 		GList *wins;
 		GList *add_buds=NULL;
+		GaimAccount *account = gaim_connection_get_account(gc);
 
 		/* Set the time the account came online */
 		time(&gc->login_time);
@@ -321,7 +322,7 @@
 			ops->connected(gc);
 
 		gaim_blist_show();
-		gaim_blist_add_account(gc->account);
+		gaim_blist_add_account(account);
 
 		/*
 		 * XXX This is a hack! Remove this and replace it with a better event
@@ -335,6 +336,17 @@
 
 		/* LOG system_log(log_signon, gc, NULL,
 		   OPT_LOG_BUDDY_SIGNON | OPT_LOG_MY_SIGNON); */
+		if(gaim_prefs_get_bool("/core/logging/log_system") &&
+		   gaim_prefs_get_bool("/core/logging/log_own_states")){
+			GaimLog *log = gaim_account_get_log(account);
+			char *msg = g_strdup_printf("+++ %s signed on",
+										gaim_account_get_username(account));
+			gaim_log_write(log, GAIM_MESSAGE_SYSTEM,
+						   gaim_account_get_username(account), gc->login_time,
+						   msg);
+			g_free(msg);						   
+		}
+
 		gaim_signal_emit(gaim_connections_get_handle(), "signed-on", gc);
 
 #if 0
@@ -380,8 +392,23 @@
 		serv_set_permit_deny(gc);
 	}
 	else if (gc->state == GAIM_DISCONNECTED) {
+		GaimAccount *account = gaim_connection_get_account(gc);
+
+		if(gaim_prefs_get_bool("/core/logging/log_system") &&
+		   gaim_prefs_get_bool("/core/logging/log_own_states")){
+			GaimLog *log = gaim_account_get_log(account);
+			char *msg = g_strdup_printf("+++ %s signed off",
+										gaim_account_get_username(account));
+			gaim_log_write(log, GAIM_MESSAGE_SYSTEM,
+						   gaim_account_get_username(account), time(NULL),
+						   msg);
+			g_free(msg);						   
+		}
+
+		gaim_account_destroy_log(account);
+
 		if (ops != NULL && ops->disconnected != NULL)
-			ops->disconnected(gc);
+			ops->disconnected(gc);		
 	}
 }
 
--- a/src/gtkblist.c	Sat Apr 03 18:01:58 2004 +0000
+++ b/src/gtkblist.c	Sat Apr 03 18:34:29 2004 +0000
@@ -559,12 +559,10 @@
 	gaim_gtk_log_show(b->name, b->account);
 }
 
-#if 0
 static void gtk_blist_show_systemlog_cb()
 {
-	/* LOG show_log(NULL); */
+	gaim_gtk_syslog_show();
 }
-#endif
 
 static void gtk_blist_show_onlinehelp_cb()
 {
@@ -2254,10 +2252,8 @@
 	{ N_("/Tools/R_oom List"), NULL, gaim_gtk_roomlist_dialog_show, 0, NULL },
 	{ N_("/Tools/Pr_eferences"), "<CTL>P", gaim_gtk_prefs_show, 0, "<StockItem>", GTK_STOCK_PREFERENCES },
 	{ N_("/Tools/Pr_ivacy"), NULL, gaim_gtk_privacy_dialog_show, 0, NULL },
-#if 0
 	{ "/Tools/sep2", NULL, NULL, 0, "<Separator>" },
 	{ N_("/Tools/View System _Log"), NULL, gtk_blist_show_systemlog_cb, 0, NULL },
-#endif
 
 	/* Help */
 	{ N_("/_Help"), NULL, NULL, 0, "<Branch>" },
--- a/src/gtkconv.c	Sat Apr 03 18:01:58 2004 +0000
+++ b/src/gtkconv.c	Sat Apr 03 18:34:29 2004 +0000
@@ -4419,7 +4419,8 @@
 			gaim_sound_play_event(GAIM_SOUND_CHAT_YOU_SAY);
 		else if (flags & GAIM_MESSAGE_RECV) {
 			if ((flags & GAIM_MESSAGE_NICK) &&
-				gaim_prefs_get_bool("/gaim/gtk/sound/enabled/nick_said")) {
+				gaim_prefs_get_bool("/gaim/gtk/sound/enabled/nick_said") &&
+				!(flags & GAIM_MESSAGE_SYSTEM)) {
 
 				gaim_sound_play_event(GAIM_SOUND_CHAT_NICK);
 			}
--- a/src/gtklog.c	Sat Apr 03 18:01:58 2004 +0000
+++ b/src/gtklog.c	Sat Apr 03 18:34:29 2004 +0000
@@ -35,6 +35,7 @@
 
 static GHashTable *log_viewers = NULL;
 static void populate_log_tree(GaimGtkLogViewer *lv);
+static GaimGtkLogViewer *syslog_viewer = NULL;
 
 struct log_viewer_hash_t {
 	char *screenname;
@@ -113,11 +114,16 @@
 }
 
 static gboolean destroy_cb(GtkWidget *w, gint resp, struct log_viewer_hash_t *ht) {
-	GaimGtkLogViewer *lv = g_hash_table_lookup(log_viewers, ht);
+	GaimGtkLogViewer *lv = syslog_viewer;
 
-	g_hash_table_remove(log_viewers, ht);
-	g_free(ht->screenname);
-	g_free(ht);
+	if(ht != NULL){
+		lv = g_hash_table_lookup(log_viewers, ht);
+		g_hash_table_remove(log_viewers, ht);
+		g_free(ht->screenname);
+		g_free(ht);
+	} else
+		syslog_viewer = NULL;
+
 	while (lv->logs) {
 		GaimLog *log = lv->logs->data;
 		GList *logs2;
@@ -128,12 +134,31 @@
 	}
 	if (lv->search)
 		g_free(lv->search);
-	g_free(lv);		
+	g_free(lv);
 	gtk_widget_destroy(w);
 
 	return TRUE;
 }
+#if 0
+static gboolean destroy_syslog_cb(GtkWidget *w, gint resp, void *cb)
+{
+	while (syslog_viewer->logs) {
+		GaimLog *log = syslog_viewer->logs->data;
+		GList *logs2;
+		gaim_log_free(log);
+		logs2 = syslog_viewer->logs->next;
+		g_list_free_1(syslog_viewer->logs);
+		syslog_viewer->logs = logs2;
+	}
+	if (syslog_viewer->search)
+		g_free(syslog_viewer->search);
+	g_free(syslog_viewer);
+	syslog_viewer = NULL;
+	gtk_widget_destroy(w);
 
+	return TRUE;
+}
+#endif
 static void log_select_cb(GtkTreeSelection *sel, GaimGtkLogViewer *viewer) {
 	GtkTreeIter   iter;
 	GValue val = { 0, };
@@ -311,3 +336,108 @@
 
 	gtk_widget_show_all(lv->window);
 }
+
+void gaim_gtk_syslog_show()
+{
+	GtkWidget *hbox, *vbox;
+	GtkCellRenderer *rend;
+	GtkTreeViewColumn *col;
+	GtkTreeSelection *sel;
+	GtkWidget *label, *pane, *sw, *button;
+	char *text;
+	GList *accounts = NULL;
+
+	if(syslog_viewer){
+		gtk_window_present(GTK_WINDOW(syslog_viewer->window));
+		return;
+	}
+
+	syslog_viewer = g_new0(GaimGtkLogViewer, 1);
+
+	for(accounts = gaim_accounts_get_all(); accounts != NULL;
+		accounts = accounts->next) {
+		GList *logs;
+		GaimAccount *account = (GaimAccount *)accounts->data;
+		if(!gaim_find_prpl(gaim_account_get_protocol_id(account)))
+			continue;
+
+		logs = gaim_log_get_system_logs(account);
+		syslog_viewer->logs = g_list_concat(syslog_viewer->logs, logs);
+	}
+	syslog_viewer->logs = g_list_sort(syslog_viewer->logs, gaim_log_compare);
+
+	/* Window ***********/
+	syslog_viewer->window = gtk_dialog_new_with_buttons(_("System Log"), NULL, 0, 
+						 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
+	gtk_container_set_border_width (GTK_CONTAINER(syslog_viewer->window), 6);
+	gtk_dialog_set_has_separator(GTK_DIALOG(syslog_viewer->window), FALSE);
+	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(syslog_viewer->window)->vbox), 0);
+	g_signal_connect(G_OBJECT(syslog_viewer->window), "response", 
+					 G_CALLBACK(destroy_cb), NULL);
+
+	hbox = gtk_hbox_new(FALSE, 6);
+	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
+	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(syslog_viewer->window)->vbox), hbox,
+					   FALSE, FALSE, 0);
+
+	/* Label ************/
+	label = gtk_label_new(NULL);
+	text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>",
+						   _("System Log"));
+	gtk_label_set_markup(GTK_LABEL(label), text);
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	g_free(text);
+
+	/* Pane *************/
+	pane = gtk_hpaned_new();
+	gtk_container_set_border_width(GTK_CONTAINER(pane), 6);
+	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(syslog_viewer->window)->vbox), pane,
+					   TRUE, TRUE, 0);
+	
+	/* List *************/
+	sw = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
+	gtk_paned_add1(GTK_PANED(pane), sw);
+	syslog_viewer->treestore = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
+	syslog_viewer->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (syslog_viewer->treestore));
+	rend = gtk_cell_renderer_text_new();
+	col = gtk_tree_view_column_new_with_attributes ("time", rend, "markup", 0, NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW(syslog_viewer->treeview), col);
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (syslog_viewer->treeview), FALSE);
+	gtk_container_add (GTK_CONTAINER (sw), syslog_viewer->treeview);
+
+	gtk_widget_set_size_request(syslog_viewer->treeview, 170, 200);
+	populate_log_tree(syslog_viewer);
+
+	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (syslog_viewer->treeview));
+	g_signal_connect (G_OBJECT (sel), "changed",
+			  G_CALLBACK (log_select_cb),
+			  syslog_viewer);
+		
+	/* Viewer ************/
+	vbox = gtk_vbox_new(FALSE, 6);
+	gtk_paned_add2(GTK_PANED(pane), vbox);
+	sw = gtk_scrolled_window_new(NULL, NULL);
+	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
+	syslog_viewer->imhtml = gtk_imhtml_new(NULL, NULL);
+	gtk_container_add(GTK_CONTAINER(sw), syslog_viewer->imhtml);
+	gaim_setup_imhtml(syslog_viewer->imhtml);
+	gtk_widget_set_size_request(syslog_viewer->imhtml, 400, 200);
+		
+	/* Search box **********/
+	hbox = gtk_hbox_new(FALSE, 6);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+	syslog_viewer->entry = gtk_entry_new();
+	gtk_box_pack_start(GTK_BOX(hbox), syslog_viewer->entry, TRUE, TRUE, 0);
+	button = gtk_button_new_from_stock(GTK_STOCK_FIND);
+	g_signal_connect (G_OBJECT (button), "pressed",
+			  G_CALLBACK (search_cb),
+			  syslog_viewer);
+	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+
+	gtk_widget_show_all(syslog_viewer->window);	
+}
+
--- a/src/gtkprefs.c	Sat Apr 03 18:01:58 2004 +0000
+++ b/src/gtkprefs.c	Sat Apr 03 18:34:29 2004 +0000
@@ -1433,6 +1433,10 @@
 	GtkWidget *ret;
 	GtkWidget *vbox;
 	GList *names;
+	GtkWidget *sys_box;
+	GtkWidget *box;
+	int syslog_enabled = gaim_prefs_get_bool("/core/logging/log_system");
+
 	ret = gtk_vbox_new(FALSE, 18);
 	gtk_container_set_border_width (GTK_CONTAINER (ret), 12);
 
@@ -1446,19 +1450,41 @@
 				  "/core/logging/log_ims", vbox);
 	gaim_gtk_prefs_checkbox(_("Log all c_hats"),
 				  "/core/logging/log_chats", vbox);
-/*
+
 	vbox = gaim_gtk_make_frame (ret, _("System Logs"));
-	gaim_gtk_prefs_checkbox(_("Log when buddies _sign on/sign off"),
-				   "/gaim/gtk/logging/log_signon_signoff", vbox);
-	gaim_gtk_prefs_checkbox(_("Log when buddies become _idle/un-idle"),
-				   "/gaim/gtk/logging/log_idle_state", vbox);
-	gaim_gtk_prefs_checkbox(_("Log when buddies go away/come _back"),
-				   "/gaim/gtk/logging/log_away_state", vbox);
-	gaim_gtk_prefs_checkbox(_("Log your _own signons/idleness/awayness"),
-				   "/gaim/gtk/logging/log_own_states", vbox);
+
+	sys_box = gaim_gtk_prefs_checkbox(_("_Enable system log"),
+									  "/core/logging/log_system", vbox);
+
+	box = gaim_gtk_prefs_checkbox(_("Log when buddies _sign on/sign off"),
+								  "/core/logging/log_signon_signoff", vbox);
+	g_signal_connect(G_OBJECT(sys_box), "clicked",
+					 G_CALLBACK(gaim_gtk_toggle_sensitive), box);
+	gtk_widget_set_sensitive(box, syslog_enabled);
+
+	box = gaim_gtk_prefs_checkbox(_("Log when buddies become _idle/un-idle"),
+								  "/core/logging/log_idle_state", vbox);
+	g_signal_connect(G_OBJECT(sys_box), "clicked",
+					 G_CALLBACK(gaim_gtk_toggle_sensitive), box);
+	gtk_widget_set_sensitive(box, syslog_enabled);
+
+	box = gaim_gtk_prefs_checkbox(_("Log when buddies go away/come _back"),
+								  "/core/logging/log_away_state", vbox);
+	g_signal_connect(G_OBJECT(sys_box), "clicked",
+					 G_CALLBACK(gaim_gtk_toggle_sensitive), box);
+	gtk_widget_set_sensitive(box, syslog_enabled);
+
+	box = gaim_gtk_prefs_checkbox(_("Log your _own signons/idleness/awayness"),
+								  "/core/logging/log_own_states", vbox);
+	g_signal_connect(G_OBJECT(sys_box), "clicked",
+					 G_CALLBACK(gaim_gtk_toggle_sensitive), box);
+	gtk_widget_set_sensitive(box, syslog_enabled);
+
+/*
 	gaim_gtk_prefs_checkbox(_("I_ndividual log file for each buddy's signons"),
 				   "/gaim/gtk/logging/individual_logs", vbox);
 */
+
 	gtk_widget_show_all(ret);
 	return ret;
 }
--- a/src/log.c	Sat Apr 03 18:01:58 2004 +0000
+++ b/src/log.c	Sat Apr 03 18:34:29 2004 +0000
@@ -47,6 +47,7 @@
 	log->name = g_strdup(name);
 	log->account = account;
 	log->time = time;
+	log->type = type;
 	log->logger_data = NULL;
 	log->logger = gaim_log_logger_get();
 	if (log->logger && log->logger->create)
@@ -63,7 +64,6 @@
 	g_free(log);
 }
 
-
 void gaim_log_write(GaimLog *log, GaimMessageFlags type,
 		    const char *from, time_t time, const char *message)
 {
@@ -72,7 +72,8 @@
 	g_return_if_fail(log->logger->write);
 
 	if ((log->type == GAIM_LOG_IM && gaim_prefs_get_bool("/core/logging/log_ims")) ||
-	    (log->type == GAIM_LOG_CHAT && gaim_prefs_get_bool("/core/logging/log_chats")))
+	    (log->type == GAIM_LOG_CHAT && gaim_prefs_get_bool("/core/logging/log_chats")) ||
++ 		(log->type == GAIM_LOG_SYSTEM && gaim_prefs_get_bool("/core/logging/log_system")))
 		(log->logger->write)(log, type, from, time, message);
 }
 
@@ -214,7 +215,7 @@
 	return list;
 }
 
-static gint log_compare(gconstpointer y, gconstpointer z)
+gint gaim_log_compare(gconstpointer y, gconstpointer z)
 {
 	const GaimLog *a = y;
 	const GaimLog *b = z;
@@ -233,7 +234,21 @@
 		logs = g_list_concat(logs, logger->list(name, account));
 	}
 
-	return g_list_sort(logs, log_compare);
+	return g_list_sort(logs, gaim_log_compare);
+}
+
+GList *gaim_log_get_system_logs(GaimAccount *account)
+{
+	GList *logs = NULL;
+	GSList *n;
+	for (n = loggers; n; n = n->next) {
+		GaimLogLogger *logger = n->data;
+		if (!logger->list_syslog)
+			continue;
+		logs = g_list_concat(logs, logger->list_syslog(account));
+	}
+
+	return g_list_sort(logs, gaim_log_compare);
 }
 
 void gaim_log_init(void)
@@ -241,6 +256,12 @@
 	gaim_prefs_add_none("/core/logging");
 	gaim_prefs_add_bool("/core/logging/log_ims", FALSE);
 	gaim_prefs_add_bool("/core/logging/log_chats", FALSE);
+	gaim_prefs_add_bool("/core/logging/log_system", FALSE);
+	gaim_prefs_add_bool("/core/logging/log_signon_signoff", FALSE);
+	gaim_prefs_add_bool("/core/logging/log_idle_state", FALSE);
+	gaim_prefs_add_bool("/core/logging/log_away_state", FALSE);
+	gaim_prefs_add_bool("/core/logging/log_own_states", FALSE);
+
 	gaim_prefs_add_string("/core/logging/format", "txt");
 	gaim_log_logger_add(&html_logger);
 	gaim_log_logger_add(&txt_logger);
@@ -503,32 +524,38 @@
 
 	gaim_markup_html_to_xhtml(message, &msg_fixed, NULL);
 
-	strftime(date, sizeof(date), "%H:%M:%S", localtime(&time));
-	if (type & GAIM_MESSAGE_SYSTEM)
-		fprintf(data->file, "<font size=\"2\">(%s)</font><b> %s</b><br/>\n", date, msg_fixed);
-	else if (type & GAIM_MESSAGE_WHISPER)
-		fprintf(data->file, "<font color=\"#6C2585\"><font size=\"2\">(%s)</font> <b>%s:</b></font> %s<br/>\n",
-			date, from, msg_fixed);
-	else if (type & GAIM_MESSAGE_AUTO_RESP) {
-		if (type & GAIM_MESSAGE_SEND)
-			fprintf(data->file, _("<font color=\"#16569E\"><font size=\"2\">(%s)</font> <b>%s &lt;AUTO-REPLY&gt;:</b></font> %s<br/>\n"), date, from, msg_fixed);
-		else if (type & GAIM_MESSAGE_RECV)
-			fprintf(data->file, _("<font color=\"#A82F2F\"><font size=\"2\">(%s)</font> <b>%s &lt;AUTO-REPLY&gt;:</b></font> %s<br/>\n"), date, from, msg_fixed);
-	} else if (type & GAIM_MESSAGE_RECV) {
-		if(gaim_message_meify(msg_fixed, -1))
-			fprintf(data->file, "<font color=\"#6C2585\"><font size=\"2\">(%s)</font> <b>***%s</b></font> <font sml=\"%s\">%s</font><br/>\n",
-					date, from, gc->prpl->info->name, msg_fixed);
-		else
-			fprintf(data->file, "<font color=\"#A82F2F\"><font size=\"2\">(%s)</font> <b>%s:</b></font> <font sml=\"%s\">%s</font><br/>\n",
-					date, from, gc->prpl->info->name, msg_fixed);
-	} else if (type & GAIM_MESSAGE_SEND) {
-		if(gaim_message_meify(msg_fixed, -1))
-			fprintf(data->file, "<font color=\"#6C2585\"><font size=\"2\">(%s)</font> <b>***%s</b></font> <font sml=\"%s\">%s</font><br/>\n",
-					date, from, gc->prpl->info->name, msg_fixed);
-		else
-			fprintf(data->file, "<font color=\"#16569E\"><font size=\"2\">(%s)</font> <b>%s:</b></font> <font sml=\"%s\">%s</font><br/>\n",
-					date, from, gc->prpl->info->name, msg_fixed);
+ 	if(log->type == GAIM_LOG_SYSTEM){
+ 		strftime(date, sizeof(date), "%c", localtime(&time));
+ 		fprintf(data->file, "---- %s @ %s ----<br/>\n", msg_fixed, date);
+ 	} else {
+ 		strftime(date, sizeof(date), "%H:%M:%S", localtime(&time));
+ 		if (type & GAIM_MESSAGE_SYSTEM)
+ 			fprintf(data->file, "(%s)<b> %s</b><br/>\n", date, msg_fixed);
+ 		else if (type & GAIM_MESSAGE_WHISPER)
+ 			fprintf(data->file, "<font color=\"#6C2585\">(%s)<b> %s:</b></font> %s<br/>\n",
+ 					date, from, msg_fixed);
+ 		else if (type & GAIM_MESSAGE_AUTO_RESP) {
+ 			if (type & GAIM_MESSAGE_SEND)
+ 				fprintf(data->file, _("<font color=\"#16569E\">(%s) <b>%s &lt;AUTO-REPLY&gt;:</b></font> %s<br/>\n"), date, from, msg_fixed);
+ 			else if (type & GAIM_MESSAGE_RECV)
+ 				fprintf(data->file, _("<font color=\"#A82F2F\">(%s) <b>%s &lt;AUTO-REPLY&gt;:</b></font> %s<br/>\n"), date, from, msg_fixed);
+ 		} else if (type & GAIM_MESSAGE_RECV) {
+ 			if(gaim_message_meify(msg_fixed, -1))
+ 				fprintf(data->file, "<font color=\"#6C2585\">(%s) <b>***%s</b></font> <font sml=\"%s\">%s</font><br/>\n",
+ 						date, from, gc->prpl->info->name, msg_fixed);
+ 			else
+ 				fprintf(data->file, "<font color=\"#A82F2F\">(%s) <b>%s:</b></font> <font sml=\"%s\">%s</font><br/>\n",
+ 						date, from, gc->prpl->info->name, msg_fixed);
+ 		} else if (type & GAIM_MESSAGE_SEND) {
+ 			if(gaim_message_meify(msg_fixed, -1))
+ 				fprintf(data->file, "<font color=\"#6C2585\">(%s) <b>***%s</b></font> <font sml=\"%s\">%s</font><br/>\n",
+ 						date, from, gc->prpl->info->name, msg_fixed);
+ 			else
+ 				fprintf(data->file, "<font color=\"#16569E\">(%s) <b>%s:</b></font> <font sml=\"%s\">%s</font><br/>\n",
+ 						date, from, gc->prpl->info->name, msg_fixed);
+ 		}
 	}
+
 	g_free(msg_fixed);
 	fflush(data->file);
 }
@@ -551,6 +578,11 @@
 	return log_lister_common(sn, account, ".html", &html_logger);
 }
 
+static GList *html_logger_list_syslog(GaimAccount *account)
+{
+	return log_lister_common(".system", account, ".html", &html_logger);
+}
+
 static char *html_logger_read(GaimLog *log, GaimLogReadFlags *flags)
 {
 	char *read, *minus_header;
@@ -570,15 +602,49 @@
 	return g_strdup(_("<font color=\"red\"><b>Could not read file: %s</b></font>"));
 }
 
+static void html_logger_create(GaimLog *log)
+{
+	if(log->type == GAIM_LOG_SYSTEM){
+		char date[64];
+		const char *prpl = GAIM_PLUGIN_PROTOCOL_INFO
+			(gaim_find_prpl(gaim_account_get_protocol_id(log->account)))->list_icon(log->account, NULL);
+		char *ud = gaim_user_dir();
+		char *dir = g_build_filename(ud, "logs", prpl, log->name, ".system", NULL);
+		char *filename;
+		struct generic_logger_data *data;
+
+		gaim_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
+		strftime(date, sizeof(date), "%Y-%m-%d.%H%M%S.html", localtime(&log->time));
+		filename = g_build_filename(dir, date, NULL);
+		g_free(dir);
+
+		log->logger_data = data = g_new0(struct generic_logger_data, 1);
+
+		data->file = fopen(filename, "a");
+		if (!data->file) {
+			gaim_debug(GAIM_DEBUG_ERROR, "log",
+					"Could not create log file %s\n", filename);
+			g_free(filename);
+			return;
+		}
+		fprintf(data->file, "<html><head><title>");
+		fprintf(data->file, "System Log for %s (%s)",
+				gaim_account_get_username(log->account), prpl);
+		fprintf(data->file, "</title></head><body>");
+		g_free(filename);
+	}
+}
+
 static GaimLogLogger html_logger = {
 	N_("HTML"), "html",
-	NULL,
+	html_logger_create,
 	html_logger_write,
 	html_logger_finalize,
 	html_logger_list,
 	html_logger_read,
 	log_sizer_common,
-	NULL
+	NULL,
+	html_logger_list_syslog
 };
 
 
@@ -599,6 +665,9 @@
 		/* This log is new.  We could use the loggers 'new' function, but
 		 * creating a new file there would result in empty files in the case
 		 * that you open a convo with someone, but don't say anything.
+		 *
+		 * The log is also not system log. Because if it is, data would be
+		 * created in txt_logger_create
 		 */
 		char *ud = gaim_user_dir();
 		char *filename;
@@ -641,33 +710,41 @@
 	if(!data->file)
 		return;
 
-	strftime(date, sizeof(date), "%H:%M:%S", localtime(&time));
-	stripped = gaim_markup_strip_html(message);
-	if (type & GAIM_MESSAGE_SEND ||
-	    type & GAIM_MESSAGE_RECV) {
-		if (type & GAIM_MESSAGE_AUTO_RESP) {
-			fprintf(data->file, _("(%s) %s <AUTO-REPLY>: %s\n"), date, from, stripped);
-		} else {
-			if(gaim_message_meify(stripped, -1))
-				fprintf(data->file, "(%s) ***%s %s\n", date, from,
-						stripped);
-			else
-				fprintf(data->file, "(%s) %s: %s\n", date, from,
-						stripped);
-		}
-	} else if (type & GAIM_MESSAGE_SYSTEM)
-		fprintf(data->file, "(%s) %s\n", date, stripped);
-	else if (type & GAIM_MESSAGE_NO_LOG) {
-		/* This shouldn't happen */
-		g_free(stripped);
-		return;
-	} else if (type & GAIM_MESSAGE_WHISPER)
-		fprintf(data->file, "(%s) *%s* %s", date, from, stripped);
-	else
-		fprintf(data->file, "(%s) %s%s %s\n", date, from ? from : "", from ? ":" : "", stripped);
-
-	fflush(data->file);
-	g_free(stripped);
+ 	stripped = gaim_markup_strip_html(message);
+  
+ 	if(log->type == GAIM_LOG_SYSTEM){
+ 		strftime(date, sizeof(date), "%c", localtime(&time));
+ 		fprintf(data->file, "---- %s @ %s ----\n", stripped, date);
+ 	} else {
+ 		strftime(date, sizeof(date), "%H:%M:%S", localtime(&time));
+ 		if (type & GAIM_MESSAGE_SEND ||
+ 			type & GAIM_MESSAGE_RECV) {
+ 			if (type & GAIM_MESSAGE_AUTO_RESP) {
+ 				fprintf(data->file, _("(%s) %s <AUTO-REPLY>: %s\n"), date,
+ 						from, stripped);
+ 			} else {
+ 				if(gaim_message_meify(stripped, -1))
+ 					fprintf(data->file, "(%s) ***%s %s\n", date, from,
+ 							stripped);
+ 				else
+ 					fprintf(data->file, "(%s) %s: %s\n", date, from,
+ 							stripped);
+ 			}
+ 		} else if (type & GAIM_MESSAGE_SYSTEM)
+ 			fprintf(data->file, "(%s) %s\n", date, stripped);
+ 		else if (type & GAIM_MESSAGE_NO_LOG) {
+ 			/* This shouldn't happen */
+ 			g_free(stripped);
+ 			return;
+ 		} else if (type & GAIM_MESSAGE_WHISPER)
+ 			fprintf(data->file, "(%s) *%s* %s", date, from, stripped);
+ 		else
+ 			fprintf(data->file, "(%s) %s%s %s\n", date, from ? from : "",
+ 					from ? ":" : "", stripped);
+ 	}
+ 
+ 	fflush(data->file);
+ 	g_free(stripped);
 }
 
 static void txt_logger_finalize(GaimLog *log)
@@ -687,6 +764,11 @@
 	return log_lister_common(sn, account, ".txt", &txt_logger);
 }
 
+static GList *txt_logger_list_syslog(GaimAccount *account)
+{
+	return log_lister_common(".system", account, ".txt", &txt_logger);
+}
+
 static char *txt_logger_read(GaimLog *log, GaimLogReadFlags *flags)
 {
 	char *read, *minus_header, *minus_header2;
@@ -708,15 +790,45 @@
         return g_strdup(_("<font color=\"red\"><b>Could not read file: %s</b></font>"));
 }
 
+static void txt_logger_create(GaimLog *log)
+{
+	if(log->type == GAIM_LOG_SYSTEM){
+		char date[64];
+		const char *prpl = GAIM_PLUGIN_PROTOCOL_INFO
+			(gaim_find_prpl(gaim_account_get_protocol_id(log->account)))->list_icon(log->account, NULL);
+		char *ud = gaim_user_dir();
+		char *dir = g_build_filename(ud, "logs", prpl, log->name, ".system", NULL);
+		char *filename;
+		struct generic_logger_data *data;
+
+		gaim_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
+		strftime(date, sizeof(date), "%Y-%m-%d.%H%M%S.txt", localtime(&log->time));
+		filename = g_build_filename(dir, date, NULL);
+		g_free(dir);
+
+		log->logger_data = data = g_new0(struct generic_logger_data, 1);
+
+		data->file = fopen(filename, "a");
+		if (!data->file) {
+			gaim_debug(GAIM_DEBUG_ERROR, "log",
+					"Could not create log file %s\n", filename);
+			g_free(filename);
+			return;
+		}
+		g_free(filename);
+	}
+}
+
 static GaimLogLogger txt_logger = {
 	N_("Plain text"), "txt",
-	NULL,
+	txt_logger_create,
 	txt_logger_write,
 	txt_logger_finalize,
 	txt_logger_list,
 	txt_logger_read,
 	log_sizer_common,
-	NULL
+	NULL,
+	txt_logger_list_syslog
 };
 
 /****************
@@ -912,5 +1024,6 @@
 	old_logger_list,
 	old_logger_read,
 	old_logger_size,
-	old_logger_total_size
+	old_logger_total_size,
+	NULL
 };
--- a/src/log.h	Sat Apr 03 18:01:58 2004 +0000
+++ b/src/log.h	Sat Apr 03 18:34:29 2004 +0000
@@ -87,6 +87,9 @@
 	/** Returns the total size of all the logs. If this is undefined a default
 	 * implementation is used */
 	int (*total_size)(const char *name, GaimAccount *account);
+
+	/** This function returns a sorted GList of available system GaimLogs */
+	GList *(*list_syslog)(GaimAccount *account);
 };
 
 /**
@@ -169,6 +172,14 @@
 	GList *gaim_log_get_logs(const char *name, GaimAccount *account);
 
 	/**
+	 * Returns a list of all available system logs
+	 *
+	 * @param account The account
+	 * @return		A sorted list of GaimLogs
+	 */
+	GList *gaim_log_get_system_logs(GaimAccount *account);
+
+	/**
 	 * Returns the size of a log 
 	 *
 	 * @param log                 The log
@@ -184,6 +195,16 @@
 	 * @return                    The size in bytes
 	 */
 	 int gaim_log_get_total_size(const char *name, GaimAccount *account);
+
+	/**
+	 * Implements GCompareFunc
+	 *
+	 * @param y				   A GaimLog
+	 * @param z				   Another GaimLog
+	 * @return					A value as specified by GCompareFunc
+	 */
+	 gint gaim_log_compare(gconstpointer y, gconstpointer z);
+
 	/******************************************
 	 ** LOGGER FUNCTIONS **********************
 	 ******************************************/
--- a/src/prpl.h	Sat Apr 03 18:01:58 2004 +0000
+++ b/src/prpl.h	Sat Apr 03 18:34:29 2004 +0000
@@ -71,10 +71,6 @@
 } GaimProtocol;
 
 
-#include "blist.h"
-#include "proxy.h"
-#include "plugin.h"
-
 /** Default protocol plugin description */
 #define GAIM_PRPL_DESC(x) \
 		"Allows gaim to use the " (x) " protocol.\n\n"      \
@@ -98,6 +94,10 @@
 	GAIM_CONV_IM_IMAGES    = 0x0002     /**< Contains images.  */
 } GaimConvImFlags;
 
+#include "blist.h"
+#include "proxy.h"
+#include "plugin.h"
+
 /**
  * Protocol options
  *
--- a/src/server.c	Sat Apr 03 18:01:58 2004 +0000
+++ b/src/server.c	Sat Apr 03 18:34:29 2004 +0000
@@ -1100,6 +1100,9 @@
 	GaimBuddy *b;
 	GSList *buddies;
 	int old_idle;
+ 	time_t current_time = time(NULL);
+ 	int signing_on = 0;
+ 	int signing_off = 0;
 
 	account = gaim_connection_get_account(gc);
 	b = gaim_find_buddy(account, name);
@@ -1148,66 +1151,136 @@
 */
 	gaim_blist_update_buddy_status(b, type);
 
-	if (!old_idle && idle) {
-		gaim_signal_emit(gaim_blist_get_handle(), "buddy-idle", b);
-	} else if (old_idle && !idle) {
-		gaim_signal_emit(gaim_blist_get_handle(), "buddy-unidle", b);
+ 	if (loggedin) {
+ 		if (!GAIM_BUDDY_IS_ONLINE(b)) {
+ 			signing_on = TRUE;
+ 		}
+ 	} else if (GAIM_BUDDY_IS_ONLINE(b)) {
+ 		signing_off = TRUE;
+ 	}
+
+
+	if (signing_on) {
+		if (gaim_prefs_get_bool("/core/conversations/im/show_login")) {
+			if (c != NULL) {
+
+				char *tmp = g_strdup_printf(_("%s logged in."),
+											gaim_get_buddy_alias(b));
+
+				gaim_conversation_write(c, NULL, tmp, GAIM_MESSAGE_SYSTEM,
+										time(NULL));
+				g_free(tmp);
+			}
+			else if (awayqueue && find_queue_total_by_name(b->name)) {
+				struct queued_message *qm = g_new0(struct queued_message, 1);
+				g_snprintf(qm->name, sizeof(qm->name), "%s", b->name);
+				qm->message = g_strdup_printf(_("%s logged in."),
+											  gaim_get_buddy_alias(b));
+				qm->account = gc->account;
+				qm->tm = time(NULL);
+				qm->flags = GAIM_MESSAGE_SYSTEM;
+				message_queue = g_slist_append(message_queue, qm);
+			}
+		}
+		gaim_sound_play_event(GAIM_SOUND_BUDDY_ARRIVE);
+
+ 		if(gaim_prefs_get_bool("/core/logging/log_system") &&
+ 		   gaim_prefs_get_bool("/core/logging/log_signon_signoff")) {
+ 			GaimAccount *account = gaim_connection_get_account(gc);
+ 			GaimLog *log = gaim_account_get_log(account);
+ 			char *tmp = g_strdup_printf(_("%s signed on"),
+ 										gaim_get_buddy_alias(b));
+ 
+ 			gaim_log_write(log, GAIM_MESSAGE_SYSTEM, gaim_get_buddy_alias(b),
+ 						   current_time, tmp);
+ 			g_free(tmp);
+ 		}
 	}
 
-	if (loggedin) {
-		if (!GAIM_BUDDY_IS_ONLINE(b)) {
-			if (gaim_prefs_get_bool("/core/conversations/im/show_login")) {
-				if (c != NULL) {
-
-					char *tmp = g_strdup_printf(_("%s logged in."),
-												gaim_get_buddy_alias(b));
+ 	if(gaim_prefs_get_bool("/core/logging/log_system") &&
+ 	   gaim_prefs_get_bool("/core/logging/log_away_state")) {
+ 		GaimAccount *account = gaim_connection_get_account(gc);
+ 		GaimLog *log = gaim_account_get_log(account);
+ 		char *tmp = NULL;
+ 
+ 		if((b->uc & UC_UNAVAILABLE) && !(type & UC_UNAVAILABLE))
+ 			tmp = g_strdup_printf(_("%s came back"), gaim_get_buddy_alias(b));
+ 		else if(!(b->uc & UC_UNAVAILABLE) && (type & UC_UNAVAILABLE))
+ 			tmp = g_strdup_printf(_("%s went away"), gaim_get_buddy_alias(b));
+ 
+ 		if(tmp){
+ 			gaim_log_write(log, GAIM_MESSAGE_SYSTEM, gaim_get_buddy_alias(b),
+ 						   current_time, tmp);
+ 			g_free(tmp);
+ 		}
+ 	}
 
-					gaim_conversation_write(c, NULL, tmp, GAIM_MESSAGE_SYSTEM,
-											time(NULL));
-					g_free(tmp);
-				}
-				else if (awayqueue && find_queue_total_by_name(b->name)) {
-					struct queued_message *qm = g_new0(struct queued_message, 1);
-					g_snprintf(qm->name, sizeof(qm->name), "%s", b->name);
-					qm->message = g_strdup_printf(_("%s logged in."),
-												  gaim_get_buddy_alias(b));
-					qm->account = gc->account;
-					qm->tm = time(NULL);
-					qm->flags = GAIM_MESSAGE_SYSTEM;
-					message_queue = g_slist_append(message_queue, qm);
-				}
+	if (!old_idle && idle) {
+		gaim_signal_emit(gaim_blist_get_handle(), "buddy-idle", b);
+ 		if(gaim_prefs_get_bool("/core/logging/log_system") &&
+ 		   gaim_prefs_get_bool("/core/logging/log_idle_state")) {
+ 			GaimAccount *account = gaim_connection_get_account(gc);
+ 			GaimLog *log = gaim_account_get_log(account);
+ 			char *tmp = g_strdup_printf(_("%s became idle"),
+ 										gaim_get_buddy_alias(b));
+ 
+ 			gaim_log_write(log, GAIM_MESSAGE_SYSTEM, gaim_get_buddy_alias(b),
+ 						   current_time, tmp);
+ 			g_free(tmp);
+ 		}
+	} else if (old_idle && !idle) {
+		gaim_signal_emit(gaim_blist_get_handle(), "buddy-unidle", b);
+ 
+ 		if(gaim_prefs_get_bool("/core/logging/log_system") &&
+ 		   gaim_prefs_get_bool("/core/logging/log_idle_state")) {
+ 			GaimAccount *account = gaim_connection_get_account(gc);
+ 			GaimLog *log = gaim_account_get_log(account);
+ 			char *tmp = g_strdup_printf(_("%s became unidle"),
+ 										gaim_get_buddy_alias(b));
+ 
+ 			gaim_log_write(log, GAIM_MESSAGE_SYSTEM, gaim_get_buddy_alias(b),
+ 						   current_time, tmp);
+ 			g_free(tmp);
+ 		}
+	}
+
+	if (signing_off) {
+		if (gaim_prefs_get_bool("/core/conversations/im/show_login")) {
+			if (c != NULL) {
+
+				char *tmp = g_strdup_printf(_("%s logged out."),
+											gaim_get_buddy_alias(b));
+				gaim_conversation_write(c, NULL, tmp,
+										GAIM_MESSAGE_SYSTEM, time(NULL));
+				g_free(tmp);
+			} else if (awayqueue && find_queue_total_by_name(b->name)) {
+				struct queued_message *qm = g_new0(struct queued_message, 1);
+				g_snprintf(qm->name, sizeof(qm->name), "%s", b->name);
+				qm->message = g_strdup_printf(_("%s logged out."),
+											  gaim_get_buddy_alias(b));
+				qm->account = gc->account;
+				qm->tm = time(NULL);
+				qm->flags = GAIM_MESSAGE_SYSTEM;
+				message_queue = g_slist_append(message_queue, qm);
 			}
-			gaim_sound_play_event(GAIM_SOUND_BUDDY_ARRIVE);
-			/* LOG system_log(log_signon, gc, b, OPT_LOG_BUDDY_SIGNON); */
 		}
-	} else {
-		if (GAIM_BUDDY_IS_ONLINE(b)) {
-
-			if (gaim_prefs_get_bool("/core/conversations/im/show_login")) {
-				if (c != NULL) {
+		serv_got_typing_stopped(gc, name); /* obviously not typing */
+		gaim_sound_play_event(GAIM_SOUND_BUDDY_LEAVE);
 
-					char *tmp = g_strdup_printf(_("%s logged out."),
-												gaim_get_buddy_alias(b));
-					gaim_conversation_write(c, NULL, tmp,
-											GAIM_MESSAGE_SYSTEM, time(NULL));
-					g_free(tmp);
-				} else if (awayqueue && find_queue_total_by_name(b->name)) {
-					struct queued_message *qm = g_new0(struct queued_message, 1);
-					g_snprintf(qm->name, sizeof(qm->name), "%s", b->name);
-					qm->message = g_strdup_printf(_("%s logged out."),
-												  gaim_get_buddy_alias(b));
-					qm->account = gc->account;
-					qm->tm = time(NULL);
-					qm->flags = GAIM_MESSAGE_SYSTEM;
-					message_queue = g_slist_append(message_queue, qm);
-				}
-			}
-			serv_got_typing_stopped(gc, name); /* obviously not typing */
-			gaim_sound_play_event(GAIM_SOUND_BUDDY_LEAVE);
-			/* LOG system_log(log_signoff, gc, b, OPT_LOG_BUDDY_SIGNON); */
-		}
+ 		if(gaim_prefs_get_bool("/core/logging/log_system") &&
+ 		   gaim_prefs_get_bool("/core/logging/log_signon_signoff")) {
+ 			GaimAccount *account = gaim_connection_get_account(gc);
+ 			GaimLog *log = gaim_account_get_log(account);
+ 			char *tmp = g_strdup_printf(_("%s signed off"),
+ 										gaim_get_buddy_alias(b));
+ 
+ 			gaim_log_write(log, GAIM_MESSAGE_SYSTEM, gaim_get_buddy_alias(b),
+ 						   current_time, tmp);
+ 			g_free(tmp);
+ 		}
 	}
 
+
 	if (c != NULL)
 		gaim_conversation_update(c, GAIM_CONV_UPDATE_AWAY);