evolution-data-server r9887 - trunk/camel



Author: mcrha
Date: Thu Jan  8 11:14:53 2009
New Revision: 9887
URL: http://svn.gnome.org/viewvc/evolution-data-server?rev=9887&view=rev

Log:
2009-01-08  Milan Crha  <mcrha redhat com>

	** Part of fix for bug #565376

	* camel-folder-search.h: (struct _CamelFolderSearchClass):
	* camel-folder-search.c: Support more search options.



Modified:
   trunk/camel/ChangeLog
   trunk/camel/camel-folder-search.c
   trunk/camel/camel-folder-search.h

Modified: trunk/camel/camel-folder-search.c
==============================================================================
--- trunk/camel/camel-folder-search.c	(original)
+++ trunk/camel/camel-folder-search.c	Thu Jan  8 11:14:53 2009
@@ -41,6 +41,7 @@
 #include "camel-exception.h"
 #include "camel-folder-search.h"
 #include "camel-folder-thread.h"
+#include "camel-iconv.h"
 #include "camel-medium.h"
 #include "camel-mime-message.h"
 #include "camel-multipart.h"
@@ -74,9 +75,13 @@
 static ESExpResult *search_header_starts_with(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
 static ESExpResult *search_header_ends_with(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
 static ESExpResult *search_header_exists(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+static ESExpResult *search_header_soundex(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+static ESExpResult *search_header_regex(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+static ESExpResult *search_header_full_regex(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
 static ESExpResult *search_match_all(struct _ESExp *f, int argc, struct _ESExpTerm **argv, CamelFolderSearch *search);
 static ESExpResult *search_match_threads(struct _ESExp *f, int argc, struct _ESExpTerm **argv, CamelFolderSearch *s);
 static ESExpResult *search_body_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+static ESExpResult *search_body_regex(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
 static ESExpResult *search_user_flag(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
 static ESExpResult *search_user_tag(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
 static ESExpResult *search_system_flag(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
@@ -85,6 +90,7 @@
 static ESExpResult *search_get_current_date(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
 static ESExpResult *search_get_size(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
 static ESExpResult *search_uid(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+static ESExpResult *search_message_location(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
 
 static ESExpResult *search_dummy(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
 
@@ -106,11 +112,15 @@
 	klass->match_all = search_match_all;
 	klass->match_threads = search_match_threads;
 	klass->body_contains = search_body_contains;
+	klass->body_regex = search_body_regex;
 	klass->header_contains = search_header_contains;
 	klass->header_matches = search_header_matches;
 	klass->header_starts_with = search_header_starts_with;
 	klass->header_ends_with = search_header_ends_with;
 	klass->header_exists = search_header_exists;
+	klass->header_soundex = search_header_soundex;
+	klass->header_regex = search_header_regex;
+	klass->header_full_regex = search_header_full_regex;
 	klass->user_tag = search_user_tag;
 	klass->user_flag = search_user_flag;
 	klass->system_flag = search_system_flag;
@@ -119,6 +129,7 @@
 	klass->get_current_date = search_get_current_date;
 	klass->get_size = search_get_size;
 	klass->uid = search_uid;
+	klass->message_location = search_message_location;
 }
 
 static void
@@ -187,11 +198,15 @@
 	{ "match-all", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, match_all), 3 },
 	{ "match-threads", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, match_threads), 3 },
 	{ "body-contains", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, body_contains), 1 },
+	{ "body-regex",  CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, body_regex), 1  },
 	{ "header-contains", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_contains), 1 },
 	{ "header-matches", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_matches), 1 },
 	{ "header-starts-with", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_starts_with), 1 },
 	{ "header-ends-with", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_ends_with), 1 },
 	{ "header-exists", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_exists), 1 },
+	{ "header-soundex", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_soundex), 1 },
+	{ "header-regex", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_regex), 1 },
+	{ "header-full-regex", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_full_regex), 1 },
 	{ "user-tag", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, user_tag), 1 },
 	{ "user-flag", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, user_flag), 1 },
 	{ "system-flag", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, system_flag), 1 },
@@ -200,6 +215,7 @@
 	{ "get-current-date", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, get_current_date), 1 },
 	{ "get-size", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, get_size), 1 },
 	{ "uid", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, uid), 1 },
