A search API for Modest
authorPhilip Van Hoof <philip@codeminded.be>
Fri, 18 May 2007 12:15:42 +0000 (12:15 +0000)
committerPhilip Van Hoof <philip@codeminded.be>
Fri, 18 May 2007 12:15:42 +0000 (12:15 +0000)
pmo-trunk-r1909

src/Makefile.am
src/modest-mime-part-search-stream.c [new file with mode: 0644]
src/modest-mime-part-search-stream.h [new file with mode: 0644]
src/modest-search.c [new file with mode: 0644]
src/modest-search.h [new file with mode: 0644]

index 2e643c7..e29b93f 100644 (file)
@@ -87,7 +87,11 @@ modest_SOURCES=\
        modest-ui-actions.h\
        modest-widget-memory-priv.h \
        modest-widget-memory.c\
-       modest-widget-memory.h 
+       modest-widget-memory.h\
+       modest-search.c\
+       modest-search.h\
+       modest-mime-part-search-stream.c\
+       modest-mime-part-search-stream.h
 
 modest_CFLAGS  = $(MAEMO_LAUNCHER_CFLAGS)
 modest_LDFLAGS = $(MAEMO_LAUNCHER_LDFLAGS)
diff --git a/src/modest-mime-part-search-stream.c b/src/modest-mime-part-search-stream.c
new file mode 100644 (file)
index 0000000..ea7ef52
--- /dev/null
@@ -0,0 +1,180 @@
+#define _GNU_SOURCE
+
+#include <glib.h>
+#include <string.h>
+
+#include "modest-mime-part-search-stream.h"
+
+static GObjectClass *parent_class = NULL;
+
+static gssize
+modest_mime_part_search_stream_read (TnyStream *self, char *buffer, gsize n)
+{
+       ModestMimePartSearchStream *me = (ModestMimePartSearchStream *) self;
+
+       if (strcasestr (buffer, me->search_for) != NULL) {
+               me->found = TRUE;
+               return -1;
+       }
+
+       return (gssize) n;
+}
+
+static gssize
+modest_mime_part_search_stream_write (TnyStream *self, const char *buffer, gsize n)
+{
+       ModestMimePartSearchStream *me = (ModestMimePartSearchStream *) self;
+
+       if (strcasestr (buffer, me->search_for) != NULL) {
+               me->found = TRUE;
+               return -1;
+       }
+
+       return (gssize) n;
+}
+
+static gint
+modest_mime_part_search_stream_flush (TnyStream *self)
+{
+       return 0;
+}
+
+static gint
+modest_mime_part_search_stream_close (TnyStream *self)
+{
+       return 0;
+}
+
+static gboolean
+modest_mime_part_search_stream_is_eos (TnyStream *self)
+{
+       return TRUE;
+}
+
+static gint
+modest_mime_part_search_stream_reset (TnyStream *self)
+{
+       return 0;
+}
+
+static gssize
+modest_mime_part_search_stream_write_to_stream (TnyStream *self, TnyStream *output)
+{
+       char tmp_buf[4096];
+       ssize_t total = 0;
+       ssize_t nb_read;
+       ssize_t nb_written;
+
+       g_assert (TNY_IS_STREAM (output));
+
+       while (G_LIKELY (!tny_stream_is_eos (self))) 
+       {
+               nb_read = tny_stream_read (self, tmp_buf, sizeof (tmp_buf));
+               if (G_UNLIKELY (nb_read < 0))
+                       return -1;
+               else if (G_LIKELY (nb_read > 0)) {
+                       nb_written = 0;
+       
+                       while (G_LIKELY (nb_written < nb_read))
+                       {
+                               ssize_t len = tny_stream_write (output, tmp_buf + nb_written,
+                                                                 nb_read - nb_written);
+                               if (G_UNLIKELY (len < 0))
+                                       return -1;
+                               nb_written += len;
+                       }
+                       total += nb_written;
+               }
+       }
+       return total;
+}
+
+
+TnyStream* 
+modest_mime_part_search_stream_new (const char *search_for)
+{
+       ModestMimePartSearchStream *me = g_object_new (MODEST_TYPE_MIME_PART_SEARCH_STREAM, NULL);
+
+       me->search_for = g_strdup (search_for);
+
+       return TNY_STREAM (me);
+}
+
+static void
+modest_mime_part_search_stream_finalize (GObject *object)
+{
+       ModestMimePartSearchStream *me = g_object_new (MODEST_TYPE_MIME_PART_SEARCH_STREAM, NULL);
+
+       g_free (me->search_for);
+
+       parent_class->finalize (object);
+}
+
+static void
+modest_mime_part_search_stream_instance_init (GTypeInstance *instance, gpointer g_class)
+{
+       ModestMimePartSearchStream *me = (ModestMimePartSearchStream *) instance;
+
+       me->found = FALSE;
+}
+
+static void
+tny_stream_init (TnyStreamIface *klass)
+{
+       klass->read_func = modest_mime_part_search_stream_read;
+       klass->write_func = modest_mime_part_search_stream_write;
+       klass->flush_func = modest_mime_part_search_stream_flush;
+       klass->close_func = modest_mime_part_search_stream_close;
+       klass->is_eos_func = modest_mime_part_search_stream_is_eos;
+       klass->reset_func = modest_mime_part_search_stream_reset;
+       klass->write_to_stream_func = modest_mime_part_search_stream_write_to_stream;
+}
+
+static void
+modest_mime_part_search_stream_class_init (ModestMimePartSearchStreamClass *klass)
+{
+       GObjectClass *object_class;
+
+       parent_class = g_type_class_peek_parent (klass);
+       object_class = (GObjectClass*) klass;
+       object_class->finalize = modest_mime_part_search_stream_finalize;
+}
+
+GType
+modest_mime_part_search_stream_get_type (void)
+{
+       static GType type = 0;
+       if (G_UNLIKELY(type == 0))
+       {
+               static const GTypeInfo info = 
+               {
+                       sizeof (ModestMimePartSearchStreamClass),
+                       NULL,   /* base_init */
+                       NULL,   /* base_finalize */
+                       (GClassInitFunc) modest_mime_part_search_stream_class_init,   /* class_init */
+                       NULL,   /* class_finalize */
+                       NULL,   /* class_data */
+                       sizeof (ModestMimePartSearchStream),
+                       0,      /* n_preallocs */
+                       modest_mime_part_search_stream_instance_init,    /* instance_init */
+                       NULL
+               };
+
+
+               static const GInterfaceInfo tny_stream_info = 
+               {
+                       (GInterfaceInitFunc) tny_stream_init, /* interface_init */
+                       NULL,         /* interface_finalize */
+                       NULL          /* interface_data */
+               };
+
+               type = g_type_register_static (G_TYPE_OBJECT,
+                       "ModestMimePartSearchStream",
+                       &info, 0);
+
+               g_type_add_interface_static (type, TNY_TYPE_STREAM,
+                       &tny_stream_info);
+
+       }
+       return type;
+}
diff --git a/src/modest-mime-part-search-stream.h b/src/modest-mime-part-search-stream.h
new file mode 100644 (file)
index 0000000..d83d2d9
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef MODEST_MIME_PART_SEARCH_STREAM_H
+#define MODEST_MIME_PART_SEARCH_STREAM_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <tny-stream.h>
+
+G_BEGIN_DECLS
+
+#define MODEST_TYPE_MIME_PART_SEARCH_STREAM             (modest_mime_part_search_stream_get_type ())
+#define MODEST_MIME_PART_SEARCH_STREAM(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), MODEST_TYPE_MIME_PART_SEARCH_STREAM, ModestMimePartSearchStream))
+#define MODEST_MIME_PART_SEARCH_STREAM_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST ((vtable), MODEST_TYPE_MIME_PART_SEARCH_STREAM, ModestMimePartSearchStreamClass))
+#define MODEST_IS_MIME_PART_SEARCH_STREAM(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MODEST_TYPE_MIME_PART_SEARCH_STREAM))
+#define MODEST_IS_MIME_PART_SEARCH_STREAM_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MODEST_TYPE_MIME_PART_SEARCH_STREAM))
+#define MODEST_MIME_PART_SEARCH_STREAM_GET_CLASS(inst)  (G_TYPE_INSTANCE_GET_CLASS ((inst), MODEST_TYPE_MIME_PART_SEARCH_STREAM, ModestMimePartSearchStreamClass))
+
+typedef struct _ModestMimePartSearchStream ModestMimePartSearchStream;
+typedef struct _ModestMimePartSearchStreamClass ModestMimePartSearchStreamClass;
+
+struct _ModestMimePartSearchStream
+{
+       GObject parent;
+       gboolean found;
+       gchar *search_for;
+};
+
+struct _ModestMimePartSearchStreamClass 
+{
+       GObjectClass parent;
+};
+
+GType  modest_mime_part_search_stream_get_type (void);
+TnyStream* modest_mime_part_search_stream_new (const char *search_for);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/modest-search.c b/src/modest-search.c
new file mode 100644 (file)
index 0000000..a152df3
--- /dev/null
@@ -0,0 +1,123 @@
+#define _GNU_SOURCE
+
+#include <string.h>
+
+#include <tny-shared.h>
+#include <tny-folder.h>
+#include <tny-list.h>
+#include <tny-iterator.h>
+#include <tny-simple-list.h>
+
+#include "modest-search.h"
+#include "modest-mime-part-search-stream.h"
+
+static GList*
+add_header (GList *list, TnyHeader *header, TnyFolder *folder)
+{
+       gchar *furl = tny_folder_get_url_string (folder);
+       const gchar *uid = tny_header_get_uid (header);
+       gchar *str  = g_strdup_printf ("%s/%s", furl, uid);
+       g_free (furl);
+       return g_list_prepend (list, str);
+}
+
+
+
+/**
+ * modest_search:
+ * @folder: a #TnyFolder instance
+ * @search: a #ModestSearch query
+ *
+ * This operation will search @folder for headers that match the query @search.
+ * It will return a doubly linked list with URIs that point to the message.
+ **/
+GList *
+modest_search (TnyFolder *folder, ModestSearch *search)
+{
+       GList *retval = NULL;
+       TnyIterator *iter;
+       TnyList *list = tny_simple_list_new ();
+       tny_folder_get_headers (folder, list, FALSE, NULL);
+
+       iter = tny_list_create_iterator (list);
+       while (!tny_iterator_is_done (iter))
+       {
+               TnyHeader *cur = (TnyHeader *) tny_iterator_get_current (iter);
+               time_t t = tny_header_get_date_sent (cur);
+
+               if (search->flags & MODEST_SEARCH_BEFORE)
+                       if (!(t <= search->before))
+                               goto go_next;
+
+               if (search->flags & MODEST_SEARCH_AFTER)
+                       if (!(t >= search->after))
+                               goto go_next;
+
+
+               if (search->flags & MODEST_SEARCH_SIZE)
+                       if (tny_header_get_message_size  (cur) < search->minsize)
+                               goto go_next;
+               
+               if (search->flags & MODEST_SEARCH_SUBJECT) {
+                       if (strcasestr (tny_header_get_subject (cur), search->subject))
+                               retval = add_header (retval, cur, folder);
+               } else if (search->flags & MODEST_SEARCH_SENDER) {
+                       if (strcasestr (tny_header_get_from (cur), search->subject))
+                               retval = add_header (retval, cur, folder);
+               } else if (search->flags & MODEST_SEARCH_RECIPIENT) {
+                       if (strcasestr (tny_header_get_to (cur), search->subject))
+                               retval = add_header (retval, cur, folder);
+               } else if (search->flags & MODEST_SEARCH_BODY) 
+               {
+                       TnyHeaderFlags flags = tny_header_get_flags (cur);
+                       
+                       if (flags & TNY_HEADER_FLAG_CACHED)
+                       {
+                               GError *err = NULL;
+                               TnyMsg *msg = tny_folder_get_msg (folder, cur, &err);
+                               
+                               if (err == NULL)
+                               {
+                                       TnyIterator *piter;
+                                       TnyList *parts = tny_simple_list_new ();
+                                       tny_mime_part_get_parts  (TNY_MIME_PART (msg), parts);
+                                       piter = tny_list_create_iterator (parts);
+
+                                       while (!tny_iterator_is_done (piter))
+                                       {
+                                               TnyStream *stream;
+                                               TnyMimePart *pcur = (TnyMimePart *) tny_iterator_get_current (piter);
+
+                                               stream = modest_mime_part_search_stream_new (search->body);
+
+                                               tny_mime_part_decode_to_stream (pcur, stream);
+
+                                               if (((ModestMimePartSearchStream *) stream)->found)
+                                                       retval = add_header (retval, cur, folder);                              
+
+                                               g_object_unref (stream);
+                                               g_object_unref (pcur);
+                                               tny_iterator_next (piter);
+                                       }
+                                       g_object_unref (piter);
+                                       g_object_unref (parts);
+                               } else
+                                       g_error_free (err);
+                               
+                               if (msg)
+                                       g_object_unref (msg);
+                       }
+               }
+
+                       
+
+go_next:
+               g_object_unref (cur);
+               tny_iterator_next (iter);
+       }
+       g_object_unref (iter);
+       g_object_unref (list);
+       
+       return retval;
+}
+
diff --git a/src/modest-search.h b/src/modest-search.h
new file mode 100644 (file)
index 0000000..104c8ae
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef MODEST_SEARCH_H
+#define MODEST_SEARCH_H
+
+typedef enum {
+       MODEST_SEARCH_SUBJECT = 0<<1,
+       MODEST_SEARCH_SENDER = 0<<2,
+       MODEST_SEARCH_RECIPIENT = 0<<3,
+       MODEST_SEARCH_SIZE = 0<<4,
+       MODEST_SEARCH_BEFORE = 0<<5,
+       MODEST_SEARCH_AFTER = 0<<6,
+       MODEST_SEARCH_BODY = 0<<7
+} ModestSearchFlags;
+
+typedef struct {
+       gchar *subject, *from, *recipient, *body;
+       time_t before, after;
+       guint minsize;
+       ModestSearchFlags flags;
+} ModestSearch;
+
+GList * modest_search (TnyFolder *folder, ModestSearch *search);
+
+#endif
+