Browse Source

Merge branch 'eb/mailinfo' into next

* eb/mailinfo:
  Allow in body headers beyond the in body header prefix.
  More accurately detect header lines in read_one_header_line
  In handle_body only read a line if we don't already have one.
  Refactor commit messge handling.
  Move B and Q decoding into check header.
  Make read_one_header_line return a flag not a length.
maint
Junio C Hamano 19 years ago
parent
commit
33b292610d
  1. 124
      mailinfo.c

124
mailinfo.c

@ -72,11 +72,14 @@ static int bogus_from(char *line)
return 1; return 1;
} }


static int handle_from(char *line) static int handle_from(char *in_line)
{ {
char *at = strchr(line, '@'); char line[1000];
char *at;
char *dst; char *dst;


strcpy(line, in_line);
at = strchr(line, '@');
if (!at) if (!at)
return bogus_from(line); return bogus_from(line);


@ -238,44 +241,45 @@ static int eatspace(char *line)
#define SEEN_DATE 02 #define SEEN_DATE 02
#define SEEN_SUBJECT 04 #define SEEN_SUBJECT 04
#define SEEN_BOGUS_UNIX_FROM 010 #define SEEN_BOGUS_UNIX_FROM 010
#define SEEN_PREFIX 020


/* First lines of body can have From:, Date:, and Subject: */ /* First lines of body can have From:, Date:, and Subject: */
static int handle_inbody_header(int *seen, char *line) static void handle_inbody_header(int *seen, char *line)
{ {
if (!memcmp(">From", line, 5) && isspace(line[5])) { if (!memcmp(">From", line, 5) && isspace(line[5])) {
if (!(*seen & SEEN_BOGUS_UNIX_FROM)) { if (!(*seen & SEEN_BOGUS_UNIX_FROM)) {
*seen |= SEEN_BOGUS_UNIX_FROM; *seen |= SEEN_BOGUS_UNIX_FROM;
return 1; return;
} }
} }
if (!memcmp("From:", line, 5) && isspace(line[5])) { if (!memcmp("From:", line, 5) && isspace(line[5])) {
if (!(*seen & SEEN_FROM) && handle_from(line+6)) { if (!(*seen & SEEN_FROM) && handle_from(line+6)) {
*seen |= SEEN_FROM; *seen |= SEEN_FROM;
return 1; return;
} }
} }
if (!memcmp("Date:", line, 5) && isspace(line[5])) { if (!memcmp("Date:", line, 5) && isspace(line[5])) {
if (!(*seen & SEEN_DATE)) { if (!(*seen & SEEN_DATE)) {
handle_date(line+6); handle_date(line+6);
*seen |= SEEN_DATE; *seen |= SEEN_DATE;
return 1; return;
} }
} }
if (!memcmp("Subject:", line, 8) && isspace(line[8])) { if (!memcmp("Subject:", line, 8) && isspace(line[8])) {
if (!(*seen & SEEN_SUBJECT)) { if (!(*seen & SEEN_SUBJECT)) {
handle_subject(line+9); handle_subject(line+9);
*seen |= SEEN_SUBJECT; *seen |= SEEN_SUBJECT;
return 1; return;
} }
} }
if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) { if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) {
if (!(*seen & SEEN_SUBJECT)) { if (!(*seen & SEEN_SUBJECT)) {
handle_subject(line); handle_subject(line);
*seen |= SEEN_SUBJECT; *seen |= SEEN_SUBJECT;
return 1; return;
} }
} }
return 0; *seen |= SEEN_PREFIX;
} }


static char *cleanup_subject(char *subject) static char *cleanup_subject(char *subject)
@ -331,6 +335,7 @@ static void cleanup_space(char *buf)
} }
} }


