--- ../tmp/imap-2002b/src/imapd/imapd.c Tue Jan 7 23:24:45 2003 +++ src/imapd/imapd.c Wed Feb 26 17:58:53 2003 @@ -239,6 +239,122 @@ msg_string_setpos /* set position in string structure */ }; + +/** + Start of the deleted_items patch by + Jason von Nieda . + This patch emulates a "Deleted Items" mailbox that + stores messages that have been deleted from other + mailboxes until they are deleted from itself. The + patch checks for the existance of a file called + .imapd_deleted_items in the user's home directory. + If the file exists the patch is enabled and any time + a message is expunged from any folder but the + Deleted Items folder it it first copied to the + Deleted Items folder. If a message is expunged from + the Deleted Items folder it is removed permanently. + The default Deleted Items folder is called + "Deleted Items". To specify an alternate folder + the .imapd_deleted_items file should contain + one line consisting of the folder name without + quotes. For instance, my file contains: + mail/Deleted Items + The following two functions make up the logic + for this patch. The server it patched in two other + places to enable it. In the handler for the + EXPUNGE command in main() and the handler for the + CLOSE command in main(). +**/ +/* trim leading and trailing whitespace from a string */ +char* strim(char* str) +{ + const static char* wspace = " \f\n\r\t\v"; + char* s = str; + char* e = str + strlen(str); + while (*s && strchr(wspace, *s)) s++; + strcpy(str, s); + while (e != str && strchr(wspace, *e)) { + *e = 0; + e--; + } + return(str); +} + +void copy_deleted_items(MAILSTREAM* stream) +{ + int i; + char options_file_path[512]; + char deleted_items_mailbox[512]; + strcpy(options_file_path, myhomedir()); + strcat(options_file_path, "/.imapd_deleted_items"); + *deleted_items_mailbox = 0; + if (!access(options_file_path, 4)) { + FILE* options_file; + if (options_file = fopen(options_file_path, "r")) { + if (fgets(deleted_items_mailbox, 512, options_file)) { + strim(deleted_items_mailbox); + } + fclose(options_file); + } + if (!*deleted_items_mailbox) strcpy(deleted_items_mailbox, "Deleted Items"); + } + if (*deleted_items_mailbox && + strcmp(deleted_items_mailbox, stream->original_mailbox)) { + char msg[512]; + SEARCHPGM *pgm; + char** searcharg = fs_get(sizeof(char*) * 2); + const size_t seqincr = 10240; + char* seq = fs_get(seqincr); + size_t seqsize = seqincr; + int nmsgs_copied = 0; + // parse_criteria seems to modify the pointer it's passed, so + // so I need to keep this around so I can free it later + char* searchargtmp = cpystr("DELETED"); + searcharg[0] = searchargtmp; + searcharg[1] = 0; + *seq = 0; + if (parse_criteria(pgm = mail_newsearchpgm(), searcharg, nmsgs, 0)) { + mail_search_full (stream,NIL,pgm,SE_FREE); + if (response == win || response == altwin) { + for (i = 1; i <= nmsgs; ++i) { + if (mail_elt(stream, i)->searched) { + if (strlen(seq) + 11 > seqsize) + fs_resize((void**) &seq, seqsize = strlen(seq) + seqincr); + if (*seq) sprintf(seq, "%s,%d", seq, i); + else sprintf(seq, "%d", i); + nmsgs_copied++; + } + } + if (nmsgs_copied) { + // we set the messages to not deleted before we copy so that + // they will show up as read but not deleted in the Deleted Items + // mailbox. Afterwards we have to re-delete them so expunge will + // work. This is sloppy but works for now. + // To make this more clean I need to find a way of getting a list of + // UIDs or sequences for the new messages in the target mailbox + mail_flag(stream, seq, "\\Deleted", ST_SILENT); + // this can fail with TRYCREATE. We should make sure the box is + // valid first so the client doesn't see that unexpected message + if(mail_copy_full(stream, seq, deleted_items_mailbox, NIL)) { + sprintf(msg, "* OK Saved %d deleted items to mailbox [%s]", nmsgs_copied, deleted_items_mailbox); + PSOUT(msg); + CRLF; + } + mail_flag(stream, seq, "\\Deleted", ST_SET | ST_SILENT); + } + } + } + else { + mail_free_searchpgm(&pgm); + } + fs_give((void**) &seq); + fs_give((void**) &searchargtmp); + fs_give((void**) &searcharg); + } +} +/* End of deleted_items patch */ + + /* Main program */ int main (int argc,char *argv[]) @@ -550,6 +666,7 @@ /* no arguments */ if (arg) response = badarg; else { + copy_deleted_items(stream); mail_expunge (stream); /* remember last checkpoint */ lastcheck = time (0); @@ -564,6 +681,7 @@ if (lastsel) fs_give ((void **) &lastsel); if (lastid) fs_give ((void **) &lastid); if (lastst.data) fs_give ((void **) &lastst.data); + if (!anonymous) copy_deleted_items(stream); stream = mail_close_full (stream,anonymous ? NIL : CL_EXPUNGE); state = SELECT; /* no longer opened */ lastcheck = 0; /* no last checkpoint */