--- /dev/null
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+
+#define ARCHIVE_PREFIX "Archive-"
+
+char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+char fromfolder[512];
+char fromdirectory[512];
+int skipped = 0;
+
+struct folder_list_t {
+ char *name;
+ int emails;
+ struct folder_list_t *next;
+};
+
+struct folder_list_t *folderhead;
+
+void move_email(const char *name, const char *folder)
+{
+ struct folder_list_t *lp;
+ int foundfolder = 0;
+ char oldfilename[512];
+ char filename[512];
+
+ for (lp = folderhead; lp->next; lp = lp->next)
+ if (!strcmp(folder, lp->name))
+ break;
+
+ if (!lp->next)
+ {
+ int fd;
+
+ lp = malloc(sizeof(*folderhead));
+ lp->next = folderhead;
+ lp->emails = 0;
+ lp->name = strdup(folder);
+ folderhead = lp;
+
+ /* create the folder */
+ sprintf(filename, ".INBOX.%s", folder);
+ mkdir(filename, 0700);
+
+ sprintf(filename, ".INBOX.%s/cur", folder);
+ if (mkdir(filename, 0700) && (errno != EEXIST))
+ {
+ perror("mkdir(cur)");
+ exit(1);
+ }
+
+ sprintf(filename, ".INBOX.%s/new", folder);
+ if (mkdir(filename, 0700) && (errno != EEXIST))
+ {
+ perror("mkdir(new)");
+ exit(1);
+ }
+
+ sprintf(filename, ".INBOX.%s/tmp", folder);
+ if (mkdir(filename, 0700) && (errno != EEXIST))
+ {
+ perror("mkdir(tmp)");
+ exit(1);
+ }
+
+ sprintf(filename, ".INBOX.%s/maildirfolder", folder);
+ if ((fd = open(filename, O_CREAT | O_WRONLY, 0700)) < 0)
+ {
+ perror("open(maildirfolder)");
+ exit(1);
+ }
+ close(fd);
+ }
+
+ lp->emails++;
+
+ sprintf(oldfilename, "%s/%s", fromdirectory, name);
+ sprintf(filename, ".INBOX.%s/cur/%s", folder, name);
+
+ /* skipped if it's the same thing, since the link won't catch it, and the unlink will kill it */
+ if (!strcmp(oldfilename, filename))
+ {
+ skipped++;
+ return;
+ }
+
+ if (link(oldfilename, filename) && (errno != EEXIST))
+ {
+ char theerror[1024];
+ sprintf(theerror, "link(%s, %s)", oldfilename, filename);
+ perror(theerror);
+ exit(1);
+ }
+
+ if (unlink(oldfilename))
+ {
+ char theerror[1024];
+ sprintf(theerror, "unlink(%s)", oldfilename);
+ perror(theerror);
+ exit(1);
+ }
+}
+
+int spinnerstate = 0;
+char spinner[] = "/-\\|";
+#define SPINNERSTATES 4
+#define MAXAGE 7*24*60*60
+
+void main(int argc, char **argv)
+{
+ DIR *cur;
+ struct dirent *de;
+ off_t dirstart;
+ int emails = 0, notemails = 0, toonew = 0, starttime = time(NULL);
+
+ if (argc == 2)
+ {
+ strcpy(fromfolder, argv[1]);
+ sprintf(fromdirectory, ".INBOX.%s/cur", fromfolder);
+ } else if (argc == 1) {
+ strcpy(fromdirectory, "cur");
+ strcpy(fromfolder, "");
+ } else {
+ printf("maildir-archiver: Usage: %s [<folder name>]\n", argv[0]);
+ exit(1);
+ }
+
+ folderhead = malloc(sizeof(*folderhead));
+ folderhead->next = NULL;
+
+ printf("maildir-archiver: Opening %s/... ", fromdirectory);
+ fflush(stdout);
+ cur = opendir(fromdirectory);
+ if (!cur)
+ {
+ perror("opendir(cur)");
+ exit(1);
+ }
+ dirstart = telldir(cur);
+ printf("done\n");
+
+ printf("maildir-archiver: Doing preliminary scan of e-mails... .");
+ fflush(stdout);
+ while ((de = readdir(cur)))
+ {
+ time_t tt;
+ struct tm *tm;
+ char archivefolder[128];
+
+ tt = atoi(de->d_name);
+ if (tt == 0)
+ {
+ notemails++;
+ continue;
+ }
+ if ((starttime - tt) < MAXAGE)
+ {
+ toonew++;
+ continue;
+ }
+ emails++;
+ if ((emails % 10000) == 0)
+ {
+ printf("\b%c", spinner[(spinnerstate++) % SPINNERSTATES]);
+ fflush(stdout);
+ }
+ }
+ printf("\bdone (%d mails to archive, %d too new, %d invalid)\n", emails, toonew, notemails);
+ seekdir(cur, dirstart);
+
+ printf("maildir-archiver: Archiving e-mail... [> ]");
+ fflush(stdout);
+ while ((de = readdir(cur)))
+ {
+ static int progresscounter = 0;
+ static int archived = 0;
+ time_t tt;
+ struct tm *tm;
+ char archivefolder[128];
+ int islist = 0;
+ char fn[256];
+ FILE *fp;
+
+ tt = atoi(de->d_name);
+ if (tt == 0)
+ continue;
+ if ((starttime - tt) < MAXAGE)
+ continue;
+
+ tm = localtime(&tt);
+
+ /* Open the file to determine if it's a mailing list or what */
+ sprintf(fn, "%s/%s", fromdirectory, de->d_name);
+ fp = fopen(fn, "r");
+ if (!fp)
+ {
+ perror("fopen(fn, r)");
+ exit(1);
+ }
+ {
+ char line[512];
+ while (fgets(line, 512, fp))
+ {
+ if (!strncmp(line, "X-BeenThere: ", 13))
+ islist++;
+ if (!strncmp(line, "List-Unsubscribe: ", 18))
+ islist++;
+ if (!strncmp(line, "X-Mailing-List", 14))
+ islist++;
+ if (!strncmp(line, "Precedence: bulk", 16))
+ islist++;
+
+ if (!line[0])
+ break;
+ }
+ }
+ fclose(fp);
+
+ /* sprintf(archivefolder, ARCHIVE_PREFIX "%d-%02d", 1900 + tm->tm_year, tm->tm_mon + 1); */
+ sprintf(archivefolder, ARCHIVE_PREFIX "%d-Q%d-%s", 1900 + tm->tm_year, (tm->tm_mon) / 3 + 1, islist ? "List" : "Personal");
+ move_email(de->d_name, archivefolder);
+ archived++;
+
+ if (((archived % 10) == 0) || (archived == emails))
+ {
+ int i;
+ progresscounter = archived * 32 / emails;
+ printf("\rmaildir-archiver: Archiving e-mail... [");
+ for (i=0; i < progresscounter; i++)
+ printf("=");
+ if (progresscounter != 32)
+ printf(">");
+ for (i=0; i < (31 - progresscounter); i++)
+ printf(" ");
+ printf("] ");
+ printf("%c ", spinner[(spinnerstate++) % SPINNERSTATES]);
+ printf("%d/%d", archived, emails);
+ fflush(stdout);
+ }
+ }
+ printf("\n");
+ printf("maildir-archiver: Statistics:\n");
+ printf("maildir-archiver: All operations performed in %d seconds\n", time(NULL)-starttime);
+ printf("maildir-archiver:\n");
+ printf("maildir-archiver: -------------------------------+----------\n");
+ printf("maildir-archiver: %-30s | Emails\n", "Status");
+ printf("maildir-archiver: -------------------------------+----------\n");
+ printf("maildir-archived: %-30s | %6d\n", "Processed", emails);
+ printf("maildir-archived: %-30s | %6d\n", "Too new", toonew);
+ printf("maildir-archived: %-30s | %6d\n", "Not an e-mail", notemails);
+ printf("maildir-archived: %-30s | %6d\n", "Already in correct folder", skipped);
+ printf("maildir-archiver: -------------------------------+----------\n");
+ printf("maildir-archiver:\n");
+ printf("maildir-archiver: -------------------------------+----------\n");
+ printf("maildir-archiver: %-30s | Emails\n", "Folder");
+ printf("maildir-archiver: -------------------------------+----------\n");
+ {
+ struct folder_list_t *lp;
+ int total = 0;
+
+ for (lp = folderhead; lp->next; lp = lp->next)
+ {
+ printf("maildir-archiver: %-30s | %6d\n", lp->name, lp->emails);
+ total += lp->emails;
+ }
+ printf("maildir-archiver: %-30s | %6d\n", "Total", total);
+ }
+ printf("maildir-archiver: -------------------------------+----------\n");
+}