static void decode_header_bq(char *it);
typedef int (*header_fn_t)(char *); typedef int (*header_fn_t)(char *);
struct header_def { struct header_def {
const char *name; const char *name;
@ -338,7 +343,7 @@ struct header_def {
int namelen; int namelen;
}; };


static void check_header(char *line, int len, struct header_def *header) static void check_header(char *line, struct header_def *header)
{ {
int i; int i;


@ -350,13 +355,17 @@ static void check_header(char *line, int len, struct header_def *header)
int len = header[i].namelen; int len = header[i].namelen;
if (!strncasecmp(line, header[i].name, len) && if (!strncasecmp(line, header[i].name, len) &&
line[len] == ':' && isspace(line[len + 1])) { line[len] == ':' && isspace(line[len + 1])) {
/* Unwrap inline B and Q encoding, and optionally
* normalize the meta information to utf8.
*/
decode_header_bq(line + len + 2);
header[i].func(line + len + 2); header[i].func(line + len + 2);
break; break;
} }
} }
} }


static void check_subheader_line(char *line, int len) static void check_subheader_line(char *line)
{ {
static struct header_def header[] = { static struct header_def header[] = {
{ "Content-Type", handle_subcontent_type }, { "Content-Type", handle_subcontent_type },
@ -364,9 +373,9 @@ static void check_subheader_line(char *line, int len)
handle_content_transfer_encoding }, handle_content_transfer_encoding },
{ NULL }, { NULL },
}; };
check_header(line, len, header); check_header(line, header);
} }
static void check_header_line(char *line, int len) static void check_header_line(char *line)
{ {
static struct header_def header[] = { static struct header_def header[] = {
{ "From", handle_from }, { "From", handle_from },
@ -377,27 +386,36 @@ static void check_header_line(char *line, int len)
handle_content_transfer_encoding }, handle_content_transfer_encoding },
{ NULL }, { NULL },
}; };
check_header(line, len, header); check_header(line, header);
} }


static int read_one_header_line(char *line, int sz, FILE *in) static int read_one_header_line(char *line, int sz, FILE *in)
{ {
int ofs = 0; int ofs = 0;
while (ofs < sz) { while (ofs < sz) {
const char *colon;
int peek, len; int peek, len;
if (fgets(line + ofs, sz - ofs, in) == NULL) if (fgets(line + ofs, sz - ofs, in) == NULL)
return ofs; break;
len = eatspace(line + ofs); len = eatspace(line + ofs);
if (len == 0) if (len == 0)
return ofs; break;
peek = fgetc(in); ungetc(peek, in); colon = strchr(line, ':');
if (peek == ' ' || peek == '\t') { if (!colon || !isspace(colon[1])) {
/* Yuck, 2822 header "folding" */ /* Re-add the newline */
ofs += len; line[ofs + len] = '\n';
continue; line[ofs + len + 1] = '\0';
break;
} }
return ofs + len; ofs += len;
/* Yuck, 2822 header "folding" */
peek = fgetc(in); ungetc(peek, in);
if (peek != ' ' && peek != '\t')
break;
} }
/* Count mbox From headers as headers */
if (!ofs && !memcmp(line, "From ", 5))
ofs = 1;
return ofs; return ofs;
} }


