changeset 11025:8d2007d738d5

[gaim-migrate @ 12899] sf patch #1180490, from Richard Laager (who else?) A pretty peach of a patch that allows you to auto-complete screen names based on log file names. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Thu, 23 Jun 2005 03:04:52 +0000
parents 1d58cc6c4552
children a659e6bac294
files plugins/ChangeLog.API src/gtkblist.c src/gtkdialogs.c src/gtkrequest.c src/log.c src/log.h
diffstat 6 files changed, 439 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/ChangeLog.API	Thu Jun 23 02:24:22 2005 +0000
+++ b/plugins/ChangeLog.API	Thu Jun 23 03:04:52 2005 +0000
@@ -60,6 +60,10 @@
 	* Added:   gaim_gtk_blist_node_is_contact_expanded, returns TRUE if
 	           the given blist node is a buddy inside an expanded contact,
 	           or is itself an expanded contact
+	* Added:   GaimLogSet struct, get_log_sets function to GaimLogLogger,
+	           gaim_log_get_log_sets, gaim_log_set_compare
+	* Changed: gaim_log_logger_new, added total_size, list_syslog, and get_log_sets
+	           parameters to bring the function up-to-date with GaimLogLogger
 
 	Signals:
 	* Changed: "received-im-msg" and "received-chat-msg" to match, both
--- a/src/gtkblist.c	Thu Jun 23 02:24:22 2005 +0000
+++ b/src/gtkblist.c	Thu Jun 23 03:04:52 2005 +0000
@@ -2660,8 +2660,8 @@
 	{ N_("/Buddies/Get User _Info..."), "<CTL>I", gaim_gtkdialogs_info, 0, "<StockItem>", GAIM_STOCK_INFO },
 	{ N_("/Buddies/View User _Log..."), "<CTL>L", gaim_gtkdialogs_log, 0, NULL },
 	{ "/Buddies/sep1", NULL, NULL, 0, "<Separator>" },
-	{ N_("/Buddies/Show _Offline Buddies"), "<CTL>O", gaim_gtk_blist_edit_mode_cb, 1, "<CheckItem>"},
-	{ N_("/Buddies/Show _Empty Groups"), "<CTL>E", gaim_gtk_blist_show_empty_groups_cb, 1, "<CheckItem>"},
+	{ N_("/Buddies/Show _Offline Buddies"), NULL, gaim_gtk_blist_edit_mode_cb, 1, "<CheckItem>"},
+	{ N_("/Buddies/Show _Empty Groups"), NULL, gaim_gtk_blist_show_empty_groups_cb, 1, "<CheckItem>"},
 	{ N_("/Buddies/_Add Buddy..."), "<CTL>B", gaim_gtk_blist_add_buddy_cb, 0, "<StockItem>", GTK_STOCK_ADD },
 	{ N_("/Buddies/Add C_hat..."), NULL, gaim_gtk_blist_add_chat_cb, 0, "<StockItem>", GTK_STOCK_ADD },
 	{ N_("/Buddies/Add _Group..."), NULL, gaim_blist_request_add_group, 0, "<StockItem>", GTK_STOCK_ADD },
--- a/src/gtkdialogs.c	Thu Jun 23 02:24:22 2005 +0000
+++ b/src/gtkdialogs.c	Thu Jun 23 03:04:52 2005 +0000
@@ -694,7 +694,7 @@
 	gaim_request_fields_add_group(fields, group);
 
 	field = gaim_request_field_string_new("screenname", _("_Name"), NULL, FALSE);
-	gaim_request_field_set_type_hint(field, "screenname");
+	gaim_request_field_set_type_hint(field, "screenname-all");
 	gaim_request_field_set_required(field, TRUE);
 	gaim_request_field_group_add_field(group, field);
 
@@ -707,7 +707,7 @@
 	gaim_request_field_set_required(field, TRUE);
 	gaim_request_field_group_add_field(group, field);
 
