$Log$
+ Revision 573.108 2001/03/06 04:44:00 ajc
+ * Probable completion of STATUS, COPY, STORE, and EXPUNGE commands in IMAP
+
Revision 573.107 2001/03/06 03:31:58 nbryant
database-related cleanups and paranoia tests;
fixed a transaction-leak/deadlock problem in cdb_delete;
Fri Jul 10 1998 Art Cancro <ajc@uncensored.citadel.org>
* Initial CVS import
+
cprintf("UID %ld", IMAP->msgids[seq-1]);
}
-void imap_fetch_flags(struct CtdlMessage *msg) {
- cprintf("FLAGS ()"); /* FIXME do something here */
+void imap_fetch_flags(int seq) {
+ cprintf("FLAGS (");
+ if (IMAP->flags[seq] & IMAP_DELETED) cprintf("\\Deleted ");
+ cprintf(")");
}
void imap_fetch_internaldate(struct CtdlMessage *msg) {
imap_fetch_envelope(IMAP->msgids[seq-1], msg);
}
else if (!strcasecmp(itemlist[i], "FLAGS")) {
- imap_fetch_flags(msg);
+ imap_fetch_flags(seq-1);
}
else if (!strcasecmp(itemlist[i], "INTERNALDATE")) {
imap_fetch_internaldate(msg);
void imap_pick_range(char *range, int is_uid);
void imap_fetch(int num_parms, char *parms[]);
void imap_uidfetch(int num_parms, char *parms[]);
+void imap_fetch_flags(int seq);
int imap_extract_data_items(char **argv, char *items);
}
}
- return(1);
+ return(0);
}
* This function is called by the main command loop.
*/
void imap_copy(int num_parms, char *parms[]) {
+ int ret;
if (num_parms != 4) {
cprintf("%s BAD invalid parameters\r\n", parms[0]);
return;
}
- if (imap_do_copy(parms[3]) == 0) {
+ ret = imap_do_copy(parms[3]);
+ if (!ret) {
cprintf("%s OK COPY completed\r\n", parms[0]);
}
else {
- cprintf("%s NO COPY failed\r\n", parms[0]);
+ cprintf("%s NO COPY failed (error %d)\r\n", parms[0], ret);
}
}
* imap_do_store() calls imap_do_store_msg() to output the deta of an
* individual message, once it has been successfully loaded from disk.
*/
-void imap_do_store_msg(int seq, struct CtdlMessage *msg,
- int num_items, char **itemlist, int is_uid) {
-
+void imap_do_store_msg(int seq, char *oper, unsigned int bits_to_twiddle) {
+
+ if (!strncasecmp(oper, "FLAGS", 5)) {
+ IMAP->flags[seq] &= IMAP_MASK_SYSTEM;
+ IMAP->flags[seq] |= bits_to_twiddle;
+ }
+ else if (!strncasecmp(oper, "+FLAGS", 6)) {
+ IMAP->flags[seq] |= bits_to_twiddle;
+ }
+ else if (!strncasecmp(oper, "-FLAGS", 6)) {
+ IMAP->flags[seq] &= (~bits_to_twiddle);
+ }
+ cprintf("* %d FETCH (", seq+1);
+ imap_fetch_flags(seq);
+ cprintf(")\r\n");
}
/*
- * imap_store() calls imap_do_store() to do its actual work, once it's
- * validated and boiled down the request a bit.
+ * imap_store() calls imap_do_store() to perform the actual bit twiddling
+ * on flags. We brazenly ignore the ".silent" protocol option because it's not
+ * harmful to send the data anyway. Fix it yourself if you don't like that.
*/
-void imap_do_store(int num_items, char **itemlist, int is_uid) {
+void imap_do_store(int num_items, char **itemlist) {
int i;
- struct CtdlMessage *msg;
-
- if (IMAP->num_msgs > 0)
- for (i = 0; i < IMAP->num_msgs; ++i)
- if (IMAP->flags[i] && IMAP_SELECTED) {
- msg = CtdlFetchMessage(IMAP->msgids[i]);
- if (msg != NULL) {
- imap_do_store_msg(i+1, msg, num_items,
- itemlist, is_uid);
- CtdlFreeMessage(msg);
+ unsigned int bits_to_twiddle = 0;
+ char *oper;
+ char flag[SIZ];
+
+ if (num_items < 2) return;
+ oper = itemlist[0];
+
+ for (i=1; i<num_items; ++i) {
+ strcpy(flag, itemlist[i]);
+ if (flag[0]=='(') strcpy(flag, &flag[1]);
+ if (flag[strlen(flag)-1]==')') flag[strlen(flag)-1]=0;
+ striplt(flag);
+
+ if (!strcasecmp(flag, "\\Deleted")) {
+ bits_to_twiddle |= IMAP_DELETED;
}
- else {
- lprintf(1, "IMAP STORE internal error\n");
+ }
+
+ if (IMAP->num_msgs > 0) {
+ for (i = 0; i < IMAP->num_msgs; ++i) {
+ if (IMAP->flags[i] && IMAP_SELECTED) {
+ imap_do_store_msg(i, oper, bits_to_twiddle);
+ }
}
}
}
return;
}
- imap_do_store(num_items, itemlist, 0);
+ imap_do_store(num_items, itemlist);
cprintf("%s OK STORE completed\r\n", parms[0]);
}
return;
}
- imap_do_store(num_items, itemlist, 1);
+ imap_do_store(num_items, itemlist);
cprintf("%s OK UID STORE completed\r\n", parms[0]);
}
+/*
+ * does the real work for expunge
+ */
+int imap_do_expunge(void) {
+ int i;
+ int num_expunged = 0;
+
+ if (IMAP->num_msgs > 0) for (i=0; i<IMAP->num_msgs; ++i) {
+ if (IMAP->flags[i] & IMAP_DELETED) {
+ CtdlDeleteMessages(CC->quickroom.QRname,
+ IMAP->msgids[i], "");
+ ++num_expunged;
+ }
+ }
+
+ if (num_expunged > 0) {
+ imap_rescan_msgids();
+ }
+
+ return(num_expunged);
+}
+
+
+/*
+ * implements the EXPUNGE command syntax
+ */
+void imap_expunge(int num_parms, char *parms[]) {
+ int num_expunged = 0;
+ imap_do_expunge();
+ cprintf("%s OK expunged %d messages.\r\n", parms[0], num_expunged);
+}
+
+
/*
* implements the CLOSE command
*/
void imap_close(int num_parms, char *parms[]) {
+
+ /* Yes, we always expunge on close. */
+ imap_do_expunge();
+
IMAP->selected = 0;
IMAP->readonly = 0;
imap_free_msgids();
/* Fail here if no such room */
if (!ok) {
strcpy(returned_roomname, "");
- return(1);
+ return(2);
}
else {
strcpy(returned_roomname, QRscratch.QRname);
int ret;
char roomname[ROOMNAMELEN];
char buf[SIZ];
- struct quickroom QRscratch;
char savedroom[ROOMNAMELEN];
int msgs, new;
* FIXME we need to implement RECENT and UNSEEN eventually...
*/
- imap_mailboxname(buf, sizeof buf, &QRscratch);
+ imap_mailboxname(buf, sizeof buf, &CC->quickroom);
cprintf("* STATUS ");
imap_strout(buf);
cprintf(" (MESSAGES %d RECENT 0 UIDNEXT %ld "
imap_uidcopy(num_parms, parms);
}
+ else if (!strcasecmp(parms[1], "EXPUNGE")) {
+ imap_expunge(num_parms, parms);
+ }
+
else if (!strcasecmp(parms[1], "CLOSE")) {
imap_close(num_parms, parms);
}
/* Flags for the above struct. Note that some of these are for internal use,
* and are not to be reported to IMAP clients.
*/
-#define IMAP_ANSWERED 1
-#define IMAP_FLAGGED 2
-#define IMAP_DELETED 4
-#define IMAP_DRAFT 8
-#define IMAP_SEEN 16
-#define IMAP_SELECTED 32 /* internal */
+#define IMAP_ANSWERED 1
+#define IMAP_FLAGGED 2
+#define IMAP_DELETED 4
+#define IMAP_DRAFT 8
+#define IMAP_SEEN 16
+
+#define IMAP_MASK_SETABLE 0x1f
+#define IMAP_MASK_SYSTEM 0xe0
+
+#define IMAP_SELECTED 32 /* internal */
#define IMAP ((struct citimap *)CtdlGetUserData(SYM_IMAP))