@ -592,25 +610,13 @@ static void decode_transfer_encoding(char *line)
static void handle_info(void) static void handle_info(void)
{ {
char *sub; char *sub;
static int done_info = 0;

if (done_info)
return;


done_info = 1;
sub = cleanup_subject(subject); sub = cleanup_subject(subject);
cleanup_space(name); cleanup_space(name);
cleanup_space(date); cleanup_space(date);
cleanup_space(email); cleanup_space(email);
cleanup_space(sub); cleanup_space(sub);


/* Unwrap inline B and Q encoding, and optionally
* normalize the meta information to utf8.
*/
decode_header_bq(name);
decode_header_bq(date);
decode_header_bq(email);
decode_header_bq(sub);
printf("Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n", printf("Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n",
name, email, sub, date); name, email, sub, date);
} }
@ -618,7 +624,7 @@ static void handle_info(void)
/* We are inside message body and have read line[] already. /* We are inside message body and have read line[] already.
* Spit out the commit log. * Spit out the commit log.
*/ */
static int handle_commit_msg(void) static int handle_commit_msg(int *seen)
{ {
if (!cmitmsg) if (!cmitmsg)
return 0; return 0;
@ -642,6 +648,11 @@ static int handle_commit_msg(void)
decode_transfer_encoding(line); decode_transfer_encoding(line);
if (metainfo_charset) if (metainfo_charset)
convert_to_utf8(line, charset); convert_to_utf8(line, charset);

handle_inbody_header(seen, line);
if (!(*seen & SEEN_PREFIX))
continue;

fputs(line, cmitmsg); fputs(line, cmitmsg);
} while (fgets(line, sizeof(line), stdin) != NULL); } while (fgets(line, sizeof(line), stdin) != NULL);
fclose(cmitmsg); fclose(cmitmsg);
@ -673,26 +684,16 @@ static void handle_patch(void)
* that the first part to contain commit message and a patch, and * that the first part to contain commit message and a patch, and
* handle other parts as pure patches. * handle other parts as pure patches.
*/ */
static int handle_multipart_one_part(void) static int handle_multipart_one_part(int *seen)
{ {
int seen = 0;
int n = 0; int n = 0;
int len;


while (fgets(line, sizeof(line), stdin) != NULL) { while (fgets(line, sizeof(line), stdin) != NULL) {
again: again:
len = eatspace(line);
n++; n++;
if (!len)
continue;
if (is_multipart_boundary(line)) if (is_multipart_boundary(line))
break; break;
if (0 <= seen && handle_inbody_header(&seen, line)) if (handle_commit_msg(seen))
continue;
seen = -1; /* no more inbody headers */
line[len] = '\n';
handle_info();
if (handle_commit_msg())
goto again; goto again;
handle_patch(); handle_patch();
break; break;
@ -704,6 +705,7 @@ static int handle_multipart_one_part(void)


static void handle_multipart_body(void) static void handle_multipart_body(void)
{ {
int seen = 0;
int part_num = 0; int part_num = 0;


/* Skip up to the first boundary */ /* Skip up to the first boundary */
@ -716,16 +718,16 @@ static void handle_multipart_body(void)
return; return;
/* We are on boundary line. Start slurping the subhead. */ /* We are on boundary line. Start slurping the subhead. */
while (1) { while (1) {
int len = read_one_header_line(line, sizeof(line), stdin); int hdr = read_one_header_line(line, sizeof(line), stdin);
if (!len) { if (!hdr) {
if (handle_multipart_one_part() < 0) if (handle_multipart_one_part(&seen) < 0)
return; return;
/* Reset per part headers */ /* Reset per part headers */
transfer_encoding = TE_DONTCARE; transfer_encoding = TE_DONTCARE;
charset[0] = 0; charset[0] = 0;
} }
else else
check_subheader_line(line, len); check_subheader_line(line);
} }
fclose(patchfile); fclose(patchfile);
if (!patch_lines) { if (!patch_lines) {
@ -739,18 +741,9 @@ static void handle_body(void)
{ {
int seen = 0; int seen = 0;


while (fgets(line, sizeof(line), stdin) != NULL) { if (line[0] || fgets(line, sizeof(line), stdin) != NULL) {
int len = eatspace(line); handle_commit_msg(&seen);
if (!len)
continue;
if (0 <= seen && handle_inbody_header(&seen, line))
continue;
seen = -1; /* no more inbody headers */
line[len] = '\n';
handle_info();
handle_commit_msg();
handle_patch(); handle_patch();
break;
} }
fclose(patchfile); fclose(patchfile);
if (!patch_lines) { if (!patch_lines) {
@ -794,15 +787,16 @@ int main(int argc, char **argv)
exit(1); exit(1);
} }
while (1) { while (1) {
int len = read_one_header_line(line, sizeof(line), stdin); int hdr = read_one_header_line(line, sizeof(line), stdin);
if (!len) { if (!hdr) {
if (multipart_boundary[0]) if (multipart_boundary[0])
handle_multipart_body(); handle_multipart_body();
else else
handle_body(); handle_body();
handle_info();
break; break;
} }
check_header_line(line, len); check_header_line(line);
} }
return 0; return 0;
} }

Loading…
Cancel
Save