imap client: implement status command
* include/mailutils/imap.h (mu_imap_status): New proto. (_mu_imap_status_name_table): New declaration. * include/mailutils/sys/imap.h (mu_imap_client_state) <MU_IMAP_STATUS_RX>: New state. * libproto/imap/status.c: New file. * libproto/imap/Makefile.am (libmu_imap_la_SOURCES): Add status.c * mu/imap.c: Implement "status"
Showing
5 changed files
with
273 additions
and
5 deletions
... | @@ -21,6 +21,7 @@ | ... | @@ -21,6 +21,7 @@ |
21 | #include <mailutils/iterator.h> | 21 | #include <mailutils/iterator.h> |
22 | #include <mailutils/debug.h> | 22 | #include <mailutils/debug.h> |
23 | #include <mailutils/stream.h> | 23 | #include <mailutils/stream.h> |
24 | #include <mailutils/kwd.h> | ||
24 | 25 | ||
25 | #ifdef __cplusplus | 26 | #ifdef __cplusplus |
26 | extern "C" { | 27 | extern "C" { |
... | @@ -95,6 +96,10 @@ struct mu_imap_stat | ... | @@ -95,6 +96,10 @@ struct mu_imap_stat |
95 | int mu_imap_select (mu_imap_t imap, const char *mbox, int writable, | 96 | int mu_imap_select (mu_imap_t imap, const char *mbox, int writable, |
96 | struct mu_imap_stat *ps); | 97 | struct mu_imap_stat *ps); |
97 | 98 | ||
99 | int mu_imap_status (mu_imap_t imap, const char *mbox, struct mu_imap_stat *ps); | ||
100 | |||
101 | extern struct mu_kwd _mu_imap_status_name_table[]; | ||
102 | |||
98 | #ifdef __cplusplus | 103 | #ifdef __cplusplus |
99 | } | 104 | } |
100 | #endif | 105 | #endif | ... | ... |
... | @@ -44,7 +44,8 @@ enum mu_imap_client_state | ... | @@ -44,7 +44,8 @@ enum mu_imap_client_state |
44 | MU_IMAP_LOGIN_RX, | 44 | MU_IMAP_LOGIN_RX, |
45 | MU_IMAP_LOGOUT_RX, | 45 | MU_IMAP_LOGOUT_RX, |
46 | MU_IMAP_ID_RX, | 46 | MU_IMAP_ID_RX, |
47 | MU_IMAP_SELECT_RX | 47 | MU_IMAP_SELECT_RX, |
48 | MU_IMAP_STATUS_RX | ||
48 | }; | 49 | }; |
49 | 50 | ||
50 | enum mu_imap_response | 51 | enum mu_imap_response | ... | ... |
libproto/imap/status.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | #include <mailutils/errno.h> | ||
25 | #include <mailutils/assoc.h> | ||
26 | #include <mailutils/stream.h> | ||
27 | #include <mailutils/imap.h> | ||
28 | #include <mailutils/sys/imap.h> | ||
29 | |||
30 | #define STATUS_FLAG_MASK \ | ||
31 | (MU_IMAP_STAT_MESSAGE_COUNT| \ | ||
32 | MU_IMAP_STAT_RECENT_COUNT| \ | ||
33 | MU_IMAP_STAT_UIDNEXT| \ | ||
34 | MU_IMAP_STAT_UIDVALIDITY| \ | ||
35 | MU_IMAP_STAT_FIRST_UNSEEN) | ||
36 | |||
37 | struct mu_kwd _mu_imap_status_name_table[] = { | ||
38 | { "MESSAGES", MU_IMAP_STAT_MESSAGE_COUNT }, | ||
39 | { "RECENT", MU_IMAP_STAT_RECENT_COUNT }, | ||
40 | { "UIDNEXT", MU_IMAP_STAT_UIDNEXT }, | ||
41 | { "UIDVALIDITY", MU_IMAP_STAT_UIDVALIDITY }, | ||
42 | { "UNSEEN", MU_IMAP_STAT_FIRST_UNSEEN }, | ||
43 | { NULL } | ||
44 | }; | ||
45 | |||
46 | static int | ||
47 | _status_mapper (void **itmv, size_t itmc, void *call_data) | ||
48 | { | ||
49 | struct mu_imap_stat *ps = call_data; | ||
50 | struct imap_list_element *kw = itmv[0], *val = itmv[1]; | ||
51 | size_t value; | ||
52 | char *p; | ||
53 | int flag; | ||
54 | |||
55 | if (kw->type != imap_eltype_string || val->type != imap_eltype_string) | ||
56 | return MU_ERR_PARSE; | ||
57 | if (mu_kwd_xlat_name_ci (_mu_imap_status_name_table, kw->v.string, &flag)) | ||
58 | return MU_ERR_PARSE; | ||
59 | |||
60 | value = strtoul (val->v.string, &p, 10); | ||
61 | if (*p) | ||
62 | return MU_ERR_PARSE; | ||
63 | |||
64 | ps->flags |= flag; | ||
65 | |||
66 | switch (flag) | ||
67 | { | ||
68 | case MU_IMAP_STAT_MESSAGE_COUNT: | ||
69 | ps->message_count = value; | ||
70 | break; | ||
71 | |||
72 | case MU_IMAP_STAT_RECENT_COUNT: | ||
73 | ps->recent_count = value; | ||
74 | break; | ||
75 | |||
76 | case MU_IMAP_STAT_UIDNEXT: | ||
77 | ps->uidnext = value; | ||
78 | break; | ||
79 | |||
80 | case MU_IMAP_STAT_UIDVALIDITY: | ||
81 | ps->uidvalidity = value; | ||
82 | break; | ||
83 | |||
84 | case MU_IMAP_STAT_FIRST_UNSEEN: | ||
85 | ps->first_unseen = value; | ||
86 | } | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int | ||
91 | _parse_status_response (mu_imap_t imap, const char *mboxname, | ||
92 | struct mu_imap_stat *ps) | ||
93 | { | ||
94 | struct imap_list_element *response, *elt; | ||
95 | size_t count; | ||
96 | int rc; | ||
97 | |||
98 | rc = mu_list_get (imap->untagged_resp, 0, (void*) &response); | ||
99 | if (rc) | ||
100 | return rc; | ||
101 | |||
102 | mu_list_count (response->v.list, &count); | ||
103 | if (count != 3) | ||
104 | return MU_ERR_PARSE; | ||
105 | rc = mu_list_get (response->v.list, 0, (void*) &elt); | ||
106 | if (rc) | ||
107 | return rc; | ||
108 | if (!_mu_imap_list_element_is_string (elt, "STATUS")) | ||
109 | return MU_ERR_NOENT; | ||
110 | |||
111 | rc = mu_list_get (response->v.list, 1, (void*) &elt); | ||
112 | if (rc) | ||
113 | return rc; | ||
114 | if (!_mu_imap_list_element_is_string (elt, mboxname)) | ||
115 | return MU_ERR_NOENT; | ||
116 | |||
117 | rc = mu_list_get (response->v.list, 2, (void*) &elt); | ||
118 | if (rc) | ||
119 | return rc; | ||
120 | if (elt->type != imap_eltype_list) | ||
121 | return MU_ERR_PARSE; | ||
122 | |||
123 | ps->flags = 0; | ||
124 | return mu_list_gmap (elt->v.list, _status_mapper, 2, ps); | ||
125 | } | ||
126 | |||
127 | int | ||
128 | mu_imap_status (mu_imap_t imap, const char *mboxname, struct mu_imap_stat *ps) | ||
129 | { | ||
130 | int status; | ||
131 | char *p; | ||
132 | int delim = 0; | ||
133 | int i; | ||
134 | |||
135 | if (imap == NULL) | ||
136 | return EINVAL; | ||
137 | if (!imap->io) | ||
138 | return MU_ERR_NO_TRANSPORT; | ||
139 | if (imap->state != MU_IMAP_CONNECTED) | ||
140 | return MU_ERR_SEQ; | ||
141 | if (imap->imap_state != MU_IMAP_STATE_AUTH && | ||
142 | imap->imap_state != MU_IMAP_STATE_SELECTED) | ||
143 | return MU_ERR_SEQ; | ||
144 | if (!ps) | ||
145 | return MU_ERR_OUT_PTR_NULL; | ||
146 | if ((ps->flags & STATUS_FLAG_MASK) == 0) | ||
147 | return EINVAL; | ||
148 | |||
149 | if (!mboxname) | ||
150 | { | ||
151 | if (imap->imap_state == MU_IMAP_STATE_SELECTED) | ||
152 | { | ||
153 | if (ps) | ||
154 | *ps = imap->mbox_stat; | ||
155 | return 0; | ||
156 | } | ||
157 | return EINVAL; | ||
158 | } | ||
159 | |||
160 | if (imap->mbox_name && strcmp (imap->mbox_name, mboxname) == 0) | ||
161 | { | ||
162 | if (ps) | ||
163 | *ps = imap->mbox_stat; | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | switch (imap->state) | ||
168 | { | ||
169 | case MU_IMAP_CONNECTED: | ||
170 | status = _mu_imap_tag_next (imap); | ||
171 | MU_IMAP_CHECK_EAGAIN (imap, status); | ||
172 | status = mu_imapio_printf (imap->io, "%s STATUS %s (", | ||
173 | imap->tag_str, mboxname); | ||
174 | MU_IMAP_CHECK_ERROR (imap, status); | ||
175 | delim = 0; | ||
176 | for (i = 0; status == 0 && _mu_imap_status_name_table[i].name; i++) | ||
177 | { | ||
178 | if (ps->flags & _mu_imap_status_name_table[i].tok) | ||
179 | { | ||
180 | if (delim) | ||
181 | status = mu_imapio_send (imap->io, " ", 1); | ||
182 | if (status == 0) | ||
183 | status = mu_imapio_printf (imap->io, "%s", | ||
184 | _mu_imap_status_name_table[i].name); | ||
185 | } | ||
186 | delim = 1; | ||
187 | } | ||
188 | if (status == 0) | ||
189 | status = mu_imapio_send (imap->io, ")\r\n", 3); | ||
190 | MU_IMAP_CHECK_ERROR (imap, status); | ||
191 | MU_IMAP_FCLR (imap, MU_IMAP_RESP); | ||
192 | imap->state = MU_IMAP_STATUS_RX; | ||
193 | |||
194 | case MU_IMAP_STATUS_RX: | ||
195 | status = _mu_imap_response (imap); | ||
196 | MU_IMAP_CHECK_EAGAIN (imap, status); | ||
197 | switch (imap->resp_code) | ||
198 | { | ||
199 | case MU_IMAP_OK: | ||
200 | memset (&imap->mbox_stat, 0, sizeof (imap->mbox_stat)); | ||
201 | status = _parse_status_response (imap, mboxname, ps); | ||
202 | break; | ||
203 | |||
204 | case MU_IMAP_NO: | ||
205 | status = EACCES; | ||
206 | break; | ||
207 | |||
208 | case MU_IMAP_BAD: | ||
209 | status = MU_ERR_BADREPLY; | ||
210 | if (mu_imapio_reply_string (imap->io, 2, &p) == 0) | ||
211 | { | ||
212 | _mu_imap_seterrstr (imap, p, strlen (p)); | ||
213 | free (p); | ||
214 | } | ||
215 | break; | ||
216 | } | ||
217 | imap->state = MU_IMAP_CONNECTED; | ||
218 | break; | ||
219 | |||
220 | default: | ||
221 | status = EINPROGRESS; | ||
222 | } | ||
223 | return status; | ||
224 | } |
... | @@ -520,6 +520,40 @@ com_examine (int argc, char **argv) | ... | @@ -520,6 +520,40 @@ com_examine (int argc, char **argv) |
520 | { | 520 | { |
521 | return select_mbox (argc, argv, 0); | 521 | return select_mbox (argc, argv, 0); |
522 | } | 522 | } |
523 | |||
524 | static int | ||
525 | com_status (int argc, char **argv) | ||
526 | { | ||
527 | struct mu_imap_stat st; | ||
528 | int i, flag; | ||
529 | int status; | ||
530 | |||
531 | st.flags = 0; | ||
532 | for (i = 2; i < argc; i++) | ||
533 | { | ||
534 | if (mu_kwd_xlat_name_ci (_mu_imap_status_name_table, argv[i], &flag)) | ||
535 | { | ||
536 | mu_error (_("unknown data item: %s"), argv[i]); | ||
537 | return 0; | ||
538 | } | ||
539 | st.flags |= flag; | ||
540 | } | ||
541 | |||
542 | status = mu_imap_status (imap, argv[1], &st); | ||
543 | if (status == 0) | ||
544 | { | ||
545 | print_imap_stats (&st); | ||
546 | } | ||
547 | else | ||
548 | { | ||
549 | const char *str; | ||
550 | |||
551 | mu_error ("status failed: %s", mu_strerror (status)); | ||
552 | if (mu_imap_strerror (imap, &str) == 0) | ||
553 | mu_error ("server reply: %s", str); | ||
554 | } | ||
555 | return 0; | ||
556 | } | ||
523 | 557 | ||
524 | 558 | ||
525 | struct mutool_command imap_comtab[] = { | 559 | struct mutool_command imap_comtab[] = { |
... | @@ -548,11 +582,14 @@ struct mutool_command imap_comtab[] = { | ... | @@ -548,11 +582,14 @@ struct mutool_command imap_comtab[] = { |
548 | N_("[-test KW] [ARG [ARG...]]"), | 582 | N_("[-test KW] [ARG [ARG...]]"), |
549 | N_("send ID command") }, | 583 | N_("send ID command") }, |
550 | { "select", 1, 2, com_select, | 584 | { "select", 1, 2, com_select, |
551 | N_("MBOX"), | 585 | N_("[MBOX]"), |
552 | N_("select a mailbox") }, | 586 | N_("select a mailbox") }, |
553 | { "examine", 1, 2, com_examine, | 587 | { "examine", 1, 2, com_examine, |
554 | N_("MBOX"), | 588 | N_("[MBOX]"), |
555 | N_("examine a mailbox") }, | 589 | N_("examine a mailbox") }, |
590 | { "status", 3, -1, com_status, | ||
591 | N_("MBOX KW [KW...]"), | ||
592 | N_("get mailbox status") }, | ||
556 | { "quit", 1, 1, com_logout, | 593 | { "quit", 1, 1, com_logout, |
557 | NULL, | 594 | NULL, |
558 | N_("same as `logout'") }, | 595 | N_("same as `logout'") }, | ... | ... |
-
Please register or sign in to post a comment