Annotated imap_list() for upcoming implementation of draft-ietf-imapext-list-extensio...
[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_list_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;
144         char *data_for_callback[3];
145
146         if (num_parms < 4) {
147                 cprintf("%s BAD arguments invalid\r\n", parms[0]);
148                 return;
149         }
150
151         /* parms[1] is the IMAP verb being used (e.g. LIST or LSUB)
152          * This tells us how to behave, and what verb to return back to the caller
153          */
154         safestrncpy(verb, parms[1], sizeof verb);
155         j = strlen(verb);
156         for (i=0; i<j; ++i) {
157                 verb[i] = toupper(verb[i]);
158         }
159
160         if (!strcasecmp(verb, "LSUB")) {
161                 subscribed_rooms_only = 1;
162         }
163
164         /*
165          * In order to implement draft-ietf-imapext-list-extensions-18
166          * ("LIST Command Extensions") we need to:
167          * 1. Extract "selection options"
168          * 2. Extract "return options"
169          * 3. Determine whether there is more than one match pattern
170          */
171
172         /* Citadel does not yet implement the abovementioned extension, and
173          * therefore the root and pattern will always be in these positions.
174          */
175         snprintf(pattern, sizeof pattern, "%s%s", parms[2], parms[3]);
176
177         data_for_callback[0] = pattern;
178         data_for_callback[1] = verb;
179         data_for_callback[2] = (char *) subscribed_rooms_only;
180
181         if (strlen(parms[3]) == 0) {
182                 cprintf("* %s (\\Noselect) \"/\" \"\"\r\n", verb);
183         }
184
185         else {
186                 imap_list_floors(verb, pattern);
187                 ForEachRoom(imap_list_listroom, data_for_callback);
188         }
189
190         cprintf("%s OK %s completed\r\n", parms[0], verb);
191 }
192
193