-	gaim_request_fields(gaim_get_blist(), _("Get User Log"),
+	gaim_request_fields(gaim_get_blist(), _("View User Log"),
 						NULL,
 						_("Please enter the screen name or alias of the person "
 						  "whose log you would like to view."),
--- a/src/gtkrequest.c	Thu Jun 23 02:24:22 2005 +0000
+++ b/src/gtkrequest.c	Thu Jun 23 03:04:52 2005 +0000
@@ -648,10 +648,12 @@
 }
 
 static GList *
-get_online_names(void)
+get_screenname_completion_data(gboolean all)
 {
 	GList *names = NULL;
 	GaimBlistNode *gnode, *cnode, *bnode;
+	GList *log_sets;
+	GList *log_set;
 
 	for (gnode = gaim_get_blist()->root; gnode != NULL; gnode = gnode->next)
 	{
@@ -667,7 +669,7 @@
 			{
 				GaimBuddy *buddy = (GaimBuddy *)bnode;
 
-				if (!gaim_account_is_connected(buddy->account))
+				if (!all && !gaim_account_is_connected(buddy->account))
 					continue;
 
 #ifdef NEW_STYLE_COMPLETION
@@ -677,11 +679,34 @@
 				names = g_list_append(names, buddy->account);
 #endif /* NEW_STYLE_COMPLETION */
 
-				names = g_list_append(names, buddy->name);
+				names = g_list_append(names, g_strdup(buddy->name));
 			}
 		}
 	}
 
+	log_sets = gaim_log_get_log_sets();
+	for (log_set = log_sets ; log_set != NULL ; log_set = log_set->next) {
+		GaimLogSet *set = log_set->data;
+
+		/* 1. Don't show buddies because we will have gotten them above.
+		 * 2. If we're not showing all accounts, then only show those with
+		 *    non-NULL accounts that are currently connected.
+		 * 3. The boxes that use this autocomplete code handle only IMs. */
+		if (!set->buddy &&
+			(all || (set->account != NULL && gaim_account_is_connected(set->account))) &&
+		    set->type != GAIM_LOG_CHAT) {
+#ifdef NEW_STYLE_COMPLETION
+				names = g_list_append(names, NULL);
+				names = g_list_append(names, NULL);
+				names = g_list_append(names, set->account);
+#endif /* NEW_STYLE_COMPLETION */
+
+				names = g_list_append(names, set->name);
+		}
+
+		g_free(set);
+	}
+
 	return names;
 }
 
@@ -759,6 +784,7 @@
 static void
 destroy_completion_data(GtkWidget *w, GaimGtkCompletionData *data)
 {
+	g_list_foreach(data->completion->items, (GFunc)g_free, NULL);
 	g_completion_free(data->completion);
 
 	g_free(data);
@@ -861,23 +887,23 @@
 #endif /* !NEW_STYLE_COMPLETION */
 
 static void
-setup_screenname_autocomplete(GtkWidget *entry, GaimRequestField *field)
+setup_screenname_autocomplete(GtkWidget *entry, GaimRequestField *field, gboolean all)
 {
 #ifdef NEW_STYLE_COMPLETION
 	GtkListStore *store;
 	GtkTreeIter iter;
 	GtkEntryCompletion *completion;
-	GList *aliases_and_screennames;
+	GList *screenname_completion_data;
 	GList *l;
 	gpointer *data;
 
-	/* Store the displayed completion value, the screenname, and the value for comparison. */
+	/* Store the displayed completion value, the screenname, the value for comparison, and the account. */
 	store = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
 
-	aliases_and_screennames = get_online_names();
+	screenname_completion_data = get_screenname_completion_data(all);
 
 	/* Loop through the list four elements at a time. */
-	for (l = aliases_and_screennames; l != NULL; l = l->next->next->next->next)
+	for (l = screenname_completion_data; l != NULL; l = l->next->next->next->next)
 	{
 		char *contact_alias = l->data;
 		char *buddy_alias = l->next->data;
@@ -929,9 +955,15 @@
 					3, account,
 					-1);
 		}
+
+		g_free(screenname);
 	}
 
