/soc/2015/igor.gajowiak/chatlog: aed0441d29e3: Implemented unrea...

Igor Gajowiak igor.gajowiak at gmail.com
Mon Jul 6 18:12:08 EDT 2015


Changeset: aed0441d29e37505574f4422e1ef5a5ccbbb48bf
Author:	 Igor Gajowiak <igor.gajowiak at gmail.com>
Date:	 2015-07-07 00:11 +0200
Branch:	 default
URL: https://hg.pidgin.im/soc/2015/igor.gajowiak/chatlog/rev/aed0441d29e3

Description:

Implemented unread messages popup on the program startup.

diffstat:

 libpurple/accounts.c              |  32 +++++++++++++++
 libpurple/conversation.h          |   7 +--
 libpurple/genericlog.c            |   8 +++
 libpurple/genericlog.h            |   5 ++
 libpurple/plugins/log/logsqlite.c |  81 +++++++++++++++++++++++++++++++++-----
 5 files changed, 117 insertions(+), 16 deletions(-)

diffs (254 lines):

diff --git a/libpurple/accounts.c b/libpurple/accounts.c
--- a/libpurple/accounts.c
+++ b/libpurple/accounts.c
@@ -24,6 +24,7 @@
 #include "dbus-maybe.h"
 #include "debug.h"
 #include "enums.h"
+#include "genericlog.h"
 #include "network.h"
 #include "pounce.h"
 
@@ -922,6 +923,35 @@ password_migration_cb(PurpleAccount *acc
 	purple_accounts_schedule_save();
 }
 
