/soc/2015/igor.gajowiak/chatlog: 227f25d5bef9: Implemented searc...
Igor Gajowiak
igor.gajowiak at gmail.com
Tue Aug 11 17:29:23 EDT 2015
Changeset: 227f25d5bef9715bf5d16b9950b0d2cd3344e2cc
Author: Igor Gajowiak <igor.gajowiak at gmail.com>
Date: 2015-08-11 23:29 +0200
Branch: default
URL: https://hg.pidgin.im/soc/2015/igor.gajowiak/chatlog/rev/227f25d5bef9
Description:
Implemented searching for messages containing given phrase.
diffstat:
libpurple/genericlog.c | 11 +
libpurple/genericlog.h | 28 ++++
libpurple/plugins/log/logsqlite.c | 66 ++++++++++
pidgin/gtkgenericlog.c | 246 ++++++++++++++++++++++++++++++++++---
pidgin/gtkgenericlog.h | 12 +
5 files changed, 338 insertions(+), 25 deletions(-)
diffs (truncated from 636 to 300 lines):
diff --git a/libpurple/genericlog.c b/libpurple/genericlog.c
--- a/libpurple/genericlog.c
+++ b/libpurple/genericlog.c
@@ -311,6 +311,16 @@ purple_genericlog_get_older_msgs(PurpleB
}
gboolean
+purple_genericlog_find_msgs(PurpleBlistNode *contact, const gchar* pattern,
+ guint limit, guint offset, GList** result, GError** error)
+{
+ DEFINE_GENERICLOG_FUNC_WITH_RETURN(find_msgs,
+ "%s does not support searching messages",
+ "Searching messages from %s failed",
+ contact, pattern, limit, offset, result);
+}
+
+gboolean
purple_genericlog_get_all_contacts(GList** result, GError** error)
{
DEFINE_GENERICLOG_FUNC_WITH_RETURN(get_all_contacts,
@@ -566,6 +576,7 @@ purple_genericlog_class_init(PurpleGener
klass->get_all_contacts = NULL;
klass->get_all_days = NULL;
klass->wipe_log_for_contact = NULL;
+ klass->find_msgs = NULL;
klass->init_export = NULL;
klass->read_chunk = NULL;
klass->finalize_export = NULL;
diff --git a/libpurple/genericlog.h b/libpurple/genericlog.h
--- a/libpurple/genericlog.h
+++ b/libpurple/genericlog.h
@@ -74,6 +74,9 @@ struct _PurpleGenericLog
* then upper bound check is skipped. Messages are sorted
* by their timestamp in descending order.
* Returns %TRUE if operation succeeds, %FALSE otherwise.
+ * @find_msgs: Gets a list of messages sent to or received from a given
+ * contact containing given phrase. Messages should be sorted
+ * by their timestamp in descending order.
* @get_all_contacts: Gets a list of all #PurpleBlistNode objects with at least
* one message in the log. Returns %TRUE if operation
* succeeds, %FALSE otherwise. The client is responsible for
@@ -127,6 +130,9 @@ struct _PurpleGenericLogClass
gboolean (*get_older_msgs)(PurpleBlistNode *contact, guint64 timestamp,
PurpleMessage *message, GList **result);
+ gboolean (*find_msgs)(PurpleBlistNode *contact, const gchar* pattern,
+ guint limit, guint offset, GList **result);
+
gboolean (*get_all_contacts)(GList **result);
gboolean (*get_all_days)(PurpleBlistNode *contact, GArray **result);
@@ -354,6 +360,28 @@ purple_genericlog_get_older_msgs(PurpleB
PurpleMessage *message, GList **result, GError **error);
/**
+ * purple_genericlog_find_msgs:
+ * @contact: The contact, must be PurpleChat or PurpleBuddy.
+ * @phrase: The phrase to search for.
+ * @limit: The limit of the size of the result.
+ * @offset: The number of messages to skip.
+ * @result[out]: The return location for the result. Contains objects of
+ * type #PurpleMessage.
+ * @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 messages sent to or received from a given contact containing
+ * given phrase from the active log.
+ *
+ * Messages are sorted by their timestamp in descending order.
+ *
+ * Returns: %TRUE if succeeds, %FALSE otherwise.
+ */
+gboolean
+purple_genericlog_find_msgs(PurpleBlistNode *contact, const gchar* phrase,
+ guint limit, guint offset, GList **result, GError **error);
+
+/**
* purple_genericlog_get_all_contacts:
* @result[out]: Return location for a #GList containing a list of #PurpleBuddy
* objects. This will not be set in case of any errors.
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
@@ -216,6 +216,22 @@ typedef enum
GET_OLDER_MSGS_UPPER_QUERY_PARAM_EXCEPTID = 4,
} GetOlderMsgsUpperQueryParam;
+static sqlite3_stmt *find_msgs_q = NULL;
+
+static const char *find_msgs_q_str =
+ "SELECT Id, Author, AuthorAlias, Recipient, Contents, MsgTime, Flags "
+ "FROM Messages "
+ "WHERE ContactId = ?1 AND Contents LIKE '%' || ?2 || '%' "
+ "ORDER BY MsgTime DESC, Id DESC LIMIT ?3 OFFSET ?4;";
+
+typedef enum
+{
+ FIND_MSGS_QUERY_PARAM_CONTACTYID = 1,
+ FIND_MSGS_QUERY_PARAM_PATTERN = 2,
+ FIND_MSGS_QUERY_PARAM_LIMIT = 3,
+ FIND_MSGS_QUERY_PARAM_OFFSET = 4,
+} FindMsgsQueryParam;
+
typedef enum
{
GET_MSGS_QUERY_COL_ID = 0,
@@ -306,6 +322,7 @@ sqlitelog_finalize_queries()
sqlitelog_finalize_query(&get_all_msgs_q);
sqlitelog_finalize_query(&get_older_msgs_q);
sqlitelog_finalize_query(&get_older_msgs_upper_q);
+ sqlitelog_finalize_query(&find_msgs_q);
sqlitelog_finalize_query(&mark_as_seen_q);
sqlitelog_finalize_query(&get_all_contacts_q);
sqlitelog_finalize_query(&get_all_days_q);
@@ -354,6 +371,7 @@ sqlitelog_prepare_queries()
!sqlitelog_prepare_query(get_older_msgs_q_str, &get_older_msgs_q) ||
!sqlitelog_prepare_query(get_older_msgs_upper_q_str,
&get_older_msgs_upper_q) ||
+ !sqlitelog_prepare_query(find_msgs_q_str, &find_msgs_q) ||
!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) ||
@@ -928,6 +946,37 @@ sqlitelog_get_older_msgs_upper_impl(Purp
}
static gboolean
+sqlitelog_find_msgs_impl(PurpleBlistNode *contact, const gchar *pattern,
+ guint limit, guint offset, GList **result)
+{
+ g_assert(contact);
+ g_assert(pattern);
+ g_assert(result);
+
+ guint contact_id;
+ if (!sqlitelog_get_contact_id_from_obj(contact, &contact_id))
+ return FALSE;
+
+ if (contact_id == SQLITELOG_DB_ID_NONE) {
+ *result = NULL;
+ return TRUE;
+ }
+
+ if (sqlite3_bind_int64(find_msgs_q, FIND_MSGS_QUERY_PARAM_CONTACTYID,
+ contact_id) != SQLITE_OK ||
+ sqlite3_bind_text(find_msgs_q, FIND_MSGS_QUERY_PARAM_PATTERN,
+ pattern, -1, SQLITE_STATIC) != SQLITE_OK ||
+ sqlite3_bind_int64(find_msgs_q, FIND_MSGS_QUERY_PARAM_LIMIT, limit)
+ != SQLITE_OK ||
+ sqlite3_bind_int64(find_msgs_q, FIND_MSGS_QUERY_PARAM_OFFSET, offset)
+ != SQLITE_OK) {
+ return FALSE;
+ }
+
+ return sqlitelog_execute_get_msgs_query(find_msgs_q, result);
+}
+
+static gboolean
sqlitelog_mark_as_seen_impl(unsigned msg_id)
{
g_assert(msg_id != SQLITELOG_DB_ID_NONE);
@@ -1282,6 +1331,22 @@ sqlitelog_get_older_msgs(PurpleBlistNode
}
static gboolean
+sqlitelog_find_msgs(PurpleBlistNode *contact, const gchar *pattern, guint limit,
+ guint offset, GList **result)
+{
+ g_return_val_if_fail(contact != NULL, FALSE);
+ g_return_val_if_fail(pattern != NULL, FALSE);
+ 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_find_msgs_impl(contact, pattern, limit, offset, result);
+}
+
+static gboolean
sqlitelog_get_all_contacts(GList **result)
{
g_return_val_if_fail(result != NULL, FALSE);
@@ -1370,6 +1435,7 @@ purple_sqlitelog_class_init (PurpleSqlit
klass->parent_class.get_unseen_msgs = sqlitelog_get_unseen_msgs;
klass->parent_class.get_all_msgs = sqlitelog_get_all_msgs;
klass->parent_class.get_older_msgs = sqlitelog_get_older_msgs;
+ klass->parent_class.find_msgs = sqlitelog_find_msgs;
klass->parent_class.get_all_contacts = sqlitelog_get_all_contacts;
klass->parent_class.get_all_days = sqlitelog_get_all_days;
klass->parent_class.wipe_log_for_contact =
diff --git a/pidgin/gtkgenericlog.c b/pidgin/gtkgenericlog.c
--- a/pidgin/gtkgenericlog.c
+++ b/pidgin/gtkgenericlog.c
@@ -30,6 +30,7 @@
#include "gtkwebview.h"
#define GTKGENERICLOG_DEBUG_CATEGORY "gtkgenericlog"
+#define GTKGENERICLOG_SEARCH_CHUNK_SIZE 50
static PidginGenericLogViewer *generic_log_viewer = NULL;
@@ -307,10 +308,26 @@ on_reload_item_clicked(GtkAction *action
GTK_TREE_MODEL(viewer->blist_tree_store));
}
+static PidginGenericLogMsgFinder*
+create_msg_finder(PidginGenericLogViewer *viewer);
+
+static void
+reset_find_state(PidginGenericLogViewer *viewer);
+
static void
on_search_item_clicked(GtkAction *action, gpointer data)
{
- printf("on_search_item_clicked\n");
+ g_assert(data);
+
+ PidginGenericLogViewer *viewer = (PidginGenericLogViewer*) data;
+
+ if (!viewer->finder)
+ viewer->finder = create_msg_finder(viewer);
+
+ reset_find_state(viewer);
+
+ gtk_widget_show_all(viewer->finder->window);
+ gtk_widget_grab_focus(viewer->finder->entry);
}
static void
@@ -348,7 +365,8 @@ on_print_item_clicked(GtkAction *action,
}
static GtkWidget *
-create_archive_menu_item(PidginGenericLogViewer *viewer)
+create_archive_menu_item(PidginGenericLogViewer *viewer,
+ GtkWidget **search_item_res)
{
g_assert(viewer);
@@ -384,6 +402,8 @@ create_archive_menu_item(PidginGenericLo
g_signal_connect(G_OBJECT(close_item), "activate",
G_CALLBACK(on_close_item_clicked), viewer);
+ *search_item_res = search_item;
+
return archive_item;
}
@@ -545,13 +565,15 @@ create_contact_menu_item(PidginGenericLo
static GtkWidget *
create_menu_bar(PidginGenericLogViewer *viewer,
GtkWidget **start_conversation_item_res,
- GtkWidget **wipe_log_for_contact_item_res)
+ GtkWidget **wipe_log_for_contact_item_res,
+ GtkWidget **search_item_res)
{
g_assert(viewer);
GtkWidget *menu_bar = gtk_menu_bar_new();
- GtkWidget *archive_item = create_archive_menu_item(viewer);
+ GtkWidget *archive_item = create_archive_menu_item(viewer,
+ search_item_res);
gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), archive_item);
GtkWidget *options_item = create_options_menu_item(viewer);
@@ -569,12 +591,12 @@ update_menu_buttons(PidginGenericLogView
{
g_assert(viewer);
- gboolean start_conv_enabled = TRUE;
- gboolean wipe_log_enabled = TRUE;
+ gboolean contact_selected = TRUE;
+ gboolean account_enabled = TRUE;
if (!viewer->current_contact) {
- start_conv_enabled = FALSE;
- wipe_log_enabled = FALSE;
+ contact_selected = FALSE;
+ account_enabled = FALSE;
}
else {
PurpleAccount *account = get_account_from_contact(
@@ -582,13 +604,14 @@ update_menu_buttons(PidginGenericLogView
/* Disable start conversation button if account is disabled */
if (!account || !purple_account_get_connection(account))
- start_conv_enabled = FALSE;
+ account_enabled = FALSE;
}
gtk_widget_set_sensitive(viewer->start_conversation_item,
- start_conv_enabled);
+ contact_selected && account_enabled);
gtk_widget_set_sensitive(viewer->wipe_log_for_contact_item,
- wipe_log_enabled);
+ contact_selected);
+ gtk_widget_set_sensitive(viewer->search_item, contact_selected);
}
More information about the Commits
mailing list