-	g_list_free(aliases_and_screennames);
+	g_list_free(screenname_completion_data);
+
+	/* Sort the completion list by screenname. */
+	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
+	                                     1, GTK_SORT_ASCENDING);
 
 	completion = gtk_entry_completion_new();
 	gtk_entry_completion_set_match_func(completion, screenname_completion_match_func, NULL, NULL);
@@ -960,7 +992,7 @@
 
 	g_completion_set_compare(data->completion, g_ascii_strncasecmp);
 
-	screennames = get_online_names();
+	screennames = get_screenname_completion_data(all);
 
 	g_completion_add_items(data->completion, screennames);
 
@@ -989,9 +1021,9 @@
 
 	if ((type_hint = gaim_request_field_get_type_hint(field)) != NULL)
 	{
-		if (!strcmp(type_hint, "screenname"))
+		if (!strncmp(type_hint, "screenname", sizeof("screenname") - 1))
 		{
-			setup_screenname_autocomplete(entry, field);
+			setup_screenname_autocomplete(entry, field, !strcmp(type_hint, "screenname-all"));
 		}
 	}
 }
--- a/src/log.c	Thu Jun 23 02:24:22 2005 +0000
+++ b/src/log.c	Thu Jun 23 03:04:52 2005 +0000
@@ -43,6 +43,7 @@
 };
 static GHashTable *logsize_users = NULL;
 
+static GList *log_get_log_sets_common();
 
 /**************************************************************************
  * PUBLIC LOGGING FUNCTIONS ***********************************************
@@ -238,15 +239,23 @@
 				void(*finalize)(GaimLog *),
 				GList*(*list)(GaimLogType type, const char*, GaimAccount*),
 				char*(*read)(GaimLog*, GaimLogReadFlags*),
-				int(*size)(GaimLog*))
+				int(*size)(GaimLog*),
+				int(*total_size)(GaimLogType type, const char *name, GaimAccount *account),
+				GList*(*list_syslog)(GaimAccount *account),
+				GList*(*get_log_sets)(void))
 {
 	GaimLogLogger *logger = g_new0(GaimLogLogger, 1);
+
 	logger->create = create;
 	logger->write = write;
 	logger->finalize = finalize;
 	logger->list = list;
 	logger->read = read;
 	logger->size = size;
+	logger->total_size = total_size;
+	logger->list_syslog = list_syslog;
+	logger->get_log_sets = get_log_sets;
+
 	return logger;
 }
 
@@ -319,6 +328,103 @@
 	return g_list_sort(logs, gaim_log_compare);
 }
 
+gint gaim_log_set_compare(gconstpointer y, gconstpointer z)
+{
+	const GaimLogSet *a = y;
+	const GaimLogSet *b = z;
+	gint ret = 0;
+	char *tmp;
+
+	/* This logic seems weird at first...
+	 * If either account is NULL, we pretend the accounts are
+	 * equal. This allows us to detect duplicates that will
+	 * exist if one logger knows the account and another
+	 * doesn't. */
+	if (a->account != NULL && b->account != NULL) {
+		ret = gaim_utf8_strcasecmp(gaim_account_get_username(a->account), gaim_account_get_username(b->account));
+		if (ret != 0)
+			return ret;
+	}
+
+	tmp = g_strdup(gaim_normalize(a->account, a->name));
+	ret = gaim_utf8_strcasecmp(tmp, gaim_normalize(b->account, b->name));
+	g_free(tmp);
+	if (ret != 0)
+		return ret;
+
+	return (gint)b->type - (gint)a->type;
+}
+
+guint log_set_hash(gconstpointer key)
+{
+	const GaimLogSet *set = key;
+
+	/* The account isn't hashed because we need GaimLogSets with NULL accounts
+	 * to be found when we search by a GaimLogSet that has a non-NULL account
+	 * but the same type and name. */
+	return g_int_hash((gint *)&set->type) + g_str_hash(set->name);
+}
+
+gboolean log_set_equal(gconstpointer a, gconstpointer b)
+{
+	/* I realize that the choices made for GList and GHashTable
+	 * make sense for those data types, but I wish the comparison
+	 * functions were compatible. */
+	return !gaim_log_set_compare(a, b);
+}
+
+void log_set_build_list(gpointer key, gpointer value, gpointer user_data)
+{
+	*((GList **)user_data) = g_list_append(*((GList **)user_data), key);
+}
+
+GList *gaim_log_get_log_sets()
+{
+	GSList *n;
+	GList *sets = NULL;
+	GList *set;
+	GHashTable *sets_ht = g_hash_table_new(log_set_hash, log_set_equal);
+
+	/* Get the log sets from all the loggers. */
+	for (n = loggers; n; n = n->next) {
+		GaimLogLogger *logger = n->data;
+
+		if (!logger->get_log_sets)
+			continue;
+
+		sets = g_list_concat(sets, logger->get_log_sets());
+	}
+
+	/* Get the log sets for loggers that use the common logger functions. */
+	sets = g_list_concat(sets, log_get_log_sets_common());
+
+	for (set = sets; set != NULL ; set = set->next) {
+		GaimLogSet *existing_set = g_hash_table_lookup(sets_ht, set->data);
+
+		if (existing_set == NULL) {
+			g_hash_table_insert(sets_ht, set->data, set->data);
+		} else if (existing_set->account == NULL && ((GaimLogSet *)set->data)->account != NULL) {
+			/* The existing entry in the hash table has no account.
+			 * This one does. We'll delete the old one and keep this one. */
+			g_hash_table_replace(sets_ht, set->data, set->data);
+			g_free(existing_set->name);
+			g_free(existing_set);
+		} else {
+			g_free(((GaimLogSet *)set->data)->name);
+			g_free(set->data);
+		}
+	}
+	g_list_free(sets);
+
+	/* At this point, we've built a GHashTable of unique GaimLogSets.
+	 * So, we build a list of those keys and destroy the GHashTable. */
+	sets = NULL;
+	g_hash_table_foreach(sets_ht, log_set_build_list, &sets);
+	g_hash_table_destroy(sets_ht);
+
+	return g_list_sort(sets, gaim_log_set_compare);
+}
+
 GList *gaim_log_get_system_logs(GaimAccount *account)
 {
 	GList *logs = NULL;
@@ -446,6 +552,124 @@
 	return st.st_size;
 }
 
