Moved to new module init structure.
[citadel.git] / citadel / imap_metadata.c
1 /*
2  * $Id:  $
3  *
4  * IMAP METADATA extension
5  *
6  * This is a partial implementation of draft-daboo-imap-annotatemore-11
7  * intended to help a specific connector product work with Citadel.
8  *
9  */
10
11
12 #include "sysdep.h"
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <stdio.h>
16 #include <fcntl.h>
17 #include <signal.h>
18 #include <pwd.h>
19 #include <errno.h>
20 #include <sys/types.h>
21
22 #if TIME_WITH_SYS_TIME
23 # include <sys/time.h>
24 # include <time.h>
25 #else
26 # if HAVE_SYS_TIME_H
27 #  include <sys/time.h>
28 # else
29 #  include <time.h>
30 # endif
31 #endif
32
33 #include <sys/wait.h>
34 #include <ctype.h>
35 #include <string.h>
36 #include <limits.h>
37 #include "citadel.h"
38 #include "server.h"
39 #include "sysdep_decls.h"
40 #include "citserver.h"
41 #include "support.h"
42 #include "config.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_misc.h"
54 #include "genstamp.h"
55
56
57
58 /*
59  * Implements the SETMETADATA command.
60  *
61  * Again, the only thing we're interested in setting here is the folder type.
62  *
63  * Attempting to set anything else calls a stub which fools the client into
64  * thinking that there is no remaining space available to store annotations.
65  */
66 void imap_setmetadata(int num_parms, char *parms[]) {
67         char roomname[ROOMNAMELEN];
68         char savedroom[ROOMNAMELEN];
69         int msgs, new;
70         int ret;
71         int setting_user_value = 0;
72         char set_value[32];
73
74         if (num_parms != 6) {
75                 cprintf("%s BAD usage error\r\n", parms[0]);
76                 return;
77         }
78
79         /*
80          * Don't allow other types of metadata to be set
81          */
82         if (strcasecmp(parms[3], "/vendor/kolab/folder-type")) {
83                 cprintf("%s NO [METADATA TOOMANY] SETMETADATA failed\r\n", parms[0]);
84                 return;
85         }
86
87         if (!strcasecmp(parms[4], "(value.shared")) {
88                 setting_user_value = 0;                         /* global view */
89         }
90         else if (!strcasecmp(parms[4], "(value.priv")) {
91                 setting_user_value = 1;                         /* per-user view */
92         }
93         else {
94                 cprintf("%s NO [METADATA TOOMANY] SETMETADATA failed\r\n", parms[0]);
95                 return;
96         }
97
98         /*
99          * Extract the folder type without any parentheses.
100          */
101         extract_token(set_value, parms[5], 0, ')', sizeof set_value);
102
103         ret = imap_grabroom(roomname, parms[2], 0);
104         if (ret != 0) {
105                 cprintf("%s NO Invalid mailbox name or access denied\r\n",
106                         parms[0]);
107                 return;
108         }
109
110         /*
111          * usergoto() formally takes us to the desired room.  (If another
112          * folder is selected, save its name so we can return there!!!!!)
113          */
114         if (IMAP->selected) {
115                 strcpy(savedroom, CC->room.QRname);
116         }
117         usergoto(roomname, 0, 0, &msgs, &new);
118
119         /*
120          * FIXME ... NOW DO SOMETHING
121         roomname
122         set_value
123         setting_user_value
124          * on success: cprintf("%s OK SETANNOTATION complete\r\n", parms[0]);
125          */
126
127         cprintf("%s NO [METADATA TOOMANY] SETMETADATA failed\r\n", parms[0]);
128
129         /*
130          * If a different folder was previously selected, return there now.
131          */
132         if ( (IMAP->selected) && (strcasecmp(roomname, savedroom)) ) {
133                 usergoto(savedroom, 0, 0, &msgs, &new);
134         }
135         return;
136 }
137
138
139 /*
140  * Implements the GETMETADATA command.
141  *
142  * Regardless of what the client asked for, we are going to supply them with
143  * the folder type.  It's the only metadata we have anyway.
144  */
145 void imap_getmetadata(int num_parms, char *parms[]) {
146         char roomname[ROOMNAMELEN];
147         char savedroom[ROOMNAMELEN];
148         int msgs, new;
149         int ret;
150
151         if (num_parms > 5) {
152                 cprintf("%s BAD usage error\r\n", parms[0]);
153                 return;
154         }
155
156         ret = imap_grabroom(roomname, parms[2], 0);
157         if (ret != 0) {
158                 cprintf("%s NO Invalid mailbox name or access denied\r\n",
159                         parms[0]);
160                 return;
161         }
162
163         /*
164          * usergoto() formally takes us to the desired room.  (If another
165          * folder is selected, save its name so we can return there!!!!!)
166          */
167         if (IMAP->selected) {
168                 strcpy(savedroom, CC->room.QRname);
169         }
170         usergoto(roomname, 0, 0, &msgs, &new);
171
172         cprintf("* METADATA ");
173         imap_strout(parms[2]);
174         cprintf(" \"/vendor/kolab/folder-type\" (\"value.shared\" \"");
175
176         /* If it's one of our hard-coded default rooms, we know what to do... */
177
178         if (!strcasecmp(&CC->room.QRname[11], MAILROOM)) {
179                 cprintf("mail.inbox");
180         }
181         else if (!strcasecmp(&CC->room.QRname[11], SENTITEMS)) {
182                 cprintf("mail.sentitems");
183         }
184         else if (!strcasecmp(&CC->room.QRname[11], USERCALENDARROOM)) {
185                 cprintf("event.default");
186         }
187         else if (!strcasecmp(&CC->room.QRname[11], USERCONTACTSROOM)) {
188                 cprintf("contact.default");
189         }
190         else if (!strcasecmp(&CC->room.QRname[11], USERNOTESROOM)) {
191                 cprintf("note.default");
192         }
193         else if (!strcasecmp(&CC->room.QRname[11], USERTASKSROOM)) {
194                 cprintf("task.default");
195         }
196
197         /* Otherwise, use the view for this room to determine the type of data.
198          * We are going with the default view rather than the user's view, because
199          * the default view almost always defines the actual contents, while the
200          * user's view might only make changes to presentation.  It also saves us
201          * an extra database access because we don't need to load the visit record.
202          */
203
204         else if (CC->room.QRdefaultview == VIEW_CALENDAR) {
205                 cprintf("event");
206         }
207         else if (CC->room.QRdefaultview == VIEW_ADDRESSBOOK) {
208                 cprintf("contact");
209         }
210         else if (CC->room.QRdefaultview == VIEW_TASKS) {
211                 cprintf("task");
212         }
213         else if (CC->room.QRdefaultview == VIEW_NOTES) {
214                 cprintf("note");
215         }
216         else if (CC->room.QRdefaultview == VIEW_JOURNAL) {
217                 cprintf("journal");
218         }
219
220         /* If none of the above conditions were met, consider it an ordinary mailbox. */
221         else {
222                 cprintf("mail");
223         }
224
225         /* "mail.outbox" and "junkemail" are not implemented. */
226
227         cprintf("\")\r\n");
228
229         /*
230          * If a different folder was previously selected, return there now.
231          */
232         if ( (IMAP->selected) && (strcasecmp(roomname, savedroom)) ) {
233                 usergoto(savedroom, 0, 0, &msgs, &new);
234         }
235
236         cprintf("%s OK GETMETADATA complete\r\n", parms[0]);
237         return;
238 }
239