Commit 6fad8e17 6fad8e1734a83c273f6283436775a6548f9c941f by Sergey Poznyakoff

Implement editheader sieve extension (RFC 5293).

Also fix iterator synchronization after removing an element and
improve Sieve API.

* include/mailutils/header.h (mu_header_get_itemptr): New proto.
* include/mailutils/iterator.h (mu_iterator_advance): Remove.
(mu_iterator_delitem): New proto.
(mu_iterator_set_delitem): New proto.
* include/mailutils/sieve.h (mu_sieve_register_t) <opt_args>: New member.
(mu_sieve_register_test_ext)
(mu_sieve_register_action_ext): New protos.
* include/mailutils/sys/iterator.h (_mu_iterator) <curitem_p>: Remove.
<delitem>: New member. All uses updated.

* libmailutils/base/iterator.c (mu_iterator_set_delitem): New function.

* libmailutils/mailbox/hdritr.c: Implement bidirectional iteration.
Implement itrctl method.
* libmailutils/mailbox/header.c: Likewise.

* libmailutils/base/assoc.c: Use delitem method instead of curitem_p.
(mu_iterator_delitem): New function.
* libmailutils/base/opool.c
* libmailutils/diag/debug.c
* libmailutils/list/iterator.c
* libmailutils/list/pop.c
* libmailutils/list/remove.c
* libmailutils/list/removenth.c
* libmailutils/mailbox/imapenv.c
* libmailutils/mailbox/mbxitr.c
* libproto/pop/pop3_iterator.c

* libmu_sieve/extensions/Makefile.am: Add editheader.c
* libmu_sieve/extensions/editheader.c: New file.

* libmu_sieve/prog.c (mu_sv_code_command): Allow for optional positional
arguments.
* libmu_sieve/register.c (mu_sieve_test_lookup)
(mu_sieve_action_lookup): Return NULL if a record with
empty (NULL) handler is found.
(mu_sieve_register_test_ext)
(mu_sieve_register_action_ext): New functions.
(mu_sieve_register_test)
(mu_sieve_register_action): Rewrite as wrappers to the above.
* libmu_sieve/util.c (mu_sieve_vlist_do): Allow for SVT_STRING
argument.
* sieve/tests/Makefile.am: Add new testcases.
* sieve/tests/testsuite.at: Include new testcases.
* sieve/tests/addheader.at: New testcase.
* sieve/tests/delheader.at: New testcase.

