4 * Implements the LIST and LSUB commands.
6 * Copyright (C) 2000-2007 by Art Cancro and others.
7 * This code is released under the terms of the GNU General Public License.
19 #include <sys/types.h>
21 #if TIME_WITH_SYS_TIME
22 # include <sys/time.h>
26 # include <sys/time.h>
38 #include "sysdep_decls.h"
39 #include "citserver.h"
42 #include "serv_extensions.h"
49 #include "internet_addressing.h"
50 #include "serv_imap.h"
51 #include "imap_tools.h"
52 #include "imap_fetch.h"
53 #include "imap_search.h"
54 #include "imap_store.h"
56 #include "imap_misc.h"
59 #include "serv_crypto.h"
63 * Used by LIST and LSUB to show the floors in the listing
65 void imap_list_floors(char *verb, char *pattern)
70 for (i = 0; i < MAXFLOORS; ++i) {
72 if (fl->f_flags & F_INUSE) {
73 if (imap_mailbox_matches_pattern
74 (pattern, fl->f_name)) {
75 cprintf("* %s (\\NoSelect) \"/\" ", verb);
76 imap_strout(fl->f_name);
85 * Back end for imap_list()
87 * Implementation note: IMAP "subscribed folder" is equivalent to Citadel "known room"
89 * The "user data" field is actually an array of pointers; see below for the breakdown
92 void imap_listroom(struct ctdlroom *qrbuf, void *data)
96 int yes_output_this_room;
98 char **data_for_callback;
101 int subscribed_rooms_only;
103 /* Here's how we break down the array of pointers passed to us */
104 data_for_callback = data;
105 pattern = data_for_callback[0];
106 verb = data_for_callback[1];
107 subscribed_rooms_only = (int) data_for_callback[2];
109 /* Only list rooms to which the user has access!! */
110 yes_output_this_room = 0;
111 CtdlRoomAccess(qrbuf, &CC->user, &ra, NULL);
113 if (subscribed_rooms_only) {
115 yes_output_this_room = 1;
119 if ((ra & UA_KNOWN) || ((ra & UA_GOTOALLOWED) && (ra & UA_ZAPPED))) {
120 yes_output_this_room = 1;
124 if (yes_output_this_room) {
125 imap_mailboxname(buf, sizeof buf, qrbuf);
126 if (imap_mailbox_matches_pattern(pattern, buf)) {
127 cprintf("* %s () \"/\" ", verb);
136 * Implements the LIST and LSUB commands
138 void imap_list(int num_parms, char *parms[])
141 int subscribed_rooms_only = 0;
143 int i, j, paren_nest;
144 char *data_for_callback[3];
146 int selection_left = (-1);
147 int selection_right = (-1);
152 cprintf("%s BAD arguments invalid\r\n", parms[0]);
156 /* parms[1] is the IMAP verb being used (e.g. LIST or LSUB)
157 * This tells us how to behave, and what verb to return back to the caller
159 safestrncpy(verb, parms[1], sizeof verb);
161 for (i=0; i<j; ++i) {
162 verb[i] = toupper(verb[i]);
165 if (!strcasecmp(verb, "LSUB")) {
166 subscribed_rooms_only = 1;
170 * In order to implement draft-ietf-imapext-list-extensions-18
171 * ("LIST Command Extensions") we need to:
172 * 1. Extract "selection options"
173 * 2. Extract "return options"
174 * 3. Determine whether there is more than one match pattern
178 * If parameter 2 begins with a '(' character, the client is specifying
179 * selection options. Extract their exact position, and then modify our
180 * expectation of where the root folder will be specified.
181 * (FIXME this is part of draft-ietf-imapext-list-extensions-18, not finished yet)
183 if (parms[2][0] == '(') {
186 for (i=2; i<num_parms; ++i) {
187 for (j=0; j<strlen(parms[i]); ++j) {
188 if (parms[i][j] == '(') ++paren_nest;
189 if (parms[i][j] == ')') --paren_nest;
191 if (paren_nest == 0) {
192 selection_right = i; /* found end of selection options */
193 root_pos = i+1; /* folder root appears after selection options */
194 i = num_parms + 1; /* break out of the loop */
199 /* The folder root appears immediately after the selection options,
200 * or in position 2 if no selection options were specified.
202 snprintf(pattern, sizeof pattern, "%s%s", parms[root_pos], parms[root_pos+1]);
204 data_for_callback[0] = pattern;
205 data_for_callback[1] = verb;
206 data_for_callback[2] = (char *) subscribed_rooms_only;
208 if (strlen(parms[3]) == 0) {
209 cprintf("* %s (\\Noselect) \"/\" \"\"\r\n", verb);
213 imap_list_floors(verb, pattern);
214 ForEachRoom(imap_listroom, data_for_callback);
217 cprintf("%s OK %s completed\r\n", parms[0], verb);