+/* This will build log sets for all loggers that use the common logger
+ * functions because they use the same directory structure. */
+static GList *log_get_log_sets_common()
+{
+	gchar *log_path = g_build_filename(gaim_user_dir(), "logs", NULL);
+	GDir *log_dir = g_dir_open(log_path, 0, NULL);
+	const gchar *protocol;
+	GList *sets = NULL;
+
+	if (log_dir == NULL) {
+		g_free(log_path);
+		return NULL;
+	}
+
+	while ((protocol = g_dir_read_name(log_dir)) != NULL) {
+		gchar *protocol_path = g_build_filename(log_path, protocol, NULL);
+		GDir *protocol_dir;
+		const gchar *username;
+		gchar *protocol_unescaped;
+		GList *account_iter;
+		GList *accounts = NULL;
+
+		if ((protocol_dir = g_dir_open(protocol_path, 0, NULL)) == NULL) {
+			g_free(protocol_path);
+			continue;
+		}
+
+		/* Using g_strdup() to cover the one-in-a-million chance that a
+		 * prpl's list_icon function uses gaim_unescape_filename(). */
+		protocol_unescaped = g_strdup(gaim_unescape_filename(protocol));
+
+		/* Find all the accounts for protocol. */
+		for (account_iter = gaim_accounts_get_all() ; account_iter != NULL ; account_iter = account_iter->next) {
+			GaimPlugin *prpl;
+			GaimPluginProtocolInfo *prpl_info;
+		
+			prpl = gaim_find_prpl(gaim_account_get_protocol_id((GaimAccount *)account_iter->data));
+			if (!prpl)
+				continue;
+			prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl);
+
+			if (!strcmp(protocol_unescaped, prpl_info->list_icon((GaimAccount *)account_iter->data, NULL)))
+				accounts = g_list_append(accounts, account_iter->data);
+		}
+		g_free(protocol_unescaped);
+
+		while ((username = g_dir_read_name(protocol_dir)) != NULL) {
+			gchar *username_path = g_build_filename(protocol_path, username, NULL);
+			GDir *username_dir;
+			const gchar *username_unescaped;
+			GaimAccount *account = NULL;
+			gchar *name;
+
+			if ((username_dir = g_dir_open(username_path, 0, NULL)) == NULL) {
+				g_free(username_path);
+				continue;
+			}
+
+			/* Find the account for username in the list of accounts for protocol. */
+			username_unescaped = gaim_unescape_filename(username);
+			for (account_iter = g_list_first(accounts) ; account_iter != NULL ; account_iter = account_iter->next) {
+				if (!strcmp(((GaimAccount *)account_iter->data)->username, username_unescaped)) {
+					account = account_iter->data;
+					break;
+				}
+			}
+
+			/* Don't worry about the cast, name will point to dynamically allocated memory shortly. */
+			while ((name = (gchar *)g_dir_read_name(username_dir)) != NULL) {
+				size_t len;
+				GaimLogSet *set = g_new0(GaimLogSet, 1);
+
+				/* Unescape the filename. */
+				name = g_strdup(gaim_unescape_filename(name));
+
+				/* Get the (possibly new) length of name. */
+				len = strlen(name);
+
+				set->account = account;
+				set->name = name;
+
+				/* Chat for .chat or .system at the end of the name to determine the type. */
+				set->type = GAIM_LOG_IM;
+				if (len > 7) {
+					gchar *tmp = &name[len - 7];
+					if (!strcmp(tmp, ".system")) {
+						set->type = GAIM_LOG_SYSTEM;
+						*tmp = '\0';
+					}
+				}
+				if (len > 5) {
+					gchar *tmp = &name[len - 5];
+					if (!strcmp(tmp, ".chat")) {
+						set->type = GAIM_LOG_CHAT;
+						*tmp = '\0';
+					}
+				}
+
+				/* Determine if this (account, name) combination exists as a buddy. */
+				if (gaim_find_buddy(account, name) != NULL)
+					set->buddy = TRUE;
+				else
+					set->buddy = FALSE;
+
+				sets = g_list_append(sets, set);
+			}
+			g_free(username_path);
+			g_dir_close(username_dir);
+		}
+		g_free(protocol_path);
+		g_dir_close(protocol_dir);
+	}
+	g_free(log_path);
+	g_dir_close(log_dir);
+
+	return sets;
+}
+
 #if 0 /* Maybe some other time. */
 /****************
  ** XML LOGGER **
@@ -541,6 +765,7 @@
 	xml_logger_finalize,
 	xml_logger_list,
 	NULL,
+	NULL,
 	NULL
 };
 #endif
@@ -672,7 +897,8 @@
 	html_logger_read,
 	gaim_log_common_sizer,
 	NULL,
-	html_logger_list_syslog
+	html_logger_list_syslog,
+	NULL
 };
 
 
@@ -804,7 +1030,8 @@
 	txt_logger_read,
 	gaim_log_common_sizer,
 	NULL,
-	txt_logger_list_syslog
+	txt_logger_list_syslog,
+	NULL
 };
 
 /****************
@@ -991,6 +1218,89 @@
 	return data ? data->length : 0;
 }
 
+static GList *old_logger_get_log_sets()
+{
+	char *log_path = g_build_filename(gaim_user_dir(), "logs", NULL);
+	GDir *log_dir = g_dir_open(log_path, 0, NULL);
+	gchar *name;
+	GList *sets = NULL;
+	GaimBlistNode *gnode, *cnode, *bnode;
+
+	g_free(log_path);
+	if (log_dir == NULL)
+		return NULL;
+
+	/* Don't worry about the cast, name will be filled with a dynamically allocated data shortly. */
+	while ((name = (gchar *)g_dir_read_name(log_dir)) != NULL) {
+		size_t len;
+		gchar *ext;
+		GaimLogSet *set;
+		gboolean found = FALSE;
+
+		/* Unescape the filename. */
+		name = g_strdup(gaim_unescape_filename(name));
+
+		/* Get the (possibly new) length of name. */
+		len = strlen(name);
+
+		if (len < 5) {
+			g_free(name);
+			continue;
+		}
+
+		/* Make sure we're dealing with a log file. */
+		ext = &name[len - 4];
+		if (strcmp(ext, ".log")) {
+			g_free(name);
+			continue;
+		}
+
+		set = g_new0(GaimLogSet, 1);
+
+		/* Chat for .chat at the end of the name to determine the type. */
+		*ext = '\0';
+		set->type = GAIM_LOG_IM;
+		if (len > 9) {
+			char *tmp = &name[len - 9];
+			if (!strcmp(tmp, ".chat")) {
+				set->type = GAIM_LOG_CHAT;
+				*tmp = '\0';
+			}
+		}
+
+		set->name = name;
+
+		/* Search the buddy list to find the account and to determine if this is a buddy. */
+		for (gnode = gaim_get_blist()->root; !found && gnode != NULL; gnode = gnode->next)
+		{
+			if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
+				continue;
+
+			for (cnode = gnode->child; !found && cnode != NULL; cnode = cnode->next)
+			{
+				if (!GAIM_BLIST_NODE_IS_CONTACT(cnode))
+					continue;
+
+				for (bnode = cnode->child; !found && bnode != NULL; bnode = bnode->next)
+				{
+					GaimBuddy *buddy = (GaimBuddy *)bnode;
+
+					if (!strcmp(buddy->name, name)) {
+						set->account = buddy->account;
+						set->buddy = TRUE;
+						found = TRUE;
+					}
+				}
+			}
+		}
+
+		sets = g_list_append(sets, set);
+	}
+	g_dir_close(log_dir);
+
+	return sets;
+}
+
 static void old_logger_finalize(GaimLog *log)
 {
 	struct old_logger_data *data = log->logger_data;
@@ -1006,5 +1316,6 @@
 	old_logger_read,
 	old_logger_size,
 	old_logger_total_size,
-	NULL
+	NULL,
+	old_logger_get_log_sets
 };
