1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2021 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 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 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 #include "imap4d.h"
18
19 /*
20 *
21 */
22
23 typedef int (*status_funcp) (mu_mailbox_t);
24
25 static int status_messages (mu_mailbox_t);
26 static int status_recent (mu_mailbox_t);
27 static int status_uidnext (mu_mailbox_t);
28 static int status_uidvalidity (mu_mailbox_t);
29 static int status_unseen (mu_mailbox_t);
30
31 struct status_table {
32 char *name;
33 status_funcp fun;
34 } status_table[] = {
35 {"MESSAGES", status_messages},
36 {"RECENT", status_recent},
37 {"UIDNEXT", status_uidnext},
38 {"UIDVALIDITY", status_uidvalidity},
39 {"UNSEEN", status_unseen},
40 { NULL }
41 };
42
43 static status_funcp
status_get_handler(const char * name)44 status_get_handler (const char *name)
45 {
46 struct status_table *p;
47
48 for (p = status_table; p->name; p++)
49 if (mu_c_strcasecmp (p->name, name) == 0)
50 return p->fun;
51 return NULL;
52 }
53
54 /*
55 6.3.10. STATUS Command
56
57 Arguments: mailbox name
58 status data item names
59
60 Responses: untagged responses: STATUS
61
62 Result: OK - status completed
63 NO - status failure: no status for that name
64 BAD - command unknown or arguments invalid
65 */
66 int
imap4d_status(struct imap4d_session * session,struct imap4d_command * command,imap4d_tokbuf_t tok)67 imap4d_status (struct imap4d_session *session,
68 struct imap4d_command *command, imap4d_tokbuf_t tok)
69 {
70 char *name;
71 char *mailbox_name;
72 mu_mailbox_t smbox = NULL;
73 int status;
74 int count = 0;
75 char *err_msg = NULL;
76 int argc = imap4d_tokbuf_argc (tok);
77 mu_record_t record;
78
79 if (argc < 4)
80 return io_completion_response (command, RESP_BAD, "Invalid arguments");
81
82 name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
83
84 mailbox_name = namespace_get_name (name, &record, NULL);
85
86 if (!mailbox_name)
87 return io_completion_response (command, RESP_NO, "Error opening mailbox");
88
89 /* We may be opening the current mailbox, so make sure the attributes are
90 preserved */
91 imap4d_enter_critical ();
92 mu_mailbox_sync (mbox);
93 imap4d_leave_critical ();
94
95 status = mu_mailbox_create_from_record (&smbox, record, mailbox_name);
96 if (status == 0)
97 {
98 status = mu_mailbox_open (smbox, MU_STREAM_READ);
99 if (status == 0)
100 {
101 int space_sent = 0;
102 int i = IMAP4_ARG_2;
103 char *item = imap4d_tokbuf_getarg (tok, i);
104
105 if (item[0] == '(')
106 {
107 if (imap4d_tokbuf_getarg (tok, argc - 1)[0] != ')')
108 return io_completion_response (command, RESP_BAD,
109 "Invalid arguments");
110 argc--;
111 i++;
112 }
113
114 for (; i < argc; i++)
115 {
116 status_funcp fun;
117
118 item = imap4d_tokbuf_getarg (tok, i);
119 fun = status_get_handler (item);
120 if (!fun)
121 {
122 err_msg = "Invalid flag in list";
123 break;
124 }
125
126 if (count++ == 0)
127 io_sendf ("* STATUS %s (", name);
128 else if (!space_sent)
129 {
130 space_sent = 1;
131 io_sendf (" ");
132 }
133
134 if (!fun (smbox))
135 space_sent = 0;
136 }
137
138
139 if (count > 0)
140 io_sendf (")\n");
141 mu_mailbox_close (smbox);
142 }
143 mu_mailbox_destroy (&smbox);
144 }
145 free (mailbox_name);
146
147 if (status == 0)
148 {
149 if (count == 0)
150 return io_completion_response (command, RESP_BAD,
151 "Too few args (empty list)");
152 else if (err_msg)
153 return io_completion_response (command, RESP_BAD, "%s", err_msg);
154 return io_completion_response (command, RESP_OK, "Completed");
155 }
156
157 return io_completion_response (command, RESP_NO, "Error opening mailbox");
158 }
159
160 static int
status_messages(mu_mailbox_t smbox)161 status_messages (mu_mailbox_t smbox)
162 {
163 size_t total = 0;
164 mu_mailbox_messages_count (smbox, &total);
165 io_sendf ("MESSAGES %lu", (unsigned long) total);
166 return 0;
167 }
168
169 static int
status_recent(mu_mailbox_t smbox)170 status_recent (mu_mailbox_t smbox)
171 {
172 size_t recent = 0;
173 mu_mailbox_messages_recent (smbox, &recent);
174 io_sendf ("RECENT %lu", (unsigned long) recent);
175 return 0;
176 }
177
178 static int
status_uidnext(mu_mailbox_t smbox)179 status_uidnext (mu_mailbox_t smbox)
180 {
181 size_t uidnext = 1;
182 mu_mailbox_uidnext (smbox, &uidnext);
183 io_sendf ("UIDNEXT %lu", (unsigned long) uidnext);
184 return 0;
185 }
186
187 static int
status_uidvalidity(mu_mailbox_t smbox)188 status_uidvalidity (mu_mailbox_t smbox)
189 {
190 unsigned long uidvalidity = 0;
191 util_uidvalidity (smbox, &uidvalidity);
192 io_sendf ("UIDVALIDITY %lu", uidvalidity);
193 return 0;
194 }
195
196 /* Note that unlike the unseen response code, which indicates the message
197 number of the first unseen message, the unseeen item in the response the
198 status command indicates the quantity of unseen messages. */
199 static int
status_unseen(mu_mailbox_t smbox)200 status_unseen (mu_mailbox_t smbox)
201 {
202 size_t total = 0;
203 size_t unseen = 0;
204 size_t i;
205 mu_mailbox_messages_count (smbox, &total);
206 for (i = 1; i <= total; i++)
207 {
208 mu_message_t msg = NULL;
209 mu_attribute_t attr = NULL;
210 mu_mailbox_get_message (smbox, i, &msg);
211 mu_message_get_attribute (msg, &attr);
212 /* RFC 3501:
213 \Seen
214 Message has been read
215 */
216 if (!mu_attribute_is_read (attr))
217 unseen++;
218 }
219 io_sendf ("UNSEEN %lu", (unsigned long) unseen);
220 return 0;
221 }
222