/soc/2015/igor.gajowiak/chatlog: 2867d33d0158: Implemented getti...

Igor Gajowiak igor.gajowiak at gmail.com
Thu Jul 23 17:49:23 EDT 2015


Changeset: 2867d33d01586124e4b989cfcc0defae72873ebc
Author:	 Igor Gajowiak <igor.gajowiak at gmail.com>
Date:	 2015-07-23 23:49 +0200
Branch:	 default
URL: https://hg.pidgin.im/soc/2015/igor.gajowiak/chatlog/rev/2867d33d0158

Description:

Implemented getting all buddies from the generic log.

diffstat:

 libpurple/genericlog.c            |  37 ++++++++++++++
 libpurple/genericlog.h            |  24 +++++++++
 libpurple/plugins/log/logsqlite.c |  98 ++++++++++++++++++++++++++++++++++++--
 pidgin/gtkgenericlog.c            |  79 ++++++++++++++++++++++++++----
 4 files changed, 219 insertions(+), 19 deletions(-)

diffs (truncated from 424 to 300 lines):

diff --git a/libpurple/genericlog.c b/libpurple/genericlog.c
--- a/libpurple/genericlog.c
+++ b/libpurple/genericlog.c
@@ -297,6 +297,43 @@ purple_genericlog_get_unseen_msgs(Purple
 	return TRUE;
 }
 
