From 38b6fc573affd9ecebd5ed37f3b85635c21d77ce Mon Sep 17 00:00:00 2001 From: Joshua Wise Date: Fri, 15 Jan 2010 12:40:43 -0500 Subject: [PATCH] Initial import --- maildir-archive.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 maildir-archive.c diff --git a/maildir-archive.c b/maildir-archive.c new file mode 100644 index 0000000..8cd2b91 --- /dev/null +++ b/maildir-archive.c @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 []\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"); +} -- 2.39.2