2005-04-12 06:46:50 +00:00
|
|
|
/*
|
|
|
|
* Another stupid program, this one parsing the headers of an
|
|
|
|
* email to figure out authorship and subject
|
|
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
2005-04-12 08:40:20 +00:00
|
|
|
static FILE *cmitmsg, *patchfile, *filelist;
|
2005-04-12 06:46:50 +00:00
|
|
|
|
|
|
|
static char line[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_subject(char *line)
|
|
|
|
{
|
|
|
|
strcpy(subject, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_subject_line(char *line)
|
|
|
|
{
|
|
|
|
while (isspace(*line))
|
|
|
|
line++;
|
|
|
|
*--line = ' ';
|
|
|
|
strcat(subject, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void check_line(char *line, int len)
|
|
|
|
{
|
|
|
|
static int cont = -1;
|
|
|
|
if (!memcmp(line, "From:", 5) && isspace(line[5])) {
|
|
|
|
handle_from(line+6);
|
|
|
|
cont = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!memcmp(line, "Subject:", 8) && isspace(line[8])) {
|
|
|
|
handle_subject(line+9);
|
|
|
|
cont = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (isspace(*line)) {
|
|
|
|
switch (cont) {
|
|
|
|
case 0:
|
|
|
|
fprintf(stderr, "I don't do 'From:' line continuations\n");
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
add_subject_line(line);
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cont = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Hacky hacky. This depends not only on -p1, but on
|
|
|
|
* filenames not having some special characters in them,
|
|
|
|
* like tilde.
|
|
|
|
*/
|
|
|
|
static void show_filename(char *line)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
char *name = strchr(line, '/');
|
|
|
|
|
|
|
|
if (!name || !isspace(*line))
|
|
|
|
return;
|
|
|
|
name++;
|
|
|
|
len = 0;
|
|
|
|
for (;;) {
|
|
|
|
unsigned char c = name[len];
|
|
|
|
switch (c) {
|
|
|
|
default:
|
|
|
|
len++;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 0: case ' ':
|
|
|
|
case '\t': case '\n':
|
|
|
|
break;
|
|
|
|
|
2005-04-12 08:40:20 +00:00
|
|
|
/* patch tends to special-case these things.. */
|
2005-04-12 06:46:50 +00:00
|
|
|
case '~':
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* remove ".orig" from the end - common patch behaviour */
|
|
|
|
if (len > 5 && !memcmp(name+len-5, ".orig", 5))
|
|
|
|
len -=5;
|
|
|
|
if (!len)
|
|
|
|
return;
|
2005-04-12 08:40:20 +00:00
|
|
|
fprintf(filelist, "%.*s\n", len, name);
|
2005-04-12 06:46:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void handle_rest(void)
|
|
|
|
{
|
|
|
|
char *sub = cleanup_subject(subject);
|
|
|
|
cleanup_space(name);
|
|
|
|
cleanup_space(email);
|
|
|
|
cleanup_space(sub);
|
|
|
|
printf("Author: %s\nEmail: %s\nSubject: %s\n\n", name, email, sub);
|
|
|
|
FILE *out = cmitmsg;
|
|
|
|
|
|
|
|
do {
|
|
|
|
/* Track filename information from the patch.. */
|
|
|
|
if (!memcmp("---", line, 3)) {
|
|
|
|
out = patchfile;
|
|
|
|
show_filename(line+3);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!memcmp("+++", line, 3))
|
|
|
|
show_filename(line+3);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* First line of body can be a From: */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
line[len] = '\n';
|
|
|
|
handle_rest();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void usage(void)
|
|
|
|
{
|
2005-04-12 08:40:20 +00:00
|
|
|
fprintf(stderr, "mailinfo msg-file path-file filelist-file < email\n");
|
2005-04-12 06:46:50 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char ** argv)
|
|
|
|
{
|
2005-04-12 08:40:20 +00:00
|
|
|
if (argc != 4)
|
2005-04-12 06:46:50 +00:00
|
|
|
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);
|
|
|
|
}
|
2005-04-12 08:40:20 +00:00
|
|
|
filelist = fopen(argv[3], "w");
|
|
|
|
if (!filelist) {
|
|
|
|
perror(argv[3]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2005-04-12 06:46:50 +00:00
|
|
|
while (fgets(line, sizeof(line), stdin) != NULL) {
|
|
|
|
int len = eatspace(line);
|
|
|
|
if (!len) {
|
|
|
|
handle_body();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
check_line(line, len);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|