]> Joshua Wise's Git repositories - maildir-archive.git/commitdiff
Initial import master
authorJoshua Wise <joshua@dashnine.joshuawise.com>
Fri, 15 Jan 2010 17:40:43 +0000 (12:40 -0500)
committerJoshua Wise <joshua@dashnine.joshuawise.com>
Fri, 15 Jan 2010 17:40:43 +0000 (12:40 -0500)
maildir-archive.c [new file with mode: 0644]

diff --git a/maildir-archive.c b/maildir-archive.c
new file mode 100644 (file)
index 0000000..8cd2b91
--- /dev/null
@@ -0,0 +1,275 @@
+#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");
+}
This page took 0.032272 seconds and 4 git commands to generate.