/soc/2015/igor.gajowiak/chatlog: 38521ffa0033: Implemented skipp...

Igor Gajowiak igor.gajowiak at gmail.com
Mon Aug 17 16:43:04 EDT 2015


Changeset: 38521ffa0033c46483d4932827362e97e26cfbeb
Author:	 Igor Gajowiak <igor.gajowiak at gmail.com>
Date:	 2015-08-17 22:42 +0200
Branch:	 default
URL: https://hg.pidgin.im/soc/2015/igor.gajowiak/chatlog/rev/38521ffa0033

Description:

Implemented skipping duplicates when importing messages.

diffstat:

 libpurple/conversation.c          |    4 +-
 libpurple/genericlog.c            |   29 +++++++-
 libpurple/genericlog.h            |   11 ++-
 libpurple/plugins/log/logsqlite.c |  122 ++++++++++++++++++++++++++++++++++++-
 4 files changed, 152 insertions(+), 14 deletions(-)

diffs (truncated from 330 to 300 lines):

diff --git a/libpurple/conversation.c b/libpurple/conversation.c
--- a/libpurple/conversation.c
+++ b/libpurple/conversation.c
@@ -642,7 +642,9 @@ void
 		}
 
 		GError *error;
-		if (!purple_genericlog_log_msg(account, contact, pmsg, &error)) {
+		int seen = (purple_message_get_flags(pmsg) & PURPLE_MESSAGE_SEND)
+			? 1 : 0;
+		if (!purple_genericlog_log_msg(account, contact, pmsg, seen, &error)) {
 			purple_debug_error("conversation", "Logging failed: %s (code=%d)",
 				error->message, error->code);
 			g_error_free(error);
diff --git a/libpurple/genericlog.c b/libpurple/genericlog.c
--- a/libpurple/genericlog.c
+++ b/libpurple/genericlog.c
@@ -261,13 +261,13 @@ purple_genericlog_set_active_log(PurpleG
 
 gboolean
 purple_genericlog_log_msg(PurpleAccount *account, PurpleBlistNode *contact,
-	PurpleMessage *msg, GError **error)
+	PurpleMessage *msg, gboolean seen, GError **error)
 {
 	GENERICLOG_CHECK_CONTACT(contact);
 
 	DEFINE_GENERICLOG_FUNC_WITH_RETURN(log_msg,
 		"%s does not support IM logging",
-		"Failed to log IM in %s", account, contact, msg);
+		"Failed to log IM in %s", account, contact, msg, seen);
 }
 
 gboolean
@@ -349,6 +349,18 @@ purple_genericlog_wipe_log_for_contact(P
 		"Removing messages from %s failed", contact);
 }
 
+static gboolean
+_purple_genericlog_import_msg(PurpleAccount *account, PurpleBlistNode *contact,
+	PurpleMessage *msg, gboolean seen, gboolean *imported, GError **error)
+{
+	GENERICLOG_CHECK_CONTACT(contact);
+
+	DEFINE_GENERICLOG_FUNC_WITH_RETURN(import_msg,
+		"%s does not support importing messages",
+		"Failed to import message into %s",
+		account, contact, msg, seen, imported);
+}
+
 #undef GENERICLOG_CHECK_CONTACT
 #undef DEFINE_GENERICLOG_FUNC_WITH_RETURN
 
@@ -413,9 +425,15 @@ run_import_iteration(gpointer unused)
 		PurpleBlistNode *contact = g_array_index(contacts, PurpleBlistNode*, i);
 		PurpleMessage *message = g_array_index(messages, PurpleMessage*, i);
 
-		/* Should we stop if logging fails? */
-		if (purple_genericlog_log_msg(account, contact, message, NULL))
-			++(import_state->imported_messages_count);
+		gboolean imported;
+
+		/* Should we stop if importing fails? */
+		if (!_purple_genericlog_import_msg(account, contact, message, TRUE,
+			&imported, NULL)) {
+			continue;
+		}
+
+		import_state->imported_messages_count += imported ? 1 : 0;
 	}
 
 	g_array_free(accounts, TRUE);
@@ -581,6 +599,7 @@ purple_genericlog_class_init(PurpleGener
 	klass->init_export = NULL;
 	klass->read_chunk = NULL;
 	klass->finalize_export = NULL;
+	klass->import_msg = NULL;
 
 	klass->reserved1 = NULL;
 	klass->reserved2 = NULL;
diff --git a/libpurple/genericlog.h b/libpurple/genericlog.h
--- a/libpurple/genericlog.h
+++ b/libpurple/genericlog.h
@@ -103,6 +103,9 @@ struct _PurpleGenericLog
  *                   export. Returns %TRUE if operation succeeds,
  *                   %FALSE otherwise.
  * @finalize_export: Finalizes an export procedure.
+ * @import_msg:      Imports a message. Behaves same as log_msg, but
+ *                   additionally skips duplicates. Returns %TRUE if operation
+ *                   succeeds, %FALSE otherwise.
  *
  * The abstract base class for all log implementations. A conforming plugin
  * must implement at least activate and deactivate methods. Not supported
@@ -118,7 +121,7 @@ struct _PurpleGenericLogClass
 	void (*deactivate)(void);
 
 	gboolean (*log_msg) (PurpleAccount *account, PurpleBlistNode* contact,
-		PurpleMessage *message);
+		PurpleMessage *message, gboolean seen);
 
 	gboolean (*mark_as_seen)(PurpleMessage *message);
 