+gboolean
+purple_genericlog_get_all_buddies(GList** result, GError** error)
+{
+	if (!purple_genericlog_inuse) {
+		if (!error) return FALSE;
+
+		*error = g_error_new(purple_genericlog_error_domain(),
+			PURPLE_GENERICLOG_ERROR_NOLOG, "No active log");
+		return FALSE;
+	}
+
+	PurpleGenericLogClass *klass =
+		PURPLE_GENERICLOG_GET_CLASS(purple_genericlog_inuse);
+
+	if (!klass->get_all_buddies) {
+		if (!error) return FALSE;
+
+		*error = g_error_new(purple_genericlog_error_domain(),
+			PURPLE_GENERICLOG_ERROR_OPERATIONNOTSUPPORTED,
+			"%s does not support getting buddies from log",
+			purple_genericlog_get_id(purple_genericlog_inuse));
+		return FALSE;
+	}
+
+	if (!klass->get_all_buddies(result)) {
+		if (!error) return FALSE;
+
+		*error = g_error_new(purple_genericlog_error_domain(),
+			PURPLE_GENERICLOG_ERROR_BACKENDFAIL,
+			"Getting buddies from %s failed",
+			purple_genericlog_get_id(purple_genericlog_inuse));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
 /**************************************************************************/
 /* Error Codes                                                            */
 /**************************************************************************/
diff --git a/libpurple/genericlog.h b/libpurple/genericlog.h
--- a/libpurple/genericlog.h
+++ b/libpurple/genericlog.h
@@ -61,6 +61,10 @@ struct _PurpleGenericLog
  *                   In case of any error the result is not set.
  *                   The client is responsible for freeing the result with
  *                   g_list_free_full(result, g_object_unref).
+ * @get_all_buddies: Gets a list of all #PurpleBuddy objects with at least one
+ *                   message in the log. Returns %TRUE if operation succeeds,
+ *                   %FALSE otherwise. The client is responsible for freeing
+ *                   the result with g_list_free_full(result, g_object_unref).
  *
  * The abstract base class for all log implementations. A conforming plugin
  * must implement at least activate and deactivate methods. Not supported
@@ -81,6 +85,8 @@ struct _PurpleGenericLogClass
 
 	gboolean (*get_unseen_msgs)(PurpleAccount *account, GList **result);
 
+	gboolean (*get_all_buddies)(GList **result);
+
 	void (*reserved1)(void);
 	void (*reserved2)(void);
 	void (*reserved3)(void);
@@ -229,6 +235,24 @@ gboolean
 purple_genericlog_get_unseen_msgs(PurpleAccount *account, GList **result,
 	GError **error);
 
+/**
+ * purple_genericlog_get_all_buddies:
+ * @result[out]: Return location for a #GList containing a list of #PurpleBuddy
+ *               objects. This will not be set in case of any errors.
+ * @error:       Return location for a #GError or %NULL. If provided, this
+ *               will be set to the reason if getting messages fails.
+ *
+ * Gets a list of all #PurpleBuddy objects with at least one message in the
+ * active log.
+ *
+ * The caller is responsible for freeing the result with
+ * g_list_free_full(result, g_object_unref).
+ *
+ * Returns: %TRUE if succeeds, %FALSE otherwise.
+ */
+gboolean
+purple_genericlog_get_all_buddies(GList **result, GError **error);
+
 /**************************************************************************/
 /* Error Codes                                                            */
 /**************************************************************************/
diff --git a/libpurple/plugins/log/logsqlite.c b/libpurple/plugins/log/logsqlite.c
--- a/libpurple/plugins/log/logsqlite.c
+++ b/libpurple/plugins/log/logsqlite.c
@@ -80,8 +80,8 @@ static sqlite3_stmt *insert_message_q = 
 
 static const char *insert_message_q_str =
 	"INSERT INTO Messages (Author, AuthorAlias, Recipient, "
-	"Contents, MsgTime, Flags, Seen, AccountId) "
-	"VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8);";
+	"Contents, MsgTime, Flags, Seen, Send, AccountId) "
+	"VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9);";
 
 typedef enum
 {
@@ -92,7 +92,8 @@ typedef enum
 	INSERT_MESSAGE_QUERY_PARAM_MSGTIME     = 5,
 	INSERT_MESSAGE_QUERY_PARAM_FLAGS       = 6,
 	INSERT_MESSAGE_QUERY_PARAM_SEEN        = 7,
-	INSERT_MESSAGE_QUERY_PARAM_ACCOUNTID   = 8,
+	INSERT_MESSAGE_QUERY_PARAM_SEND        = 8,
+	INSERT_MESSAGE_QUERY_PARAM_ACCOUNTID   = 9,
 } InsertMessageQueryParam;
 
 static sqlite3_stmt *get_unseen_msgs_q = NULL;
@@ -132,6 +133,26 @@ typedef enum
 	MARK_AS_SEEN_QUERY_PARAM_ID = 1
 } MarkAsSeenQueryParam;
 
+static sqlite3_stmt *get_all_buddies_q = NULL;
+
+static const char *get_all_buddies_q_str =
+	"SELECT Username, ProtocolId, Author Buddy FROM "
+	"Messages JOIN Accounts on Accounts.Id = AccountId "
+	"WHERE Send = 0 "
+	"GROUP BY Username, ProtocolId, Buddy "
+	"UNION "
+	"SELECT Username, ProtocolId, Recipient Buddy FROM "
+	"Messages JOIN Accounts on Accounts.Id = AccountId "
+	"WHERE Send = 1 "
+	"GROUP BY Username, ProtocolId, Buddy;";
+
+typedef enum
+{
+	GET_ALL_BUDDIES_QUERY_COL_USERNAME = 0,
+	GET_ALL_BUDDIES_QUERY_COL_PROTOCOL = 1,
+	GET_ALL_BUDDIES_QUERY_COL_BUDDY    = 2,
+} GetAllBuddiesQueryCol;
+
 static void
 sqlitelog_finalize_query(sqlite3_stmt **query)
 {
@@ -153,6 +174,7 @@ sqlitelog_finalize_queries()
 	sqlitelog_finalize_query(&insert_message_q);
 	sqlitelog_finalize_query(&get_unseen_msgs_q);
 	sqlitelog_finalize_query(&mark_as_seen_q);
+	sqlitelog_finalize_query(&get_all_buddies_q);
 }
 
 static gboolean
@@ -184,7 +206,8 @@ sqlitelog_prepare_queries()
 	    !sqlitelog_prepare_query(insert_account_q_str, &insert_account_q) ||
 		!sqlitelog_prepare_query(insert_message_q_str, &insert_message_q) ||
 		!sqlitelog_prepare_query(get_unseen_msgs_q_str, &get_unseen_msgs_q) ||
-		!sqlitelog_prepare_query(mark_as_seen_q_str, &mark_as_seen_q)) {
+		!sqlitelog_prepare_query(mark_as_seen_q_str, &mark_as_seen_q) ||
+		!sqlitelog_prepare_query(get_all_buddies_q_str, &get_all_buddies_q)) {
 
 		sqlitelog_finalize_queries();
 		return FALSE;
@@ -219,10 +242,12 @@ sqlitelog_create_tables(sqlite3 *db_hand
 		"MsgTime INTEGER NOT NULL,"
 		"Flags INTEGER NOT NULL,"
 		"Seen BOOLEAN DEFAULT 0,"
+		"Send BOOLEAN NOT NULL,"
 		"AccountId INTEGER NOT NULL,"
 		"FOREIGN KEY(AccountId) REFERENCES Accounts(Id)); "
 
 		"CREATE INDEX SeenIndex ON Messages (Seen); "
+		"CREATE INDEX SendIndex ON Messages (Send); "
 
 		"CREATE TRIGGER AccountDeleted AFTER DELETE ON Accounts "
 		"BEGIN "
@@ -339,9 +364,10 @@ sqlitelog_insert_account(const PurpleAcc
 }
 
 static gboolean
-sqlitelog_insert_message(unsigned account_id, const PurpleMessage *msg,
-	unsigned *id)
+sqlitelog_insert_message(PurpleAccount *account, unsigned account_id,
+	const PurpleMessage *msg, unsigned *id)
 {
+	g_assert(account);
 	g_assert(account_id != SQLITELOG_DB_ID_NONE);
 	g_assert(msg);
 	g_assert(id);
@@ -349,12 +375,15 @@ sqlitelog_insert_message(unsigned accoun
 	g_assert(insert_message_q);
 
 	const char *author = purple_message_get_author(msg);
+	author = author ? purple_normalize(account, author) : NULL;
 	const char *author_alias = purple_message_get_author_alias(msg);
 	const char *recipient = purple_message_get_recipient(msg);
+	recipient = recipient ? purple_normalize(account, recipient) : NULL;
 	const char *contents = purple_message_get_contents(msg);
 	guint64 msg_time = purple_message_get_time(msg);
 	PurpleMessageFlags msg_flags = purple_message_get_flags(msg);
 	int seen = (msg_flags & PURPLE_MESSAGE_SEND) ? 1 : 0;
+	int send = (msg_flags & PURPLE_MESSAGE_SEND) ? 1 : 0;
 
 	if (sqlite3_bind_text(insert_message_q, INSERT_MESSAGE_QUERY_PARAM_AUTHOR,
 			author, -1, SQLITE_STATIC) != SQLITE_OK ||
@@ -372,6 +401,8 @@ sqlitelog_insert_message(unsigned accoun
 			msg_flags) != SQLITE_OK ||
 		sqlite3_bind_int(insert_message_q, INSERT_MESSAGE_QUERY_PARAM_SEEN,
 			seen) != SQLITE_OK ||
+		sqlite3_bind_int(insert_message_q, INSERT_MESSAGE_QUERY_PARAM_SEND,
+			send) != SQLITE_OK ||
 		sqlite3_bind_int(insert_message_q, INSERT_MESSAGE_QUERY_PARAM_ACCOUNTID,
 			account_id) != SQLITE_OK) {
 		return FALSE;
@@ -465,6 +496,44 @@ sqlitelog_mark_as_seen_impl(unsigned msg
 	return rc == SQLITE_DONE;
 }
 
+static gboolean
+sqlitelog_get_all_buddies_impl(GList **result)
+{
+	g_assert(result);
+
+	g_assert(get_all_buddies_q);
+
+	GList *buddies = NULL;
+	int rc;
+	while ((rc = sqlite3_step(get_all_buddies_q)) == SQLITE_ROW) {
+		const char *username = (const char*) sqlite3_column_text(
+			get_all_buddies_q, GET_ALL_BUDDIES_QUERY_COL_USERNAME);
+		const char *protocol = (const char*) sqlite3_column_text(
+			get_all_buddies_q, GET_ALL_BUDDIES_QUERY_COL_PROTOCOL);
+		const char *buddy = (const char*) sqlite3_column_text(
+			get_all_buddies_q, GET_ALL_BUDDIES_QUERY_COL_BUDDY);
+
+		PurpleAccount *account = purple_accounts_find(username, protocol);
+		if (!account)
+			continue;
+
+		PurpleBuddy *prpl_buddy = purple_blist_find_buddy(account, buddy);
+		if (!prpl_buddy)
+			continue;
+
+		buddies = g_list_prepend(buddies, prpl_buddy);
+		g_object_ref(prpl_buddy);
+	}
+
+	if (rc != SQLITE_DONE) {
+		g_list_free_full(buddies, g_object_unref);
+		return FALSE;
+	}
+
+	*result = buddies;
+	return TRUE;
+}
+
 /**************************************************************************/
 /* PurpleGenericLog API implementation                                    */
 /**************************************************************************/
@@ -540,7 +609,7 @@ sqlitelog_log_im(PurpleAccount *account,
 	}
 
 	unsigned message_id;
-	if (!sqlitelog_insert_message(account_id, message, &message_id))
+	if (!sqlitelog_insert_message(account, account_id, message, &message_id))
 		return FALSE;
 
 	g_object_set_data(G_OBJECT(message), SQLITELOG_MESSAGE_ID_ATTR,
@@ -583,6 +652,20 @@ sqlitelog_get_unseen_msgs(PurpleAccount 
 	return sqlitelog_get_unseen_msgs_impl(account, result);
 }
 
+static gboolean
+sqlitelog_get_all_buddies(GList **result)
+{
+	g_return_val_if_fail(result != NULL, FALSE);
+
+	if (!sqlitelog_db_handle) {
+		purple_debug_error(SQLITELOG_DEBUG_CATEGORY,
+			"Log is not active");
+		return FALSE;
+	}
+
+	return sqlitelog_get_all_buddies_impl(result);
+}
+
 /**************************************************************************/
 /* GObject stuff                                                          */
 /**************************************************************************/
@@ -627,6 +710,7 @@ purple_sqlitelog_class_init (PurpleSqlit
 	klass->parent_class.log_im = sqlitelog_log_im;
 	klass->parent_class.mark_as_seen = sqlitelog_mark_as_seen;
 	klass->parent_class.get_unseen_msgs = sqlitelog_get_unseen_msgs;
+	klass->parent_class.get_all_buddies = sqlitelog_get_all_buddies;
 }
 
 static GType
diff --git a/pidgin/gtkgenericlog.c b/pidgin/gtkgenericlog.c
--- a/pidgin/gtkgenericlog.c



More information about the Commits mailing list