+2011-01-25 [colin] 3.7.8cvs47
+
+ * src/matcher.c
+ Fix matcher body parsing: decode mails with our
+ MIME parser. This speeds up body search a bit as
+ binary attachments are not searched anymore, slows
+ down a bit full message searches, but not awfully.
+ * src/summary_search.c
+ Use matcher API to search, in all cases (advanced search or
+ not). Also, fix little logic bugs related to combos history
+ * src/common/utils.c
+ * src/common/utils.h
+ * src/procmime.c
+ * src/procmime.h
+ Remove dead code, export functions needed by matcher.c
+
2011-01-25 [colin] 3.7.8cvs46
* src/compose.c
( cvs diff -u -r 1.1.2.16 -r 1.1.2.17 manual/es/advanced.xml; ) > 3.7.8cvs44.patchset
( cvs diff -u -r 1.56.2.66 -r 1.56.2.67 src/pop.c; ) > 3.7.8cvs45.patchset
( cvs diff -u -r 1.382.2.566 -r 1.382.2.567 src/compose.c; cvs diff -u -r 1.204.2.199 -r 1.204.2.200 src/prefs_common.c; cvs diff -u -r 1.2.2.9 -r 1.2.2.10 src/common/md5.c; cvs diff -u -r 1.4.2.36 -r 1.4.2.37 src/common/ssl_certificate.c; ) > 3.7.8cvs46.patchset
+( cvs diff -u -r 1.75.2.67 -r 1.75.2.68 src/matcher.c; cvs diff -u -r 1.49.2.137 -r 1.49.2.138 src/procmime.c; cvs diff -u -r 1.17.2.24 -r 1.17.2.25 src/procmime.h; cvs diff -u -r 1.15.2.59 -r 1.15.2.60 src/summary_search.c; cvs diff -u -r 1.36.2.189 -r 1.36.2.190 src/common/utils.c; cvs diff -u -r 1.20.2.74 -r 1.20.2.75 src/common/utils.h; ) > 3.7.8cvs47.patchset
MICRO_VERSION=8
INTERFACE_AGE=0
BINARY_AGE=0
-EXTRA_VERSION=46
+EXTRA_VERSION=47
EXTRA_RELEASE=
EXTRA_GTK2_VERSION=
}
}
-gboolean str_find(const gchar *haystack, const gchar *needle)
-{
- return strstr(haystack, needle) != NULL ? TRUE : FALSE;
-}
-
-gboolean str_case_find(const gchar *haystack, const gchar *needle)
-{
- return strcasestr(haystack, needle) != NULL ? TRUE : FALSE;
-}
-
gint to_number(const gchar *nstr)
{
register const gchar *p;
void ptr_array_free_strings (GPtrArray *array);
-typedef gboolean (*StrFindFunc) (const gchar *haystack,
- const gchar *needle);
-
-gboolean str_find (const gchar *haystack,
- const gchar *needle);
-gboolean str_case_find (const gchar *haystack,
- const gchar *needle);
/* number-string conversion */
gint to_number (const gchar *nstr);
gchar *itos_buf (gchar *nstr,
return FALSE;
}
-/* FIXME body search is a hack. */
-static gboolean matcherprop_string_decode_match(MatcherProp *prop, const gchar *str,
- const gchar *debug_context)
+static gboolean matcherprop_header_line_match(MatcherProp *prop, const gchar *hdr,
+ const gchar *str, const gchar *debug_context)
{
- gchar *utf = NULL;
- gchar tmp[BUFFSIZE];
+ gchar *line = NULL;
gboolean res = FALSE;
- if (str == NULL)
+ if (hdr == NULL || str == NULL)
return FALSE;
- /* we try to decode QP first, because it's faster than base64 */
- qp_decode_const(tmp, BUFFSIZE-1, str);
- if (!g_utf8_validate(tmp, -1, NULL)) {
- utf = conv_codeset_strdup
- (tmp, conv_get_locale_charset_str_no_utf8(),
- CS_INTERNAL);
- res = matcherprop_string_match(prop, utf, debug_context);
- g_free(utf);
- } else {
- res = matcherprop_string_match(prop, tmp, debug_context);
- }
-
- if (res == FALSE && (strchr(prop->expr, '=') || strchr(prop->expr, '_')
- || strchr(str, '=') || strchr(str, '_'))) {
- /* if searching for something with an equal char, maybe
- * we should try to match the non-decoded string.
- * In case it was not qp-encoded. */
- if (!g_utf8_validate(str, -1, NULL)) {
- utf = conv_codeset_strdup
- (str, conv_get_locale_charset_str_no_utf8(),
- CS_INTERNAL);
- res = matcherprop_string_match(prop, utf, debug_context);
- g_free(utf);
- } else {
- res = matcherprop_string_match(prop, str, debug_context);
- }
- }
-
- /* FIXME base64 decoding is too slow, especially since text can
- * easily be handled as base64. Don't even try now. */
-
+ line = g_strdup_printf("%s %s", hdr, str);
+ res = matcherprop_string_match(prop, line, debug_context);
+ g_free(line);
+
return res;
}
}
break;
case MATCHCRITERIA_HEADERS_PART:
- return matcherprop_string_match(matcher, buf, _("header line"));
- case MATCHCRITERIA_NOT_HEADERS_PART:
- return !matcherprop_string_match(matcher, buf, _("headers line"));
case MATCHCRITERIA_MESSAGE:
- return matcherprop_string_decode_match(matcher, buf, _("message line"));
+ header = procheader_parse_header(buf);
+ if (!header)
+ return FALSE;
+ result = matcherprop_header_line_match(matcher,
+ header->name, header->body, _("header line"));
+ procheader_header_free(header);
+ return result;
+ case MATCHCRITERIA_NOT_HEADERS_PART:
case MATCHCRITERIA_NOT_MESSAGE:
- return !matcherprop_string_decode_match(matcher, buf, _("message line"));
+ header = procheader_parse_header(buf);
+ if (!header)
+ return FALSE;
+ result = !matcherprop_header_line_match(matcher,
+ header->name, header->body, _("header line"));
+ procheader_header_free(header);
+ return result;
case MATCHCRITERIA_FOUND_IN_ADDRESSBOOK:
case MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK:
{
}
}
-/*!
- *\brief Check if a (line) string matches the criteria
- * described by a matcher structure
- *
- *\param matcher Matcher structure
- *\param line String
- *
- *\return gboolean TRUE if string matches criteria
- */
-static gboolean matcherprop_match_line(MatcherProp *matcher, const gchar *line)
-{
- switch (matcher->criteria) {
- case MATCHCRITERIA_BODY_PART:
- case MATCHCRITERIA_MESSAGE:
- return matcherprop_string_decode_match(matcher, line, _("body line"));
- case MATCHCRITERIA_NOT_BODY_PART:
- case MATCHCRITERIA_NOT_MESSAGE:
- return !matcherprop_string_decode_match(matcher, line, _("body line"));
- }
- return FALSE;
-}
-
/*!
*\brief Check if a line in a message file's body matches
* the criteria
*
*\return gboolean TRUE if succesful match
*/
-static gboolean matcherlist_match_body(MatcherList *matchers, FILE *fp)
+static gboolean matcherlist_match_body(MatcherList *matchers, gboolean body_only, MsgInfo *info)
{
GSList *l;
+ MimeInfo *mimeinfo = NULL;
+ MimeInfo *partinfo = NULL;
gchar buf[BUFFSIZE];
-
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- for (l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
- MatcherProp *matcher = (MatcherProp *) l->data;
-
- if (matcher->done)
- continue;
+ gboolean first_text_found = FALSE;
+ FILE *outfp = NULL;
- /* if the criteria is ~body_part or ~message, ZERO lines
- * must NOT match for the rule to match. */
- if (matcher->criteria == MATCHCRITERIA_NOT_BODY_PART ||
- matcher->criteria == MATCHCRITERIA_NOT_MESSAGE) {
- if (matcherprop_match_line(matcher, buf)) {
- matcher->result = TRUE;
- } else {
- matcher->result = FALSE;
- matcher->done = TRUE;
- }
- /* else, just one line has to match */
- } else if (matcherprop_criteria_body(matcher) ||
- matcherprop_criteria_message(matcher)) {
- if (matcherprop_match_line(matcher, buf)) {
- matcher->result = TRUE;
- matcher->done = TRUE;
+ cm_return_val_if_fail(info != NULL, FALSE);
+
+ mimeinfo = procmime_scan_message(info);
+
+ /* Skip headers */
+ partinfo = procmime_mimeinfo_next(mimeinfo);
+
+ for (; partinfo != NULL; partinfo = procmime_mimeinfo_next(partinfo)) {
+
+ if (partinfo->type != MIMETYPE_TEXT && body_only)
+ continue;
+
+ if (partinfo->type == MIMETYPE_TEXT) {
+ first_text_found = TRUE;
+ outfp = procmime_get_text_content(partinfo);
+ } else
+ outfp = procmime_get_binary_content(partinfo);
+
+ if (!outfp) {
+ procmime_mimeinfo_free_all(mimeinfo);
+ return FALSE;
+ }
+
+ while (fgets(buf, sizeof(buf), outfp) != NULL) {
+ strretchomp(buf);
+
+ for (l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
+ MatcherProp *matcher = (MatcherProp *) l->data;
+
+ if (matcher->done)
+ continue;
+
+ /* Don't scan non-text parts when looking in body, only
+ * when looking in whole message
+ */
+ if (partinfo && partinfo->type != MIMETYPE_TEXT &&
+ (matcher->criteria == MATCHCRITERIA_NOT_BODY_PART ||
+ matcher->criteria == MATCHCRITERIA_BODY_PART))
+ continue;
+
+ /* if the criteria is ~body_part or ~message, ZERO lines
+ * must match for the rule to match.
+ */
+ if (matcher->criteria == MATCHCRITERIA_NOT_BODY_PART ||
+ matcher->criteria == MATCHCRITERIA_NOT_MESSAGE) {
+ if (matcherprop_string_match(matcher, buf,
+ _("body line"))) {
+ matcher->result = FALSE;
+ matcher->done = TRUE;
+ } else
+ matcher->result = TRUE;
+ /* else, just one line has to match */
+ } else if (matcherprop_criteria_body(matcher) ||
+ matcherprop_criteria_message(matcher)) {
+ if (matcherprop_string_match(matcher, buf,
+ _("body line"))) {
+ matcher->result = TRUE;
+ matcher->done = TRUE;
+ }
}
- }
- /* if the matchers are OR'ed and the rule matched,
- * no need to check the others. */
- if (matcher->result && matcher->done) {
- if (!matchers->bool_and)
- return TRUE;
+ /* if the matchers are OR'ed and the rule matched,
+ * no need to check the others. */
+ if (matcher->result && matcher->done) {
+ if (!matchers->bool_and) {
+ procmime_mimeinfo_free_all(mimeinfo);
+ fclose(outfp);
+ return TRUE;
+ }
+ }
}
}
+ fclose(outfp);
+
+ if (body_only && first_text_found)
+ break;
}
+ procmime_mimeinfo_free_all(mimeinfo);
+
return FALSE;
}
{
gboolean read_headers;
gboolean read_body;
+ gboolean body_only;
GSList *l;
FILE *fp;
gchar *file;
read_headers = FALSE;
read_body = FALSE;
+ body_only = TRUE;
for (l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
MatcherProp *matcher = (MatcherProp *) l->data;
if (matcherprop_criteria_message(matcher)) {
read_headers = TRUE;
read_body = TRUE;
+ body_only = FALSE;
}
matcher->result = FALSE;
matcher->done = FALSE;
/* read the body */
if (read_body) {
- matcherlist_match_body(matchers, fp);
+ matcherlist_match_body(matchers, body_only, info);
}
for (l = matchers->matchers; l != NULL; l = g_slist_next(l)) {
{
gchar *filename;
MimeInfo *mimeinfo;
- START_TIMING("");
- filename = procmsg_get_message_file_path(msginfo);
+
+ filename = procmsg_get_message_file_path(msginfo);
if (!filename || !is_file_exist(filename)) {
g_free(filename);
return NULL;
mimeinfo = procmime_scan_queue_file(filename);
g_free(filename);
- END_TIMING();
return mimeinfo;
}
return 0;
}
-static FILE *procmime_get_text_content(MimeInfo *mimeinfo)
+FILE *procmime_get_text_content(MimeInfo *mimeinfo)
{
FILE *tmpfp, *outfp;
const gchar *src_codeset;
return outfp;
}
+FILE *procmime_get_binary_content(MimeInfo *mimeinfo)
+{
+ FILE *outfp;
+ gchar *tmpfile;
+
+ cm_return_val_if_fail(mimeinfo != NULL, NULL);
+
+ if (!procmime_decode_content(mimeinfo))
+ return NULL;
+
+ tmpfile = procmime_get_tmp_file_name(mimeinfo);
+ if (tmpfile == NULL)
+ return NULL;
+
+ if (procmime_get_part(tmpfile, mimeinfo) < 0) {
+ g_free(tmpfile);
+ return NULL;
+ }
+
+ outfp = g_fopen(tmpfile, "rb");
+ if (outfp == NULL) {
+ g_unlink(tmpfile);
+ g_free(tmpfile);
+ return NULL;
+ }
+
+ g_unlink(tmpfile);
+ g_free(tmpfile);
+
+ return outfp;
+}
+
/* search the first text part of (multipart) MIME message,
decode, convert it and output to outfp. */
FILE *procmime_get_first_text_content(MsgInfo *msginfo)
FILE *outfp = NULL;
MimeInfo *mimeinfo, *partinfo;
gboolean empty_ok = FALSE, short_scan = TRUE;
- START_TIMING("");
- cm_return_val_if_fail(msginfo != NULL, NULL);
+
+ cm_return_val_if_fail(msginfo != NULL, NULL);
/* first we try to short-scan (for speed), refusing empty parts */
scan_again:
goto scan_again;
}
procmime_mimeinfo_free_all(mimeinfo);
- END_TIMING();
return outfp;
}
return result;
}
-static gboolean procmime_find_string_part(MimeInfo *mimeinfo, const gchar *filename,
- const gchar *str, StrFindFunc find_func)
-{
- FILE *outfp;
- gchar buf[BUFFSIZE];
-
- cm_return_val_if_fail(mimeinfo != NULL, FALSE);
- cm_return_val_if_fail(mimeinfo->type == MIMETYPE_TEXT, FALSE);
- cm_return_val_if_fail(str != NULL, FALSE);
- cm_return_val_if_fail(find_func != NULL, FALSE);
-
- outfp = procmime_get_text_content(mimeinfo);
-
- if (!outfp)
- return FALSE;
-
- while (fgets(buf, sizeof(buf), outfp) != NULL) {
- strretchomp(buf);
- if (find_func(buf, str)) {
- fclose(outfp);
- return TRUE;
- }
- }
-
- fclose(outfp);
-
- return FALSE;
-}
-
-gboolean procmime_find_string(MsgInfo *msginfo, const gchar *str,
- StrFindFunc find_func)
-{
- MimeInfo *mimeinfo;
- MimeInfo *partinfo;
- gchar *filename;
- gboolean found = FALSE;
-
- cm_return_val_if_fail(msginfo != NULL, FALSE);
- cm_return_val_if_fail(str != NULL, FALSE);
- cm_return_val_if_fail(find_func != NULL, FALSE);
-
- filename = procmsg_get_message_file(msginfo);
- if (!filename) return FALSE;
- mimeinfo = procmime_scan_message(msginfo);
-
- for (partinfo = mimeinfo; partinfo != NULL;
- partinfo = procmime_mimeinfo_next(partinfo)) {
- if (partinfo->type == MIMETYPE_TEXT) {
- if (procmime_find_string_part
- (partinfo, filename, str, find_func) == TRUE) {
- found = TRUE;
- break;
- }
- }
- }
-
- procmime_mimeinfo_free_all(mimeinfo);
- g_free(filename);
-
- return found;
-}
-
gchar *procmime_get_tmp_file_name(MimeInfo *mimeinfo)
{
static guint32 id = 0;
FILE *procmime_get_first_encrypted_text_content
(MsgInfo *msginfo);
-gboolean procmime_find_string (MsgInfo *msginfo,
- const gchar *str,
- StrFindFunc find_func);
-
gchar *procmime_get_tmp_file_name (MimeInfo *mimeinfo);
gchar *procmime_get_part_file_name (MimeInfo *mimeinfo);
void procmime_mimeparser_register(MimeParser *mimeparser);
void procmime_mimeparser_unregister(MimeParser *mimeparser);
+FILE *procmime_get_text_content(MimeInfo *mimeinfo);
+FILE *procmime_get_binary_content(MimeInfo *mimeinfo);
#ifdef __cplusplus
}
gchar *from_str = NULL, *to_str = NULL, *subject_str = NULL;
gchar *body_str = NULL;
gchar *adv_condition = NULL;
- StrFindFunc str_find_func = NULL;
gboolean is_fast = TRUE;
gint interval = 1000;
gint i = 0;
+ GSList *matchers = NULL;
if (summary_is_locked(summaryview)) {
return;
adv_search = gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON(search_window.adv_search_checkbtn));
+ if (search_window.matcher_list != NULL) {
+ matcherlist_free(search_window.matcher_list);
+ search_window.matcher_list = NULL;
+ }
if (adv_search) {
- if (search_window.matcher_list != NULL) {
- matcherlist_free(search_window.matcher_list);
- search_window.matcher_list = NULL;
- }
adv_condition = gtk_combo_box_get_active_text(GTK_COMBO_BOX(search_window.adv_condition_entry));
if (!adv_condition)
adv_condition = gtk_editable_get_chars(
case_sens = gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON(search_window.case_checkbtn));
- if (case_sens) {
- str_find_func = str_find;
- } else {
- str_find_func = str_case_find;
- }
-
from_str = gtk_combo_box_get_active_text(GTK_COMBO_BOX(search_window.from_entry));
to_str = gtk_combo_box_get_active_text(GTK_COMBO_BOX(search_window.to_entry));
subject_str = gtk_combo_box_get_active_text(GTK_COMBO_BOX(search_window.subject_entry));
}
/* add to history */
- if (from_str[0] != '\0')
+ if (from_str[0] != '\0') {
+ MatcherProp *prop = matcherprop_new(MATCHCRITERIA_FROM,
+ NULL, case_sens ? MATCHTYPE_MATCH:MATCHTYPE_MATCHCASE,
+ from_str, 0);
+ matchers = g_slist_append(matchers, prop);
combobox_unset_popdown_strings(GTK_COMBO_BOX(search_window.from_entry));
prefs_common.summary_search_from_history = add_history(
prefs_common.summary_search_from_history, from_str);
combobox_set_popdown_strings(GTK_COMBO_BOX(search_window.from_entry),
prefs_common.summary_search_from_history);
- if (to_str[0] != '\0')
+ }
+ if (to_str[0] != '\0') {
+ MatcherProp *prop = matcherprop_new(MATCHCRITERIA_TO,
+ NULL, case_sens ? MATCHTYPE_MATCH:MATCHTYPE_MATCHCASE,
+ to_str, 0);
+ matchers = g_slist_append(matchers, prop);
combobox_unset_popdown_strings(GTK_COMBO_BOX(search_window.to_entry));
prefs_common.summary_search_to_history = add_history(
prefs_common.summary_search_to_history, to_str);
combobox_set_popdown_strings(GTK_COMBO_BOX(search_window.to_entry),
prefs_common.summary_search_to_history);
- if (subject_str[0] != '\0')
+ }
+ if (subject_str[0] != '\0') {
+ MatcherProp *prop = matcherprop_new(MATCHCRITERIA_SUBJECT,
+ NULL, case_sens ? MATCHTYPE_MATCH:MATCHTYPE_MATCHCASE,
+ subject_str, 0);
+ matchers = g_slist_append(matchers, prop);
combobox_unset_popdown_strings(GTK_COMBO_BOX(search_window.subject_entry));
prefs_common.summary_search_subject_history = add_history(
prefs_common.summary_search_subject_history, subject_str);
combobox_set_popdown_strings(GTK_COMBO_BOX(search_window.subject_entry),
prefs_common.summary_search_subject_history);
- if (body_str[0] != '\0')
+ }
+ if (body_str[0] != '\0') {
+ MatcherProp *prop = matcherprop_new(MATCHCRITERIA_BODY_PART,
+ NULL, case_sens ? MATCHTYPE_MATCH:MATCHTYPE_MATCHCASE,
+ body_str, 0);
+ matchers = g_slist_append(matchers, prop);
combobox_unset_popdown_strings(GTK_COMBO_BOX(search_window.body_entry));
prefs_common.summary_search_body_history = add_history(
prefs_common.summary_search_body_history, body_str);
combobox_set_popdown_strings(GTK_COMBO_BOX(search_window.body_entry),
prefs_common.summary_search_body_history);
+ }
+ search_window.matcher_list = matcherlist_new(matchers, bool_and);
}
search_window.is_searching = TRUE;
msginfo = gtk_cmctree_node_get_row_data(ctree, node);
body_matched = FALSE;
- if (adv_search) {
- matched = matcherlist_match(search_window.matcher_list, msginfo);
- } else {
- if (bool_and) {
- matched = TRUE;
- if (*from_str) {
- if (!msginfo->from ||
- !str_find_func(msginfo->from, from_str)) {
- matched = FALSE;
- }
- }
- if (matched && *to_str) {
- if (!msginfo->to ||
- !str_find_func(msginfo->to, to_str)) {
- matched = FALSE;
- }
- }
- if (matched && *subject_str) {
- if (!msginfo->subject ||
- !str_find_func(msginfo->subject, subject_str)) {
- matched = FALSE;
- }
- }
- if (matched && *body_str) {
- if (procmime_find_string(msginfo, body_str,
- str_find_func)) {
- body_matched = TRUE;
- } else {
- matched = FALSE;
- }
- }
- if (matched && !*from_str && !*to_str &&
- !*subject_str && !*body_str) {
- matched = FALSE;
- }
- } else {
- matched = FALSE;
- if (*from_str && msginfo->from) {
- if (str_find_func(msginfo->from, from_str)) {
- matched = TRUE;
- }
- }
- if (!matched && *to_str && msginfo->to) {
- if (str_find_func(msginfo->to, to_str)) {
- matched = TRUE;
- }
- }
- if (!matched && *subject_str && msginfo->subject) {
- if (str_find_func(msginfo->subject, subject_str)) {
- matched = TRUE;
- }
- }
- if (!matched && *body_str) {
- if (procmime_find_string(msginfo, body_str,
- str_find_func)) {
- matched = TRUE;
- body_matched = TRUE;
- }
- }
- }
- }
+ matched = matcherlist_match(search_window.matcher_list, msginfo);
if (matched) {
if (search_all) {