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