diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2019-01-26 00:30:28 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2019-01-26 01:05:52 +0200 |
commit | 3798a0f09da7fcaa6daa12e9ae483ebf99f7c46a (patch) | |
tree | 97c80866168b24c3c45f2d1961311d80b6ff1823 | |
parent | bc4d023a3810a7da6ede2cc522cdc34fa3129378 (diff) | |
download | mailutils-3798a0f09da7fcaa6daa12e9ae483ebf99f7c46a.tar.gz mailutils-3798a0f09da7fcaa6daa12e9ae483ebf99f7c46a.tar.bz2 |
imap4d: implement SEARCH CHARSET; fix BODY and TEXT searches.
* imap4d/search.c: Implement proper BODY searches. Implement CHARSET.
* imap4d/util.c (util_strcasestr): Remove. Use mu_c_strcasestr instead.
* imap4d/imap4d.h: Likewise.
* NEWS: Document changes.
-rw-r--r-- | NEWS | 11 | ||||
-rw-r--r-- | imap4d/imap4d.h | 1 | ||||
-rw-r--r-- | imap4d/search.c | 262 | ||||
-rw-r--r-- | imap4d/util.c | 8 | ||||
-rw-r--r-- | libmailutils/mailbox/header.c | 0 |
5 files changed, 241 insertions, 41 deletions
@@ -1,4 +1,4 @@ | |||
1 | GNU mailutils NEWS -- history of user-visible changes. 2019-01-23 | 1 | GNU mailutils NEWS -- history of user-visible changes. 2019-01-26 |
2 | Copyright (C) 2002-2019 Free Software Foundation, Inc. | 2 | Copyright (C) 2002-2019 Free Software Foundation, Inc. |
3 | See the end of file for copying conditions. | 3 | See the end of file for copying conditions. |
4 | 4 | ||
@@ -6,6 +6,15 @@ Please send mailutils bug reports to <bug-mailutils@gnu.org>. | |||
6 | 6 | ||
7 | Version 3.5.90 (git) | 7 | Version 3.5.90 (git) |
8 | 8 | ||
9 | * imap4d: SEARCH command | ||
10 | |||
11 | ** Implemented SEARCH CHARSET | ||
12 | |||
13 | ** Improved SEARCH BODY and SEARCH TEXT commands | ||
14 | |||
15 | Both commands now properly descend into multipart message parts and | ||
16 | decode messages, if necessary | ||
17 | |||
9 | * Fixes in the 'mail' utility | 18 | * Fixes in the 'mail' utility |
10 | 19 | ||
11 | ** New mailbox notation @ | 20 | ** New mailbox notation @ |
diff --git a/imap4d/imap4d.h b/imap4d/imap4d.h index 2ad339a30..b90d653a0 100644 --- a/imap4d/imap4d.h +++ b/imap4d/imap4d.h | |||
@@ -454,7 +454,6 @@ extern int util_parse_822_date (const char *date, time_t *timep, | |||
454 | enum datetime_parse_mode flag); | 454 | enum datetime_parse_mode flag); |
455 | extern int util_parse_ctime_date (const char *date, time_t *timep, | 455 | extern int util_parse_ctime_date (const char *date, time_t *timep, |
456 | enum datetime_parse_mode flag); | 456 | enum datetime_parse_mode flag); |
457 | extern char *util_strcasestr (const char *haystack, const char *needle); | ||
458 | extern char *util_localname (void); | 457 | extern char *util_localname (void); |
459 | 458 | ||
460 | void util_print_flags (mu_attribute_t attr); | 459 | void util_print_flags (mu_attribute_t attr); |
diff --git a/imap4d/search.c b/imap4d/search.c index 1d28b570f..3c243eddf 100644 --- a/imap4d/search.c +++ b/imap4d/search.c | |||
@@ -15,6 +15,7 @@ | |||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | 15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ |
16 | 16 | ||
17 | #include "imap4d.h" | 17 | #include "imap4d.h" |
18 | #include <mailutils/assoc.h> | ||
18 | 19 | ||
19 | /* | 20 | /* |
20 | * This will be a royal pain in the arse to implement | 21 | * This will be a royal pain in the arse to implement |
@@ -224,6 +225,7 @@ struct parsebuf | |||
224 | int isuid; /* UIDs instead of msgnos are required */ | 225 | int isuid; /* UIDs instead of msgnos are required */ |
225 | char *err_mesg; /* Error message if a parse error occured */ | 226 | char *err_mesg; /* Error message if a parse error occured */ |
226 | struct mem_chain *alloc; /* Chain of objects allocated during parsing */ | 227 | struct mem_chain *alloc; /* Chain of objects allocated during parsing */ |
228 | char *charset; /* Charset, other than US-ASCII requested */ | ||
227 | 229 | ||
228 | struct search_node *tree; /* Parse tree */ | 230 | struct search_node *tree; /* Parse tree */ |
229 | 231 | ||
@@ -241,6 +243,7 @@ static struct search_node *parse_search_key (struct parsebuf *pb); | |||
241 | static int parse_gettoken (struct parsebuf *pb, int req); | 243 | static int parse_gettoken (struct parsebuf *pb, int req); |
242 | static int search_run (struct parsebuf *pb); | 244 | static int search_run (struct parsebuf *pb); |
243 | static void do_search (struct parsebuf *pb); | 245 | static void do_search (struct parsebuf *pb); |
246 | static int available_charset (const char *charset); | ||
244 | 247 | ||
245 | /* | 248 | /* |
246 | 6.4.4. SEARCH Command | 249 | 6.4.4. SEARCH Command |
@@ -296,16 +299,21 @@ imap4d_search0 (imap4d_tokbuf_t tok, int isuid, char **err_text) | |||
296 | /* Currently only ASCII is supported */ | 299 | /* Currently only ASCII is supported */ |
297 | if (mu_c_strcasecmp (parsebuf.token, "US-ASCII")) | 300 | if (mu_c_strcasecmp (parsebuf.token, "US-ASCII")) |
298 | { | 301 | { |
299 | *err_text = "Charset not supported"; | 302 | parsebuf.charset = parse_strdup (&parsebuf, parsebuf.token); |
303 | if (!available_charset (parsebuf.charset)) | ||
304 | { | ||
305 | *err_text = "[BADCHARSET] Charset not supported"; | ||
300 | return RESP_NO; | 306 | return RESP_NO; |
301 | } | 307 | } |
308 | } | ||
309 | else | ||
310 | parsebuf.charset = NULL; | ||
302 | 311 | ||
303 | if (!parse_gettoken (&parsebuf, 0)) | 312 | if (!parse_gettoken (&parsebuf, 0)) |
304 | { | 313 | { |
305 | *err_text = "Too few args"; | 314 | *err_text = "Too few args"; |
306 | return RESP_BAD; | 315 | return RESP_BAD; |
307 | } | 316 | } |
308 | |||
309 | } | 317 | } |
310 | 318 | ||
311 | /* Compile the expression */ | 319 | /* Compile the expression */ |
@@ -796,15 +804,38 @@ search_run (struct parsebuf *pb) | |||
796 | static int | 804 | static int |
797 | _scan_header (struct parsebuf *pb, char *name, char *value) | 805 | _scan_header (struct parsebuf *pb, char *name, char *value) |
798 | { | 806 | { |
799 | const char *hval; | 807 | char *hval; |
800 | mu_header_t header = NULL; | 808 | mu_header_t header = NULL; |
809 | int i, rc; | ||
810 | int result = 0; | ||
801 | 811 | ||
802 | mu_message_get_header (pb->msg, &header); | 812 | mu_message_get_header (pb->msg, &header); |
803 | if (mu_header_sget_value (header, name, &hval) == 0) | 813 | |
814 | for (i = 1; | ||
815 | result == 0 | ||
816 | && (rc = mu_header_aget_value_unfold_n (header, name, i, &hval)) == 0; | ||
817 | i++) | ||
818 | { | ||
819 | if (pb->charset) | ||
820 | { | ||
821 | char *tmp; | ||
822 | rc = mu_rfc2047_decode (pb->charset, hval, &tmp); | ||
823 | if (rc) | ||
804 | { | 824 | { |
805 | return util_strcasestr (hval, value) != NULL; | 825 | mu_diag_funcall (MU_DIAG_ERR, "mu_rfc2047_decode", hval, rc); |
826 | free (hval); | ||
827 | continue; | ||
806 | } | 828 | } |
807 | return 0; | 829 | free (hval); |
830 | hval = tmp; | ||
831 | } | ||
832 | result = mu_c_strcasestr (hval, value) != NULL; | ||
833 | free (hval); | ||
834 | } | ||
835 | if (!(rc == 0 || rc == MU_ERR_NOENT)) | ||
836 | mu_diag_funcall (MU_DIAG_ERR, "mu_header_aget_value_unfold_n", NULL, rc); | ||
837 | |||
838 | return result; | ||
808 | } | 839 | } |
809 | 840 | ||
810 | /* Get the value of Date: field and convert it to timestamp */ | 841 | /* Get the value of Date: field and convert it to timestamp */ |
@@ -825,47 +856,192 @@ _header_date (struct parsebuf *pb, time_t *timep) | |||
825 | static int | 856 | static int |
826 | _scan_header_all (struct parsebuf *pb, char *text) | 857 | _scan_header_all (struct parsebuf *pb, char *text) |
827 | { | 858 | { |
828 | const char *hval; | ||
829 | mu_header_t header = NULL; | 859 | mu_header_t header = NULL; |
830 | size_t fcount = 0; | 860 | size_t fcount = 0; |
831 | int i, rc; | 861 | int i, rc; |
862 | int result; | ||
832 | 863 | ||
833 | mu_message_get_header (pb->msg, &header); | 864 | mu_message_get_header (pb->msg, &header); |
834 | mu_header_get_field_count (header, &fcount); | 865 | mu_header_get_field_count (header, &fcount); |
835 | for (i = rc = 0; i < fcount; i++) | 866 | result = 0; |
867 | for (i = 1; result == 0 && i < fcount; i++) | ||
836 | { | 868 | { |
837 | if (mu_header_sget_field_value (header, i, &hval) == 0) | 869 | char *hval; |
838 | rc = util_strcasestr (hval, text) != NULL; | 870 | |
871 | rc = mu_header_aget_field_value_unfold (header, i, &hval); | ||
872 | if (rc) | ||
873 | { | ||
874 | mu_diag_funcall (MU_DIAG_ERR, "mu_header_aget_field_value_unfold", | ||
875 | NULL, rc); | ||
876 | continue; | ||
839 | } | 877 | } |
840 | return rc; | 878 | |
879 | if (pb->charset) | ||
880 | { | ||
881 | char *tmp; | ||
882 | rc = mu_rfc2047_decode (pb->charset, hval, &tmp); | ||
883 | if (rc) | ||
884 | { | ||
885 | mu_diag_funcall (MU_DIAG_ERR, "mu_rfc2047_decode", hval, rc); | ||
886 | free (hval); | ||
887 | continue; | ||
888 | } | ||
889 | |||
890 | free (hval); | ||
891 | hval = tmp; | ||
892 | } | ||
893 | result = mu_c_strcasestr (hval, text) != NULL; | ||
894 | free (hval); | ||
895 | } | ||
896 | return result; | ||
841 | } | 897 | } |
842 | 898 | ||
843 | /* Scan body of the message for the occurrence of a substring */ | ||
844 | /* FIXME: The algorithm below is broken */ | ||
845 | static int | 899 | static int |
846 | _scan_body (struct parsebuf *pb, char *text) | 900 | _match_text (struct parsebuf *pb, mu_message_t msg, mu_content_type_t ct, |
901 | char const *encoding, | ||
902 | char *text) | ||
847 | { | 903 | { |
848 | mu_body_t body = NULL; | 904 | mu_body_t body; |
849 | mu_stream_t stream = NULL; | 905 | mu_stream_t str; |
850 | size_t size = 0, lines = 0; | ||
851 | char buffer[128]; | ||
852 | size_t n = 0; | ||
853 | int rc; | 906 | int rc; |
907 | int result; | ||
908 | char *buffer = NULL; | ||
909 | size_t bufsize = 0; | ||
910 | size_t n; | ||
911 | |||
912 | mu_message_get_body (msg, &body); | ||
913 | mu_body_get_streamref (body, &str); | ||
914 | |||
915 | if (encoding) | ||
916 | { | ||
917 | mu_stream_t flt; | ||