]> code.citadel.org Git - citadel.git/blob - citadel/imap_list.c
e878590ce9fd3ecf6f7445a8c5ea364c4b224e6e
[citadel.git] / citadel / imap_list.c
1 /*
2  * $Id$ 
3  *
4  * Implements the LIST and LSUB commands.
5  *
6  * Copyright (C) 2000-2007 by Art Cancro and others.
7  * This code is released under the terms of the GNU General Public License.
8  *
9  */
10
11 #include "sysdep.h"
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <fcntl.h>
16 #include <signal.h>
17 #include <pwd.h>
18 #include <errno.h>
19 #include <sys/types.h>
20
21 #if TIME_WITH_SYS_TIME
22 # include <sys/time.h>
23 # include <time.h>
24 #else
25 # if HAVE_SYS_TIME_H
26 #  include <sys/time.h>
27 # else
28 #  include <time.h>
29 # endif
30 #endif
31
32 #include <sys/wait.h>
33 #include <ctype.h>
34 #include <string.h>
35 #include <limits.h>
36 #include "citadel.h"
37 #include "server.h"
38 #include "sysdep_decls.h"
39 #include "citserver.h"
40 #include "support.h"
41 #include "config.h"
42 #include "serv_extensions.h"
43 #include "room_ops.h"
44 #include "user_ops.h"
45 #include "policy.h"
46 #include "database.h"
47 #include "msgbase.h"
48 #include "tools.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"
55 #include "imap_acl.h"
56 #include "imap_misc.h"
57
58 #ifdef HAVE_OPENSSL
59 #include "serv_crypto.h"
60 #endif
61
62 /*
63  * Used by LIST and LSUB to show the floors in the listing
64  */
65 void imap_list_floors(char *verb, char *pattern)
66 {
67         int i;
68         struct floor *fl;
69
70         for (i = 0; i < MAXFLOORS; ++i) {
71                 fl = cgetfloor(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);
77                                 cprintf("\r\n");
78                         }
79                 }
80         }
81 }
82
83
84 /*
85  * Back end for imap_list()
86  *
87  * Implementation note: IMAP "subscribed folder" is equivalent to Citadel "known room"
88  *
89  * The "user data" field is actually an array of pointers; see below for the breakdown
90  *
91  */
92 void imap_listroom(struct ctdlroom *qrbuf, void *data)
93 {
94         char buf[SIZ];
95         int ra;
96         int yes_output_this_room;
97
98         char **data_for_callback;
99         char *pattern;
100         char *verb;
101         int subscribed_rooms_only;
102
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];
108
109         /* Only list rooms to which the user has access!! */
110         yes_output_this_room = 0;
111         CtdlRoomAccess(qrbuf, &CC->user, &ra, NULL);
112
113         if (subscribed_rooms_only) {
114                 if (ra & UA_KNOWN) {
115                         yes_output_this_room = 1;
116                 }
117         }
118         else {
119                 if ((ra & UA_KNOWN) || ((ra & UA_GOTOALLOWED) && (ra & UA_ZAPPED))) {
120                         yes_output_this_room = 1;
121                 }
122         }
123
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);
128                         imap_strout(buf);
129                         cprintf("\r\n");
130                 }
131         }
132 }
133
134
135 /*
136  * Implements the LIST and LSUB commands
137  */
138 void imap_list(int num_parms, char *parms[])
139 {
140         char pattern[SIZ];
141         int subscribed_rooms_only = 0;
142         char verb[16];
143         int i, j, paren_nest;
144         char *data_for_callback[3];
145
146         int selection_left = (-1);
147         int selection_right = (-1);
148
149         int root_pos = 2;
150
151         if (num_parms < 4) {
152                 cprintf("%s BAD arguments invalid\r\n", parms[0]);
153                 return;
154         }
155
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
158          */
159         safestrncpy(verb, parms[1], sizeof verb);
160         j = strlen(verb);
161         for (i=0; i<j; ++i) {
162                 verb[i] = toupper(verb[i]);
163         }
164
165         if (!strcasecmp(verb, "LSUB")) {
166                 subscribed_rooms_only = 1;
167         }
168
169         /*
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
175          */
176
177         /*
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)
182          */
183         if (parms[2][0] == '(') {
184                 selection_left = 2;
185                 paren_nest = 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;
190                         }
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 */
195                         }
196                 }
197         }
198
199         /* The folder root appears immediately after the selection options,
200          * or in position 2 if no selection options were specified.
201          */
202         snprintf(pattern, sizeof pattern, "%s%s", parms[root_pos], parms[root_pos+1]);
203
204         data_for_callback[0] = pattern;
205         data_for_callback[1] = verb;
206         data_for_callback[2] = (char *) subscribed_rooms_only;
207
208         if (strlen(parms[3]) == 0) {
209                 cprintf("* %s (\\Noselect) \"/\" \"\"\r\n", verb);
210         }
211
212         else {
213                 imap_list_floors(verb, pattern);
214                 ForEachRoom(imap_listroom, data_for_callback);
215         }
216
217         cprintf("%s OK %s completed\r\n", parms[0], verb);
218 }
219
220