4 * IMAP METADATA extension
6 * This is an implementation of the Bynari variant of the METADATA extension.
19 #include <sys/types.h>
21 #if TIME_WITH_SYS_TIME
22 # include <sys/time.h>
26 # include <sys/time.h>
36 #include <libcitadel.h>
39 #include "sysdep_decls.h"
40 #include "citserver.h"
48 #include "internet_addressing.h"
49 #include "serv_imap.h"
50 #include "imap_tools.h"
51 #include "imap_fetch.h"
52 #include "imap_misc.h"
58 * Implements the SETMETADATA command.
60 * Again, the only thing we're interested in setting here is the folder type.
62 * Attempting to set anything else calls a stub which fools the client into
63 * thinking that there is no remaining space available to store annotations.
65 void imap_setmetadata(int num_parms, char *parms[]) {
66 char roomname[ROOMNAMELEN];
67 char savedroom[ROOMNAMELEN];
70 int setting_user_value = 0;
72 int set_view = VIEW_BBS;
76 cprintf("%s BAD usage error\r\n", parms[0]);
81 * Don't allow other types of metadata to be set
83 if (strcasecmp(parms[3], "/vendor/kolab/folder-type")) {
84 cprintf("%s NO [METADATA TOOMANY] SETMETADATA failed\r\n", parms[0]);
88 if (!strcasecmp(parms[4], "(value.shared")) {
89 setting_user_value = 0; /* global view */
91 else if (!strcasecmp(parms[4], "(value.priv")) {
92 setting_user_value = 1; /* per-user view */
95 cprintf("%s NO [METADATA TOOMANY] SETMETADATA failed\r\n", parms[0]);
100 * Extract the folder type without any parentheses. Then learn
101 * the Citadel view type based on the supplied folder type.
103 extract_token(set_value, parms[5], 0, ')', sizeof set_value);
104 if (!strncasecmp(set_value, "mail", 4)) {
105 set_view = VIEW_MAILBOX;
107 else if (!strncasecmp(set_value, "event", 5)) {
108 set_view = VIEW_CALENDAR;
110 else if (!strncasecmp(set_value, "contact", 7)) {
111 set_view = VIEW_ADDRESSBOOK;
113 else if (!strncasecmp(set_value, "journal", 7)) {
114 set_view = VIEW_JOURNAL;
116 else if (!strncasecmp(set_value, "note", 4)) {
117 set_view = VIEW_NOTES;
119 else if (!strncasecmp(set_value, "task", 4)) {
120 set_view = VIEW_TASKS;
123 set_view = VIEW_MAILBOX;
126 ret = imap_grabroom(roomname, parms[2], 1);
128 cprintf("%s NO Invalid mailbox name or access denied\r\n",
134 * usergoto() formally takes us to the desired room. (If another
135 * folder is selected, save its name so we can return there!!!!!)
137 if (IMAP->selected) {
138 strcpy(savedroom, CC->room.QRname);
140 usergoto(roomname, 0, 0, &msgs, &new);
143 * Always set the per-user view to the requested one.
145 CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
146 vbuf.v_view = set_view;
147 CtdlSetRelationship(&vbuf, &CC->user, &CC->room);
149 /* If this is a "value.priv" set operation, we're done. */
151 if (setting_user_value)
153 cprintf("%s OK SETANNOTATION complete\r\n", parms[0]);
156 /* If this is a "value.shared" set operation, we are allowed to perform it
157 * under certain conditions.
159 else if ( (is_room_aide()) /* aide or room aide */
160 || ( (CC->room.QRflags & QR_MAILBOX)
161 && (CC->user.usernum == atol(CC->room.QRname)) /* mailbox owner */
163 || (msgs == 0) /* hack: if room is empty, assume we just created it */
165 lgetroom(&CC->room, CC->room.QRname);
166 CC->room.QRdefaultview = set_view;
168 cprintf("%s OK SETANNOTATION complete\r\n", parms[0]);
171 /* If we got to this point, we don't have permission to set the default view. */
173 cprintf("%s NO [METADATA TOOMANY] SETMETADATA failed\r\n", parms[0]);
177 * If a different folder was previously selected, return there now.
179 if ( (IMAP->selected) && (strcasecmp(roomname, savedroom)) ) {
180 usergoto(savedroom, 0, 0, &msgs, &new);
187 * Implements the GETMETADATA command.
189 * Regardless of what the client asked for, we are going to supply them with
190 * the folder type. It's the only metadata we have anyway.
192 void imap_getmetadata(int num_parms, char *parms[]) {
193 char roomname[ROOMNAMELEN];
194 char savedroom[ROOMNAMELEN];
199 cprintf("%s BAD usage error\r\n", parms[0]);
203 ret = imap_grabroom(roomname, parms[2], 1);
205 cprintf("%s NO Invalid mailbox name or access denied\r\n",
211 * usergoto() formally takes us to the desired room. (If another
212 * folder is selected, save its name so we can return there!!!!!)
214 if (IMAP->selected) {
215 strcpy(savedroom, CC->room.QRname);
217 usergoto(roomname, 0, 0, &msgs, &new);
219 cprintf("* METADATA ");
220 imap_strout(parms[2]);
221 cprintf(" \"/vendor/kolab/folder-type\" (\"value.shared\" \"");
223 /* If it's one of our hard-coded default rooms, we know what to do... */
225 if (!strcasecmp(&CC->room.QRname[11], MAILROOM)) {
226 cprintf("mail.inbox");
228 else if (!strcasecmp(&CC->room.QRname[11], SENTITEMS)) {
229 cprintf("mail.sentitems");
231 else if (!strcasecmp(&CC->room.QRname[11], USERDRAFTROOM)) {
232 cprintf("mail.drafts");
234 else if (!strcasecmp(&CC->room.QRname[11], USERCALENDARROOM)) {
235 cprintf("event.default");
237 else if (!strcasecmp(&CC->room.QRname[11], USERCONTACTSROOM)) {
238 cprintf("contact.default");
240 else if (!strcasecmp(&CC->room.QRname[11], USERNOTESROOM)) {
241 cprintf("note.default");
243 else if (!strcasecmp(&CC->room.QRname[11], USERTASKSROOM)) {
244 cprintf("task.default");
247 /* Otherwise, use the view for this room to determine the type of data.
248 * We are going with the default view rather than the user's view, because
249 * the default view almost always defines the actual contents, while the
250 * user's view might only make changes to presentation. It also saves us
251 * an extra database access because we don't need to load the visit record.
254 else if (CC->room.QRdefaultview == VIEW_CALENDAR) {
257 else if (CC->room.QRdefaultview == VIEW_ADDRESSBOOK) {
260 else if (CC->room.QRdefaultview == VIEW_TASKS) {
263 else if (CC->room.QRdefaultview == VIEW_NOTES) {
266 else if (CC->room.QRdefaultview == VIEW_JOURNAL) {
270 /* If none of the above conditions were met, consider it an ordinary mailbox. */
275 /* "mail.outbox" and "junkemail" are not implemented. */
280 * If a different folder was previously selected, return there now.
282 if ( (IMAP->selected) && (strcasecmp(roomname, savedroom)) ) {
283 usergoto(savedroom, 0, 0, &msgs, &new);
286 cprintf("%s OK GETMETADATA complete\r\n", parms[0]);