/*
- * 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)
{
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)
}
}
-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;
}
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);
}
else
{
- want = want_header(c, argv+1, argc-1);
+ want = want_header(c);
if (want)
{
putchar('\n');
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;
}