--- a/src/log.h	Thu Jun 23 02:24:22 2005 +0000
+++ b/src/log.h	Thu Jun 23 03:04:52 2005 +0000
@@ -35,6 +35,7 @@
 typedef struct _GaimLog GaimLog;
 typedef struct _GaimLogLogger GaimLogLogger;
 typedef struct _GaimLogCommonLoggerData GaimLogCommonLoggerData;
+typedef struct _GaimLogSet GaimLogSet;
 
 typedef enum {
 	GAIM_LOG_IM,
@@ -91,6 +92,13 @@
 
 	/** This function returns a sorted GList of available system GaimLogs */
 	GList *(*list_syslog)(GaimAccount *account);
+
+	/** Returns a list of GaimLogSets. By passing the data in the GaimLogSets
+	 *  to list, the caller can get every available GaimLog from the logger.
+	 *  Loggers using gaim_log_common_writer() (or otherwise storing their
+	 *  logs in the same directory structure as the stock loggers) do not
+	 *  need to implement this function. */
+	GList *(*get_log_sets)(void);
 };
 
 /**
@@ -118,6 +126,26 @@
 	void *extra_data;
 };
 
+/**
+ * Describes available logs.
+ *
+ * By passing the elements of this struct to gaim_log_get_logs(), the caller
+ * can get all available GaimLogs.
+ */
+struct _GaimLogSet {
+	GaimLogType type;                     /**< The type of logs available */
+	char *name;                           /**< The name of the logs available */
+	GaimAccount *account;                 /**< The account the available logs
+	                                           took place on. This will be
+	                                           NULL if the account no longer
+	                                           exists. (Depending on a
+	                                           logger's implementation of
+	                                           list, it may not be possible
+	                                           to load such logs.) */
+	gboolean buddy;                       /**< Is this (account, name) a buddy
+	                                           on the buddy list? */
+};
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -131,7 +159,7 @@
  * Creates a new log
  *
  * @param type        The type of log this is.
