/* * Totally braindamaged mbox splitter program. * * It just splits a mbox into a list of files: "0001" "0002" .. * so you can process them further from there. */ #include #include #include #include #include #include #include #include #include #include static int usage(void) { fprintf(stderr, "mailsplit \n"); exit(1); } static int linelen(const char *map, unsigned long size) { int len = 0, c; do { c = *map; map++; size--; len++; } while (size && c != '\n'); return len; } static int is_from_line(const char *line, int len) { const char *colon; if (len < 20 || memcmp("From ", line, 5)) return 0; colon = line + len - 2; line += 5; for (;;) { if (colon < line) return 0; if (*--colon == ':') break; } if (!isdigit(colon[-4]) || !isdigit(colon[-2]) || !isdigit(colon[-1]) || !isdigit(colon[ 1]) || !isdigit(colon[ 2])) return 0; /* year */ if (strtol(colon+3, NULL, 10) <= 90) return 0; /* Ok, close enough */ return 1; } static int parse_email(const void *map, unsigned long size) { unsigned long offset; if (size < 6 || memcmp("From ", map, 5)) goto corrupt; /* Make sure we don't trigger on this first line */ map++; size--; offset=1; /* * Search for a line beginning with "From ", and * having something that looks like a date format. */ do { int len = linelen(map, size); if (is_from_line(map, len)) return offset; map += len; size -= len; offset += len; } while (size); return offset; corrupt: fprintf(stderr, "corrupt mailbox\n"); exit(1); } int main(int argc, char **argv) { int fd, nr; struct stat st; unsigned long size; void *map; if (argc != 3) usage(); fd = open(argv[1], O_RDONLY); if (fd < 0) { perror(argv[1]); exit(1); } if (chdir(argv[2]) < 0) usage(); if (fstat(fd, &st) < 0) { perror("stat"); exit(1); } size = st.st_size; map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); if (map == MAP_FAILED) { perror("mmap"); close(fd); exit(1); } close(fd); nr = 0; do { char name[10]; unsigned long len = parse_email(map, size); assert(len <= size); sprintf(name, "%04d", ++nr); fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0600); if (fd < 0) { perror(name); exit(1); } if (write(fd, map, len) != len) { perror("write"); exit(1); } close(fd); map += len; size -= len; } while (size > 0); return 0; }