Implement IMAP SEARCH. New function mu_mailbox_access_time.
* include/mailutils/imap.h (mu_imap_search): New proto. * libproto/imap/search.c: New file. * include/mailutils/sys/imap.h (MU_IMAP_CLIENT_SEARCH_RX): New state. * libproto/imap/fetch.c: Fix debugging categories * libproto/imap/mbox.c (_imap_messages_recent) (_imap_message_unseen): Use search if information is not readily available. * libproto/imap/status.c (_mu_imap_status_name_table): Comment out UNSEEN: its semantics is entirely different from what we need. * libproto/imap/Makefile.am: Add new file. * mu/imap.c: Implement search. * include/mailutils/sys/mailbox.h (_mu_mailbox) <_get_atime>: New method. * include/mailutils/mailbox.h (mu_mailbox_access_time): New proto. * libproto/mbox/mbox.c (_mailbox_mbox_init): Initialize >_get_atime. * libmailutils/mailbox/mailbox.c (mu_mailbox_access_time): New function. * libmailutils/datetime/utcoff.c (mu_utc_offset): Rewrite using tzset. * mh/msgchk.c: Implement --date. Check for new mail using both recent and unseen messages.
Showing
14 changed files
with
272 additions
and
18 deletions
... | @@ -143,6 +143,9 @@ int mu_imap_session_state_str (int state, const char **pstr); | ... | @@ -143,6 +143,9 @@ int mu_imap_session_state_str (int state, const char **pstr); |
143 | 143 | ||
144 | int mu_imap_tag (mu_imap_t imap, const char **pseq); | 144 | int mu_imap_tag (mu_imap_t imap, const char **pseq); |
145 | 145 | ||
146 | int mu_imap_search (mu_imap_t imap, int uid, const char *expr, | ||
147 | mu_msgset_t *msgset); | ||
148 | |||
146 | 149 | ||
147 | #define MU_IMAP_STAT_DEFINED_FLAGS 0x01 | 150 | #define MU_IMAP_STAT_DEFINED_FLAGS 0x01 |
148 | #define MU_IMAP_STAT_PERMANENT_FLAGS 0x02 | 151 | #define MU_IMAP_STAT_PERMANENT_FLAGS 0x02 | ... | ... |
... | @@ -20,7 +20,7 @@ | ... | @@ -20,7 +20,7 @@ |
20 | #define _MAILUTILS_MAILBOX_H | 20 | #define _MAILUTILS_MAILBOX_H |
21 | 21 | ||
22 | #include <sys/types.h> | 22 | #include <sys/types.h> |
23 | 23 | #include <time.h> | |
24 | #include <mailutils/types.h> | 24 | #include <mailutils/types.h> |
25 | 25 | ||
26 | #ifdef __cplusplus | 26 | #ifdef __cplusplus |
... | @@ -56,6 +56,7 @@ extern int mu_mailbox_get_folder (mu_mailbox_t, mu_folder_t *); | ... | @@ -56,6 +56,7 @@ extern int mu_mailbox_get_folder (mu_mailbox_t, mu_folder_t *); |
56 | extern int mu_mailbox_set_folder (mu_mailbox_t, mu_folder_t); | 56 | extern int mu_mailbox_set_folder (mu_mailbox_t, mu_folder_t); |
57 | extern int mu_mailbox_uidvalidity (mu_mailbox_t, unsigned long *); | 57 | extern int mu_mailbox_uidvalidity (mu_mailbox_t, unsigned long *); |
58 | extern int mu_mailbox_uidnext (mu_mailbox_t, size_t *); | 58 | extern int mu_mailbox_uidnext (mu_mailbox_t, size_t *); |
59 | extern int mu_mailbox_access_time (mu_mailbox_t mbox, time_t *return_time); | ||
59 | 60 | ||
60 | /* Messages. */ | 61 | /* Messages. */ |
61 | extern int mu_mailbox_get_message (mu_mailbox_t, size_t msgno, | 62 | extern int mu_mailbox_get_message (mu_mailbox_t, size_t msgno, | ... | ... |
... | @@ -71,6 +71,7 @@ enum mu_imap_client_state | ... | @@ -71,6 +71,7 @@ enum mu_imap_client_state |
71 | MU_IMAP_CLIENT_UNSUBSCRIBE_RX, | 71 | MU_IMAP_CLIENT_UNSUBSCRIBE_RX, |
72 | MU_IMAP_CLIENT_LSUB_RX, | 72 | MU_IMAP_CLIENT_LSUB_RX, |
73 | MU_IMAP_CLIENT_STARTTLS_RX, | 73 | MU_IMAP_CLIENT_STARTTLS_RX, |
74 | MU_IMAP_CLIENT_SEARCH_RX, | ||
74 | MU_IMAP_CLIENT_CLOSING | 75 | MU_IMAP_CLIENT_CLOSING |
75 | }; | 76 | }; |
76 | 77 | ... | ... |
... | @@ -20,6 +20,7 @@ | ... | @@ -20,6 +20,7 @@ |
20 | # define _MAILUTILS_SYS_MAILBOX_H | 20 | # define _MAILUTILS_SYS_MAILBOX_H |
21 | 21 | ||
22 | # include <sys/types.h> | 22 | # include <sys/types.h> |
23 | # include <time.h> | ||
23 | # include <stdio.h> | 24 | # include <stdio.h> |
24 | 25 | ||
25 | # include <mailutils/monitor.h> | 26 | # include <mailutils/monitor.h> |
... | @@ -76,6 +77,7 @@ struct _mu_mailbox | ... | @@ -76,6 +77,7 @@ struct _mu_mailbox |
76 | 77 | ||
77 | int (*_translate) (mu_mailbox_t, int cmd, size_t, size_t *); | 78 | int (*_translate) (mu_mailbox_t, int cmd, size_t, size_t *); |
78 | int (*_copy) (mu_mailbox_t, mu_msgset_t, const char *, int); | 79 | int (*_copy) (mu_mailbox_t, mu_msgset_t, const char *, int); |
80 | int (*_get_atime) (mu_mailbox_t, time_t *); | ||
79 | }; | 81 | }; |
80 | 82 | ||
81 | # ifdef __cplusplus | 83 | # ifdef __cplusplus | ... | ... |
... | @@ -20,13 +20,10 @@ | ... | @@ -20,13 +20,10 @@ |
20 | #endif | 20 | #endif |
21 | #include <time.h> | 21 | #include <time.h> |
22 | 22 | ||
23 | /* Convert time 0 at UTC to our localtime, that tells us the offset | 23 | /* Returns the offset of our timezone from UTC, in seconds. */ |
24 | of our current timezone from UTC. */ | ||
25 | int | 24 | int |
26 | mu_utc_offset (void) | 25 | mu_utc_offset (void) |
27 | { | 26 | { |
28 | time_t t = 0; | 27 | tzset (); |
29 | struct tm *tm = gmtime (&t); | 28 | return - timezone; |
30 | |||
31 | return - mktime (tm); | ||
32 | } | 29 | } | ... | ... |
... | @@ -918,3 +918,12 @@ mu_mailbox_translate (mu_mailbox_t mbox, int cmd, size_t from, size_t *to) | ... | @@ -918,3 +918,12 @@ mu_mailbox_translate (mu_mailbox_t mbox, int cmd, size_t from, size_t *to) |
918 | return rc; | 918 | return rc; |
919 | } | 919 | } |
920 | 920 | ||
921 | int | ||
922 | mu_mailbox_access_time (mu_mailbox_t mbox, time_t *return_time) | ||
923 | { | ||
924 | _MBOX_CHECK_Q (mbox, _get_atime); | ||
925 | if (!return_time) | ||
926 | return MU_ERR_OUT_PTR_NULL; | ||
927 | return mbox->_get_atime (mbox, return_time); | ||
928 | } | ||
929 | ... | ... |
... | @@ -1004,7 +1004,7 @@ _fetch_fold (void *item, void *data) | ... | @@ -1004,7 +1004,7 @@ _fetch_fold (void *item, void *data) |
1004 | 1004 | ||
1005 | if (!mt->name) | 1005 | if (!mt->name) |
1006 | { | 1006 | { |
1007 | mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_TRACE9, | 1007 | mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE9, |
1008 | ("ignoring unknown FETCH item '%s'", kw)); | 1008 | ("ignoring unknown FETCH item '%s'", kw)); |
1009 | env->state = resp_skip; | 1009 | env->state = resp_skip; |
1010 | return 0; | 1010 | return 0; |
... | @@ -1112,7 +1112,7 @@ _mu_imap_parse_fetch_response (mu_list_t input, mu_list_t *result_list) | ... | @@ -1112,7 +1112,7 @@ _mu_imap_parse_fetch_response (mu_list_t input, mu_list_t *result_list) |
1112 | status = mu_list_create (&result); | 1112 | status = mu_list_create (&result); |
1113 | if (status) | 1113 | if (status) |
1114 | { | 1114 | { |
1115 | mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, | 1115 | mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, |
1116 | ("mu_list_create: %s", mu_strerror (status))); | 1116 | ("mu_list_create: %s", mu_strerror (status))); |
1117 | return 1; | 1117 | return 1; |
1118 | } | 1118 | } | ... | ... |
... | @@ -812,7 +812,7 @@ _imap_messages_count (mu_mailbox_t mbox, size_t *pcount) | ... | @@ -812,7 +812,7 @@ _imap_messages_count (mu_mailbox_t mbox, size_t *pcount) |
812 | return MU_ERR_INFO_UNAVAILABLE; | 812 | return MU_ERR_INFO_UNAVAILABLE; |
813 | return 0; | 813 | return 0; |
814 | } | 814 | } |
815 | 815 | ||
816 | static int | 816 | static int |
817 | _imap_messages_recent (mu_mailbox_t mbox, size_t *pcount) | 817 | _imap_messages_recent (mu_mailbox_t mbox, size_t *pcount) |
818 | { | 818 | { |
... | @@ -820,7 +820,20 @@ _imap_messages_recent (mu_mailbox_t mbox, size_t *pcount) | ... | @@ -820,7 +820,20 @@ _imap_messages_recent (mu_mailbox_t mbox, size_t *pcount) |
820 | if (imbx->stats.flags & MU_IMAP_STAT_RECENT_COUNT) | 820 | if (imbx->stats.flags & MU_IMAP_STAT_RECENT_COUNT) |
821 | *pcount = imbx->stats.recent_count; | 821 | *pcount = imbx->stats.recent_count; |
822 | else | 822 | else |
823 | return MU_ERR_INFO_UNAVAILABLE; | 823 | { |
824 | int rc; | ||
825 | mu_folder_t folder = mbox->folder; | ||
826 | mu_imap_t imap = folder->data; | ||
827 | mu_msgset_t msgset; | ||
828 | |||
829 | rc = mu_imap_search (imap, 0, "RECENT", &msgset); | ||
830 | if (rc) | ||
831 | return rc; | ||
832 | |||
833 | rc = mu_msgset_count (msgset, pcount); | ||
834 | mu_msgset_free (msgset); | ||
835 | return rc; | ||
836 | } | ||
824 | return 0; | 837 | return 0; |
825 | } | 838 | } |
826 | 839 | ||
... | @@ -840,9 +853,36 @@ _imap_message_unseen (mu_mailbox_t mbox, size_t *pn) | ... | @@ -840,9 +853,36 @@ _imap_message_unseen (mu_mailbox_t mbox, size_t *pn) |
840 | { | 853 | { |
841 | struct _mu_imap_mailbox *imbx = mbox->data; | 854 | struct _mu_imap_mailbox *imbx = mbox->data; |
842 | if (imbx->stats.flags & MU_IMAP_STAT_FIRST_UNSEEN) | 855 | if (imbx->stats.flags & MU_IMAP_STAT_FIRST_UNSEEN) |
843 | *pn = imbx->stats.uidnext; | 856 | *pn = imbx->stats.first_unseen; |
844 | else | 857 | else |
845 | return MU_ERR_INFO_UNAVAILABLE; | 858 | { |
859 | int rc; | ||
860 | mu_folder_t folder = mbox->folder; | ||
861 | mu_imap_t imap = folder->data; | ||
862 | mu_msgset_t msgset; | ||
863 | mu_list_t list; | ||
864 | |||
865 | rc = mu_imap_search (imap, 0, "UNSEEN", &msgset); | ||
866 | if (rc) | ||
867 | return rc; | ||
868 | |||
869 | if (mu_msgset_is_empty (msgset)) | ||
870 | { | ||
871 | mu_msgset_free (msgset); | ||
872 | return MU_ERR_NOENT; | ||
873 | } | ||
874 | |||
875 | rc = mu_msgset_get_list (msgset, &list); | ||
876 | if (rc == 0) | ||
877 | { | ||
878 | struct mu_msgrange r; | ||
879 | rc = mu_list_head (list, (void **) &r); | ||
880 | if (rc == 0) | ||
881 | *pn = r.msg_beg; | ||
882 | } | ||
883 | mu_msgset_free (msgset); | ||
884 | return rc; | ||
885 | } | ||
846 | return 0; | 886 | return 0; |
847 | } | 887 | } |
848 | 888 | ... | ... |
libproto/imap/search.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011-2013 Free Software Foundation, Inc. | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Lesser General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 3 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library 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 GNU | ||
12 | Lesser General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Lesser General | ||
15 | Public License along with this library. If not, see | ||
16 | <http://www.gnu.org/licenses/>. */ | ||
17 | |||
18 | #include <config.h> | ||
19 | |||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | #include <mailutils/errno.h> | ||
23 | #include <mailutils/msgset.h> | ||
24 | #include <mailutils/nls.h> | ||
25 | #include <mailutils/imap.h> | ||
26 | #include <mailutils/sys/imap.h> | ||
27 | |||
28 | struct search_closure | ||
29 | { | ||
30 | mu_msgset_t msgset; | ||
31 | int retcode; | ||
32 | }; | ||
33 | |||
34 | static int | ||
35 | add_msgno (void *item, void *data) | ||
36 | { | ||
37 | int rc; | ||
38 | struct imap_list_element *elt = item; | ||
39 | struct search_closure *scp = data; | ||
40 | char *p; | ||
41 | unsigned long num; | ||
42 | |||
43 | if (elt->type != imap_eltype_string) | ||
44 | { | ||
45 | mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, | ||
46 | (_("unexpected list element in untagged response from SEARCH"))); | ||
47 | scp->retcode = MU_ERR_BADREPLY; | ||
48 | return 1; | ||
49 | } | ||
50 | |||
51 | if (!scp->msgset) | ||
52 | { | ||
53 | /* First element (SEARCH): create the message set and return */ | ||
54 | rc = mu_msgset_create (&scp->msgset, NULL, MU_MSGSET_NUM); | ||
55 | if (rc) | ||
56 | { | ||
57 | mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, | ||
58 | (_("cannot create msgset: %s"), | ||
59 | mu_strerror (rc))); | ||
60 | scp->retcode = rc; | ||
61 | return rc; | ||
62 | } | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | num = strtoul (elt->v.string, &p, 10); | ||
67 | if (*p) | ||
68 | { | ||
69 | mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, | ||
70 | (_("not a number in untagged response from SEARCH: %s"), | ||
71 | elt->v.string)); | ||
72 | scp->retcode = MU_ERR_BADREPLY; | ||
73 | return 1; | ||
74 | } | ||
75 | |||
76 | rc = mu_msgset_add_range (scp->msgset, num, num, MU_MSGSET_NUM); | ||
77 | if (rc) | ||
78 | { | ||
79 | mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, | ||
80 | ("mu_msgset_add_range: %s", mu_strerror (rc))); | ||
81 | scp->retcode = rc; | ||
82 | return 1; | ||
83 | } | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static void | ||
88 | search_handler (mu_imap_t imap, mu_list_t resp, void *data) | ||
89 | { | ||
90 | mu_list_foreach (resp, add_msgno, data); | ||
91 | } | ||
92 | |||
93 | int | ||
94 | mu_imap_search (mu_imap_t imap, int uid, const char *expr, mu_msgset_t *msgset) | ||
95 | { | ||
96 | char const *argv[3]; | ||
97 | int i, rc; | ||
98 | static struct imap_command com; | ||
99 | struct search_closure clos; | ||
100 | |||
101 | if (!expr) | ||
102 | return EINVAL; | ||
103 | if (!msgset) | ||
104 | return MU_ERR_OUT_PTR_NULL; | ||
105 | i = 0; | ||
106 | if (uid) | ||
107 | argv[i++] = "UID"; | ||
108 | argv[i++] = "SEARCH"; | ||
109 | |||
110 | clos.msgset = NULL; | ||
111 | clos.retcode = 0; | ||
112 | |||
113 | com.session_state = MU_IMAP_SESSION_SELECTED; | ||
114 | com.capa = NULL; | ||
115 | com.rx_state = MU_IMAP_CLIENT_SEARCH_RX; | ||
116 | com.argc = i; | ||
117 | com.argv = argv; | ||
118 | com.extra = expr; | ||
119 | com.msgset = NULL; | ||
120 | com.tagged_handler = NULL; | ||
121 | com.untagged_handler = search_handler; | ||
122 | com.untagged_handler_data = &clos; | ||
123 | rc = mu_imap_gencom (imap, &com); | ||
124 | if (rc) | ||
125 | mu_msgset_free (clos.msgset); | ||
126 | else if (clos.retcode) | ||
127 | { | ||
128 | mu_msgset_free (clos.msgset); | ||
129 | rc = clos.retcode; | ||
130 | } | ||
131 | else | ||
132 | *msgset = clos.msgset; | ||
133 | return rc; | ||
134 | } |
... | @@ -39,7 +39,7 @@ struct mu_kwd _mu_imap_status_name_table[] = { | ... | @@ -39,7 +39,7 @@ struct mu_kwd _mu_imap_status_name_table[] = { |
39 | { "RECENT", MU_IMAP_STAT_RECENT_COUNT }, | 39 | { "RECENT", MU_IMAP_STAT_RECENT_COUNT }, |
40 | { "UIDNEXT", MU_IMAP_STAT_UIDNEXT }, | 40 | { "UIDNEXT", MU_IMAP_STAT_UIDNEXT }, |
41 | { "UIDVALIDITY", MU_IMAP_STAT_UIDVALIDITY }, | 41 | { "UIDVALIDITY", MU_IMAP_STAT_UIDVALIDITY }, |
42 | { "UNSEEN", MU_IMAP_STAT_FIRST_UNSEEN }, | 42 | /* { "UNSEEN", MU_IMAP_STAT_NUM_UNSEEN }, */ |
43 | { NULL } | 43 | { NULL } |
44 | }; | 44 | }; |
45 | 45 | ... | ... |
... | @@ -1436,6 +1436,20 @@ mbox_expunge0 (mu_mailbox_t mailbox, int remove_deleted) | ... | @@ -1436,6 +1436,20 @@ mbox_expunge0 (mu_mailbox_t mailbox, int remove_deleted) |
1436 | return status; | 1436 | return status; |
1437 | } | 1437 | } |
1438 | 1438 | ||
1439 | static int | ||
1440 | mbox_get_atime (mu_mailbox_t mailbox, time_t *return_time) | ||
1441 | { | ||
1442 | mbox_data_t mud = mailbox->data; | ||
1443 | struct stat st; | ||
1444 | |||
1445 | if (mud == NULL) | ||
1446 | return EINVAL; | ||
1447 | if (stat (mud->name, &st)) | ||
1448 | return errno; | ||
1449 | *return_time = st.st_atime; | ||
1450 | return 0; | ||
1451 | } | ||
1452 | |||
1439 | 1453 | ||
1440 | /* Allocate the mbox_data_t struct(concrete mailbox), but don't do any | 1454 | /* Allocate the mbox_data_t struct(concrete mailbox), but don't do any |
1441 | parsing on the name or even test for existence. However we do strip any | 1455 | parsing on the name or even test for existence. However we do strip any |
... | @@ -1498,6 +1512,8 @@ _mailbox_mbox_init (mu_mailbox_t mailbox) | ... | @@ -1498,6 +1512,8 @@ _mailbox_mbox_init (mu_mailbox_t mailbox) |
1498 | 1512 | ||
1499 | mailbox->_get_size = mbox_get_size; | 1513 | mailbox->_get_size = mbox_get_size; |
1500 | 1514 | ||
1515 | mailbox->_get_atime = mbox_get_atime; | ||
1516 | |||
1501 | /* Set our properties. */ | 1517 | /* Set our properties. */ |
1502 | { | 1518 | { |
1503 | mu_property_t property = NULL; | 1519 | mu_property_t property = NULL; | ... | ... |
... | @@ -18,6 +18,7 @@ | ... | @@ -18,6 +18,7 @@ |
18 | #include "mailutils/kwd.h" | 18 | #include "mailutils/kwd.h" |
19 | #include "mailutils/folder.h" | 19 | #include "mailutils/folder.h" |
20 | #include "mailutils/auth.h" | 20 | #include "mailutils/auth.h" |
21 | #include "mailutils/datetime.h" | ||
21 | #include <pwd.h> | 22 | #include <pwd.h> |
22 | 23 | ||
23 | static char doc[] = N_("GNU MH msgchk")"\v" | 24 | static char doc[] = N_("GNU MH msgchk")"\v" |
... | @@ -295,11 +296,20 @@ checkmail (const char *username, int personal) | ... | @@ -295,11 +296,20 @@ checkmail (const char *username, int personal) |
295 | { | 296 | { |
296 | mu_off_t mbsiz = 0; | 297 | mu_off_t mbsiz = 0; |
297 | 298 | ||
298 | rc = mu_mailbox_messages_recent (mbox, &recent); | 299 | rc = mu_mailbox_message_unseen (mbox, &recent); |
299 | if (rc) | 300 | if (rc) |
300 | { | 301 | { |
301 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_messages_recent", | 302 | if (rc != ENOSYS && rc != MU_ERR_INFO_UNAVAILABLE) |
302 | mu_url_to_string (url), rc); | 303 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_messages_unseen", |
304 | mu_url_to_string (url), rc); | ||
305 | rc = mu_mailbox_messages_recent (mbox, &recent); | ||
306 | } | ||
307 | |||
308 | if (rc) | ||
309 | { | ||
310 | if (rc != ENOSYS && rc != MU_ERR_INFO_UNAVAILABLE) | ||
311 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_messages_recent", | ||
312 | mu_url_to_string (url), rc); | ||
303 | 313 | ||
304 | mu_mailbox_get_size (mbox, &mbsiz); | 314 | mu_mailbox_get_size (mbox, &mbsiz); |
305 | if (personal) | 315 | if (personal) |
... | @@ -327,7 +337,14 @@ checkmail (const char *username, int personal) | ... | @@ -327,7 +337,14 @@ checkmail (const char *username, int personal) |
327 | } | 337 | } |
328 | 338 | ||
329 | if (date_option) | 339 | if (date_option) |
330 | /*FIXME*/; | 340 | { |
341 | time_t t; | ||
342 | |||
343 | if (mu_mailbox_access_time (mbox, &t) == 0) | ||
344 | mu_c_streamftime (mu_strout, | ||
345 | _("; last read on %a, %d %b %Y %H:%M:%S %z"), | ||
346 | localtime (&t), NULL); | ||
347 | } | ||
331 | 348 | ||
332 | mu_printf ("\n"); | 349 | mu_printf ("\n"); |
333 | } | 350 | } | ... | ... |
... | @@ -1122,6 +1122,35 @@ com_copy (int argc, char **argv) | ... | @@ -1122,6 +1122,35 @@ com_copy (int argc, char **argv) |
1122 | } | 1122 | } |
1123 | 1123 | ||
1124 | static int | 1124 | static int |
1125 | com_search (int argc, char **argv) | ||
1126 | { | ||
1127 | mu_msgset_t mset; | ||
1128 | size_t count; | ||
1129 | int rc; | ||
1130 | |||
1131 | rc = mu_imap_search (imap, uid_mode, argv[1], &mset); | ||
1132 | if (rc) | ||
1133 | { | ||
1134 | report_failure ("search", rc); | ||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | rc = mu_msgset_count (mset, &count); | ||
1139 | if (rc == EINVAL || count == 0) | ||
1140 | { | ||
1141 | mu_printf (_("no matches")); | ||
1142 | return 0; | ||
1143 | } | ||
1144 | mu_printf ("%lu matches:", (unsigned long) count); | ||
1145 | mu_msgset_print (mu_strout, mset); | ||
1146 | mu_printf ("\n"); | ||
1147 | mu_msgset_free (mset); | ||
1148 | |||
1149 | return 0; | ||
1150 | } | ||
1151 | |||
1152 | |||
1153 | static int | ||
1125 | print_list_item (void *item, void *data) | 1154 | print_list_item (void *item, void *data) |
1126 | { | 1155 | { |
1127 | struct mu_list_response *resp = item; | 1156 | struct mu_list_response *resp = item; |
... | @@ -1293,6 +1322,10 @@ struct mutool_command imap_comtab[] = { | ... | @@ -1293,6 +1322,10 @@ struct mutool_command imap_comtab[] = { |
1293 | com_uid, | 1322 | com_uid, |
1294 | N_("[on|off]"), | 1323 | N_("[on|off]"), |
1295 | N_("control UID mode") }, | 1324 | N_("control UID mode") }, |
1325 | { "search", 2, 2, CMD_COALESCE_EXTRA_ARGS, | ||
1326 | com_search, | ||
1327 | N_("args..."), | ||
1328 | N_("search the mailbox") }, | ||
1296 | { "quit", 1, 1, 0, | 1329 | { "quit", 1, 1, 0, |
1297 | com_logout, | 1330 | com_logout, |
1298 | NULL, | 1331 | NULL, | ... | ... |
-
Please register or sign in to post a comment