+	{ "message-location", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, message_location), 1 },
 };
 
 void
@@ -519,6 +535,24 @@
 	return count;
 }
 
+static gboolean
+do_search_in_memory (const char *expr)
+{
+	/* if the expression contains any of these tokens, then perform a memory search, instead of the SQL one */
+	const char *in_memory_tokens[] = { "body-contains", "body-regex", "match-threads", "message-location", "header-soundex", "header-regex", "header-full-regex", "header-contains", NULL };
+	int i;
+
+	if (!expr)
+		return FALSE;
+
+	for (i = 0; in_memory_tokens [i]; i++) {
+		if (strstr (expr, in_memory_tokens [i]))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
 /**
  * camel_folder_search_search:
  * @search: 
@@ -548,7 +582,7 @@
 	p->ex = ex;
 
 	/* We route body-contains / thread based search and uid search through memory and not via db. */
-	if (uids || strstr((const char *) expr, "body-contains") || strstr((const char *) expr, "match-threads")) {
+	if (uids || do_search_in_memory (expr)) {
 		/* setup our search list only contains those we're interested in */
 		search->summary = camel_folder_get_summary(search->folder);
 
@@ -973,6 +1007,23 @@
 	return r;
 }
 
+static CamelMimeMessage *
+get_current_message (CamelFolderSearch *search)
+{
+	CamelException x = CAMEL_EXCEPTION_INITIALISER;
+	CamelMimeMessage *res;
+
+	if (!search || !search->folder || !search->current)
+		return NULL;
+
+	res = camel_folder_get_message (search->folder, search->current->uid, &x);
+
+	if (!res)
+		camel_exception_clear (&x);
+
+	return res;
+}
+
 static ESExpResult *
 check_header (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search, camel_search_match_t how)
 {
@@ -985,11 +1036,13 @@
 	if (search->current && argc>1
 	    && argv[0]->type == ESEXP_RES_STRING) {
 		char *headername;
-		const char *header = NULL;
+		const char *header = NULL, *charset = NULL;
 		char strbuf[32];
 		int i, j;
 		camel_search_t type = CAMEL_SEARCH_TYPE_ASIS;
 		struct _camel_search_words *words;
+		CamelMimeMessage *message = NULL;
+		struct _camel_header_raw *raw_header;
 
 		/* only a subset of headers are supported .. */
 		headername = argv[0]->value.string;
@@ -1012,8 +1065,15 @@
 			header = camel_message_info_mlist(search->current);
 			type = CAMEL_SEARCH_TYPE_MLIST;
 		} else {
-			e_sexp_resultv_free(f, argc, argv);
-			e_sexp_fatal_error(f, _("Performing query on unknown header: %s"), headername);
+			message = get_current_message (search);
+			if (message) {
+				CamelContentType *ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (message));
+
+				if (ct) {
+					charset = camel_content_type_param (ct, "charset");
+					charset = camel_iconv_charset_name (charset);
+				}
+			}
 		}
 
 		if (header == NULL)
@@ -1029,14 +1089,34 @@
 					words = camel_search_words_split((const unsigned char *) argv[i]->value.string);
 					truth = TRUE;
 					for (j=0;j<words->len && truth;j++) {
-						truth = camel_search_header_match(header, words->words[j]->word, how, type, NULL);
+						if (message) {
+							for (raw_header = ((CamelMimePart *)message)->headers; raw_header; raw_header = raw_header->next) {
+								if (!g_ascii_strcasecmp (raw_header->name, headername)) {
+									if (camel_search_header_match (raw_header->value, words->words[j]->word, how, type, charset))
+										break;;
+								}
+							}
+
+							truth = raw_header != NULL;
+						} else
+							truth = camel_search_header_match(header, words->words[j]->word, how, type, charset);
 					}
 					camel_search_words_free(words);
 				} else {
-					truth = camel_search_header_match(header, argv[i]->value.string, how, type, NULL);
+					if (message) {
+						for (raw_header = ((CamelMimePart *)message)->headers; raw_header && !truth; raw_header = raw_header->next) {
+							if (!g_ascii_strcasecmp (raw_header->name, headername)) {
+								truth = camel_search_header_match(raw_header->value, argv[i]->value.string, how, type, charset);
+							}
+						}
+					} else
+						truth = camel_search_header_match(header, argv[i]->value.string, how, type, charset);
 				}
 			}
 		}