@@ -146,6 +149,9 @@ struct _PurpleGenericLogClass
 
 	void (*finalize_export) (void *export_state);
 
+	gboolean (*import_msg) (PurpleAccount *account, PurpleBlistNode* contact,
+		PurpleMessage *message, gboolean seen, gboolean *imported);
+
 	void (*reserved1)(void);
 	void (*reserved2)(void);
 	void (*reserved3)(void);
@@ -272,6 +278,7 @@ purple_genericlog_set_active_log(PurpleG
  * @account: The account.
  * @contact  The contact, must be PurpleChat or PurpleBuddy.
  * @msg:     The message.
+ * @seen:    %TRUE if message should be marked as seen.
  * @error:   Return location for a #GError or %NULL. If provided, this
  *           will be set to the reason if logging fails.
  *
@@ -281,7 +288,7 @@ purple_genericlog_set_active_log(PurpleG
  */
 gboolean
 purple_genericlog_log_msg(PurpleAccount *account, PurpleBlistNode* contact,
-	PurpleMessage *msg, GError **error);
+	PurpleMessage *msg, gboolean seen, GError **error);
 
 /**
  * purple_genericlog_mark_as_seen:
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
@@ -311,6 +311,23 @@ typedef enum
 	DELETE_CONTACT_QUERY_PARAM_ACCOUNTID   = 2,
 } DeleteContactQueryParam;
 
+static sqlite3_stmt *contains_msg_q = NULL;
+
+static const char *contains_msg_q_str =
+	"SELECT NULL FROM Messages "
+	"WHERE AccountId = ?1 AND ContactId = ?2 AND MsgTime = ?3 "
+	"AND Author IS ?4 AND Recipient IS ?5 AND Contents IS ?6 LIMIT 1;";
+
+typedef enum
+{
+	CONTAINS_MSG_QUERY_PARAM_ACCOUNTID = 1,
+	CONTAINS_MSG_QUERY_PARAM_CONTACTID = 2,
+	CONTAINS_MSG_QUERY_PARAM_MSGTIME   = 3,
+	CONTAINS_MSG_QUERY_PARAM_AUTHOR    = 4,
+	CONTAINS_MSG_QUERY_PARAM_RECIPIENT = 5,
+	CONTAINS_MSG_QUERY_PARAM_CONTENTS  = 6,
+} ContainsMsgQueryParam;
+
 static void
 sqlitelog_finalize_query(sqlite3_stmt **query)
 {
@@ -347,6 +364,7 @@ sqlitelog_finalize_queries()
 	sqlitelog_finalize_query(&get_all_contacts_q);
 	sqlitelog_finalize_query(&get_all_days_q);
 	sqlitelog_finalize_query(&delete_contact_q);
+	sqlitelog_finalize_query(&contains_msg_q);
 }
 
 static gboolean
@@ -396,7 +414,8 @@ sqlitelog_prepare_queries()
 		!sqlitelog_prepare_query(mark_as_seen_q_str, &mark_as_seen_q) ||
 		!sqlitelog_prepare_query(get_all_contacts_q_str, &get_all_contacts_q) ||
 		!sqlitelog_prepare_query(get_all_days_q_str, &get_all_days_q) ||
-		!sqlitelog_prepare_query(delete_contact_q_str, &delete_contact_q)) {
+		!sqlitelog_prepare_query(delete_contact_q_str, &delete_contact_q) ||
+		!sqlitelog_prepare_query(contains_msg_q_str, &contains_msg_q)) {
 
 		sqlitelog_finalize_queries();
 		return FALSE;
@@ -695,7 +714,7 @@ sqlitelog_insert_day(guint64 time, unsig
 static gboolean
 sqlitelog_insert_message(PurpleAccount *account, unsigned account_id,
 	unsigned contact_id, unsigned day_id, const PurpleMessage *msg,
-	unsigned *id)
+	gboolean seen, unsigned *id)
 {
 	g_assert(account);
 	g_assert(account_id != SQLITELOG_DB_ID_NONE);
@@ -714,7 +733,6 @@ sqlitelog_insert_message(PurpleAccount *
 	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;
 
 	if (sqlite3_bind_text(insert_message_q, INSERT_MESSAGE_QUERY_PARAM_AUTHOR,
 			author, -1, SQLITE_STATIC) != SQLITE_OK ||
@@ -731,7 +749,7 @@ sqlitelog_insert_message(PurpleAccount *
 		sqlite3_bind_int(insert_message_q, INSERT_MESSAGE_QUERY_PARAM_FLAGS,
 			msg_flags) != SQLITE_OK ||
 		sqlite3_bind_int(insert_message_q, INSERT_MESSAGE_QUERY_PARAM_SEEN,
-			seen) != SQLITE_OK ||
+			seen ? 1 : 0) != SQLITE_OK ||
 		sqlite3_bind_int64(insert_message_q,
 			INSERT_MESSAGE_QUERY_PARAM_ACCOUNTID, account_id) != SQLITE_OK ||
 		sqlite3_bind_int64(insert_message_q,
@@ -1168,6 +1186,73 @@ sqlitelog_delete_contact_impl(PurpleBlis
 	return rc == SQLITE_DONE;
 }
 
+static gboolean
+sqlitelog_contains_msg(PurpleAccount *account, PurpleBlistNode* contact,
+	PurpleMessage *message, gboolean *result)
+{
+	g_assert(account);
+	g_assert(contact);
+	g_assert(message);
+	g_assert(result);
+
+	unsigned account_id;
+	if (!sqlitelog_get_account_id(account, &account_id))
+		return FALSE;
+
+	if (account_id == SQLITELOG_DB_ID_NONE) {
+		*result = FALSE;
+		return TRUE;
+	}
+
+	const char *contact_name = PURPLE_IS_CHAT(contact) ?
+		purple_chat_get_name_only(PURPLE_CHAT(contact)) :
+		purple_buddy_get_name(PURPLE_BUDDY(contact));
+
+	if (!contact_name)
+		return FALSE;
+
+	unsigned contact_id;
+	if (!sqlitelog_get_contact_id(account_id, contact_name, &contact_id))
+		return FALSE;
+
+	if (contact_id == SQLITELOG_DB_ID_NONE) {
+		*result = FALSE;
+		return TRUE;
+	}
+
+	if (sqlite3_bind_int64(contains_msg_q, CONTAINS_MSG_QUERY_PARAM_ACCOUNTID,
+			account_id) != SQLITE_OK ||
+		sqlite3_bind_int64(contains_msg_q, CONTAINS_MSG_QUERY_PARAM_CONTACTID,
+			contact_id) != SQLITE_OK ||
+		sqlite3_bind_int64(contains_msg_q, CONTAINS_MSG_QUERY_PARAM_MSGTIME,
+			purple_message_get_time(message)) != SQLITE_OK ||
+		sqlite3_bind_text(contains_msg_q, CONTAINS_MSG_QUERY_PARAM_AUTHOR,
+			purple_message_get_author(message), -1, SQLITE_STATIC)
+		!= SQLITE_OK ||
+		sqlite3_bind_text(contains_msg_q, CONTAINS_MSG_QUERY_PARAM_RECIPIENT,
+			purple_message_get_recipient(message), -1, SQLITE_STATIC)
+		!= SQLITE_OK ||
+		sqlite3_bind_text(contains_msg_q, CONTAINS_MSG_QUERY_PARAM_CONTENTS,
+			purple_message_get_contents(message), -1, SQLITE_STATIC)
+		!= SQLITE_OK) {
+		return FALSE;
+	}
+
+	gboolean msg_found = FALSE;
+
+	int rc;
+	while ((rc = sqlite3_step(contains_msg_q)) == SQLITE_ROW)
+		msg_found |= TRUE;
+
+	sqlite3_reset(contains_msg_q);
+
+	if (rc != SQLITE_DONE)
+		return FALSE;
+
+	*result = msg_found;
+	return TRUE;
+}
+
 /**************************************************************************/
 /* PurpleGenericLog API implementation                                    */
 /**************************************************************************/
@@ -1235,7 +1320,7 @@ guint64 truncate_to_days(guint64 timesta
 
 static gboolean
 sqlitelog_log_msg(PurpleAccount *account, PurpleBlistNode *contact,
-	PurpleMessage *message)
+	PurpleMessage *message, gboolean seen)
 {
 	g_return_val_if_fail(account != NULL, FALSE);
 	g_return_val_if_fail(contact != NULL, FALSE);
@@ -1299,7 +1384,7 @@ sqlitelog_log_msg(PurpleAccount *account
 
 	unsigned message_id;
 	if (!sqlitelog_insert_message(account, account_id, contact_id, day_id,
-		message, &message_id)) {
+		message, seen, &message_id)) {
 		sqlite3_step(rollback_transation_q);
 		return FALSE;
 	}
@@ -1442,6 +1527,30 @@ sqlitelog_wipe_log_for_contact(PurpleBli
 	return sqlitelog_delete_contact_impl(contact);
 }
 
+gboolean sqlitelog_import_msg(PurpleAccount *account, PurpleBlistNode* contact,
+	PurpleMessage *message, gboolean seen, gboolean *imported)
+{
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(contact != NULL, FALSE);



More information about the Commits mailing list