9 #include <tny-shared.h>
10 #include <tny-folder.h>
12 #include <tny-iterator.h>
13 #include <tny-simple-list.h>
15 #include "modest-text-utils.h"
17 #include "modest-search.h"
21 add_header (GList *list, TnyHeader *header, TnyFolder *folder)
23 gchar *furl = tny_folder_get_url_string (folder);
24 const gchar *uid = tny_header_get_uid (header);
25 gchar *str = g_strdup_printf ("%s/%s", furl, uid);
27 return g_list_prepend (list, str);
31 read_chunk (TnyStream *stream, char *buffer, gsize count, gsize *nread)
37 while (_nread < count) {
38 res = tny_stream_read (stream,
58 #ifdef MODEST_HAVE_OGS
60 search_mime_part_ogs (TnyMimePart *part, ModestSearch *search)
66 gboolean is_html = FALSE;
71 if (! tny_mime_part_content_type_is (part, "text/ *") ||
72 ! (is_html = tny_mime_part_content_type_is (part, "text/html"))) {
77 len = sizeof (buffer);
78 stream = tny_mime_part_get_stream (part);
80 while ((res = read_chunk (stream, buffer, len, &nread))) {
84 found = ogs_text_searcher_search_html (search->text_searcher,
89 found = ogs_text_searcher_search_text (search->text_searcher,
101 found = ogs_text_searcher_search_done (search->text_searcher);
104 ogs_text_searcher_reset (search->text_searcher);
111 search_mime_part_strcmp (TnyMimePart *part, ModestSearch *search)
121 if (! tny_mime_part_content_type_is (part, "text/ *")) {
126 len = (sizeof (buffer) - 1) / 2;
128 if (strlen (search->body) > len) {
129 g_warning ("Search term bigger then chunk."
130 "We might not find everything");
133 stream = tny_mime_part_get_stream (part);
135 memset (buffer, 0, sizeof (buffer));
137 chunk[1] = buffer + len;
139 res = read_chunk (stream, chunk[0], len, &nread);
145 found = !modest_text_utils_utf8_strcmp (search->body,
152 /* This works like this:
153 * buffer: [ooooooooooo|xxxxxxxxxxxx|\0]
154 * ^chunk[0] ^chunk[1]
155 * we have prefilled chunk[0] now we always read into chunk[1]
156 * and then move the content of chunk[1] to chunk[0].
157 * The idea is to prevent not finding search terms that are
158 * spread across 2 reads:
159 * buffer: [ooooooooTES|Txxxxxxxxxxx|\0]
160 * We should catch that because we always search the whole
161 * buffer not only the chunks.
163 * Of course that breaks for search terms > sizeof (chunk)
164 * but sizeof (chunk) should be big enough I guess (see
165 * the g_warning in this function)
167 while ((res = read_chunk (stream, chunk[1], len, &nread))) {
168 buffer[len + nread] = '\0';
170 found = !modest_text_utils_utf8_strcmp (search->body,
178 /* also move the \0 */
179 g_memmove (chunk[0], chunk[1], len + 1);
183 g_object_unref (stream);
188 search_string (const char *what,
190 ModestSearch *search)
193 #ifdef MODEST_HAVE_OGS
194 if (search->flags & MODEST_SEARCH_USE_OGS) {
195 found = ogs_text_searcher_search_text (search->text_searcher,
199 ogs_text_searcher_reset (search->text_searcher);
202 found = !modest_text_utils_utf8_strcmp (what, where, TRUE);
203 #ifdef MODEST_HAVE_OGS
212 * @folder: a #TnyFolder instance
213 * @search: a #ModestSearch query
215 * This operation will search @folder for headers that match the query @search.
216 * It will return a doubly linked list with URIs that point to the message.
219 modest_search (TnyFolder *folder, ModestSearch *search)
221 GList *retval = NULL;
224 gboolean (*part_search_func) (TnyMimePart *part, ModestSearch *search);
226 part_search_func = search_mime_part_strcmp;
228 #ifdef MODEST_HAVE_OGS
229 if (search->flags & MODEST_SEARCH_USE_OGS) {
231 if (search->text_searcher == NULL && search->query != NULL) {
232 OgsTextSearcher *text_searcher;
234 text_searcher = ogs_text_searcher_new (FALSE);
235 ogs_text_searcher_parse_query (text_searcher, search->query);
236 search->text_searcher = text_searcher;
239 part_search_func = search_mime_part_ogs;
243 list = tny_simple_list_new ();
244 tny_folder_get_headers (folder, list, FALSE, NULL);
246 iter = tny_list_create_iterator (list);
248 while (!tny_iterator_is_done (iter)) {
249 TnyHeader *cur = (TnyHeader *) tny_iterator_get_current (iter);
250 time_t t = tny_header_get_date_sent (cur);
251 gboolean found = FALSE;
253 if (search->flags & MODEST_SEARCH_BEFORE)
254 if (!(t <= search->before))
257 if (search->flags & MODEST_SEARCH_AFTER)
258 if (!(t >= search->after))
261 if (search->flags & MODEST_SEARCH_SIZE)
262 if (tny_header_get_message_size (cur) < search->minsize)
265 if (search->flags & MODEST_SEARCH_SUBJECT) {
266 const char *str = tny_header_get_subject (cur);
268 if ((found = search_string (search->subject, str, search))) {
269 retval = add_header (retval, cur, folder);
273 if (!found && search->flags & MODEST_SEARCH_SENDER) {
274 const char *str = tny_header_get_from (cur);
276 if ((found = search_string (search->from, str, search))) {
277 retval = add_header (retval, cur, folder);
281 if (!found && search->flags & MODEST_SEARCH_RECIPIENT) {
282 const char *str = tny_header_get_to (cur);
284 if ((found = search_string (search->recipient, str, search))) {
285 retval = add_header (retval, cur, folder);
289 if (!found && search->flags & MODEST_SEARCH_BODY) {
290 TnyHeaderFlags flags;
296 flags = tny_header_get_flags (cur);
298 if (!(flags & TNY_HEADER_FLAG_CACHED)) {
302 msg = tny_folder_get_msg (folder, cur, &err);
304 if (err != NULL || msg == NULL) {
305 g_warning ("Could not get message\n");
309 g_object_unref (msg);
313 parts = tny_simple_list_new ();
314 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
316 piter = tny_list_create_iterator (parts);
317 while (!found && !tny_iterator_is_done (piter)) {
318 TnyMimePart *pcur = (TnyMimePart *) tny_iterator_get_current (piter);
320 if ((found = part_search_func (pcur, search))) {
321 retval = add_header (retval, cur, folder);
324 g_object_unref (pcur);
325 tny_iterator_next (piter);
328 g_object_unref (piter);
329 g_object_unref (parts);
330 g_object_unref (msg);
334 g_object_unref (cur);
335 tny_iterator_next (iter);
338 g_object_unref (iter);
339 g_object_unref (list);