+
+		if (message)
+			camel_object_unref (message);
 	}
 	/* TODO: else, find all matches */
 
@@ -1098,6 +1178,98 @@
 	return r;
 }
 
+static ESExpResult *
+search_header_soundex (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+	return check_header (f, argc, argv, search, CAMEL_SEARCH_MATCH_SOUNDEX);
+}
+
+static ESExpResult *
+search_header_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+	ESExpResult *r;
+	CamelMimeMessage *msg;
+
+	msg = get_current_message (search);
+
+	if (msg) {
+		regex_t pattern;
+		const char *contents;
+
+		r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+
+		if (argc > 1 && argv[0]->type == ESEXP_RES_STRING
+		    && (contents = camel_medium_get_header (CAMEL_MEDIUM (msg), argv[0]->value.string))
+		    && camel_search_build_match_regex (&pattern, CAMEL_SEARCH_MATCH_REGEX|CAMEL_SEARCH_MATCH_ICASE, argc-1, argv+1, search->priv->ex) == 0) {
+			r->value.bool = regexec (&pattern, contents, 0, NULL, 0) == 0;
+			regfree (&pattern);
+		} else
+			r->value.bool = FALSE;
+
+		camel_object_unref (msg);
+	} else {
+		r = e_sexp_result_new (f, ESEXP_RES_ARRAY_PTR);
+		r->value.ptrarray = g_ptr_array_new();
+	}
+
+	return r;
+}
+
+static gchar *
+get_full_header (CamelMimeMessage *message)
+{
+	CamelMimePart *mp = CAMEL_MIME_PART (message);
+	GString *str = g_string_new ("");
+	struct _camel_header_raw *h;
+	
+	for (h = mp->headers; h; h = h->next) {
+		if (h->value != NULL) {
+			g_string_append (str, h->name);
+			if (isspace (h->value[0]))
+				g_string_append (str, ":");
+			else
+				g_string_append (str, ": ");
+			g_string_append (str, h->value);
+			g_string_append_c (str, '\n');
+		}
+	}
+	
+	return g_string_free (str, FALSE);
+}
+
+static ESExpResult *
+search_header_full_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+	ESExpResult *r;
+	CamelMimeMessage *msg;
+
+	msg = get_current_message (search);
+
+	if (msg) {
+		regex_t pattern;
+
+		r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+
+		if (camel_search_build_match_regex (&pattern, CAMEL_SEARCH_MATCH_REGEX|CAMEL_SEARCH_MATCH_ICASE|CAMEL_SEARCH_MATCH_NEWLINE, argc, argv, search->priv->ex) == 0) {
+			char *contents;
+
+			contents = get_full_header (msg);
+			r->value.bool = regexec (&pattern, contents, 0, NULL, 0) == 0;
+
+			g_free (contents);
+			regfree (&pattern);
+		} else
+			r->value.bool = FALSE;
+
+		camel_object_unref (msg);
+	} else {
+		r = e_sexp_result_new (f, ESEXP_RES_ARRAY_PTR);
+		r->value.ptrarray = g_ptr_array_new();
+	}
+
+	return r;
+}
+
 /* this is just to OR results together */
 struct _glib_sux_donkeys {
 	int count;
@@ -1374,6 +1546,58 @@
 }
 
 static ESExpResult *
