/* * Another stupid program, this one parsing the headers of an * email to figure out authorship and subject */ #include #include #include #include static FILE *cmitmsg, *patchfile; static char line[1000]; static char date[1000]; static char name[1000]; static char email[1000]; static char subject[1000]; static char *sanity_check(char *name, char *email) { int len = strlen(name); if (len < 3 || len > 60) return email; if (strchr(name, '@') || strchr(name, '<') || strchr(name, '>')) return email; return name; } static int handle_from(char *line) { char *at = strchr(line, '@'); char *dst; if (!at) return 0; /* * If we already have one email, don't take any confusing lines */ if (*email && strchr(at+1, '@')) return 0; while (at > line) { char c = at[-1]; if (isspace(c) || c == '<') break; at--; } dst = email; for (;;) { unsigned char c = *at; if (!c || c == '>' || isspace(c)) break; *at++ = ' '; *dst++ = c; } *dst++ = 0; at = line + strlen(line); while (at > line) { unsigned char c = *--at; if (isalnum(c)) break; *at = 0; } at = line; for (;;) { unsigned char c = *at; if (!c) break; if (isalnum(c)) break; at++; } at = sanity_check(at, email); strcpy(name, at); return 1; } static void handle_date(char *line) { strcpy(date, line); } static void handle_subject(char *line) { strcpy(subject, line); } static void check_line(char *line, int len) { if (!memcmp(line, "From:", 5) && isspace(line[5])) handle_from(line+6); else if (!memcmp(line, "Date:", 5) && isspace(line[5])) handle_date(line+6); else if (!memcmp(line, "Subject:", 8) && isspace(line[8])) handle_subject(line+9); } static char * cleanup_subject(char *subject) { for (;;) { char *p; int len, remove; switch (*subject) { case 'r': case 'R': if (!memcmp("e:", subject+1, 2)) { subject +=3; continue; } break; case ' ': case '\t': case ':': subject++; continue; case '[': p = strchr(subject, ']'); if (!p) { subject++; continue; } len = strlen(p); remove = p - subject; if (remove <= len *2) { subject = p+1; continue; } break; } return subject; } } static void cleanup_space(char *buf) { unsigned char c; while ((c = *buf) != 0) { buf++; if (isspace(c)) { buf[-1] = ' '; c = *buf; while (isspace(c)) { int len = strlen(buf); memmove(buf, buf+1, len); c = *buf; } } } } static void handle_rest(void) { char *sub = cleanup_subject(subject); cleanup_space(name); cleanup_space(date); cleanup_space(email); cleanup_space(sub); printf("Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n", name, email, sub, date); FILE *out = cmitmsg; do { if (!memcmp("diff -", line, 6) || !memcmp("---", line, 3) || !memcmp("Index: ", line, 7)) out = patchfile; fputs(line, out); } while (fgets(line, sizeof(line), stdin) != NULL); if (out == cmitmsg) { fprintf(stderr, "No patch found\n"); exit(1); } fclose(cmitmsg); fclose(patchfile); } static int eatspace(char *line) { int len = strlen(line); while (len > 0 && isspace(line[len-1])) line[--len] = 0; return len; } static void handle_body(void) { int has_from = 0; int has_date = 0; /* First lines of body can have From: and Date: */ while (fgets(line, sizeof(line), stdin) != NULL) { int len = eatspace(line); if (!len) continue; if (!memcmp("From:", line, 5) && isspace(line[5])) { if (!has_from && handle_from(line+6)) { has_from = 1; continue; } } if (!memcmp("Date:", line, 5) && isspace(line[5])) { if (!has_date) { handle_date(line+6); has_date = 1; continue; } } line[len] = '\n'; handle_rest(); break; } } static int read_one_header_line(char *line, int sz, FILE *in) { int ofs = 0; while (ofs < sz) { int peek, len; if (fgets(line + ofs, sz - ofs, in) == NULL) return ofs; len = eatspace(line + ofs); if (len == 0) return ofs; peek = fgetc(in); ungetc(peek, in); if (peek == ' ' || peek == '\t') { /* Yuck, 2822 header "folding" */ ofs += len; continue; } return ofs + len; } return ofs; } static void usage(void) { fprintf(stderr, "mailinfo msg-file patch-file < email\n"); exit(1); } int main(int argc, char ** argv) { if (argc != 3) usage(); cmitmsg = fopen(argv[1], "w"); if (!cmitmsg) { perror(argv[1]); exit(1); } patchfile = fopen(argv[2], "w"); if (!patchfile) { perror(argv[2]); exit(1); } while (1) { int len = read_one_header_line(line, sizeof(line), stdin); if (!len) { handle_body(); break; } check_line(line, len); } return 0; }