+static void
+show_unread_im_msgs(PurpleConnection *gc)
+{
+	PurpleAccount *account = purple_connection_get_account(gc);
+
+	g_return_if_fail(account != NULL);
+
+	GList *unread_msgs = NULL;
+	GError *error = purple_genericlog_get_unread_msgs(account, &unread_msgs);
+	if(error){
+		g_error_free(error);
+		return;
+	}
+
+	g_return_if_fail(unread_msgs != NULL);
+
+	GList *it = NULL;
+	for(it = unread_msgs; it != NULL; it = it->next) {
+		PurpleMessage *msg = it->data;
+
+		// Create or get a conversation
+		PurpleIMConversation *conv = purple_im_conversation_new(
+			account, purple_message_get_author(msg));
+
+		purple_conversation_write_message(PURPLE_CONVERSATION(conv), msg);
+	}
+	g_list_free_full(unread_msgs, (GDestroyNotify) g_object_unref);
+}
+
 void
 purple_accounts_init(void)
 {
@@ -1011,6 +1041,8 @@ purple_accounts_init(void)
 
 	purple_signal_connect(conn_handle, "signed-on", handle,
 	                      PURPLE_CALLBACK(signed_on_cb), NULL);
+	purple_signal_connect(conn_handle, "signed-on", handle,
+						  PURPLE_CALLBACK(show_unread_im_msgs), NULL);
 	purple_signal_connect(conn_handle, "signed-off", handle,
 	                      PURPLE_CALLBACK(signed_off_cb), NULL);
 	purple_signal_connect(conn_handle, "connection-error", handle,
diff --git a/libpurple/conversation.h b/libpurple/conversation.h
--- a/libpurple/conversation.h
+++ b/libpurple/conversation.h
@@ -471,11 +471,8 @@ void purple_conversation_close_logs(Purp
 
 /**
  * purple_conversation_write_message:
- * @conv:    The conversation.
- * @who:     The user who sent the message.
- * @message: The message to write.
- * @flags:   The message flags.
- * @mtime:   The time the message was sent.
+ * @conv: The conversation.
+ * @msg:  The message.
  *
  * Writes to a chat or an IM.
  */
diff --git a/libpurple/genericlog.c b/libpurple/genericlog.c
--- a/libpurple/genericlog.c
+++ b/libpurple/genericlog.c
@@ -185,6 +185,14 @@ purple_genericlog_mark_as_read(PurpleMes
 	return klass->mark_as_read(msg);
 }
 
+GError*
+purple_genericlog_get_unread_msgs(PurpleAccount* account, GList** result)
+{
+	PurpleGenericLogClass *klass =
+		PURPLE_GENERICLOG_GET_CLASS(purple_genericlog_inuse);
+	return klass->get_unread_msgs(account, result);
+}
+
 /**************************************************************************/
 /* Error Codes                                                            */
 /**************************************************************************/
diff --git a/libpurple/genericlog.h b/libpurple/genericlog.h
--- a/libpurple/genericlog.h
+++ b/libpurple/genericlog.h
@@ -55,6 +55,8 @@ struct _PurpleGenericLogClass
 
 	GError* (*mark_as_read)(PurpleMessage *message);
 
+	GError* (*get_unread_msgs)(PurpleAccount *account, GList **result);
+
 	GError* (*get_messages)(PurpleAccount *account, GList **result,
 		time_t timestamp, size_t limit);
 
@@ -103,6 +105,9 @@ purple_genericlog_logim(PurpleAccount *a
 GError*
 purple_genericlog_mark_as_read(PurpleMessage *msg);
 
+GError*
+purple_genericlog_get_unread_msgs(PurpleAccount *account, GList **result);
+
 
 /**************************************************************************/
 /* 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
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include <stdlib.h>
 #include <sqlite3.h>
 
 // TODO: Why changing the order of these includes causes a crash?!
@@ -64,8 +65,6 @@ sqlite_log_db_exists(const gchar *db_pat
 static int
 sqlite_log_create_tables()
 {
-	// TODO: Moze warto dodac constraint ze para
-	// user, protocol jest unikalna?
 	const char *sql_statement =
 		"CREATE TABLE Accounts("
 		"Id INTEGER PRIMARY KEY AUTOINCREMENT,"
@@ -74,14 +73,21 @@ sqlite_log_create_tables()
 
 		"CREATE TABLE Messages("
 		"Author TEXT,"
-		"Author_alias TEXT,"
+		"AuthorAlias TEXT,"
 		"Recipient TEXT NOT NULL,"
 		"Contents TEXT NOT NULL,"
-		"Msgtime INTEGER NOT NULL,"
+		"MsgTime INTEGER NOT NULL,"
 		"Flags INTEGER NOT NULL,"
-		"Acc INTEGER NOT NULL,"
-		"Seen BOOLEAN DEFAULT FALSE,"
-		"FOREIGN KEY(Acc) REFERENCES Accounts(Id));";
+		"AccountId INTEGER NOT NULL,"
+		"Read BOOLEAN DEFAULT 0,"
+		"FOREIGN KEY(AccountId) REFERENCES Accounts(Id)); "
+
+		"CREATE INDEX SeenIndex ON Messages (Read); "
+
+		"CREATE TRIGGER AccountDeleted AFTER DELETE ON Accounts "
+		"BEGIN "
+		"DELETE FROM Messages WHERE AccountId = OLD.Id; "
+		"END; ";
 
 	return sqlite3_exec(sqlite_log_db, sql_statement, NULL, NULL, NULL);
 }
@@ -161,6 +167,12 @@ sqlite_log_get_max_acc_id()
 static GError*
 sqlite_log_log_im(PurpleAccount *account, PurpleMessage *message)
 {
+	PurpleMessageFlags msg_flags = purple_message_get_flags(message);
+	if((msg_flags & PURPLE_MESSAGE_NO_LOG) ||
+		(msg_flags & PURPLE_MESSAGE_SYSTEM) ||
+		(msg_flags & PURPLE_MESSAGE_NOTIFY))
+		return NULL;
+
 	char *sql_statement;
 
 	int db_account_id = sqlite_log_db_get_account_id(account);
@@ -184,15 +196,16 @@ sqlite_log_log_im(PurpleAccount *account
 	}
 
 	sql_statement = g_strdup_printf(
-		"INSERT INTO Messages (Author, Author_alias, Recipient, Contents, Msgtime, Flags, Acc) "
-		"VALUES(\'%s\', \'%s\', \'%s\', \'%s\', %lu, %d, %d);",
+		"INSERT INTO Messages "
+		"VALUES(\'%s\', \'%s\', \'%s\', \'%s\', %lu, %d, %d, %d);",
 		purple_message_get_author(message),
 		purple_message_get_author_alias(message),
 		purple_message_get_recipient(message),
 		purple_message_get_contents(message),
 		purple_message_get_time(message),
-		purple_message_get_flags(message),
-		db_account_id);
+		msg_flags,
+		db_account_id,
+		msg_flags & PURPLE_MESSAGE_SEND ? 1 : 0);
 
 	if(sqlite3_exec(sqlite_log_db, sql_statement, NULL, NULL, NULL) != SQLITE_OK) {
 		g_free(sql_statement);
@@ -212,6 +225,51 @@ sqlite_log_mark_as_read(PurpleMessage *m
 	return NULL;
 }
 
+static int
+sqlite_log_get_unread_cb(void *data, int argc, char **argv, char **azColName)
+{
+	GList **list = (GList**) data;
+
+	PurpleMessage *msg = purple_message_new_incoming(argv[0], argv[1],
+		atoi(argv[2]), strtoull(argv[3], NULL, 10));
+
+	if (strcmp(argv[4], "(null)") != 0)
+		purple_message_set_author_alias(msg, argv[4]);
+
+	purple_message_set_flags(msg, purple_message_get_flags(msg) |
+		PURPLE_MESSAGE_NO_LOG);
+
+	// Here we can use prepend because we ordered SQLite to
+	// order elements in a descending order
+	*list = g_list_prepend(*list, msg);
+	g_object_ref(msg);
+	return 0;
+}
+
+static GError*
+sqlite_log_get_unread_msgs(PurpleAccount *account, GList **result)
+{
+	char *sql_statement = g_strdup_printf(
+		"SELECT Author, Contents, Flags, MsgTime, AuthorAlias "
+		"FROM Messages JOIN Accounts ON Id = AccountId "
+		"WHERE Username LIKE \'%s\' AND Read = 0 "
+		"ORDER BY Username, MsgTime desc",
+		purple_account_get_username(account));
+
+	int rc = sqlite3_exec(sqlite_log_db, sql_statement,
+		sqlite_log_get_unread_cb, result, NULL);
+
+	if (rc != SQLITE_OK) {
+		g_free(sql_statement);
+		return g_error_new(purple_genericlog_error_domain(),
+			PURPLE_GENERICLOG_ERROR_BACKENDFAIL,
+			"SQLITE database error while getting unread messages");
+	}
+
+	g_free(sql_statement);
+	return NULL;
+}
+
 static GError*
 sqlite_log_activate(void)
 {
@@ -291,6 +349,7 @@ purple_sqlitelog_class_init (PurpleSqlit
 
 	klass->parent_class.log_im = sqlite_log_log_im;
 	klass->parent_class.mark_as_read = sqlite_log_mark_as_read;
+	klass->parent_class.get_unread_msgs = sqlite_log_get_unread_msgs;
 	klass->parent_class.activate = sqlite_log_activate;
 	klass->parent_class.deactivate = sqlite_log_deactivate;
 }



More information about the Commits mailing list