- * @param name        The name of this conversation (Screenname, chat name,
+ * @param name        The name of this conversation (screenname, chat name,
  *                    etc.)
  * @param account     The account the conversation is occurring on
  * @param time        The time this conversation started
@@ -184,6 +212,20 @@
 GList *gaim_log_get_logs(GaimLogType type, const char *name, GaimAccount *account);
 
 /**
+ * Returns a list of GaimLogSets.
+ *
+ * A "log set" here means the information necessary to gather the
+ * GaimLogs for a given buddy/chat. This information would be passed
+ * to gaim_log_list to get a list of GaimLogs.
+ *
+ * The primary use of this function is to get a list of everyone the
+ * user has ever talked to (assuming he or she uses logging).
+ *
+ * @return A sorted list of all available unique GaimLogSets
+ */
+GList *gaim_log_get_log_sets(void);
+
+/**
  * Returns a list of all available system logs
  *
  * @param account The account
@@ -222,13 +264,23 @@
 char *gaim_log_get_log_dir(GaimLogType type, const char *name, GaimAccount *account);
 
 /**
- * Implements GCompareFunc
+ * Implements GCompareFunc for GaimLogs
  *
  * @param y				   A GaimLog
  * @param z				   Another GaimLog
  * @return					A value as specified by GCompareFunc
  */
 gint gaim_log_compare(gconstpointer y, gconstpointer z);
+
+/**
+ * Implements GCompareFunc for GaimLogSets
+ *
+ * @param y                   A GaimLogSet
+ * @param z                   Another GaimLogSet
+ * @return                    A value as specified by GCompareFunc
+ */
+gint gaim_log_set_compare(gconstpointer y, gconstpointer z);
+
 /*@}*/
 
 /******************************************/
@@ -287,12 +339,15 @@
 /**
  * Creates a new logger
  *
- * @param create   The logger's new function.
- * @param write    The logger's write function.
- * @param finalize The logger's finalize function.
- * @param list     The logger's list function.
- * @param read     The logger's read function.
- * @param size     The logger's size function.
+ * @param create       The logger's new function.
+ * @param write        The logger's write function.
+ * @param finalize     The logger's finalize function.
+ * @param list         The logger's list function.
+ * @param read         The logger's read function.
+ * @param size         The logger's size function.
+ * @param total_size   The logger's total_size function.
+ * @param list_syslog  The logger's list_syslog function.
+ * @param get_log_sets The logger's get_log_sets function.
  *
  * @return The new logger
  */
@@ -302,7 +357,11 @@
 				void(*finalize)(GaimLog *),
 				GList*(*list)(GaimLogType type, const char*, GaimAccount*),
 				char*(*read)(GaimLog*, GaimLogReadFlags*),
-				int(*size)(GaimLog*));
+				int(*size)(GaimLog*),
+				int(*total_size)(GaimLogType type, const char *name, GaimAccount *account),
+				GList*(*list_syslog)(GaimAccount *account),
+				GList*(*get_log_sets)(void));
+
 /**
  * Frees a logger
  *
@@ -342,13 +401,16 @@
 GaimLogLogger *gaim_log_logger_get (void);
 
 /**
- * Returns a GList containing the IDs and Names of the registered log
+ * Returns a GList containing the IDs and names of the registered
  * loggers.
  *
  * @return The list of IDs and names.
  */
 GList *gaim_log_logger_get_options(void);
 
+/**
+ * Initializes the log subsystem.
+ */
 void gaim_log_init(void);
 /*@}*/