--- ../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 <jason@vonnieda.org>.
+  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 */