* NEWS: Update.
* doc/rfc/README: Update.
1 parent a7a174d5
1 GNU mailutils NEWS -- history of user-visible changes. 2012-08-07 1 GNU mailutils NEWS -- history of user-visible changes. 2012-11-12
2 Copyright (C) 2002-2012 Free Software Foundation, Inc. 2 Copyright (C) 2002-2012 Free Software Foundation, Inc.
3 See the end of file for copying conditions. 3 See the end of file for copying conditions.
4 4
...@@ -114,6 +114,10 @@ header field with the given date. ...@@ -114,6 +114,10 @@ header field with the given date.
114 114
115 See <http://mailutils.org/wiki/Timestamp_(Sieve_test)>. 115 See <http://mailutils.org/wiki/Timestamp_(Sieve_test)>.
116 116
117 Implemented the Editheader extension: `addheader' and `delheader' actions.
118
119 See <http://tools.ietf.org/html/rfc5293>.
120
117 ** mail: sending attachments 121 ** mail: sending attachments
118 122
119 The mail[x] utility now allows for sending attachments. Any number of 123 The mail[x] utility now allows for sending attachments. Any number of
......
...@@ -53,3 +53,4 @@ the actual RFC number. ...@@ -53,3 +53,4 @@ the actual RFC number.
53 3501 INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1 53 3501 INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1
54 3691 Internet Message Access Protocol (IMAP) UNSELECT command 54 3691 Internet Message Access Protocol (IMAP) UNSELECT command
55 4314 IMAP4 Access Control List (ACL) Extension 55 4314 IMAP4 Access Control List (ACL) Extension
56 5293 Sieve Email Filtering: Editheader Extension
......
...@@ -169,6 +169,8 @@ extern int mu_header_set_fill (mu_header_t, ...@@ -169,6 +169,8 @@ extern int mu_header_set_fill (mu_header_t,
169 int (*_fill) (void *data, char **, size_t *), 169 int (*_fill) (void *data, char **, size_t *),
170 void *data); 170 void *data);
171 171
172 extern int mu_header_get_itemptr (mu_header_t header, size_t num,
173 const void **sptr);
172 174
173 #ifdef __cplusplus 175 #ifdef __cplusplus
174 } 176 }
......
...@@ -53,7 +53,7 @@ extern int mu_iterator_ctl (mu_iterator_t, enum mu_itrctl_req, void *); ...@@ -53,7 +53,7 @@ extern int mu_iterator_ctl (mu_iterator_t, enum mu_itrctl_req, void *);
53 53
54 extern int mu_iterator_attach (mu_iterator_t *root, mu_iterator_t iterator); 54 extern int mu_iterator_attach (mu_iterator_t *root, mu_iterator_t iterator);
55 extern int mu_iterator_detach (mu_iterator_t *root, mu_iterator_t iterator); 55 extern int mu_iterator_detach (mu_iterator_t *root, mu_iterator_t iterator);
56 extern void mu_iterator_advance (mu_iterator_t iterator, void *e); 56 extern void mu_iterator_delitem (mu_iterator_t iterator, void *e);
57 57
58 extern int mu_iterator_set_first (mu_iterator_t, int (*first) (void *)); 58 extern int mu_iterator_set_first (mu_iterator_t, int (*first) (void *));
59 extern int mu_iterator_set_next (mu_iterator_t, int (*next) (void *)); 59 extern int mu_iterator_set_next (mu_iterator_t, int (*next) (void *));
...@@ -66,8 +66,13 @@ extern int mu_iterator_set_dup (mu_iterator_t itr, ...@@ -66,8 +66,13 @@ extern int mu_iterator_set_dup (mu_iterator_t itr,
66 int (*dup) (void **ptr, void *data)); 66 int (*dup) (void **ptr, void *data));
67 extern int mu_iterator_set_destroy (mu_iterator_t itr, 67 extern int mu_iterator_set_destroy (mu_iterator_t itr,
68 int (*destroy) (mu_iterator_t, void *data)); 68 int (*destroy) (mu_iterator_t, void *data));
69 extern int mu_iterator_set_curitem_p (mu_iterator_t itr, 69
70 int (*curitem_p) (void *, void *)); 70 #define MU_ITR_DELITEM_NOTHING 0
71 #define MU_ITR_DELITEM_NEXT 1
72 #define MU_ITR_DELITEM_ADVANCE 2
73
74 extern int mu_iterator_set_delitem (mu_iterator_t itr,
75 int (*delitem) (void *, void *));
71 extern int mu_iterator_set_itrctl (mu_iterator_t itr, 76 extern int mu_iterator_set_itrctl (mu_iterator_t itr,
72 int (*itrctl) (void *, 77 int (*itrctl) (void *,
73 enum mu_itrctl_req, 78 enum mu_itrctl_req,
......
...@@ -100,6 +100,7 @@ typedef struct ...@@ -100,6 +100,7 @@ typedef struct
100 int required; 100 int required;
101 mu_sieve_handler_t handler; 101 mu_sieve_handler_t handler;
102 mu_sieve_data_type *req_args; 102 mu_sieve_data_type *req_args;
103 mu_sieve_data_type *opt_args;
103 mu_sieve_tag_group_t *tags; 104 mu_sieve_tag_group_t *tags;
104 } mu_sieve_register_t; 105 } mu_sieve_register_t;
105 106
...@@ -146,10 +147,21 @@ mu_sieve_register_t *mu_sieve_test_lookup (mu_sieve_machine_t mach, ...@@ -146,10 +147,21 @@ mu_sieve_register_t *mu_sieve_test_lookup (mu_sieve_machine_t mach,
146 const char *name); 147 const char *name);
147 mu_sieve_register_t *mu_sieve_action_lookup (mu_sieve_machine_t mach, 148 mu_sieve_register_t *mu_sieve_action_lookup (mu_sieve_machine_t mach,
148 const char *name); 149 const char *name);
150 int mu_sieve_register_test_ext (mu_sieve_machine_t mach,
151 const char *name, mu_sieve_handler_t handler,
152 mu_sieve_data_type *req_args,
153 mu_sieve_data_type *opt_args,
154 mu_sieve_tag_group_t *tags, int required);
149 int mu_sieve_register_test (mu_sieve_machine_t mach, 155 int mu_sieve_register_test (mu_sieve_machine_t mach,
150 const char *name, mu_sieve_handler_t handler, 156 const char *name, mu_sieve_handler_t handler,
151 mu_sieve_data_type * arg_types, 157 mu_sieve_data_type * arg_types,
152 mu_sieve_tag_group_t * tags, int required); 158 mu_sieve_tag_group_t * tags, int required);
159
160 int mu_sieve_register_action_ext (mu_sieve_machine_t mach,
161 const char *name, mu_sieve_handler_t handler,
162 mu_sieve_data_type *req_args,
163 mu_sieve_data_type *opt_args,
164 mu_sieve_tag_group_t *tags, int required);
153 int mu_sieve_register_action (mu_sieve_machine_t mach, 165 int mu_sieve_register_action (mu_sieve_machine_t mach,
154 const char *name, mu_sieve_handler_t handler, 166 const char *name, mu_sieve_handler_t handler,
155 mu_sieve_data_type * arg_types, 167 mu_sieve_data_type * arg_types,
......
...@@ -36,7 +36,7 @@ struct _mu_iterator ...@@ -36,7 +36,7 @@ struct _mu_iterator
36 int (*first) (void *owner); 36 int (*first) (void *owner);
37 int (*next) (void *owner); 37 int (*next) (void *owner);
38 int (*getitem) (void *owner, void **pret, const void **pkey); 38 int (*getitem) (void *owner, void **pret, const void **pkey);
39 int (*curitem_p) (void *owner, void *item); 39 int (*delitem) (void *owner, void *item);
40 int (*finished_p) (void *owner); 40 int (*finished_p) (void *owner);
41 int (*itrctl) (void *owner, enum mu_itrctl_req req, void *arg); 41 int (*itrctl) (void *owner, enum mu_itrctl_req req, void *arg);
42 void *(*dataptr) (void *); 42 void *(*dataptr) (void *);
......
...@@ -452,13 +452,13 @@ destroy (mu_iterator_t iterator, void *data) ...@@ -452,13 +452,13 @@ destroy (mu_iterator_t iterator, void *data)
452 } 452 }
453 453
454 static int 454 static int
455 curitem_p (void *owner, void *item) 455 delitem (void *owner, void *item)
456 { 456 {
457 struct assoc_iterator *itr = owner; 457 struct assoc_iterator *itr = owner;
458 mu_assoc_t assoc = itr->assoc; 458 mu_assoc_t assoc = itr->assoc;
459 struct _mu_assoc_elem *elem = ASSOC_ELEM (assoc, itr->index); 459 struct _mu_assoc_elem *elem = ASSOC_ELEM (assoc, itr->index);
460 460
461 return elem == item; 461 return elem == item ? MU_ITR_DELITEM_NEXT : MU_ITR_DELITEM_NOTHING;
462 } 462 }
463 463
464 static int 464 static int
...@@ -498,7 +498,7 @@ mu_assoc_get_iterator (mu_assoc_t assoc, mu_iterator_t *piterator) ...@@ -498,7 +498,7 @@ mu_assoc_get_iterator (mu_assoc_t assoc, mu_iterator_t *piterator)
498 mu_iterator_set_next (iterator, next); 498 mu_iterator_set_next (iterator, next);
499 mu_iterator_set_getitem (iterator, getitem); 499 mu_iterator_set_getitem (iterator, getitem);
500 mu_iterator_set_finished_p (iterator, finished_p); 500 mu_iterator_set_finished_p (iterator, finished_p);
501 mu_iterator_set_curitem_p (iterator, curitem_p); 501 mu_iterator_set_delitem (iterator, delitem);
502 mu_iterator_set_destroy (iterator, destroy); 502 mu_iterator_set_destroy (iterator, destroy);
503 mu_iterator_set_dup (iterator, assoc_data_dup); 503 mu_iterator_set_dup (iterator, assoc_data_dup);
504 504
......
...@@ -81,12 +81,12 @@ mu_iterator_set_finished_p (mu_iterator_t itr, int (*finished_p) (void *)) ...@@ -81,12 +81,12 @@ mu_iterator_set_finished_p (mu_iterator_t itr, int (*finished_p) (void *))
81 } 81 }
82 82
83 int 83 int
84 mu_iterator_set_curitem_p (mu_iterator_t itr, 84 mu_iterator_set_delitem (mu_iterator_t itr,
85 int (*curitem_p) (void *, void *)) 85 int (*delitem) (void *, void *))
86 { 86 {
87 if (!itr) 87 if (!itr)
88 return EINVAL; 88 return EINVAL;
89 itr->curitem_p = curitem_p; 89 itr->delitem = delitem;
90 return 0; 90 return 0;
91 } 91 }
92 92
...@@ -158,7 +158,7 @@ mu_iterator_dup (mu_iterator_t *piterator, mu_iterator_t orig) ...@@ -158,7 +158,7 @@ mu_iterator_dup (mu_iterator_t *piterator, mu_iterator_t orig)
158 iterator->first = orig->first; 158 iterator->first = orig->first;
159 iterator->next = orig->next; 159 iterator->next = orig->next;
160 iterator->getitem = orig->getitem; 160 iterator->getitem = orig->getitem;
161 iterator->curitem_p = orig->curitem_p; 161 iterator->delitem = orig->delitem;
162 iterator->finished_p = orig->finished_p; 162 iterator->finished_p = orig->finished_p;
163 iterator->itrctl = orig->itrctl; 163 iterator->itrctl = orig->itrctl;
164 164
...@@ -250,16 +250,21 @@ iterator_get_owner (mu_iterator_t iterator, void **powner) ...@@ -250,16 +250,21 @@ iterator_get_owner (mu_iterator_t iterator, void **powner)
250 } 250 }
251 251
252 void 252 void
253 mu_iterator_advance (mu_iterator_t iterator, void *e) 253 mu_iterator_delitem (mu_iterator_t iterator, void *itm)
254 { 254 {
255 for (; iterator; iterator = iterator->next_itr) 255 for (; iterator; iterator = iterator->next_itr)
256 { 256 {
257 if (iterator->curitem_p (iterator->owner, e)) 257 if (iterator->delitem)
258 { 258 {
259 switch (iterator->delitem (iterator->owner, itm))
260 {
261 case MU_ITR_DELITEM_NEXT:
259 iterator->next (iterator->owner); 262 iterator->next (iterator->owner);
263 case MU_ITR_DELITEM_ADVANCE:
260 iterator->is_advanced++; 264 iterator->is_advanced++;
261 } 265 }
262 } 266 }
267 }
263 } 268 }
264 269
265 int 270 int
......
...@@ -384,10 +384,11 @@ opitr_finished_p (void *owner) ...@@ -384,10 +384,11 @@ opitr_finished_p (void *owner)
384 } 384 }
385 385
386 static int 386 static int
387 opitr_curitem_p (void *owner, void *item) 387 opitr_delitem (void *owner, void *item)
388 { 388 {
389 struct opool_iterator *itr = owner; 389 struct opool_iterator *itr = owner;
390 return itr->cur && itr->cur->buf == item; 390 return (itr->cur && itr->cur->buf == item) ?
391 MU_ITR_DELITEM_NEXT : MU_ITR_DELITEM_NOTHING;
391 } 392 }
392 393
393 static int 394 static int
...@@ -446,7 +447,7 @@ mu_opool_get_iterator (mu_opool_t opool, mu_iterator_t *piterator) ...@@ -446,7 +447,7 @@ mu_opool_get_iterator (mu_opool_t opool, mu_iterator_t *piterator)
446 mu_iterator_set_next (iterator, opitr_next); 447 mu_iterator_set_next (iterator, opitr_next);
447 mu_iterator_set_getitem (iterator, opitr_getitem); 448 mu_iterator_set_getitem (iterator, opitr_getitem);
448 mu_iterator_set_finished_p (iterator, opitr_finished_p); 449 mu_iterator_set_finished_p (iterator, opitr_finished_p);
449 mu_iterator_set_curitem_p (iterator, opitr_curitem_p); 450 mu_iterator_set_delitem (iterator, opitr_delitem);
450 mu_iterator_set_destroy (iterator, opitr_destroy); 451 mu_iterator_set_destroy (iterator, opitr_destroy);
451 mu_iterator_set_dup (iterator, opitr_data_dup); 452 mu_iterator_set_dup (iterator, opitr_data_dup);
452 453
......
...@@ -572,10 +572,11 @@ finished_p (void *owner) ...@@ -572,10 +572,11 @@ finished_p (void *owner)
572 } 572 }
573 573
574 static int 574 static int
575 curitem_p (void *owner, void *item) 575 delitem (void *owner, void *item)
576 { 576 {
577 struct debug_iterator *itr = owner; 577 struct debug_iterator *itr = owner;
578 return mu_c_strcasecmp (cattab[itr->pos].name, (char *) item) == 0; 578 return mu_c_strcasecmp (cattab[itr->pos].name, (char *) item) == 0 ?
579 MU_ITR_DELITEM_NEXT : MU_ITR_DELITEM_NOTHING;
579 } 580 }
580 581
581 static int 582 static int
...@@ -659,7 +660,7 @@ mu_debug_get_iterator (mu_iterator_t *piterator, int skipunset) ...@@ -659,7 +660,7 @@ mu_debug_get_iterator (mu_iterator_t *piterator, int skipunset)
659 mu_iterator_set_next (iterator, next); 660 mu_iterator_set_next (iterator, next);
660 mu_iterator_set_getitem (iterator, getitem); 661 mu_iterator_set_getitem (iterator, getitem);
661 mu_iterator_set_finished_p (iterator, finished_p); 662 mu_iterator_set_finished_p (iterator, finished_p);
662 mu_iterator_set_curitem_p (iterator, curitem_p); 663 mu_iterator_set_delitem (iterator, delitem);
663 mu_iterator_set_dup (iterator, list_data_dup); 664 mu_iterator_set_dup (iterator, list_data_dup);
664 mu_iterator_set_itrctl (iterator, list_itrctl); 665 mu_iterator_set_itrctl (iterator, list_itrctl);
665 666
......
...@@ -84,10 +84,10 @@ destroy (mu_iterator_t iterator, void *data) ...@@ -84,10 +84,10 @@ destroy (mu_iterator_t iterator, void *data)
84 } 84 }
85 85
86 static int 86 static int
87 curitem_p (void *owner, void *item) 87 delitem (void *owner, void *item)
88 { 88 {
89 struct list_iterator *itr = owner; 89 struct list_iterator *itr = owner;
90 return itr->cur == item; 90 return itr->cur == item ? MU_ITR_DELITEM_NEXT : MU_ITR_DELITEM_NOTHING;
91 } 91 }
92 92
93 static int 93 static int
...@@ -142,7 +142,7 @@ list_itrctl (void *owner, enum mu_itrctl_req req, void *arg) ...@@ -142,7 +142,7 @@ list_itrctl (void *owner, enum mu_itrctl_req req, void *arg)
142 ptr = itr->cur; 142 ptr = itr->cur;
143 prev = ptr->prev; 143 prev = ptr->prev;
144 144
145 mu_iterator_advance (list->itr, ptr); 145 mu_iterator_delitem (list->itr, ptr);
146 prev->next = ptr->next; 146 prev->next = ptr->next;
147 ptr->next->prev = prev; 147 ptr->next->prev = prev;
148 if (req == mu_itrctl_delete) 148 if (req == mu_itrctl_delete)
...@@ -238,7 +238,7 @@ mu_list_get_iterator (mu_list_t list, mu_iterator_t *piterator) ...@@ -238,7 +238,7 @@ mu_list_get_iterator (mu_list_t list, mu_iterator_t *piterator)
238 mu_iterator_set_next (iterator, next); 238 mu_iterator_set_next (iterator, next);
239 mu_iterator_set_getitem (iterator, getitem); 239 mu_iterator_set_getitem (iterator, getitem);
240 mu_iterator_set_finished_p (iterator, finished_p); 240 mu_iterator_set_finished_p (iterator, finished_p);
241 mu_iterator_set_curitem_p (iterator, curitem_p); 241 mu_iterator_set_delitem (iterator, delitem);
242 mu_iterator_set_destroy (iterator, destroy); 242 mu_iterator_set_destroy (iterator, destroy);
243 mu_iterator_set_dup (iterator, list_data_dup); 243 mu_iterator_set_dup (iterator, list_data_dup);
244 mu_iterator_set_itrctl (iterator, list_itrctl); 244 mu_iterator_set_itrctl (iterator, list_itrctl);
......
...@@ -35,7 +35,7 @@ mu_list_pop (mu_list_t list, void **item) ...@@ -35,7 +35,7 @@ mu_list_pop (mu_list_t list, void **item)
35 35
36 last = list->head.prev; 36 last = list->head.prev;
37 prev = last->prev; 37 prev = last->prev;
38 mu_iterator_advance (list->itr, last); 38 mu_iterator_delitem (list->itr, last);
39 prev->next = last->next; 39 prev->next = last->next;
40 prev->next->prev = prev; 40 prev->next->prev = prev;
41 if (item) 41 if (item)
......
...@@ -41,7 +41,7 @@ mu_list_remove (mu_list_t list, void *item) ...@@ -41,7 +41,7 @@ mu_list_remove (mu_list_t list, void *item)
41 { 41 {
42 struct list_data *previous = current->prev; 42 struct list_data *previous = current->prev;
43 43
44 mu_iterator_advance (list->itr, current); 44 mu_iterator_delitem (list->itr, current);
45 previous->next = current->next; 45 previous->next = current->next;
46 current->next->prev = previous; 46 current->next->prev = previous;
47 DESTROY_ITEM (list, current); 47 DESTROY_ITEM (list, current);
......
...@@ -26,7 +26,6 @@ int ...@@ -26,7 +26,6 @@ int
26 mu_list_remove_nth (mu_list_t list, size_t n) 26 mu_list_remove_nth (mu_list_t list, size_t n)
27 { 27 {
28 struct list_data *current; 28 struct list_data *current;
29 mu_list_comparator_t comp;
30 int status = MU_ERR_NOENT; 29 int status = MU_ERR_NOENT;
31 size_t i; 30 size_t i;
32 31
...@@ -42,7 +41,7 @@ mu_list_remove_nth (mu_list_t list, size_t n) ...@@ -42,7 +41,7 @@ mu_list_remove_nth (mu_list_t list, size_t n)
42 { 41 {
43 struct list_data *previous = current->prev; 42 struct list_data *previous = current->prev;
44 43
45 mu_iterator_advance (list->itr, current); 44 mu_iterator_delitem (list->itr, current);
46 previous->next = current->next; 45 previous->next = current->next;
47 current->next->prev = previous; 46 current->next->prev = previous;
48 DESTROY_ITEM (list, current); 47 DESTROY_ITEM (list, current);
......
...@@ -30,12 +30,19 @@ struct header_iterator ...@@ -30,12 +30,19 @@ struct header_iterator
30 { 30 {
31 mu_header_t header; 31 mu_header_t header;
32 size_t index; 32 size_t index;
33 int backwards;
33 }; 34 };
34 35
35 static int 36 static int
36 hdr_first (void *owner) 37 hdr_first (void *owner)
37 { 38 {
38 struct header_iterator *itr = owner; 39 struct header_iterator *itr = owner;
40 if (itr->backwards)
41 {
42 if (mu_header_get_field_count (itr->header, &itr->index))
43 return 1;
44 }
45 else
39 itr->index = 1; 46 itr->index = 1;
40 return 0; 47 return 0;
41 } 48 }
...@@ -44,6 +51,12 @@ static int ...@@ -44,6 +51,12 @@ static int
44 hdr_next (void *owner) 51 hdr_next (void *owner)
45 { 52 {
46 struct header_iterator *itr = owner; 53 struct header_iterator *itr = owner;
54 if (itr->backwards)
55 {
56 if (itr->index != 0)
57 itr->index--;
58 }
59 else
47 itr->index++; 60 itr->index++;
48 return 0; 61 return 0;
49 } 62 }
...@@ -58,16 +71,16 @@ hdr_getitem (void *owner, void **pret, const void **pkey) ...@@ -58,16 +71,16 @@ hdr_getitem (void *owner, void **pret, const void **pkey)
58 rc = mu_header_get_field_count (itr->header, &count); 71 rc = mu_header_get_field_count (itr->header, &count);
59 if (rc) 72 if (rc)
60 return rc; 73 return rc;
61 if (itr->index > count) 74 if (itr->index < 1 || itr->index > count)
62 return MU_ERR_NOENT; 75 return MU_ERR_NOENT;
63 76
64 rc = mu_header_sget_field_name (itr->header, itr->index, 77 rc = mu_header_sget_field_value (itr->header, itr->index,
65 (const char**) pkey); 78 (const char**) pret);
66 if (rc == 0) 79 if (rc == 0)
67 { 80 {
68 if (pkey) 81 if (pkey)
69 rc = mu_header_sget_field_value (itr->header, itr->index, 82 rc = mu_header_sget_field_name (itr->header, itr->index,
70 (const char**) pret); 83 (const char**) pkey);
71 } 84 }
72 return rc; 85 return rc;
73 } 86 }
...@@ -78,6 +91,9 @@ hdr_finished_p (void *owner) ...@@ -78,6 +91,9 @@ hdr_finished_p (void *owner)
78 struct header_iterator *itr = owner; 91 struct header_iterator *itr = owner;
79 size_t count; 92 size_t count;
80 93
94 if (itr->backwards)
95 return itr->index < 1;
96
81 if (mu_header_get_field_count (itr->header, &count)) 97 if (mu_header_get_field_count (itr->header, &count))
82 return 1; 98 return 1;
83 return itr->index > count; 99 return itr->index > count;
...@@ -93,13 +109,16 @@ hdr_destroy (mu_iterator_t iterator, void *data) ...@@ -93,13 +109,16 @@ hdr_destroy (mu_iterator_t iterator, void *data)
93 } 109 }
94 110
95 static int 111 static int
96 hdr_curitem_p (void *owner, void *item) 112 hdr_delitem (void *owner, void *item)
97 { 113 {
98 void *ptr; 114 struct header_iterator *itr = owner;
115 const void *ptr;
99 116
100 if (hdr_getitem (owner, &ptr, NULL)) 117 if (mu_header_get_itemptr (itr->header, itr->index, &ptr))
101 return 0; 118 return MU_ITR_DELITEM_NOTHING;
102 return ptr == item; 119 if (ptr == item && !itr->backwards)
120 return MU_ITR_DELITEM_ADVANCE;
121 return MU_ITR_DELITEM_NOTHING;
103 } 122 }
104 123
105 static int 124 static int
...@@ -115,6 +134,51 @@ hdr_data_dup (void **ptr, void *owner) ...@@ -115,6 +134,51 @@ hdr_data_dup (void **ptr, void *owner)
115 return 0; 134 return 0;
116 } 135 }
117 136
137 static int
138 hdr_itrctl (void *owner, enum mu_itrctl_req req, void *arg)
139 {
140 struct header_iterator *itr = owner;
141
142 switch (req)
143 {
144 case mu_itrctl_tell:
145 /* Return current position in the object */
146 if (hdr_finished_p (owner))
147 return MU_ERR_NOENT;
148 else
149 *(size_t*)arg = itr->index;
150 return 0;
151 break;
152
153 case mu_itrctl_delete:
154 /* Delete current element */
155 if (hdr_finished_p (owner))
156 return MU_ERR_NOENT;
157 else
158 return mu_header_remove (itr->header, NULL, itr->index);
159 break;
160
161 case mu_itrctl_qry_direction:
162 if (!arg)
163 return EINVAL;
164 else
165 *(int*)arg = itr->backwards;
166 break;
167
168 case mu_itrctl_set_direction:
169 if (!arg)
170 return EINVAL;
171 else
172 itr->backwards = !!*(int*)arg;
173 break;
174
175 default:
176 return ENOSYS;
177 }
178 return 0;
179 }
180
181
118 int 182 int
119 mu_header_get_iterator (mu_header_t hdr, mu_iterator_t *piterator) 183 mu_header_get_iterator (mu_header_t hdr, mu_iterator_t *piterator)
120 { 184 {
...@@ -142,9 +206,10 @@ mu_header_get_iterator (mu_header_t hdr, mu_iterator_t *piterator) ...@@ -142,9 +206,10 @@ mu_header_get_iterator (mu_header_t hdr, mu_iterator_t *piterator)
142 mu_iterator_set_next (iterator, hdr_next); 206 mu_iterator_set_next (iterator, hdr_next);
143 mu_iterator_set_getitem (iterator, hdr_getitem); 207 mu_iterator_set_getitem (iterator, hdr_getitem);
144 mu_iterator_set_finished_p (iterator, hdr_finished_p); 208 mu_iterator_set_finished_p (iterator, hdr_finished_p);
145 mu_iterator_set_curitem_p (iterator, hdr_curitem_p); 209 mu_iterator_set_delitem (iterator, hdr_delitem);
146 mu_iterator_set_destroy (iterator, hdr_destroy); 210 mu_iterator_set_destroy (iterator, hdr_destroy);
147 mu_iterator_set_dup (iterator, hdr_data_dup); 211 mu_iterator_set_dup (iterator, hdr_data_dup);
212 mu_iterator_set_itrctl (iterator, hdr_itrctl);
148 213
149 mu_iterator_attach (&hdr->itr, iterator); 214 mu_iterator_attach (&hdr->itr, iterator);
150 215
......
...@@ -80,13 +80,15 @@ mu_hdrent_find (struct _mu_header *hdr, const char *name, int pos) ...@@ -80,13 +80,15 @@ mu_hdrent_find (struct _mu_header *hdr, const char *name, int pos)
80 if (pos > 0) 80 if (pos > 0)
81 { 81 {
82 for (p = hdr->head; p; p = p->next) 82 for (p = hdr->head; p; p = p->next)
83 if (mu_c_strcasecmp (MU_HDRENT_NAME (hdr,p), name) == 0 && pos-- == 1) 83 if ((!name || mu_c_strcasecmp (MU_HDRENT_NAME (hdr,p), name) == 0) &&
84 pos-- == 1)
84 break; 85 break;
85 } 86 }
86 else if (pos < 0) 87 else if (pos < 0)
87 { 88 {
88 for (p = hdr->tail; p; p = p->prev) 89 for (p = hdr->tail; p; p = p->prev)
89 if (mu_c_strcasecmp (MU_HDRENT_NAME (hdr,p), name) == 0 && ++pos == 0) 90 if ((!name || mu_c_strcasecmp (MU_HDRENT_NAME (hdr,p), name) == 0) &&
91 ++pos == 0)
90 break; 92 break;
91 } 93 }
92 else 94 else
...@@ -544,7 +546,7 @@ mu_header_remove (mu_header_t header, const char *fn, int n) ...@@ -544,7 +546,7 @@ mu_header_remove (mu_header_t header, const char *fn, int n)
544 int status; 546 int status;
545 struct mu_hdrent *ent; 547 struct mu_hdrent *ent;
546 548
547 if (header == NULL || fn == NULL) 549 if (header == NULL)
548 return EINVAL; 550 return EINVAL;
549 551
550 status = mu_header_fill (header); 552 status = mu_header_fill (header);
...@@ -555,6 +557,7 @@ mu_header_remove (mu_header_t header, const char *fn, int n) ...@@ -555,6 +557,7 @@ mu_header_remove (mu_header_t header, const char *fn, int n)
555 if (!ent) 557 if (!ent)
556 return MU_ERR_NOENT; 558 return MU_ERR_NOENT;
557 559
560 mu_iterator_delitem (header->itr, ent);
558 mu_hdrent_remove (header, ent); 561 mu_hdrent_remove (header, ent);
559 HEADER_SET_MODIFIED (header); 562 HEADER_SET_MODIFIED (header);
560 free (ent); 563 free (ent);
...@@ -782,6 +785,26 @@ mu_header_get_field_count (mu_header_t header, size_t *pcount) ...@@ -782,6 +785,26 @@ mu_header_get_field_count (mu_header_t header, size_t *pcount)
782 } 785 }
783 786
784 int 787 int
788 mu_header_get_itemptr (mu_header_t header, size_t num, const void **sptr)
789 {
790 int status;
791
792 if (header == NULL)
793 return EINVAL;
794
795 status = mu_header_fill (header);
796 if (status == 0)
797 {
798 struct mu_hdrent *ent = mu_hdrent_nth (header, num);
799 if (ent)
800 *sptr = ent;
801 else
802 status = MU_ERR_NOENT;
803 }
804 return status;
805 }
806
807 int
785 mu_header_sget_field_name (mu_header_t header, size_t num, const char **sptr) 808 mu_header_sget_field_name (mu_header_t header, size_t num, const char **sptr)
786 { 809 {
787 int status; 810 int status;
......
...@@ -52,7 +52,7 @@ mu_message_get_imapenvelope (mu_message_t msg, struct mu_imapenvelope **pimapenv ...@@ -52,7 +52,7 @@ mu_message_get_imapenvelope (mu_message_t msg, struct mu_imapenvelope **pimapenv
52 52
53 if (msg == NULL) 53 if (msg == NULL)
54 return EINVAL; 54 return EINVAL;
55 if (imapenvelope == NULL) 55 if (pimapenvelope == NULL)
56 return MU_ERR_OUT_PTR_NULL; 56 return MU_ERR_OUT_PTR_NULL;
57 if (msg->_imapenvelope) 57 if (msg->_imapenvelope)
58 return msg->_imapenvelope (msg, pimapenvelope); 58 return msg->_imapenvelope (msg, pimapenvelope);
......
...@@ -111,13 +111,14 @@ mbx_destroy (mu_iterator_t iterator, void *data) ...@@ -111,13 +111,14 @@ mbx_destroy (mu_iterator_t iterator, void *data)
111 } 111 }
112 112
113 static int 113 static int
114 mbx_curitem_p (void *owner, void *item) 114 mbx_delitem (void *owner, void *item)
115 { 115 {
116 void *ptr; 116 void *ptr;
117 117
118 if (mbx_getitem (owner, &ptr, NULL)) 118 if (mbx_getitem (owner, &ptr, NULL))
119 return 0; 119 return 0;
120 return ptr == item;/* FIXME: Is it ok? */ 120 return ptr == item ? MU_ITR_DELITEM_NEXT : MU_ITR_DELITEM_NOTHING;
121 /* FIXME: is it ok? */
121 } 122 }
122 123
123 static int 124 static int
...@@ -210,7 +211,7 @@ mu_mailbox_get_iterator (mu_mailbox_t mbx, mu_iterator_t *piterator) ...@@ -210,7 +211,7 @@ mu_mailbox_get_iterator (mu_mailbox_t mbx, mu_iterator_t *piterator)
210 mu_iterator_set_next (iterator, mbx_next); 211 mu_iterator_set_next (iterator, mbx_next);
211 mu_iterator_set_getitem (iterator, mbx_getitem); 212 mu_iterator_set_getitem (iterator, mbx_getitem);
212 mu_iterator_set_finished_p (iterator, mbx_finished_p); 213 mu_iterator_set_finished_p (iterator, mbx_finished_p);
213 mu_iterator_set_curitem_p (iterator, mbx_curitem_p); 214 mu_iterator_set_delitem (iterator, mbx_delitem);
214 mu_iterator_set_destroy (iterator, mbx_destroy); 215 mu_iterator_set_destroy (iterator, mbx_destroy);
215 mu_iterator_set_dup (iterator, mbx_data_dup); 216 mu_iterator_set_dup (iterator, mbx_data_dup);
216 mu_iterator_set_itrctl (iterator, mbx_itrctl); 217 mu_iterator_set_itrctl (iterator, mbx_itrctl);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 16
17 moddir=@MU_SIEVE_MODDIR@ 17 moddir=@MU_SIEVE_MODDIR@
18 mod_LTLIBRARIES = \ 18 mod_LTLIBRARIES = \
19 editheader.la\
19 list.la\ 20 list.la\
20 moderator.la\ 21 moderator.la\
21 pipe.la\ 22 pipe.la\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2012 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with GNU Mailutils. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 /* This module implements the Editheader Extension (RFC 5293) */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <mailutils/types.h>
25 #include <mailutils/message.h>
26 #include <mailutils/header.h>
27 #include <mailutils/error.h>
28 #include <mailutils/errno.h>
29 #include <mailutils/sieve.h>
30
31 /* Syntax: addheader [:last] <field-name: string> <value: string>
32 */
33 int
34 sieve_addheader (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
35 {
36 mu_sieve_value_t *val;
37 const char *field_name;
38 const char *field_value;
39 mu_message_t msg;
40 mu_header_t hdr;
41 int rc;
42
43 val = mu_sieve_value_get (args, 0);
44 if (!val)
45 {
46 mu_sieve_error (mach, "%lu: %s",
47 (unsigned long) mu_sieve_get_message_num (mach),
48 _("cannot get field name"));
49 mu_sieve_abort (mach);
50 }
51 field_name = val->v.string;
52
53 val = mu_sieve_value_get (args, 1);
54 if (!val)
55 {
56 mu_sieve_error (mach, "%lu: %s",
57 (unsigned long) mu_sieve_get_message_num (mach),
58 _("cannot get field value"));
59 mu_sieve_abort (mach);
60 }
61 field_value = val->v.string;
62
63 mu_sieve_log_action (mach, "ADDHEADER", "%s: %s", field_name, field_value);
64
65 if (mu_sieve_is_dry_run (mach))
66 return 0;
67
68 msg = mu_sieve_get_message (mach);
69 rc = mu_message_get_header (msg, &hdr);
70 if (rc)
71 {
72 mu_sieve_error (mach, "%lu: %s: %s",
73 (unsigned long) mu_sieve_get_message_num (mach),
74 _("cannot get message header"),
75 mu_strerror (rc));
76 mu_sieve_abort (mach);
77 }
78
79 rc = (mu_sieve_tag_lookup (tags, "last", NULL) ?
80 mu_header_append : mu_header_prepend) (hdr, field_name, field_value);
81 if (rc)
82 {
83 mu_sieve_error (mach, "%lu: %s: %s",
84 (unsigned long) mu_sieve_get_message_num (mach),
85 _("cannot append message header"),
86 mu_strerror (rc));
87 mu_sieve_abort (mach);
88 }
89 return 0;
90 }
91
92 /* Syntax: deleteheader [:index <fieldno: number> [:last]]
93 [COMPARATOR] [MATCH-TYPE]
94 <field-name: string>
95 [<value-patterns: string-list>]
96 */
97 int
98 sieve_deleteheader (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
99 {
100 mu_sieve_value_t *val;
101 const char *field_name;
102 const char *field_pattern;
103 mu_message_t msg;
104 mu_header_t hdr;
105 int rc;
106 mu_sieve_comparator_t comp;
107 mu_iterator_t itr;
108 unsigned long i, idx = 0;
109
110 val = mu_sieve_value_get (args, 0);
111 if (!val)
112 {
113 mu_sieve_error (mach, "%lu: %s",
114 (unsigned long) mu_sieve_get_message_num (mach),
115 _("cannot get field name"));
116 mu_sieve_abort (mach);
117 }
118 field_name = val->v.string;
119
120 val = mu_sieve_value_get (args, 1);
121 if (!val)
122 {
123 field_pattern = NULL;
124 mu_sieve_log_action (mach, "DELETEHEADER", "%s", field_name);
125 }
126 else
127 {
128 switch (val->type)
129 {
130 case SVT_STRING_LIST:
131 if (mu_list_get (val->v.list, 0, (void**)&field_pattern))
132 {
133 mu_sieve_error (mach, "%lu: %s",
134 (unsigned long) mu_sieve_get_message_num (mach),
135 _("cannot get list item"));
136 mu_sieve_abort (mach);
137 }
138 mu_sieve_log_action (mach, "DELETEHEADER", "%s: (regexp)",
139 field_name);
140 break;
141
142 case SVT_STRING:
143 field_pattern = val->v.string;
144 mu_sieve_log_action (mach, "DELETEHEADER", "%s: %s", field_name,
145 field_pattern);
146 break;
147
148 default:
149 mu_sieve_error (mach, "%lu: %s: %d",
150 (unsigned long) mu_sieve_get_message_num (mach),
151 _("unexpected value type"), val->type);
152 mu_sieve_abort (mach);
153
154 }
155 }
156
157 if (mu_sieve_is_dry_run (mach))
158 return 0;
159
160 msg = mu_sieve_get_message (mach);
161 rc = mu_message_get_header (msg, &hdr);
162 if (rc)
163 {
164 mu_sieve_error (mach, "%lu: %s: %s",
165 (unsigned long) mu_sieve_get_message_num (mach),
166 _("cannot get message header"),
167 mu_strerror (rc));
168 mu_sieve_abort (mach);
169 }
170
171 mu_header_get_iterator (hdr, &itr);
172 if (mu_sieve_tag_lookup (tags, "last", NULL))
173 {
174 int backwards = 1;
175 mu_iterator_ctl (itr, mu_itrctl_set_direction, &backwards);
176 }
177 comp = mu_sieve_get_comparator (mach, tags);
178
179 if (mu_sieve_tag_lookup (tags, "index", &val))
180 idx = val->v.number;
181
182 for (i = 0, mu_iterator_first (itr); !mu_iterator_is_done (itr);
183 mu_iterator_next (itr))
184 {
185 const char *fn, *fv;
186
187 mu_iterator_current_kv (itr, (const void **)&fn, (void **)&fv);
188 if (strcmp (field_name, fn))
189 continue;
190 if (idx && ++i < idx)
191 continue;
192
193 if (field_pattern)
194 {
195 if (comp (field_pattern, fv))
196 mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
197 }
198 else
199 mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
200
201 if (idx)
202 break;
203 }
204 mu_iterator_destroy (&itr);
205 return 0;
206 }
207
208
209 /* addheader tagged arguments: */
210 static mu_sieve_tag_def_t addheader_tags[] = {
211 { "last", SVT_VOID },
212 { NULL }
213 };
214
215 static mu_sieve_tag_group_t addheader_tag_groups[] = {
216 { addheader_tags, NULL },
217 { NULL }
218 };
219
220 /* addheader required arguments: */
221 static mu_sieve_data_type addheader_args[] = {
222 SVT_STRING, /* field name */
223 SVT_STRING, /* field value */
224 SVT_VOID
225 };
226
227 #if 0
228 /* FIXME: The checker interface should be redone. Until then this function
229 is commented out. Problems:
230
231 1. Checkers are called per group, there's no way to call them per tag.
232 2. See FIXMEs in the code.
233 */
234 static int
235 index_checker (const char *name, mu_list_t tags, mu_list_t args)
236 {
237 mu_iterator_t itr;
238 mu_sieve_runtime_tag_t *match = NULL;
239 int err;
240
241 if (!tags || mu_list_get_iterator (tags, &itr))
242 return 0;
243
244 err = 0;
245 for (mu_iterator_first (itr); !err && !mu_iterator_is_done (itr);
246 mu_iterator_next (itr))
247 {
248 mu_sieve_runtime_tag_t *t;
249 mu_iterator_current (itr, (void **)&t);
250
251 if (strcmp (t->tag, "index") == 0)
252 {
253 if (match)
254 {
255 /* FIXME: 1. This function must be public.
256 2. locus should be included in t
257 */
258 mu_sv_compile_error (&mu_sieve_locus,
259 _("index specified twice in call to `%s'"),
260 name);
261 err = 1;
262 break;
263 }
264 }
265 }
266
267 mu_iterator_destroy (&itr);
268
269 if (err)
270 return 1;
271
272 if (match)
273 {
274 if (match->arg->v.number < 1)
275 {
276 // See FIXME above
277 mu_sv_compile_error (&mu_sieve_locus,
278 _("invalid index value: %s"),
279 match->arg->v.string);
280 return 1;
281 }
282 }
283
284 return 0;
285 }
286 #endif
287
288 static mu_sieve_tag_def_t match_part_tags[] = {
289 { "is", SVT_VOID },
290 { "contains", SVT_VOID },
291 { "matches", SVT_VOID },
292 { "regex", SVT_VOID },
293 { "count", SVT_STRING },
294 { "value", SVT_STRING },
295 { "comparator", SVT_STRING },
296 { NULL }
297 };
298
299 /* deleteheader tagged arguments: */
300 static mu_sieve_tag_def_t deleteheader_tags[] = {
301 { "last", SVT_VOID },
302 { "index", SVT_NUMBER },
303 { NULL }
304 };
305
306 static mu_sieve_tag_group_t deleteheader_tag_groups[] = {
307 { deleteheader_tags, NULL },
308 { match_part_tags, mu_sieve_match_part_checker },
309 { NULL }
310 };
311
312 /* deleteheader required arguments: */
313 static mu_sieve_data_type deleteheader_args[] = {
314 SVT_STRING, /* field name or value pattern */
315 SVT_VOID
316 };
317
318 int
319 SIEVE_EXPORT (editheader, init) (mu_sieve_machine_t mach)
320 {
321 int rc;
322
323 /* This dummy record is required by libmu_sieve */
324 rc = mu_sieve_register_action (mach, "editheader", NULL, NULL, NULL, 1);
325 if (rc)
326 return rc;
327 rc = mu_sieve_register_action (mach, "addheader", sieve_addheader,
328 addheader_args, addheader_tag_groups, 1);
329 if (rc)
330 return rc;
331 rc = mu_sieve_register_action_ext (mach, "deleteheader", sieve_deleteheader,
332 deleteheader_args, deleteheader_args,
333 deleteheader_tag_groups,
334 1);
335 if (rc)
336 return rc;
337
338 return rc;
339 }
...@@ -139,6 +139,7 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist) ...@@ -139,6 +139,7 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
139 mu_list_t tag_list = NULL; 139 mu_list_t tag_list = NULL;
140 mu_list_t chk_list = NULL; 140 mu_list_t chk_list = NULL;
141 mu_sieve_data_type *exp_arg; 141 mu_sieve_data_type *exp_arg;
142 int opt_args = 0;
142 int rc, err = 0; 143 int rc, err = 0;
143 static mu_sieve_data_type empty[] = { SVT_VOID }; 144 static mu_sieve_data_type empty[] = { SVT_VOID };
144 145
...@@ -237,7 +238,16 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist) ...@@ -237,7 +238,16 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
237 mu_list_append (chk_list, cf); 238 mu_list_append (chk_list, cf);
238 } 239 }
239 } 240 }
240 else if (*exp_arg == SVT_VOID) 241 else
242 {
243 if (*exp_arg == SVT_VOID)
244 {
245 if (reg->opt_args)
246 {
247 exp_arg = reg->opt_args;
248 opt_args = 1;
249 }
250 else
241 { 251 {
242 mu_sv_compile_error (&mu_sieve_locus, 252 mu_sv_compile_error (&mu_sieve_locus,
243 _("too many arguments in call to `%s'"), 253 _("too many arguments in call to `%s'"),
...@@ -245,8 +255,8 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist) ...@@ -245,8 +255,8 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
245 err = 1; 255 err = 1;
246 break; 256 break;
247 } 257 }
248 else 258 }
249 { 259
250 if (*exp_arg != val->type) 260 if (*exp_arg != val->type)
251 { 261 {
252 if (*exp_arg == SVT_STRING_LIST && val->type == SVT_STRING) 262 if (*exp_arg == SVT_STRING_LIST && val->type == SVT_STRING)
...@@ -291,7 +301,7 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist) ...@@ -291,7 +301,7 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
291 301
292 if (!err) 302 if (!err)
293 { 303 {
294 if (*exp_arg != SVT_VOID) 304 if (!opt_args && *exp_arg != SVT_VOID)
295 { 305 {
296 mu_sv_compile_error (&mu_sieve_locus, 306 mu_sv_compile_error (&mu_sieve_locus,
297 _("too few arguments in call to `%s'"), 307 _("too few arguments in call to `%s'"),
......
...@@ -50,13 +50,15 @@ reg_lookup (mu_list_t list, const char *name) ...@@ -50,13 +50,15 @@ reg_lookup (mu_list_t list, const char *name)
50 mu_sieve_register_t * 50 mu_sieve_register_t *
51 mu_sieve_test_lookup (mu_sieve_machine_t mach, const char *name) 51 mu_sieve_test_lookup (mu_sieve_machine_t mach, const char *name)
52 { 52 {
53 return reg_lookup (mach->test_list, name); 53 mu_sieve_register_t *reg = reg_lookup (mach->test_list, name);
54 return (reg && reg->handler) ? reg : NULL;
54 } 55 }
55 56
56 mu_sieve_register_t * 57 mu_sieve_register_t *
57 mu_sieve_action_lookup (mu_sieve_machine_t mach, const char *name) 58 mu_sieve_action_lookup (mu_sieve_machine_t mach, const char *name)
58 { 59 {
59 return reg_lookup (mach->action_list, name); 60 mu_sieve_register_t *reg = reg_lookup (mach->action_list, name);
61 return (reg && reg->handler) ? reg : NULL;
60 } 62 }
61 63
62 static int 64 static int
...@@ -90,7 +92,8 @@ static int ...@@ -90,7 +92,8 @@ static int
90 sieve_register (mu_list_t *pool, 92 sieve_register (mu_list_t *pool,
91 mu_list_t *list, 93 mu_list_t *list,
92 const char *name, mu_sieve_handler_t handler, 94 const char *name, mu_sieve_handler_t handler,
93 mu_sieve_data_type *arg_types, 95 mu_sieve_data_type *req_arg_types,
96 mu_sieve_data_type *opt_arg_types,
94 mu_sieve_tag_group_t *tags, int required) 97 mu_sieve_tag_group_t *tags, int required)
95 { 98 {
96 mu_sieve_register_t *reg = mu_sieve_palloc (pool, sizeof (*reg)); 99 mu_sieve_register_t *reg = mu_sieve_palloc (pool, sizeof (*reg));
...@@ -100,7 +103,8 @@ sieve_register (mu_list_t *pool, ...@@ -100,7 +103,8 @@ sieve_register (mu_list_t *pool,
100 reg->name = name; 103 reg->name = name;
101 reg->handler = handler; 104 reg->handler = handler;
102 105
103 reg->req_args = arg_types; 106 reg->req_args = req_arg_types;
107 reg->opt_args = opt_arg_types;
104 reg->tags = tags; 108 reg->tags = tags;
105 reg->required = required; 109 reg->required = required;
106 110
...@@ -119,23 +123,49 @@ sieve_register (mu_list_t *pool, ...@@ -119,23 +123,49 @@ sieve_register (mu_list_t *pool,
119 123
120 124
121 int 125 int
122 mu_sieve_register_test (mu_sieve_machine_t mach, 126 mu_sieve_register_test_ext (mu_sieve_machine_t mach,
123 const char *name, mu_sieve_handler_t handler, 127 const char *name, mu_sieve_handler_t handler,
124 mu_sieve_data_type *arg_types, 128 mu_sieve_data_type *req_args,
129 mu_sieve_data_type *opt_args,
125 mu_sieve_tag_group_t *tags, int required) 130 mu_sieve_tag_group_t *tags, int required)
126 { 131 {
127 return sieve_register (&mach->memory_pool, 132 return sieve_register (&mach->memory_pool,
128 &mach->test_list, name, handler, 133 &mach->test_list, name, handler,
129 arg_types, tags, required); 134 req_args, opt_args, tags, required);
130 } 135 }
131 136
132 int 137 int
133 mu_sieve_register_action (mu_sieve_machine_t mach, 138 mu_sieve_register_test (mu_sieve_machine_t mach,
134 const char *name, mu_sieve_handler_t handler, 139 const char *name, mu_sieve_handler_t handler,
135 mu_sieve_data_type *arg_types, 140 mu_sieve_data_type *arg_types,
136 mu_sieve_tag_group_t *tags, int required) 141 mu_sieve_tag_group_t *tags, int required)
137 { 142 {
143 return mu_sieve_register_test_ext (mach, name, handler,
144 arg_types, NULL,
145 tags,
146 required);
147 }
148
149 int
150 mu_sieve_register_action_ext (mu_sieve_machine_t mach,
151 const char *name, mu_sieve_handler_t handler,
152 mu_sieve_data_type *req_args,
153 mu_sieve_data_type *opt_args,
154 mu_sieve_tag_group_t *tags, int required)
155 {
138 return sieve_register (&mach->memory_pool, 156 return sieve_register (&mach->memory_pool,
139 &mach->action_list, name, handler, 157 &mach->action_list, name, handler,
140 arg_types, tags, required); 158 req_args, opt_args, tags, required);
159 }
160
161 int
162 mu_sieve_register_action (mu_sieve_machine_t mach,
163 const char *name, mu_sieve_handler_t handler,
164 mu_sieve_data_type *arg_types,
165 mu_sieve_tag_group_t *tags, int required)
166 {
167 return mu_sieve_register_action_ext (mach, name, handler,
168 arg_types, NULL,
169 tags,
170 required);
141 } 171 }
......
...@@ -426,8 +426,10 @@ mu_sieve_vlist_do (mu_sieve_value_t *val, mu_list_action_t ac, void *data) ...@@ -426,8 +426,10 @@ mu_sieve_vlist_do (mu_sieve_value_t *val, mu_list_action_t ac, void *data)
426 case SVT_VALUE_LIST: 426 case SVT_VALUE_LIST:
427 case SVT_STRING_LIST: 427 case SVT_STRING_LIST:
428 return mu_list_foreach (val->v.list, ac, data); 428 return mu_list_foreach (val->v.list, ac, data);
429 429 case SVT_STRING:
430 return ac (val->v.string, data);
430 default: 431 default:
432 mu_error ("mu_sieve_vlist_do: unexpected list type %d", val->type);
431 return EINVAL; 433 return EINVAL;
432 } 434 }
433 } 435 }
......
...@@ -35,7 +35,7 @@ static int pop3_itr_destroy (mu_iterator_t itr, void *owner); ...@@ -35,7 +35,7 @@ static int pop3_itr_destroy (mu_iterator_t itr, void *owner);
35 static int pop3_itr_first (void *owner); 35 static int pop3_itr_first (void *owner);
36 static int pop3_itr_next (void *woner); 36 static int pop3_itr_next (void *woner);
37 static int pop3_itr_getitem (void *owner, void **pret, const void **pkey); 37 static int pop3_itr_getitem (void *owner, void **pret, const void **pkey);
38 static int pop3_itr_curitem_p (void *owner, void *data); 38 static int pop3_itr_delitem (void *owner, void *data);
39 static int pop3_itr_finished_p (void *owner); 39 static int pop3_itr_finished_p (void *owner);
40 40
41 struct pop3_iterator 41 struct pop3_iterator
...@@ -81,7 +81,7 @@ mu_pop3_iterator_create (mu_pop3_t pop3, mu_iterator_t *piterator) ...@@ -81,7 +81,7 @@ mu_pop3_iterator_create (mu_pop3_t pop3, mu_iterator_t *piterator)
81 mu_iterator_set_next (iterator, pop3_itr_next); 81 mu_iterator_set_next (iterator, pop3_itr_next);
82 mu_iterator_set_getitem (iterator, pop3_itr_getitem); 82 mu_iterator_set_getitem (iterator, pop3_itr_getitem);
83 mu_iterator_set_finished_p (iterator, pop3_itr_finished_p); 83 mu_iterator_set_finished_p (iterator, pop3_itr_finished_p);
84 mu_iterator_set_curitem_p (iterator, pop3_itr_curitem_p); 84 mu_iterator_set_delitem (iterator, pop3_itr_delitem);
85 mu_iterator_set_destroy (iterator, pop3_itr_destroy); 85 mu_iterator_set_destroy (iterator, pop3_itr_destroy);
86 mu_iterator_set_dup (iterator, pop3_itr_dup); 86 mu_iterator_set_dup (iterator, pop3_itr_dup);
87 87
...@@ -183,9 +183,10 @@ pop3_itr_finished_p (void *owner) ...@@ -183,9 +183,10 @@ pop3_itr_finished_p (void *owner)
183 } 183 }
184 184
185 static int 185 static int
186 pop3_itr_curitem_p (void *owner, void *item) 186 pop3_itr_delitem (void *owner, void *item)
187 { 187 {
188 struct pop3_iterator *pop3_iterator = (struct pop3_iterator *)owner; 188 struct pop3_iterator *pop3_iterator = (struct pop3_iterator *)owner;
189 return *((char **)item) == pop3_iterator->item; 189 return *((char **)item) == pop3_iterator->item ?
190 MU_ITR_DELITEM_NEXT : MU_ITR_DELITEM_NOTHING;
190 } 191 }
191 192
......
...@@ -41,9 +41,11 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac ...@@ -41,9 +41,11 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
41 41
42 TESTSUITE_AT = \ 42 TESTSUITE_AT = \
43 action.at\ 43 action.at\
44 addheader.at\
44 address.at\ 45 address.at\
45 allof.at\ 46 allof.at\
46 anyof.at\ 47 anyof.at\
48 delheader.at\
47 compile.at\ 49 compile.at\
48 envelope.at\ 50 envelope.at\
49 exists.at\ 51 exists.at\
......
1 # This file is part of GNU Mailutils. -*- Autotest -*-
2 # Copyright (C) 2012 Free Software Foundation, Inc.
3 #
4 # GNU Mailutils is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3, or (at
7 # your option) any later version.
8 #
9 # GNU Mailutils is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
16
17 AT_BANNER([addheader])
18 m4_pushdef([MUT_SIEVE_EXT_NAME],[addheader])
19
20 MUT_SIEVE_EXT_TEST([prepend header],[addheader addheader00],
21 [require "editheader";
22 addheader "X-Sieve-Filtered" "<kim@job.example.com>";
23 ],
24 [MUT_MBCOPY($abs_top_srcdir/testsuite/spool/sieve.mbox,mailbox)
25 sieve MUT_SIEVE_CMDLINE MUT_SIEVE_OPTIONS -f ./mailbox prog
26 sed '/X-IMAPbase:/d;s/ *$//' mailbox
27 ],
28 [From coyote@desert.example.org Sun May 6 22:16:47 2001
29 X-Sieve-Filtered: <kim@job.example.com>
30 From: coyote@desert.example.org
31 To: roadrunner@acme.example.com
32 Subject: I have a present for you
33 X-Caffeine: C8H10N4O2
34 Status:
35 X-UID: 1
36
37 Look, I'm sorry about the whole anvil thing, and I really
38 didn't mean to try and drop it on you from the top of the
39 cliff. I want to try to make it up to you. I've got some
40 great birdseed over here at my place--top of the line
41 stuff--and if you come by, I'll have it all wrapped up
42 for you. I'm really sorry for all the problems I've caused
43 for you over the years, but I know we can work this out.
44
45 --
46 Wile E. Coyote "Super Genius" coyote@desert.example.org
47
48 From b1ff@de.res.example.com Sun May 6 22:17:15 2001
49 X-Sieve-Filtered: <kim@job.example.com>
50 From: youcouldberich!@reply-by-postal-mail.invalid
51 To: rube@landru.example.edu
52 Subject: $$$ YOU, TOO, CAN BE A MILLIONAIRE! $$$
53 Date: TBD
54 X-Number: 0015
55 Status:
56 X-UID: 2
57
58 YOU MAY HAVE ALREADY WON TEN MILLION DOLLARS, BUT I DOUBT
59 IT! SO JUST POST THIS TO SIX HUNDRED NEWSGROUPS! IT WILL
60 GUARANTEE THAT YOU GET AT LEAST FIVE RESPONSES WITH MONEY!
61 MONEY! MONEY! COLD HARD CASH! YOU WILL RECEIVE OVER
62 $20,000 IN LESS THAN TWO MONTHS! AND IT'S LEGAL!!!!!!!!!
63 !!!!!!!!!!!!!!!!!!111111111!!!!!!!11111111111!!1 JUST
64 SEND $5 IN SMALL, UNMARKED BILLS TO THE ADDRESSES BELOW!
65
66 From bar@dontmailme.org Fri Dec 28 23:28:09 2001
67 X-Sieve-Filtered: <kim@job.example.com>
68 Received: (from bar@dontmailme.org)
69 by dontmailme.org id fERKR9N16790
70 for foobar@nonexistent.net; Fri, 28 Dec 2001 22:18:08 +0200
71 Date: Fri, 28 Dec 2001 23:28:08 +0200
72 From: Bar <bar@dontmailme.org>
73 To: Foo Bar <foobar@nonexistent.net>
74 Message-Id: <200112232808.fERKR9N16790@dontmailme.org>
75 Subject: Coffee
76 Status:
77 X-UID: 3
78
79 How about some coffee?
80
81 ],
82 [ADDHEADER on msg uid 1: X-Sieve-Filtered: <kim@job.example.com>
83 ADDHEADER on msg uid 2: X-Sieve-Filtered: <kim@job.example.com>
84 ADDHEADER on msg uid 3: X-Sieve-Filtered: <kim@job.example.com>
85 ])
86
87 MUT_SIEVE_EXT_TEST([append header],[addheader addheader01],
88 [require "editheader";
89 addheader :last "X-Sieve-Filtered" "<kim@job.example.com>";
90 ],
91 [MUT_MBCOPY($abs_top_srcdir/testsuite/spool/sieve.mbox,mailbox)
92 sieve MUT_SIEVE_CMDLINE MUT_SIEVE_OPTIONS -f ./mailbox prog
93 sed '/X-IMAPbase:/d;s/ *$//' mailbox
94 ],
95 [From coyote@desert.example.org Sun May 6 22:16:47 2001
96 From: coyote@desert.example.org
97 To: roadrunner@acme.example.com
98 Subject: I have a present for you
99 X-Caffeine: C8H10N4O2
100 X-Sieve-Filtered: <kim@job.example.com>
101 Status:
102 X-UID: 1
103
104 Look, I'm sorry about the whole anvil thing, and I really
105 didn't mean to try and drop it on you from the top of the
106 cliff. I want to try to make it up to you. I've got some
107 great birdseed over here at my place--top of the line
108 stuff--and if you come by, I'll have it all wrapped up
109 for you. I'm really sorry for all the problems I've caused
110 for you over the years, but I know we can work this out.
111
112 --
113 Wile E. Coyote "Super Genius" coyote@desert.example.org
114
115 From b1ff@de.res.example.com Sun May 6 22:17:15 2001
116 From: youcouldberich!@reply-by-postal-mail.invalid
117 To: rube@landru.example.edu
118 Subject: $$$ YOU, TOO, CAN BE A MILLIONAIRE! $$$
119 Date: TBD
120 X-Number: 0015
121 X-Sieve-Filtered: <kim@job.example.com>
122 Status:
123 X-UID: 2
124
125 YOU MAY HAVE ALREADY WON TEN MILLION DOLLARS, BUT I DOUBT
126 IT! SO JUST POST THIS TO SIX HUNDRED NEWSGROUPS! IT WILL
127 GUARANTEE THAT YOU GET AT LEAST FIVE RESPONSES WITH MONEY!
128 MONEY! MONEY! COLD HARD CASH! YOU WILL RECEIVE OVER
129 $20,000 IN LESS THAN TWO MONTHS! AND IT'S LEGAL!!!!!!!!!
130 !!!!!!!!!!!!!!!!!!111111111!!!!!!!11111111111!!1 JUST
131 SEND $5 IN SMALL, UNMARKED BILLS TO THE ADDRESSES BELOW!
132
133 From bar@dontmailme.org Fri Dec 28 23:28:09 2001
134 Received: (from bar@dontmailme.org)
135 by dontmailme.org id fERKR9N16790
136 for foobar@nonexistent.net; Fri, 28 Dec 2001 22:18:08 +0200
137 Date: Fri, 28 Dec 2001 23:28:08 +0200
138 From: Bar <bar@dontmailme.org>
139 To: Foo Bar <foobar@nonexistent.net>
140 Message-Id: <200112232808.fERKR9N16790@dontmailme.org>
141 Subject: Coffee
142 X-Sieve-Filtered: <kim@job.example.com>
143 Status:
144 X-UID: 3
145
146 How about some coffee?
147
148 ],
149 [ADDHEADER on msg uid 1: X-Sieve-Filtered: <kim@job.example.com>
150 ADDHEADER on msg uid 2: X-Sieve-Filtered: <kim@job.example.com>
151 ADDHEADER on msg uid 3: X-Sieve-Filtered: <kim@job.example.com>
152 ])
153
154 m4_popdef([MUT_SIEVE_EXT_NAME])
...\ No newline at end of file ...\ No newline at end of file
1 # This file is part of GNU Mailutils. -*- Autotest -*-
2 # Copyright (C) 2012 Free Software Foundation, Inc.
3 #
4 # GNU Mailutils is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3, or (at
7 # your option) any later version.
8 #
9 # GNU Mailutils is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
16
17 AT_BANNER([deleteheader])
18 m4_pushdef([MUT_SIEVE_EXT_NAME],[deleteheader])
19
20 m4_define([mkmailbox],[
21 AT_DATA([$1],
22 [From coyote@desert.example.org Sun May 6 22:16:47 2001
23 From: coyote@desert.example.org
24 To: roadrunner@acme.example.com
25 X-Agent: Agent A
26 Received: (from bar@example.org)
27 by example.org id fERKR9N16790
28 for roadrunner@example.com; Fri, 28 Dec 2001 22:18:08 +0200
29 X-Agent: Agent 22
30 X-Agent: Agent C
31 Subject: Ping
32
33 Test message, please discard.
34
35 ])])
36
37
38 MUT_SIEVE_EXT_TEST([delete all],[deleteheader delheader delheader00],
39 [require "editheader";
40 deleteheader "X-Agent";
41 ],
42 [mkmailbox(mailbox)
43 sieve MUT_SIEVE_CMDLINE MUT_SIEVE_OPTIONS -f ./mailbox prog
44 sed '/^X-IMAPbase:/d;/^Status:/d;/^X-UID:/d;s/ *$//' mailbox
45 ],
46 [From coyote@desert.example.org Sun May 6 22:16:47 2001
47 From: coyote@desert.example.org
48 To: roadrunner@acme.example.com
49 Received: (from bar@example.org)
50 by example.org id fERKR9N16790
51 for roadrunner@example.com; Fri, 28 Dec 2001 22:18:08 +0200
52 Subject: Ping
53
54 Test message, please discard.
55
56 ],
57 [DELETEHEADER on msg uid 1: X-Agent
58 ])
59
60 MUT_SIEVE_EXT_TEST([delete index],[deleteheader delheader delheader01],
61 [require "editheader";
62 deleteheader :index 1 "X-Agent";
63 ],
64 [mkmailbox(mailbox)
65 sieve MUT_SIEVE_CMDLINE MUT_SIEVE_OPTIONS -f ./mailbox prog
66 sed '/^X-IMAPbase:/d;/^Status:/d;/^X-UID:/d;s/ *$//' mailbox
67 ],
68 [From coyote@desert.example.org Sun May 6 22:16:47 2001
69 From: coyote@desert.example.org
70 To: roadrunner@acme.example.com
71 Received: (from bar@example.org)
72 by example.org id fERKR9N16790
73 for roadrunner@example.com; Fri, 28 Dec 2001 22:18:08 +0200
74 X-Agent: Agent 22
75 X-Agent: Agent C
76 Subject: Ping
77
78 Test message, please discard.
79
80 ],
81 [DELETEHEADER on msg uid 1: X-Agent
82 ])
83
84 MUT_SIEVE_EXT_TEST([delete index backwards],[deleteheader delheader delheader02],
85 [require "editheader";
86 deleteheader :index 2 :last "X-Agent";
87 ],
88 [mkmailbox(mailbox)
89 sieve MUT_SIEVE_CMDLINE MUT_SIEVE_OPTIONS -f ./mailbox prog
90 sed '/^X-IMAPbase:/d;/^Status:/d;/^X-UID:/d;s/ *$//' mailbox
91 ],
92 [From coyote@desert.example.org Sun May 6 22:16:47 2001
93 From: coyote@desert.example.org
94 To: roadrunner@acme.example.com
95 X-Agent: Agent A
96 Received: (from bar@example.org)
97 by example.org id fERKR9N16790
98 for roadrunner@example.com; Fri, 28 Dec 2001 22:18:08 +0200
99 X-Agent: Agent C
100 Subject: Ping
101
102 Test message, please discard.
103
104 ],
105 [DELETEHEADER on msg uid 1: X-Agent
106 ])
107
108 MUT_SIEVE_EXT_TEST([delete regex],[deleteheader delheader delheader03],
109 [require "editheader";
110 deleteheader :regex "X-Agent" "Agent [[A-Z]]";
111 ],
112 [mkmailbox(mailbox)
113 sieve MUT_SIEVE_CMDLINE MUT_SIEVE_OPTIONS -f ./mailbox prog
114 sed '/^X-IMAPbase:/d;/^Status:/d;/^X-UID:/d;s/ *$//' mailbox
115 ],
116 [From coyote@desert.example.org Sun May 6 22:16:47 2001
117 From: coyote@desert.example.org
118 To: roadrunner@acme.example.com
119 Received: (from bar@example.org)
120 by example.org id fERKR9N16790
121 for roadrunner@example.com; Fri, 28 Dec 2001 22:18:08 +0200
122 X-Agent: Agent 22
123 Subject: Ping
124
125 Test message, please discard.
126
127 ],
128 [DELETEHEADER on msg uid 1: X-Agent: (regexp)
129 ])
130
131 m4_popdef([MUT_SIEVE_EXT_NAME])
...@@ -147,6 +147,7 @@ m4_include([moderator.at]) ...@@ -147,6 +147,7 @@ m4_include([moderator.at])
147 m4_include([pipeact.at]) 147 m4_include([pipeact.at])
148 m4_include([pipetest.at]) 148 m4_include([pipetest.at])
149 m4_include([list.at]) 149 m4_include([list.at])
150 150 m4_include([addheader.at])
151 m4_include([delheader.at])
151 152
152 153
......