* rework imap tokenizer, we no longer copy the stuff around, we keep a reference...
[citadel.git] / citadel / modules / imap / imap_acl.c
1 /*
2  * $Id$
3  *
4  * Functions which implement RFC2086 (and maybe RFC4314) (IMAP ACL extension)
5  *
6  *
7  * Copyright (c) 2007-2009 by the citadel.org team
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 3 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "sysdep.h"
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <pwd.h>
31 #include <errno.h>
32 #include <sys/types.h>
33
34 #if TIME_WITH_SYS_TIME
35 # include <sys/time.h>
36 # include <time.h>
37 #else
38 # if HAVE_SYS_TIME_H
39 #  include <sys/time.h>
40 # else
41 #  include <time.h>
42 # endif
43 #endif
44
45 #include <sys/wait.h>
46 #include <ctype.h>
47 #include <string.h>
48 #include <limits.h>
49 #include <libcitadel.h>
50 #include "citadel.h"
51 #include "server.h"
52 #include "sysdep_decls.h"
53 #include "citserver.h"
54 #include "support.h"
55 #include "config.h"
56 #include "user_ops.h"
57 #include "policy.h"
58 #include "database.h"
59 #include "msgbase.h"
60 #include "internet_addressing.h"
61 #include "imap_tools.h"
62 #include "serv_imap.h"
63 #include "imap_fetch.h"
64 #include "imap_misc.h"
65 #include "genstamp.h"
66 #include "ctdl_module.h"
67
68
69 /*
70  * Implements the SETACL command.
71  */
72 void imap_setacl(int num_parms, ConstStr *Params) {
73
74         cprintf("%s BAD not yet implemented FIXME\r\n", Params[0].Key);
75         return;
76 }
77
78
79 /*
80  * Implements the DELETEACL command.
81  */
82 void imap_deleteacl(int num_parms, ConstStr *Params) {
83
84         cprintf("%s BAD not yet implemented FIXME\r\n", Params[0].Key);
85         return;
86 }
87
88
89 /*
90  * Given the bits returned by CtdlRoomAccess(), populate a string buffer
91  * with IMAP ACL format flags.   This code is common to GETACL and MYRIGHTS.
92  */
93 void imap_acl_flags(char *rights, int ra)
94 {
95         strcpy(rights, "");
96
97         /* l - lookup (mailbox is visible to LIST/LSUB commands)
98          * r - read (SELECT the mailbox, perform STATUS et al)
99          * s - keep seen/unseen information across sessions (STORE SEEN flag)
100          */
101         if (    (ra & UA_KNOWN)                                 /* known rooms */
102            ||   ((ra & UA_GOTOALLOWED) && (ra & UA_ZAPPED))     /* zapped rooms */
103         ) {
104                 strcat(rights, "l");
105                 strcat(rights, "r");
106                 strcat(rights, "s");
107
108                 /* Only output the remaining flags if the room is known */
109
110                 /* w - write (set or clear flags other than SEEN or DELETED, not supported in Citadel */
111
112                 /* i - insert (perform APPEND, COPY into mailbox) */
113                 /* p - post (send mail to submission address for mailbox - not enforced) */
114                 /* c - create (CREATE new sub-mailboxes) */
115                 if (ra & UA_POSTALLOWED) {
116                         strcat(rights, "i");
117                         strcat(rights, "p");
118                         strcat(rights, "c");
119                 }
120
121                 /* d - delete messages (STORE DELETED flag, perform EXPUNGE) */
122                 if (ra & UA_DELETEALLOWED) {
123                         strcat(rights, "d");
124                 }
125
126                 /* a - administer (perform SETACL/DELETEACL/GETACL/LISTRIGHTS) */
127                 if (ra & UA_ADMINALLOWED) {
128                         /*
129                          * This is the correct place to put the "a" flag.  We are leaving
130                          * it commented out for now, because it implies that we could
131                          * perform any of SETACL/DELETEACL/GETACL/LISTRIGHTS.  Since these
132                          * commands are not yet implemented, omitting the flag should
133                          * theoretically prevent compliant clients from attempting to
134                          * perform them.
135                          *
136                          * strcat(rights, "a");
137                          */
138                 }
139         }
140 }
141
142
143 /*
144  * Implements the GETACL command.
145  */
146 void imap_getacl(int num_parms, ConstStr *Params) {
147         char roomname[ROOMNAMELEN];
148         char savedroom[ROOMNAMELEN];
149         int msgs, new;
150         int ret;
151         struct ctdluser temp;
152         struct cdbdata *cdbus;
153         int ra;
154         char rights[32];
155
156         if (num_parms != 3) {
157                 cprintf("%s BAD usage error\r\n", Params[0].Key);
158                 return;
159         }
160
161         /*
162          * Search for the specified room or folder
163          */
164         ret = imap_grabroom(roomname, Params[2].Key, 1);
165         if (ret != 0) {
166                 cprintf("%s NO Invalid mailbox name or access denied\r\n", Params[0].Key);
167                 return;
168         }
169
170         /*
171          * CtdlUserGoto() formally takes us to the desired room.  (If another
172          * folder is selected, save its name so we can return there!!!!!)
173          */
174         if (IMAP->selected) {
175                 strcpy(savedroom, CC->room.QRname);
176         }
177         CtdlUserGoto(roomname, 0, 0, &msgs, &new);
178
179         cprintf("* ACL");
180         cprintf(" ");
181         imap_strout(&Params[2]);
182
183         /*
184          * Traverse the userlist
185          */
186         cdb_rewind(CDB_USERS);
187         while (cdbus = cdb_next_item(CDB_USERS), cdbus != NULL) {
188                 memset(&temp, 0, sizeof temp);
189                 memcpy(&temp, cdbus->ptr, sizeof temp);
190                 cdb_free(cdbus);
191
192                 CtdlRoomAccess(&CC->room, &temp, &ra, NULL);
193                 if (!IsEmptyStr(temp.fullname)) {
194                         imap_acl_flags(rights, ra);
195                         if (!IsEmptyStr(rights)) {
196                                 cprintf(" ");
197                                 plain_imap_strout(temp.fullname);
198                                 cprintf(" %s", rights);
199                         }
200                 }
201         }
202
203         cprintf("\r\n");
204
205         /*
206          * If another folder is selected, go back to that room so we can resume
207          * our happy day without violent explosions.
208          */
209         if (IMAP->selected) {
210                 CtdlUserGoto(savedroom, 0, 0, &msgs, &new);
211         }
212
213         cprintf("%s OK GETACL completed\r\n", Params[0].Key);
214 }
215
216
217 /*
218  * Implements the LISTRIGHTS command.
219  */
220 void imap_listrights(int num_parms, ConstStr *Params) {
221         char roomname[ROOMNAMELEN];
222         char savedroom[ROOMNAMELEN];
223         int msgs, new;
224         int ret;
225         struct recptypes *valid;
226         struct ctdluser temp;
227
228         if (num_parms != 4) {
229                 cprintf("%s BAD usage error\r\n", Params[0].Key);
230                 return;
231         }
232
233         /*
234          * Search for the specified room/folder
235          */
236         ret = imap_grabroom(roomname, Params[2].Key, 1);
237         if (ret != 0) {
238                 cprintf("%s NO Invalid mailbox name or access denied\r\n", Params[0].Key);
239                 return;
240         }
241
242         /*
243          * Search for the specified user
244          */
245         ret = (-1);
246         valid = validate_recipients(Params[3].Key, NULL, 0);
247         if (valid != NULL) {
248                 if (valid->num_local == 1) {
249                         ret = CtdlGetUser(&temp, valid->recp_local);
250                 }
251                 free_recipients(valid);
252         }
253         if (ret != 0) {
254                 cprintf("%s NO Invalid user name or access denied\r\n", Params[0].Key);
255                 return;
256         }
257
258         /*
259          * CtdlUserGoto() formally takes us to the desired room.  (If another
260          * folder is selected, save its name so we can return there!!!!!)
261          */
262         if (IMAP->selected) {
263                 strcpy(savedroom, CC->room.QRname);
264         }
265         CtdlUserGoto(roomname, 0, 0, &msgs, &new);
266
267         /*
268          * Now output the list of rights
269          */
270         cprintf("* LISTRIGHTS ");
271         imap_strout(&Params[2]);
272         cprintf(" ");
273         imap_strout(&Params[3]);
274         cprintf(" ");
275         plain_imap_strout("");          /* FIXME ... do something here */
276         cprintf("\r\n");
277
278         /*
279          * If another folder is selected, go back to that room so we can resume
280          * our happy day without violent explosions.
281          */
282         if (IMAP->selected) {
283                 CtdlUserGoto(savedroom, 0, 0, &msgs, &new);
284         }
285
286         cprintf("%s OK LISTRIGHTS completed\r\n", Params[0].Key);
287         return;
288 }
289
290
291 /*
292  * Implements the MYRIGHTS command.
293  */
294 void imap_myrights(int num_parms, ConstStr *Params) {
295         char roomname[ROOMNAMELEN];
296         char savedroom[ROOMNAMELEN];
297         int msgs, new;
298         int ret;
299         int ra;
300         char rights[32];
301
302         if (num_parms != 3) {
303                 cprintf("%s BAD usage error\r\n", Params[0].Key);
304                 return;
305         }
306
307         ret = imap_grabroom(roomname, Params[2].Key, 1);
308         if (ret != 0) {
309                 cprintf("%s NO Invalid mailbox name or access denied\r\n", Params[0].Key);
310                 return;
311         }
312
313         /*
314          * CtdlUserGoto() formally takes us to the desired room.  (If another
315          * folder is selected, save its name so we can return there!!!!!)
316          */
317         if (IMAP->selected) {
318                 strcpy(savedroom, CC->room.QRname);
319         }
320         CtdlUserGoto(roomname, 0, 0, &msgs, &new);
321
322         CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL);
323         imap_acl_flags(rights, ra);
324
325         cprintf("* MYRIGHTS ");
326         imap_strout(&Params[2]);
327         cprintf(" %s\r\n", rights);
328
329         /*
330          * If a different folder was previously selected, return there now.
331          */
332         if ( (IMAP->selected) && (strcasecmp(roomname, savedroom)) ) {
333                 CtdlUserGoto(savedroom, 0, 0, &msgs, &new);
334         }
335
336         cprintf("%s OK MYRIGHTS completed\r\n", Params[0].Key);
337         return;
338 }