+search_body_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+	ESExpResult *r;
+	CamelMimeMessage *msg = get_current_message (search);
+
+	if (msg) {
+		regex_t pattern;
+
+		r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+	
+		if (camel_search_build_match_regex (&pattern, CAMEL_SEARCH_MATCH_ICASE|CAMEL_SEARCH_MATCH_REGEX|CAMEL_SEARCH_MATCH_NEWLINE, argc, argv, search->priv->ex) == 0) {
+			r->value.bool = camel_search_message_body_contains ((CamelDataWrapper *) msg, &pattern);
+			regfree (&pattern);
+		} else
+			r->value.bool = FALSE;
+
+		camel_object_unref (msg);
+	} else {
+		regex_t pattern;
+
+		r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
+		r->value.ptrarray = g_ptr_array_new ();
+
+		if (camel_search_build_match_regex (&pattern, CAMEL_SEARCH_MATCH_ICASE|CAMEL_SEARCH_MATCH_REGEX|CAMEL_SEARCH_MATCH_NEWLINE, argc, argv, search->priv->ex) == 0) {
+			int i;
+			GPtrArray *v = search->summary_set?search->summary_set:search->summary;
+			CamelException x = CAMEL_EXCEPTION_INITIALISER;
+			CamelMimeMessage *message;
+
+			for (i = 0; i < v->len; i++) {
+				char *uid = g_ptr_array_index(v, i);
+
+				message = camel_folder_get_message (search->folder, uid, &x);
+				if (message) {
+					if (camel_search_message_body_contains ((CamelDataWrapper *) message, &pattern)) {
+						g_ptr_array_add (r->value.ptrarray, uid);
+					}
+
+					camel_object_unref ((CamelObject *)message);
+				} else {
+					camel_exception_clear (&x);
+				}
+			}
+		
+			regfree (&pattern);
+		}
+	}
+	
+	return r;
+}
+
+static ESExpResult *
 search_user_flag(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
 {
 	ESExpResult *r;
@@ -1558,3 +1782,43 @@
 	g_ptr_array_add (matches, (gpointer) camel_pstring_strdup (cols [0]));
 	return 0;
 }
+
+static ESExpResult *
+search_message_location (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+	ESExpResult *r;
+	gboolean same = FALSE;
+
+	if (argc == 1 && argv[0]->type == ESEXP_RES_STRING) {
+		if (argv[0]->value.string && search->folder && search->folder->parent_store && camel_folder_get_full_name (search->folder)) {
+			CamelFolderInfo *fi = camel_store_get_folder_info (search->folder->parent_store, camel_folder_get_full_name (search->folder), 0, NULL);
+			if (fi) {
+				same = g_str_equal (fi->uri ? fi->uri : "", argv[0]->value.string);
+
+				camel_store_free_folder_info (search->folder->parent_store, fi);
+			}
+		}
+	}
+
+	if (search->current) {
+		r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+		r->value.bool = same ? TRUE : FALSE;
+	} else {
+		r = e_sexp_result_new (f, ESEXP_RES_ARRAY_PTR);
+		r->value.ptrarray = g_ptr_array_new ();
+
+		if (same) {
+			/* all matches */
+			int i;
+			GPtrArray *v = search->summary_set ? search->summary_set : search->summary;
+
+			for (i = 0; i < v->len; i++) {
+				char *uid = g_ptr_array_index (v, i);
+
+				g_ptr_array_add (r->value.ptrarray, uid);
+			}
+		}
+	}
+
+	return r;
+}

Modified: trunk/camel/camel-folder-search.h
==============================================================================
--- trunk/camel/camel-folder-search.h	(original)
+++ trunk/camel/camel-folder-search.h	Thu Jan  8 11:14:53 2009
@@ -74,6 +74,9 @@
 	/* (body-contains "string1" "string2" ...) Returns a list of matches, or true if in single-message mode */
 	ESExpResult * (*body_contains)(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
 
+	/* (body-regex "regex") Returns a list of matches, or true if in single-message mode */
+	ESExpResult * (*body_regex)(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+
 	/* (header-contains "headername" "string1" ...) List of matches, or true if in single-message mode */
 	ESExpResult * (*header_contains)(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
 	
@@ -89,6 +92,15 @@
 	/* (header-exists "headername") */
 	ESExpResult * (*header_exists)(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
 	
+	/* (header-soundex "headername" "string") */
+	ESExpResult * (*header_soundex)(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+
+	/* (header-regex "headername" "regex_string") */
+	ESExpResult * (*header_regex)(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+
+	/* (header-full-regex "regex") */
+	ESExpResult * (*header_full_regex)(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+
 	/* (user-flag "flagname" "flagname" ...) If one of user-flag set */
 	ESExpResult * (*user_flag)(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
 
@@ -112,6 +124,10 @@
 
 	/* (uid "uid" ...) True if the uid is in the list */
 	ESExpResult * (*uid)(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+	
+	/* (message-location "folder_string") True if the message is in the folder's full name "folder_string" */
+	ESExpResult * (*message_location)(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+	
 };
 
 CamelType		camel_folder_search_get_type	(void);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]