]> mj.ucw.cz Git - maildups.git/commitdiff
Teach mparse to handle maildirs master
authorMartin Mares <mj@ucw.cz>
Tue, 6 Mar 2018 11:58:29 +0000 (12:58 +0100)
committerMartin Mares <mj@ucw.cz>
Tue, 6 Mar 2018 11:58:29 +0000 (12:58 +0100)
mparse.c

index 962755e5bf2f4f81e1a1dc732a5963a52c3a26d3..425adbaaa61aaead90508cef37b37ceb2de08752 100644 (file)
--- a/mparse.c
+++ b/mparse.c
@@ -1,22 +1,34 @@
 /*
- *     Mailbox Parser (so far very primitive)
+ *     Mailbox and Maildir Parser (so far very primitive)
  *
- *     (c) 2010 Martin Mares <mj@ucw.cz>
+ *     (c) 2010--2018 Martin Mares <mj@ucw.cz>
  */
 
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
 #include <unistd.h>
+#include <sys/stat.h>
 
 #include "util.h"
 
 const char progname[] = "mparse";
+static char **field_names;
+static int num_fields;
+static int mbox_fd;
 
 #define BUFSIZE 65536
 
 static char buf[BUFSIZE];
-static char *bpos=buf, *bend=buf;
+static char *bpos, *bend;
+
+static void reset_buf(void)
+{
+  bpos = buf;
+  bend = buf;
+}
 
 static char *get_line(void)
 {
@@ -46,7 +58,7 @@ static char *get_line(void)
       int space = BUFSIZE - remains;
       if (!space)
        die("Line too long");
-      int len = read(0, bend, space);
+      int len = read(mbox_fd, bend, space);
       if (len < 0)
        die("Read error: %m");
       if (!len)
@@ -63,15 +75,15 @@ static char *get_line(void)
     }
 }
 
-static int want_header(char *line, char **want, int n_want)
+static int want_header(char *line)
 {
-  if (!n_want)
+  if (!num_fields)
     return 1;
 
-  for (int i=0; i<n_want; i++)
+  for (int i=0; i<num_fields; i++)
     {
-      int len = strlen(want[i]);
-      if (!strncasecmp(line, want[i], len))
+      int len = strlen(field_names[i]);
+      if (!strncasecmp(line, field_names[i], len))
        return 1;
     }
 
@@ -84,13 +96,13 @@ enum state {
   S_BODY,
 };
 
-int
-main(int argc, char **argv)
+static void parse_mbox(void)
 {
   char *c;
   enum state state = S_INITIAL;
   int want = 0;
 
+  reset_buf();
   while (c = get_line())
     {
       // printf("<%s>\n", c);
@@ -121,7 +133,7 @@ main(int argc, char **argv)
            }
          else
            {
-             want = want_header(c, argv+1, argc-1);
+             want = want_header(c);
              if (want)
                {
                  putchar('\n');
@@ -133,6 +145,119 @@ main(int argc, char **argv)
 
   if (state == S_HEADER)
     printf("\nX-Warning: Incomplete mail\n\n");
+}
+
+static void parse_maildir_file(void)
+{
+  char *c;
+  int want = 0;
+
+  reset_buf();
+  while (c = get_line())
+    {
+      // printf("<%s>\n", c);
+      if (!*c)
+       {
+         putchar('\n');
+         return;
+       }
+      else if (*c == ' ' || *c == '\t')
+       {
+         if (want)
+           {
+             while (*c == ' ' || *c == '\t')
+               c++;
+             putchar(' ');
+             fputs(c, stdout);
+           }
+       }
+      else
+       {
+         want = want_header(c);
+         if (want)
+           {
+             putchar('\n');
+             fputs(c, stdout);
+           }
+       }
+    }
+
+  printf("\nX-Warning: Incomplete mail\n\n");
+}
+
+static void parse_maildir(char *dir, char *subdir)
+{
+  char buf[4096];
+  snprintf(buf, sizeof(buf), "%s/%s", dir, subdir);
+
+  DIR *d = opendir(buf);
+  if (!d)
+    return;
+
+  struct dirent *e;
+  while (e = readdir(d))
+    {
+      if (e->d_name[0] == '.')
+       continue;
+      snprintf(buf, sizeof(buf), "%s/%s/%s", dir, subdir, e->d_name);
+      mbox_fd = open(buf, O_RDONLY);
+      if (mbox_fd < 0)
+       continue;
+      parse_maildir_file();
+      close(mbox_fd);
+    }
+
+  closedir(d);
+}
+
+static void usage(void)
+{
+  fprintf(stderr, "Usage: mparse [-f <mailbox>] <header-field> ...\n");
+  exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+  int opt;
+  char *folder = NULL;
+
+  while ((opt = getopt(argc, argv, "f:")) >= 0)
+    switch (opt)
+      {
+      case 'f':
+       folder = optarg;
+       break;
+      default:
+       usage();
+      }
+
+  field_names = argv + optind;
+  num_fields = argc - optind;
+
+  if (!folder)
+    {
+      parse_mbox();
+      return 0;
+    }
+
+  struct stat st;
+  if (stat(folder, &st) < 0)
+    die("Cannot stat %s: %m", folder);
+
+  if (st.st_mode & S_IFDIR)
+    {
+      parse_maildir(folder, "cur");
+      parse_maildir(folder, "new");
+    }
+  else
+    {
+      mbox_fd = open(folder, O_RDONLY);
+      if (mbox_fd < 0)
+       die("Cannot open %s: %m", folder);
+      parse_mbox();
+      close(mbox_fd);
+    }
 
   return 0;
 }