summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-01-25 22:30:28 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-01-25 23:05:52 (GMT)
commit3798a0f09da7fcaa6daa12e9ae483ebf99f7c46a (patch) (unidiff)
tree97c80866168b24c3c45f2d1961311d80b6ff1823
parentbc4d023a3810a7da6ede2cc522cdc34fa3129378 (diff)
downloadmailutils-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.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--NEWS11
-rw-r--r--imap4d/imap4d.h1
-rw-r--r--imap4d/search.c458
-rw-r--r--imap4d/util.c8
-rw-r--r--libmailutils/mailbox/header.c4
5 files changed, 341 insertions, 141 deletions
diff --git a/NEWS b/NEWS
index 84d3601..4f5c0de 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
1GNU mailutils NEWS -- history of user-visible changes. 2019-01-23 1GNU mailutils NEWS -- history of user-visible changes. 2019-01-26
2Copyright (C) 2002-2019 Free Software Foundation, Inc. 2Copyright (C) 2002-2019 Free Software Foundation, Inc.
3See the end of file for copying conditions. 3See 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
7Version 3.5.90 (git) 7Version 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
15Both commands now properly descend into multipart message parts and
16decode 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 2ad339a..b90d653 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);
455extern int util_parse_ctime_date (const char *date, time_t *timep, 455extern int util_parse_ctime_date (const char *date, time_t *timep,
456 enum datetime_parse_mode flag); 456 enum datetime_parse_mode flag);
457extern char *util_strcasestr (const char *haystack, const char *needle);
458extern char *util_localname (void); 457extern char *util_localname (void);
459 458
460void util_print_flags (mu_attribute_t attr); 459void util_print_flags (mu_attribute_t attr);
diff --git a/imap4d/search.c b/imap4d/search.c
index 1d28b57..3c243ed 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
@@ -90,43 +91,43 @@ struct search_node
90}; 91};
91 92
92static void cond_msgset (struct parsebuf *, struct search_node *, 93static void cond_msgset (struct parsebuf *, struct search_node *,
93 struct value *, struct value *); 94 struct value *, struct value *);
94static void cond_bcc (struct parsebuf *, struct search_node *, 95static void cond_bcc (struct parsebuf *, struct search_node *,
95 struct value *, struct value *); 96 struct value *, struct value *);
96static void cond_before (struct parsebuf *, struct search_node *, 97static void cond_before (struct parsebuf *, struct search_node *,
97 struct value *, struct value *); 98 struct value *, struct value *);
98static void cond_body (struct parsebuf *, struct search_node *, 99static void cond_body (struct parsebuf *, struct search_node *,
99 struct value *, struct value *); 100 struct value *, struct value *);
100static void cond_cc (struct parsebuf *, struct search_node *, 101static void cond_cc (struct parsebuf *, struct search_node *,
101 struct value *, struct value *); 102 struct value *, struct value *);
102static void cond_from (struct parsebuf *, struct search_node *, 103static void cond_from (struct parsebuf *, struct search_node *,
103 struct value *, struct value *); 104 struct value *, struct value *);
104static void cond_header (struct parsebuf *, struct search_node *, 105static void cond_header (struct parsebuf *, struct search_node *,
105 struct value *, struct value *); 106 struct value *, struct value *);
106static void cond_keyword (struct parsebuf *, struct search_node *, 107static void cond_keyword (struct parsebuf *, struct search_node *,
107 struct value *, struct value *); 108 struct value *, struct value *);
108static void cond_larger (struct parsebuf *, struct search_node *, 109static void cond_larger (struct parsebuf *, struct search_node *,
109 struct value *, struct value *); 110 struct value *, struct value *);
110static void cond_on (struct parsebuf *, struct search_node *, 111static void cond_on (struct parsebuf *, struct search_node *,
111 struct value *, struct value *); 112 struct value *, struct value *);
112static void cond_sentbefore (struct parsebuf *, struct search_node *, 113static void cond_sentbefore (struct parsebuf *, struct search_node *,
113 struct value *, struct value *); 114 struct value *, struct value *);
114static void cond_senton (struct parsebuf *, struct search_node *, 115static void cond_senton (struct parsebuf *, struct search_node *,
115 struct value *, struct value *); 116 struct value *, struct value *);
116static void cond_sentsince (struct parsebuf *, struct search_node *, 117static void cond_sentsince (struct parsebuf *, struct search_node *,
117 struct value *, struct value *); 118 struct value *, struct value *);
118static void cond_since (struct parsebuf *, struct search_node *, 119static void cond_since (struct parsebuf *, struct search_node *,
119 struct value *, struct value *); 120 struct value *, struct value *);
120static void cond_smaller (struct parsebuf *, struct search_node *, 121static void cond_smaller (struct parsebuf *, struct search_node *,
121 struct value *, struct value *); 122 struct value *, struct value *);
122static void cond_subject (struct parsebuf *, struct search_node *, 123static void cond_subject (struct parsebuf *, struct search_node *,
123 struct value *, struct value *); 124 struct value *, struct value *);
124static void cond_text (struct parsebuf *, struct search_node *, 125static void cond_text (struct parsebuf *, struct search_node *,
125 struct value *, struct value *); 126 struct value *, struct value *);
126static void cond_to (struct parsebuf *, struct search_node *, 127static void cond_to (struct parsebuf *, struct search_node *,
127 struct value *, struct value *); 128 struct value *, struct value *);
128static void cond_uid (struct parsebuf *, struct search_node *, 129static void cond_uid (struct parsebuf *, struct search_node *,
129 struct value *, struct value *); 130 struct value *, struct value *);
130 131
131/* A basic condition structure */ 132/* A basic condition structure */
132struct cond 133struct cond
@@ -138,7 +139,7 @@ struct cond
138}; 139};
139 140
140/* Types are: s -- string 141/* Types are: s -- string
141 n -- number 142 n -- number
142 d -- date 143 d -- date
143 m -- message set 144 m -- message set
144*/ 145*/
@@ -213,23 +214,24 @@ struct mem_chain
213 214
214/* Maximum length of a token. Tokens longer than that are accepted, provided 215/* Maximum length of a token. Tokens longer than that are accepted, provided
215 that they are enclosed in doublequotes */ 216 that they are enclosed in doublequotes */
216#define MAXTOKEN 64 217#define MAXTOKEN 64
217 218
218/* Parse buffer structure */ 219/* Parse buffer structure */
219struct parsebuf 220struct parsebuf
220{ 221{
221 imap4d_tokbuf_t tok; /* Token buffer */ 222 imap4d_tokbuf_t tok; /* Token buffer */
222 int arg; /* Argument number */ 223 int arg; /* Argument number */
223 char *token; /* Current token */ 224 char *token; /* Current token */
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 */
227 228 char *charset; /* Charset, other than US-ASCII requested */
229
228 struct search_node *tree; /* Parse tree */ 230 struct search_node *tree; /* Parse tree */
229 231
230 /* Execution time only: */ 232 /* Execution time only: */
231 size_t msgno; /* Number of current message */ 233 size_t msgno; /* Number of current message */
232 mu_message_t msg; /* Current message */ 234 mu_message_t msg; /* Current message */
233}; 235};
234 236
235static void parse_free_mem (struct parsebuf *pb); 237static void parse_free_mem (struct parsebuf *pb);
@@ -241,37 +243,38 @@ static struct search_node *parse_search_key (struct parsebuf *pb);
241static int parse_gettoken (struct parsebuf *pb, int req); 243static int parse_gettoken (struct parsebuf *pb, int req);
242static int search_run (struct parsebuf *pb); 244static int search_run (struct parsebuf *pb);
243static void do_search (struct parsebuf *pb); 245static void do_search (struct parsebuf *pb);
246static int available_charset (const char *charset);
244 247
245/* 248/*
2466.4.4. SEARCH Command 2496.4.4. SEARCH Command
247 250
248 Arguments: OPTIONAL [CHARSET] specification 251 Arguments: OPTIONAL [CHARSET] specification
249 searching criteria (one or more) 252 searching criteria (one or more)
250 253
251 Responses: REQUIRED untagged response: SEARCH 254 Responses: REQUIRED untagged response: SEARCH
252 255
253 Result: OK - search completed 256 Result: OK - search completed
254 NO - search error: can't search that [CHARSET] or 257 NO - search error: can't search that [CHARSET] or
255 criteria 258 criteria
256 BAD - command unknown or arguments invalid 259 BAD - command unknown or arguments invalid
257*/ 260*/
258 261
259int 262int
260imap4d_search (struct imap4d_session *session, 263imap4d_search (struct imap4d_session *session,
261 struct imap4d_command *command, imap4d_tokbuf_t tok) 264 struct imap4d_command *command, imap4d_tokbuf_t tok)
262{ 265{
263 int rc; 266 int rc;
264 char *err_text= ""; 267 char *err_text= "";
265 268
266 rc = imap4d_search0 (tok, 0, &err_text); 269 rc = imap4d_search0 (tok, 0, &err_text);
267 return io_completion_response (command, rc, "%s", err_text); 270 return io_completion_response (command, rc, "%s", err_text);
268} 271}
269 272
270int 273int
271imap4d_search0 (imap4d_tokbuf_t tok, int isuid, char **err_text) 274imap4d_search0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
272{ 275{
273 struct parsebuf parsebuf; 276 struct parsebuf parsebuf;
274 277
275 memset (&parsebuf, 0, sizeof(parsebuf)); 278 memset (&parsebuf, 0, sizeof(parsebuf));
276 parsebuf.tok = tok; 279 parsebuf.tok = tok;
277 parsebuf.arg = IMAP4_ARG_1 + !!isuid; 280 parsebuf.arg = IMAP4_ARG_1 + !!isuid;
@@ -284,7 +287,7 @@ imap4d_search0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
284 *err_text = "Too few args"; 287 *err_text = "Too few args";
285 return RESP_BAD; 288 return RESP_BAD;
286 } 289 }
287 290
288 if (mu_c_strcasecmp (parsebuf.token, "CHARSET") == 0) 291 if (mu_c_strcasecmp (parsebuf.token, "CHARSET") == 0)
289 { 292 {
290 if (!parse_gettoken (&parsebuf, 0)) 293 if (!parse_gettoken (&parsebuf, 0))
@@ -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);
300 return RESP_NO; 303 if (!available_charset (parsebuf.charset))
304 {
305 *err_text = "[BADCHARSET] Charset not supported";
306 return RESP_NO;
307 }
301 } 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 */
@@ -323,12 +331,12 @@ imap4d_search0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
323 *err_text = "Junk at the end of statement"; 331 *err_text = "Junk at the end of statement";
324 return RESP_BAD; 332 return RESP_BAD;
325 } 333 }
326 334
327 /* Execute compiled expression */ 335 /* Execute compiled expression */
328 do_search (&parsebuf); 336 do_search (&parsebuf);
329 337
330 parse_free_mem (&parsebuf); 338 parse_free_mem (&parsebuf);
331 339
332 *err_text = "Completed"; 340 *err_text = "Completed";
333 return RESP_OK; 341 return RESP_OK;
334} 342}
@@ -339,7 +347,7 @@ void
339do_search (struct parsebuf *pb) 347do_search (struct parsebuf *pb)
340{ 348{
341 size_t count = 0; 349 size_t count = 0;
342 350
343 mu_mailbox_messages_count (mbox, &count); 351 mu_mailbox_messages_count (mbox, &count);
344 352
345 io_sendf ("* SEARCH"); 353 io_sendf ("* SEARCH");
@@ -417,7 +425,7 @@ parse_alloc (struct parsebuf *pb, size_t size)
417 return parse_regmem (pb, p, NULL); 425 return parse_regmem (pb, p, NULL);
418} 426}
419 427
420/* Create a copy of the string. */ 428/* Create a copy of the string. */
421char * 429char *
422parse_strdup (struct parsebuf *pb, char *s) 430parse_strdup (struct parsebuf *pb, char *s)
423{ 431{
@@ -445,11 +453,11 @@ parse_msgset_create (struct parsebuf *pb, mu_mailbox_t mbox, int flags)
445 453
446/* A recursive-descent parser for the following grammar: 454/* A recursive-descent parser for the following grammar:
447 search_key_list : search_key 455 search_key_list : search_key
448 | search_key_list search_key 456 | search_key_list search_key
449 ; 457 ;
450 458
451 search_key : simple_key 459 search_key : simple_key
452 | NOT simple_key 460 | NOT simple_key
453 | OR simple_key simple_key 461 | OR simple_key simple_key
454 | '(' search_key_list ')' 462 | '(' search_key_list ')'
455 ; 463 ;
@@ -486,16 +494,16 @@ struct search_node *
486parse_search_key (struct parsebuf *pb) 494parse_search_key (struct parsebuf *pb)
487{ 495{
488 struct search_node *node; 496 struct search_node *node;
489 497
490 if (strcmp (pb->token, "(") == 0) 498 if (strcmp (pb->token, "(") == 0)
491 { 499 {
492 if (parse_gettoken (pb, 1) == 0) 500 if (parse_gettoken (pb, 1) == 0)
493 return NULL; 501 return NULL;
494 502
495 node = parse_search_key_list (pb); 503 node = parse_search_key_list (pb);
496 if (!node) 504 if (!node)
497 return NULL; 505 return NULL;
498 506
499 if (strcmp (pb->token, ")")) 507 if (strcmp (pb->token, ")"))
500 { 508 {
501 pb->err_mesg = "Unbalanced parenthesis"; 509 pb->err_mesg = "Unbalanced parenthesis";
@@ -581,7 +589,7 @@ parse_equiv_key (struct parsebuf *pb)
581 /* shouldn't happen? */ 589 /* shouldn't happen? */
582 mu_diag_output (MU_DIAG_CRIT, _("%s:%d: INTERNAL ERROR (please report)"), 590 mu_diag_output (MU_DIAG_CRIT, _("%s:%d: INTERNAL ERROR (please report)"),
583 __FILE__, __LINE__); 591 __FILE__, __LINE__);
584 abort (); 592 abort ();
585 } 593 }
586 imap4d_tokbuf_destroy (&pb->tok); 594 imap4d_tokbuf_destroy (&pb->tok);
587 595
@@ -601,29 +609,29 @@ parse_simple_key (struct parsebuf *pb)
601 for (condp = condlist; condp->name && mu_c_strcasecmp (condp->name, pb->token); 609 for (condp = condlist; condp->name && mu_c_strcasecmp (condp->name, pb->token);
602 condp++) 610 condp++)
603 ; 611 ;
604 612
605 if (!condp->name) 613 if (!condp->name)
606 { 614 {
607 mu_msgset_t msgset = parse_msgset_create (pb, mbox, MU_MSGSET_NUM); 615 mu_msgset_t msgset = parse_msgset_create (pb, mbox, MU_MSGSET_NUM);
608 616
609 if (mu_msgset_parse_imap (msgset, 617 if (mu_msgset_parse_imap (msgset,
610 pb->isuid ? MU_MSGSET_UID : MU_MSGSET_NUM, 618 pb->isuid ? MU_MSGSET_UID : MU_MSGSET_NUM,
611 pb->token, NULL) == 0) 619 pb->token, NULL) == 0)
612 { 620 {
613 struct search_node *np = parse_alloc (pb, sizeof *np); 621 struct search_node *np = parse_alloc (pb, sizeof *np);
614 np->type = node_value; 622 np->type = node_value;
615 np->v.value.type = value_msgset; 623 np->v.value.type = value_msgset;
616 np->v.value.v.msgset = msgset; 624 np->v.value.v.msgset = msgset;
617 625
618 node = parse_alloc (pb, sizeof *node); 626 node = parse_alloc (pb, sizeof *node);
619 node->type = node_call; 627 node->type = node_call;
620 node->v.key.keyword = "msgset"; 628 node->v.key.keyword = "msgset";
621 node->v.key.narg = 1; 629 node->v.key.narg = 1;
622 node->v.key.arg[0] = np; 630 node->v.key.arg[0] = np;
623 node->v.key.fun = cond_msgset; 631 node->v.key.fun = cond_msgset;
624 632
625 parse_gettoken (pb, 0); 633 parse_gettoken (pb, 0);
626 634
627 return node; 635 return node;
628 } 636 }
629 else 637 else
@@ -632,13 +640,13 @@ parse_simple_key (struct parsebuf *pb)
632 return NULL; 640 return NULL;
633 } 641 }
634 } 642 }
635 643
636 node = parse_alloc (pb, sizeof *node); 644 node = parse_alloc (pb, sizeof *node);
637 node->type = node_call; 645 node->type = node_call;
638 node->v.key.keyword = condp->name; 646 node->v.key.keyword = condp->name;
639 node->v.key.fun = condp->inst; 647 node->v.key.fun = condp->inst;
640 node->v.key.narg = 0; 648 node->v.key.narg = 0;
641 649
642 parse_gettoken (pb, 0); 650 parse_gettoken (pb, 0);
643 if (condp->argtypes) 651 if (condp->argtypes)
644 { 652 {
@@ -646,7 +654,7 @@ parse_simple_key (struct parsebuf *pb)
646 char *s; 654 char *s;
647 mu_off_t number; 655 mu_off_t number;
648 struct search_node *arg; 656 struct search_node *arg;
649 657
650 for (; *t; t++, parse_gettoken (pb, 0)) 658 for (; *t; t++, parse_gettoken (pb, 0))
651 { 659 {
652 if (node->v.key.narg >= MAX_NODE_ARGS) 660 if (node->v.key.narg >= MAX_NODE_ARGS)
@@ -654,13 +662,13 @@ parse_simple_key (struct parsebuf *pb)
654 pb->err_mesg = "INTERNAL ERROR: too many arguments"; 662 pb->err_mesg = "INTERNAL ERROR: too many arguments";
655 return NULL; 663 return NULL;
656 } 664 }
657 665
658 if (!pb->token) 666 if (!pb->token)
659 { 667 {
660 pb->err_mesg = "Not enough arguments for criterion"; 668 pb->err_mesg = "Not enough arguments for criterion";
661 return NULL; 669 return NULL;
662 } 670 }
663 671
664 arg = parse_alloc (pb, sizeof *arg); 672 arg = parse_alloc (pb, sizeof *arg);
665 arg->type = node_value; 673 arg->type = node_value;
666 switch (*t) 674 switch (*t)
@@ -669,7 +677,7 @@ parse_simple_key (struct parsebuf *pb)
669 arg->v.value.type = value_string; 677 arg->v.value.type = value_string;
670 arg->v.value.v.string = parse_strdup (pb, pb->token); 678 arg->v.value.v.string = parse_strdup (pb, pb->token);
671 break; 679 break;
672 680
673 case 'n': /* number */ 681 case 'n': /* number */
674 number = strtoul (pb->token, &s, 10); 682 number = strtoul (pb->token, &s, 10);
675 if (*s) 683 if (*s)
@@ -680,7 +688,7 @@ parse_simple_key (struct parsebuf *pb)
680 arg->v.value.type = value_number; 688 arg->v.value.type = value_number;
681 arg->v.value.v.number = number; 689 arg->v.value.v.number = number;
682 break; 690 break;
683 691
684 case 'd': /* date */ 692 case 'd': /* date */
685 if (util_parse_internal_date (pb->token, &time, 693 if (util_parse_internal_date (pb->token, &time,
686 datetime_date_only)) 694 datetime_date_only))
@@ -691,19 +699,19 @@ parse_simple_key (struct parsebuf *pb)
691 arg->v.value.type = value_date; 699 arg->v.value.type = value_date;
692 arg->v.value.v.date = time; 700 arg->v.value.v.date = time;
693 break; 701 break;
694 702
695 case 'u': /* UID message set */ 703 case 'u': /* UID message set */
696 arg->v.value.v.msgset = parse_msgset_create (pb, NULL, 704 arg->v.value.v.msgset = parse_msgset_create (pb, NULL,
697 MU_MSGSET_NUM); 705 MU_MSGSET_NUM);
698 arg->v.value.type = value_msgset; 706 arg->v.value.type = value_msgset;
699 if (mu_msgset_parse_imap (arg->v.value.v.msgset, MU_MSGSET_UID, 707 if (mu_msgset_parse_imap (arg->v.value.v.msgset, MU_MSGSET_UID,
700 pb->token, NULL)) 708 pb->token, NULL))
701 { 709 {
702 pb->err_mesg = "Bogus number set"; 710 pb->err_mesg = "Bogus number set";
703 return NULL; 711 return NULL;
704 } 712 }
705 break; 713 break;
706 714
707 default: 715 default:
708 mu_diag_output (MU_DIAG_CRIT, 716 mu_diag_output (MU_DIAG_CRIT,
709 _("%s:%d: INTERNAL ERROR (please report)"), 717 _("%s:%d: INTERNAL ERROR (please report)"),
@@ -711,7 +719,7 @@ parse_simple_key (struct parsebuf *pb)
711 abort (); /* should never happen */ 719 abort (); /* should never happen */
712 } 720 }
713 node->v.key.arg[node->v.key.narg++] = arg; 721 node->v.key.arg[node->v.key.narg++] = arg;
714 } 722 }
715 } 723 }
716 return node; 724 return node;
717} 725}
@@ -723,7 +731,7 @@ evaluate_node (struct search_node *node, struct parsebuf *pb,
723{ 731{
724 int i; 732 int i;
725 struct value argval[MAX_NODE_ARGS]; 733 struct value argval[MAX_NODE_ARGS];
726 734
727 switch (node->type) 735 switch (node->type)
728 { 736 {
729 case node_call: 737 case node_call:
@@ -733,7 +741,7 @@ evaluate_node (struct search_node *node, struct parsebuf *pb,
733 evaluate_node (node->v.key.arg[i], pb, &argval[i]); 741 evaluate_node (node->v.key.arg[i], pb, &argval[i]);
734 /* FIXME: node types? */ 742 /* FIXME: node types? */
735 } 743 }
736 744
737 node->v.key.fun (pb, node, argval, val); 745 node->v.key.fun (pb, node, argval, val);
738 break; 746 break;
739 747
@@ -748,7 +756,7 @@ evaluate_node (struct search_node *node, struct parsebuf *pb,
748 val->v.number = argval[1].v.number; 756 val->v.number = argval[1].v.number;
749 } 757 }
750 break; 758 break;
751 759
752 case node_or: 760 case node_or:
753 val->type = value_number; 761 val->type = value_number;
754 evaluate_node (node->v.arg[0], pb, &argval[0]); 762 evaluate_node (node->v.arg[0], pb, &argval[0]);
@@ -766,7 +774,7 @@ evaluate_node (struct search_node *node, struct parsebuf *pb,
766 val->type = value_number; 774 val->type = value_number;
767 val->v.number = !argval[0].v.number; 775 val->v.number = !argval[0].v.number;
768 break; 776 break;
769 777
770 case node_value: 778 case node_value:
771 *val = node->v.value; 779 *val = node->v.value;
772 break; 780 break;
@@ -796,15 +804,38 @@ search_run (struct parsebuf *pb)
796static int 804static 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;
801 809 int i, rc;
810 int result = 0;
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++)
804 { 818 {
805 return util_strcasestr (hval, value) != NULL; 819 if (pb->charset)
820 {
821 char *tmp;
822 rc = mu_rfc2047_decode (pb->charset, hval, &tmp);
823 if (rc)
824 {
825 mu_diag_funcall (MU_DIAG_ERR, "mu_rfc2047_decode", hval, rc);
826 free (hval);
827 continue;
828 }
829 free (hval);
830 hval = tmp;
831 }
832 result = mu_c_strcasestr (hval, value) != NULL;
833 free (hval);
806 } 834 }
807 return 0; 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 */
@@ -813,7 +844,7 @@ _header_date (struct parsebuf *pb, time_t *timep)
813{ 844{
814 const char *hval; 845 const char *hval;
815 mu_header_t header = NULL; 846 mu_header_t header = NULL;
816 847
817 mu_message_get_header (pb->msg, &header); 848 mu_message_get_header (pb->msg, &header);
818 if (mu_header_sget_value (header, "Date", &hval) == 0 849 if (mu_header_sget_value (header, "Date", &hval) == 0
819 && util_parse_822_date (hval, timep, datetime_date_only)) 850 && util_parse_822_date (hval, timep, datetime_date_only))
@@ -825,49 +856,194 @@ _header_date (struct parsebuf *pb, time_t *timep)
825static int 856static 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;
877 }
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);
839 } 895 }
840 return rc; 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 */
845static int 899static 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;
854 907 int result;
855 mu_message_get_body (pb->msg, &body); 908 char *buffer = NULL;
856 mu_body_size (body, &size); 909 size_t bufsize = 0;
857 mu_body_lines (body, &lines); 910 size_t n;
858 mu_body_get_streamref (body, &stream); 911
859 rc = 0; 912 mu_message_get_body (msg, &body);
860 while (rc == 0 913 mu_body_get_streamref (body, &str);
861 && mu_stream_read (stream, buffer, sizeof(buffer)-1, &n) == 0 914
915 if (encoding)
916 {
917 mu_stream_t flt;
918 rc = mu_filter_create (&flt, str, encoding,
919 MU_FILTER_DECODE,
920 MU_STREAM_READ);
921 mu_stream_unref (str);
922 if (rc)
923 {
924 mu_error (_("can't handle encoding %s: %s"),
925 encoding, mu_strerror (rc));
926 return 0;
927 }
928 str = flt;
929 }
930
931 if (pb->charset)
932 {
933 struct mu_mime_param *param;
934 if (mu_assoc_lookup (ct->param, "charset", &param) == 0
935 && mu_c_strcasecmp (param->value, pb->charset))
936 {
937 char const *argv[] = { "iconv", NULL, NULL, NULL };
938 mu_stream_t flt;
939
940 argv[1] = param->value;
941 argv[2] = pb->charset;
942 rc = mu_filter_chain_create (&flt, str,
943 MU_FILTER_ENCODE,
944 MU_STREAM_READ,
945 MU_ARRAY_SIZE (argv) - 1,
946 (char**) argv);
947 mu_stream_unref (str);
948 if (rc)
949 {
950 mu_error (_("can't convert from charset %s to %s"),
951 param->value, pb->charset);
952 return 0;
953 }
954 str = flt;
955 }
956 }
957
958 result = 0;
959 while ((rc = mu_stream_getline (str, &buffer, &bufsize, &n)) == 0
862 && n > 0) 960 && n > 0)
863 { 961 {
864 buffer[n] = 0; 962 result = mu_c_strcasestr (buffer, text) != NULL;
865 rc = util_strcasestr (buffer, text) != NULL; 963 if (result)
964 break;
866 } 965 }
867 mu_stream_destroy (&stream); 966 mu_stream_destroy (&str);
868 return rc; 967 if (rc)
968 mu_diag_funcall (MU_DIAG_ERR, "mu_stream_getline", NULL, rc);
969 return result;
869} 970}
870 971
972static int
973_match_multipart (struct parsebuf *pb, mu_message_t msg, char *text)
974{
975 mu_header_t hdr;
976 char *encoding;
977 int ismp;
978 int result;
979 mu_content_type_t ct;
980 char *buf;
981 int rc;
982
983 if (mu_message_is_multipart (msg, &ismp))
984 return 0;
985 if (mu_message_get_header (msg, &hdr))
986 return 0;
987
988 if (mu_header_aget_value_unfold (hdr, MU_HEADER_CONTENT_TYPE, &buf))
989 {
990 buf = strdup ("text/plain");
991 if (!buf)
992 return 0;
993 }
994 rc = mu_content_type_parse (buf, NULL, &ct);
995 free (buf);
996 if (rc)
997 return 0;
998
999 if (mu_header_aget_value_unfold (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING,
1000 &encoding))
1001 encoding = NULL;
1002
1003 if (ismp)
1004 {
1005 size_t i, nparts;
1006
1007 mu_message_get_num_parts (msg, &nparts);
1008
1009 for (i = 1; i <= nparts; i++)
1010 {
1011 mu_message_t submsg = NULL;
1012
1013 if (mu_message_get_part (msg, i, &submsg) == 0)
1014 {
1015 result = _match_multipart (pb, submsg, text);
1016 if (result)
1017 break;
1018 }
1019 }
1020 }
1021 else if (mu_c_strcasecmp (ct->type, "message") == 0
1022 && mu_c_strcasecmp (ct->subtype, "rfc822") == 0)
1023 {
1024 mu_message_t submsg = NULL;
1025
1026 if (mu_message_unencapsulate (msg, &submsg, NULL) == 0)
1027 {
1028 result = _match_multipart (pb, submsg, text);
1029 }
1030 }
1031 else if (mu_c_strcasecmp (ct->type, "text") == 0)
1032 result = _match_text (pb, msg, ct, encoding, text);
1033
1034 free (encoding);
1035 mu_content_type_destroy (&ct);
1036
1037 return result;
1038}
1039
1040/* Scan body of the message for the occurrence of a substring */
1041static int
1042_scan_body (struct parsebuf *pb, char *text)
1043{
1044 return _match_multipart (pb, pb->msg, text);
1045}
1046
871/* Basic instructions */ 1047/* Basic instructions */
872 1048
873static void 1049static void
@@ -885,7 +1061,7 @@ cond_bcc (struct parsebuf *pb, struct search_node *node, struct value *arg,
885{ 1061{
886 retval->type = value_number; 1062 retval->type = value_number;
887 retval->v.number = _scan_header (pb, MU_HEADER_BCC, arg[0].v.string); 1063 retval->v.number = _scan_header (pb, MU_HEADER_BCC, arg[0].v.string);
888} 1064}
889 1065
890static void 1066static void
891cond_before (struct parsebuf *pb, struct search_node *node, struct value *arg, 1067cond_before (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -895,7 +1071,7 @@ cond_before (struct parsebuf *pb, struct search_node *node, struct value *arg,
895 time_t mesg_time; 1071 time_t mesg_time;
896 const char *date; 1072 const char *date;
897 mu_envelope_t env; 1073 mu_envelope_t env;
898 1074
899 mu_message_get_envelope (pb->msg, &env); 1075 mu_message_get_envelope (pb->msg, &env);
900 retval->type = value_number; 1076 retval->type = value_number;
901 if (mu_envelope_sget_date (env, &date)) 1077 if (mu_envelope_sget_date (env, &date))
@@ -905,7 +1081,7 @@ cond_before (struct parsebuf *pb, struct search_node *node, struct value *arg,
905 util_parse_ctime_date (date, &mesg_time, datetime_date_only); 1081 util_parse_ctime_date (date, &mesg_time, datetime_date_only);
906 retval->v.number = mesg_time < t; 1082 retval->v.number = mesg_time < t;
907 } 1083 }
908} 1084}
909 1085
910static void 1086static void
911cond_body (struct parsebuf *pb, struct search_node *node, struct value *arg, 1087cond_body (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -913,7 +1089,7 @@ cond_body (struct parsebuf *pb, struct search_node *node, struct value *arg,
913{ 1089{
914 retval->type = value_number; 1090 retval->type = value_number;
915 retval->v.number = _scan_body (pb, arg[0].v.string); 1091 retval->v.number = _scan_body (pb, arg[0].v.string);
916} 1092}
917 1093
918static void 1094static void
919cond_cc (struct parsebuf *pb, struct search_node *node, struct value *arg, 1095cond_cc (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -921,7 +1097,7 @@ cond_cc (struct parsebuf *pb, struct search_node *node, struct value *arg,
921{ 1097{
922 retval->type = value_number; 1098 retval->type = value_number;
923 retval->v.number = _scan_header (pb, MU_HEADER_CC, arg[0].v.string); 1099 retval->v.number = _scan_header (pb, MU_HEADER_CC, arg[0].v.string);
924} 1100}
925 1101
926static void 1102static void
927cond_from (struct parsebuf *pb, struct search_node *node, struct value *arg, 1103cond_from (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -931,14 +1107,14 @@ cond_from (struct parsebuf *pb, struct search_node *node, struct value *arg,
931 mu_envelope_t env; 1107 mu_envelope_t env;
932 const char *from; 1108 const char *from;
933 int rc = 0; 1109 int rc = 0;
934 1110
935 mu_message_get_envelope (pb->msg, &env); 1111 mu_message_get_envelope (pb->msg, &env);
936 if (mu_envelope_sget_sender (env, &from) == 0) 1112 if (mu_envelope_sget_sender (env, &from) == 0)
937 rc = util_strcasestr (from, s) != NULL; 1113 rc = mu_c_strcasestr (from, s) != NULL;
938 1114
939 retval->type = value_number; 1115 retval->type = value_number;
940 retval->v.number = rc || _scan_header (pb, MU_HEADER_FROM, s); 1116 retval->v.number = rc || _scan_header (pb, MU_HEADER_FROM, s);
941} 1117}
942 1118
943static void 1119static void
944cond_header (struct parsebuf *pb, struct search_node *node, struct value *arg, 1120cond_header (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -949,7 +1125,7 @@ cond_header (struct parsebuf *pb, struct search_node *node, struct value *arg,
949 1125
950 retval->type = value_number; 1126 retval->type = value_number;
951 retval->v.number = _scan_header (pb, name, value); 1127 retval->v.number = _scan_header (pb, name, value);
952} 1128}
953 1129
954static void 1130static void
955cond_keyword (struct parsebuf *pb, struct search_node *node, struct value *arg, 1131cond_keyword (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -957,22 +1133,22 @@ cond_keyword (struct parsebuf *pb, struct search_node *node, struct value *arg,
957{ 1133{
958 char *s = arg[0].v.string; 1134 char *s = arg[0].v.string;
959 mu_attribute_t attr = NULL; 1135 mu_attribute_t attr = NULL;
960 1136
961 mu_message_get_attribute (pb->msg, &attr); 1137 mu_message_get_attribute (pb->msg, &attr);
962 retval->type = value_number; 1138 retval->type = value_number;
963 retval->v.number = util_attribute_matches_flag (attr, s); 1139 retval->v.number = util_attribute_matches_flag (attr, s);
964} 1140}
965 1141
966static void 1142static void
967cond_larger (struct parsebuf *pb, struct search_node *node, struct value *arg, 1143cond_larger (struct parsebuf *pb, struct search_node *node, struct value *arg,
968 struct value *retval) 1144 struct value *retval)
969{ 1145{
970 size_t size = 0; 1146 size_t size = 0;
971 1147
972 mu_message_size (pb->msg, &size); 1148 mu_message_size (pb->msg, &size);
973 retval->type = value_number; 1149 retval->type = value_number;
974 retval->v.number = size > arg[0].v.number; 1150 retval->v.number = size > arg[0].v.number;
975} 1151}
976 1152
977static void 1153static void
978cond_on (struct parsebuf *pb, struct search_node *node, struct value *arg, 1154cond_on (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -982,7 +1158,7 @@ cond_on (struct parsebuf *pb, struct search_node *node, struct value *arg,
982 time_t mesg_time; 1158 time_t mesg_time;
983 const char *date; 1159 const char *date;
984 mu_envelope_t env; 1160 mu_envelope_t env;
985 1161
986 mu_message_get_envelope (pb->msg, &env); 1162 mu_message_get_envelope (pb->msg, &env);
987 retval->type = value_number; 1163 retval->type = value_number;
988 if (mu_envelope_sget_date (env, &date)) 1164 if (mu_envelope_sget_date (env, &date))
@@ -992,7 +1168,7 @@ cond_on (struct parsebuf *pb, struct search_node *node, struct value *arg,
992 util_parse_ctime_date (date, &mesg_time, datetime_date_only); 1168 util_parse_ctime_date (date, &mesg_time, datetime_date_only);
993 retval->v.number = t <= mesg_time && mesg_time <= t + 86400; 1169 retval->v.number = t <= mesg_time && mesg_time <= t + 86400;
994 } 1170 }
995} 1171}
996 1172
997static void 1173static void
998cond_sentbefore (struct parsebuf *pb, struct search_node *node, 1174cond_sentbefore (struct parsebuf *pb, struct search_node *node,
@@ -1005,7 +1181,7 @@ cond_sentbefore (struct parsebuf *pb, struct search_node *node,
1005 _header_date (pb, &mesg_time); 1181 _header_date (pb, &mesg_time);
1006 retval->type = value_number; 1182 retval->type = value_number;
1007 retval->v.number = mesg_time < t; 1183 retval->v.number = mesg_time < t;
1008} 1184}
1009 1185
1010static void 1186static void
1011cond_senton (struct parsebuf *pb, struct search_node *node, struct value *arg, 1187cond_senton (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -1017,7 +1193,7 @@ cond_senton (struct parsebuf *pb, struct search_node *node, struct value *arg,
1017 _header_date (pb, &mesg_time); 1193 _header_date (pb, &mesg_time);
1018 retval->type = value_number; 1194 retval->type = value_number;
1019 retval->v.number = t <= mesg_time && mesg_time <= t + 86400; 1195 retval->v.number = t <= mesg_time && mesg_time <= t + 86400;
1020} 1196}
1021 1197
1022static void 1198static void
1023cond_sentsince (struct parsebuf *pb, struct search_node *node, 1199cond_sentsince (struct parsebuf *pb, struct search_node *node,
@@ -1030,7 +1206,7 @@ cond_sentsince (struct parsebuf *pb, struct search_node *node,
1030 _header_date (pb, &mesg_time); 1206 _header_date (pb, &mesg_time);
1031 retval->type = value_number; 1207 retval->type = value_number;
1032 retval->v.number = mesg_time >= t; 1208 retval->v.number = mesg_time >= t;
1033} 1209}
1034 1210
1035static void 1211static void
1036cond_since (struct parsebuf *pb, struct search_node *node, struct value *arg, 1212cond_since (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -1040,7 +1216,7 @@ cond_since (struct parsebuf *pb, struct search_node *node, struct value *arg,
1040 time_t mesg_time; 1216 time_t mesg_time;
1041 const char *date; 1217 const char *date;
1042 mu_envelope_t env; 1218 mu_envelope_t env;
1043 1219
1044 mu_message_get_envelope (pb->msg, &env); 1220 mu_message_get_envelope (pb->msg, &env);
1045 retval->type = value_number; 1221 retval->type = value_number;
1046 if (mu_envelope_sget_date (env, &date)) 1222 if (mu_envelope_sget_date (env, &date))
@@ -1050,18 +1226,18 @@ cond_since (struct parsebuf *pb, struct search_node *node, struct value *arg,
1050 util_parse_ctime_date (date, &mesg_time, datetime_date_only); 1226 util_parse_ctime_date (date, &mesg_time, datetime_date_only);
1051 retval->v.number = mesg_time >= t; 1227 retval->v.number = mesg_time >= t;
1052 } 1228 }
1053} 1229}
1054 1230
1055static void 1231static void
1056cond_smaller (struct parsebuf *pb, struct search_node *node, struct value *arg, 1232cond_smaller (struct parsebuf *pb, struct search_node *node, struct value *arg,
1057 struct value *retval) 1233 struct value *retval)
1058{ 1234{
1059 size_t size = 0; 1235 size_t size = 0;
1060 1236
1061 mu_message_size (pb->msg, &size); 1237 mu_message_size (pb->msg, &size);
1062 retval->type = value_number; 1238 retval->type = value_number;
1063 retval->v.number = size < arg[0].v.number; 1239 retval->v.number = size < arg[0].v.number;
1064} 1240}
1065 1241
1066static void 1242static void
1067cond_subject (struct parsebuf *pb, struct search_node *node, struct value *arg, 1243cond_subject (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -1069,7 +1245,7 @@ cond_subject (struct parsebuf *pb, struct search_node *node, struct value *arg,
1069{ 1245{
1070 retval->type = value_number; 1246 retval->type = value_number;
1071 retval->v.number = _scan_header (pb, MU_HEADER_SUBJECT, arg[0].v.string); 1247 retval->v.number = _scan_header (pb, MU_HEADER_SUBJECT, arg[0].v.string);
1072} 1248}
1073 1249
1074static void 1250static void
1075cond_text (struct parsebuf *pb, struct search_node *node, struct value *arg, 1251cond_text (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -1078,7 +1254,7 @@ cond_text (struct parsebuf *pb, struct search_node *node, struct value *arg,
1078 char *s = arg[0].v.string; 1254 char *s = arg[0].v.string;
1079 retval->type = value_number; 1255 retval->type = value_number;
1080 retval->v.number = _scan_header_all (pb, s) || _scan_body (pb, s); 1256 retval->v.number = _scan_header_all (pb, s) || _scan_body (pb, s);
1081} 1257}
1082 1258
1083static void 1259static void
1084cond_to (struct parsebuf *pb, struct search_node *node, struct value *arg, 1260cond_to (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -1086,7 +1262,7 @@ cond_to (struct parsebuf *pb, struct search_node *node, struct value *arg,
1086{ 1262{
1087 retval->type = value_number; 1263 retval->type = value_number;
1088 retval->v.number = _scan_header (pb, MU_HEADER_TO, arg[0].v.string); 1264 retval->v.number = _scan_header (pb, MU_HEADER_TO, arg[0].v.string);
1089} 1265}
1090 1266
1091static void 1267static void
1092cond_uid (struct parsebuf *pb, struct search_node *node, struct value *arg, 1268cond_uid (struct parsebuf *pb, struct search_node *node, struct value *arg,
@@ -1094,10 +1270,34 @@ cond_uid (struct parsebuf *pb, struct search_node *node, struct value *arg,
1094{ 1270{
1095 int rc; 1271 int rc;
1096 size_t uid = 0; 1272 size_t uid = 0;
1097 1273
1098 mu_message_get_uid (pb->msg, &uid); 1274 mu_message_get_uid (pb->msg, &uid);
1099 rc = mu_msgset_locate (arg[0].v.msgset, pb->msgno, NULL); 1275 rc = mu_msgset_locate (arg[0].v.msgset, pb->msgno, NULL);
1100 retval->type = value_number; 1276 retval->type = value_number;
1101 retval->v.number = rc == 0; 1277 retval->v.number = rc == 0;
1102} 1278}
1103 1279
1280/* Return 1 if the CHARSET is available.
1281 This function assumes that charset is available if it is possible
1282 to create a filter for encoding ASCII data into it.
1283 */
1284static int
1285available_charset (const char *charset)
1286{
1287 int rc;
1288 mu_stream_t flt;
1289 mu_stream_t null;
1290 char const *argv[] = { "iconv", "US-ASCII", NULL, NULL };
1291
1292 rc = mu_nullstream_create (&null, MU_STREAM_READ);
1293 if (rc)
1294 return 0;
1295 argv[2] = charset;
1296 rc = mu_filter_chain_create (&flt, null, MU_FILTER_ENCODE, MU_STREAM_READ,
1297 MU_ARRAY_SIZE (argv) - 1, (char**) argv);
1298 mu_stream_unref (null);
1299 if (rc)
1300 return 0;
1301 mu_stream_destroy (&flt);
1302 return 1;
1303}
diff --git a/imap4d/util.c b/imap4d/util.c
index 19a7d82..cc49478 100644
--- a/imap4d/util.c
+++ b/imap4d/util.c
@@ -156,14 +156,6 @@ util_parse_ctime_date (const char *date, time_t *timep,
156 return 1; 156 return 1;
157} 157}
158 158
159/* Return the first ocurrence of NEEDLE in HAYSTACK. Case insensitive
160 comparison */
161char *
162util_strcasestr (const char *haystack, const char *needle)
163{
164 return mu_c_strcasestr (haystack, needle);
165}
166
167void 159void
168util_print_flags (mu_attribute_t attr) 160util_print_flags (mu_attribute_t attr)
169{ 161{
diff --git a/libmailutils/mailbox/header.c b/libmailutils/mailbox/header.c
index 66af142..98433b7 100644
--- a/libmailutils/mailbox/header.c
+++ b/libmailutils/mailbox/header.c
@@ -688,8 +688,8 @@ mu_header_sget_value_n (mu_header_t header,
688 688
689int 689int
690mu_header_aget_value_n (mu_header_t header, 690mu_header_aget_value_n (mu_header_t header,
691 const char *name, int n, 691 const char *name, int n,
692 char **pval) 692 char **pval)
693{ 693{
694 const char *s; 694 const char *s;
695 int status = mu_header_sget_value_n (header, name, n, &s); 695 int status = mu_header_sget_value_n (header, name, n, &s);

Return to:

Send suggestions and report system problems to the System administrator.