preserve stringlengths when outputting stuff in the imap module
[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-2011 by the citadel.org team
6  *
7  *  This program is open source 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 "serv_imap.h"
59 #include "imap_tools.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         IReply("BAD not yet implemented FIXME");
72         return;
73 }
74
75
76 /*
77  * Implements the DELETEACL command.
78  */
79 void imap_deleteacl(int num_parms, ConstStr *Params) {
80
81         IReply("BAD not yet implemented FIXME");
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(StrBuf *rights, int ra)
91 {
92         FlushStrBuf(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                 StrBufAppendBufPlain(rights, HKEY("l"), 0);
102                 StrBufAppendBufPlain(rights, HKEY("r"), 0);
103                 StrBufAppendBufPlain(rights, HKEY("s"), 0);
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                         StrBufAppendBufPlain(rights, HKEY("i"), 0);
114                         StrBufAppendBufPlain(rights, HKEY("p"), 0);
115                         StrBufAppendBufPlain(rights, HKEY("c"), 0);
116                 }
117
118                 /* d - delete messages (STORE DELETED flag, perform EXPUNGE) */
119                 if (ra & UA_DELETEALLOWED) {
120                         StrBufAppendBufPlain(rights, HKEY("d"), 0);
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                          * StrBufAppendBufPlain(rights, HKEY("a"), 0);
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         StrBuf *rights;
152
153         if (num_parms != 3) {
154                 IReply("BAD usage error");
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                 IReply("NO Invalid mailbox name or access denied");
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         IAPuts("* ACL ");
177         IPutCParamStr(2);
178
179         /*
180          * Traverse the userlist
181          */
182         rights = NewStrBuf();
183         cdb_rewind(CDB_USERS);
184         while (cdbus = cdb_next_item(CDB_USERS), cdbus != NULL) 
185         {
186                 memset(&temp, 0, sizeof temp);
187                 memcpy(&temp, cdbus->ptr, sizeof temp);
188                 cdb_free(cdbus);
189
190                 CtdlRoomAccess(&CC->room, &temp, &ra, NULL);
191                 if (!IsEmptyStr(temp.fullname)) {
192                         imap_acl_flags(rights, ra);
193                         if (StrLength(rights) > 0) {
194                                 IAPuts(" ");
195                                 IPutStr(temp.fullname, strlen(temp.fullname));
196                                 IAPuts(" ");
197                                 iaputs(SKEY( rights));
198                         }
199                 }
200         }
201         FreeStrBuf(&rights);
202         IAPuts("\r\n");
203
204         /*
205          * If another folder is selected, go back to that room so we can resume
206          * our happy day without violent explosions.
207          */
208         if (IMAP->selected) {
209                 CtdlUserGoto(savedroom, 0, 0, &msgs, &new);
210         }
211
212         IReply("OK GETACL completed");
213 }
214
215
216 /*
217  * Implements the LISTRIGHTS command.
218  */
219 void imap_listrights(int num_parms, ConstStr *Params) {
220         char roomname[ROOMNAMELEN];
221         char savedroom[ROOMNAMELEN];
222         int msgs, new;
223         int ret;
224         recptypes *valid;
225         struct ctdluser temp;
226
227         if (num_parms != 4) {
228                 IReply("BAD usage error");
229                 return;
230         }
231
232         /*
233          * Search for the specified room/folder
234          */
235         ret = imap_grabroom(roomname, Params[2].Key, 1);
236         if (ret != 0) {
237                 IReply("NO Invalid mailbox name or access denied");
238                 return;
239         }
240
241         /*
242          * Search for the specified user
243          */
244         ret = (-1);
245         valid = validate_recipients(Params[3].Key, NULL, 0);
246         if (valid != NULL) {
247                 if (valid->num_local == 1) {
248                         ret = CtdlGetUser(&temp, valid->recp_local);
249                 }
250                 free_recipients(valid);
251         }
252         if (ret != 0) {
253                 IReply("NO Invalid user name or access denied");
254                 return;
255         }
256
257         /*
258          * CtdlUserGoto() formally takes us to the desired room.  (If another
259          * folder is selected, save its name so we can return there!!!!!)
260          */
261         if (IMAP->selected) {
262                 strcpy(savedroom, CC->room.QRname);
263         }
264         CtdlUserGoto(roomname, 0, 0, &msgs, &new);
265
266         /*
267          * Now output the list of rights
268          */
269         IAPuts("* LISTRIGHTS ");
270         IPutCParamStr(2);
271         IAPuts(" ");
272         IPutCParamStr(3);
273         IAPuts(" ");
274         IPutStr(HKEY(""));              /* FIXME ... do something here */
275         IAPuts("\r\n");
276
277         /*
278          * If another folder is selected, go back to that room so we can resume
279          * our happy day without violent explosions.
280          */
281         if (IMAP->selected) {
282                 CtdlUserGoto(savedroom, 0, 0, &msgs, &new);
283         }
284
285         IReply("OK LISTRIGHTS completed");
286         return;
287 }
288
289
290 /*
291  * Implements the MYRIGHTS command.
292  */
293 void imap_myrights(int num_parms, ConstStr *Params) {
294         char roomname[ROOMNAMELEN];
295         char savedroom[ROOMNAMELEN];
296         int msgs, new;
297         int ret;
298         int ra;
299         StrBuf *rights;
300
301         if (num_parms != 3) {
302                 IReply("BAD usage error");
303                 return;
304         }
305
306         ret = imap_grabroom(roomname, Params[2].Key, 1);
307         if (ret != 0) {
308                 IReply("NO Invalid mailbox name or access denied");
309                 return;
310         }
311
312         /*
313          * CtdlUserGoto() formally takes us to the desired room.  (If another
314          * folder is selected, save its name so we can return there!!!!!)
315          */
316         if (IMAP->selected) {
317                 strcpy(savedroom, CC->room.QRname);
318         }
319         CtdlUserGoto(roomname, 0, 0, &msgs, &new);
320
321         CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL);
322         rights = NewStrBuf();
323         imap_acl_flags(rights, ra);
324
325         IAPuts("* MYRIGHTS ");
326         IPutCParamStr(2);
327         IAPuts(" ");
328         IPutStr(SKEY(rights));
329         IAPuts("\r\n");
330
331         FreeStrBuf(&rights);
332
333         /*
334          * If a different folder was previously selected, return there now.
335          */
336         if ( (IMAP->selected) && (strcasecmp(roomname, savedroom)) ) {
337                 CtdlUserGoto(savedroom, 0, 0, &msgs, &new);
338         }
339
340         IReply("OK MYRIGHTS completed");
341         return;
342 }