4 * IMAP METADATA extension
6 * This is an implementation of the Bynari variant of the METADATA extension.
8 * Copyright (c) 2007-2009 by the citadel.org team
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #include <sys/types.h>
36 #if TIME_WITH_SYS_TIME
37 # include <sys/time.h>
41 # include <sys/time.h>
51 #include <libcitadel.h>
54 #include "sysdep_decls.h"
55 #include "citserver.h"
63 #include "internet_addressing.h"
64 #include "serv_imap.h"
65 #include "imap_tools.h"
66 #include "imap_fetch.h"
67 #include "imap_misc.h"
73 * Implements the SETMETADATA command.
75 * Again, the only thing we're interested in setting here is the folder type.
77 * Attempting to set anything else calls a stub which fools the client into
78 * thinking that there is no remaining space available to store annotations.
80 void imap_setmetadata(int num_parms, char *parms[]) {
81 char roomname[ROOMNAMELEN];
82 char savedroom[ROOMNAMELEN];
85 int setting_user_value = 0;
87 int set_view = VIEW_BBS;
91 cprintf("%s BAD usage error\r\n", parms[0]);
96 * Don't allow other types of metadata to be set
98 if (strcasecmp(parms[3], "/vendor/kolab/folder-type")) {
99 cprintf("%s NO [METADATA TOOMANY] SETMETADATA failed\r\n", parms[0]);
103 if (!strcasecmp(parms[4], "(value.shared")) {
104 setting_user_value = 0; /* global view */
106 else if (!strcasecmp(parms[4], "(value.priv")) {
107 setting_user_value = 1; /* per-user view */
110 cprintf("%s NO [METADATA TOOMANY] SETMETADATA failed\r\n", parms[0]);
115 * Extract the folder type without any parentheses. Then learn
116 * the Citadel view type based on the supplied folder type.
118 extract_token(set_value, parms[5], 0, ')', sizeof set_value);
119 if (!strncasecmp(set_value, "mail", 4)) {
120 set_view = VIEW_MAILBOX;
122 else if (!strncasecmp(set_value, "event", 5)) {
123 set_view = VIEW_CALENDAR;
125 else if (!strncasecmp(set_value, "contact", 7)) {
126 set_view = VIEW_ADDRESSBOOK;
128 else if (!strncasecmp(set_value, "journal", 7)) {
129 set_view = VIEW_JOURNAL;
131 else if (!strncasecmp(set_value, "note", 4)) {
132 set_view = VIEW_NOTES;
134 else if (!strncasecmp(set_value, "task", 4)) {
135 set_view = VIEW_TASKS;
138 set_view = VIEW_MAILBOX;
141 ret = imap_grabroom(roomname, parms[2], 1);
143 cprintf("%s NO Invalid mailbox name or access denied\r\n",
149 * usergoto() formally takes us to the desired room. (If another
150 * folder is selected, save its name so we can return there!!!!!)
152 if (IMAP->selected) {
153 strcpy(savedroom, CC->room.QRname);
155 usergoto(roomname, 0, 0, &msgs, &new);
158 * Always set the per-user view to the requested one.
160 CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
161 vbuf.v_view = set_view;
162 CtdlSetRelationship(&vbuf, &CC->user, &CC->room);
164 /* If this is a "value.priv" set operation, we're done. */
166 if (setting_user_value)
168 cprintf("%s OK SETANNOTATION complete\r\n", parms[0]);
171 /* If this is a "value.shared" set operation, we are allowed to perform it
172 * under certain conditions.
174 else if ( (is_room_aide()) /* aide or room aide */
175 || ( (CC->room.QRflags & QR_MAILBOX)
176 && (CC->user.usernum == atol(CC->room.QRname)) /* mailbox owner */
178 || (msgs == 0) /* hack: if room is empty, assume we just created it */
180 lgetroom(&CC->room, CC->room.QRname);
181 CC->room.QRdefaultview = set_view;
183 cprintf("%s OK SETANNOTATION complete\r\n", parms[0]);
186 /* If we got to this point, we don't have permission to set the default view. */
188 cprintf("%s NO [METADATA TOOMANY] SETMETADATA failed\r\n", parms[0]);
192 * If a different folder was previously selected, return there now.
194 if ( (IMAP->selected) && (strcasecmp(roomname, savedroom)) ) {
195 usergoto(savedroom, 0, 0, &msgs, &new);
202 * Implements the GETMETADATA command.
204 * Regardless of what the client asked for, we are going to supply them with
205 * the folder type. It's the only metadata we have anyway.
207 void imap_getmetadata(int num_parms, char *parms[]) {
208 char roomname[ROOMNAMELEN];
209 char savedroom[ROOMNAMELEN];
214 cprintf("%s BAD usage error\r\n", parms[0]);
218 ret = imap_grabroom(roomname, parms[2], 1);
220 cprintf("%s NO Invalid mailbox name or access denied\r\n",
226 * usergoto() formally takes us to the desired room. (If another
227 * folder is selected, save its name so we can return there!!!!!)
229 if (IMAP->selected) {
230 strcpy(savedroom, CC->room.QRname);
232 usergoto(roomname, 0, 0, &msgs, &new);
234 cprintf("* METADATA ");
235 imap_strout(parms[2]);
236 cprintf(" \"/vendor/kolab/folder-type\" (\"value.shared\" \"");
238 /* If it's one of our hard-coded default rooms, we know what to do... */
240 if (!strcasecmp(&CC->room.QRname[11], MAILROOM)) {
241 cprintf("mail.inbox");
243 else if (!strcasecmp(&CC->room.QRname[11], SENTITEMS)) {
244 cprintf("mail.sentitems");
246 else if (!strcasecmp(&CC->room.QRname[11], USERDRAFTROOM)) {
247 cprintf("mail.drafts");
249 else if (!strcasecmp(&CC->room.QRname[11], USERCALENDARROOM)) {
250 cprintf("event.default");
252 else if (!strcasecmp(&CC->room.QRname[11], USERCONTACTSROOM)) {
253 cprintf("contact.default");
255 else if (!strcasecmp(&CC->room.QRname[11], USERNOTESROOM)) {
256 cprintf("note.default");
258 else if (!strcasecmp(&CC->room.QRname[11], USERTASKSROOM)) {
259 cprintf("task.default");
262 /* Otherwise, use the view for this room to determine the type of data.
263 * We are going with the default view rather than the user's view, because
264 * the default view almost always defines the actual contents, while the
265 * user's view might only make changes to presentation. It also saves us
266 * an extra database access because we don't need to load the visit record.
269 else if (CC->room.QRdefaultview == VIEW_CALENDAR) {
272 else if (CC->room.QRdefaultview == VIEW_ADDRESSBOOK) {
275 else if (CC->room.QRdefaultview == VIEW_TASKS) {
278 else if (CC->room.QRdefaultview == VIEW_NOTES) {
281 else if (CC->room.QRdefaultview == VIEW_JOURNAL) {
285 /* If none of the above conditions were met, consider it an ordinary mailbox. */
290 /* "mail.outbox" and "junkemail" are not implemented. */
295 * If a different folder was previously selected, return there now.
297 if ( (IMAP->selected) && (strcasecmp(roomname, savedroom)) ) {
298 usergoto(savedroom, 0, 0, &msgs, &new);
301 cprintf("%s OK GETMETADATA complete\r\n", parms[0]);