add support for incomplete headers to copy_msg_convert()
in the spirit of being liberal about what we accept. this completely re-structures the header processing loop, with the nice side effect of eliminating the gotos. REFMAIL: 87bkyzhoov.fsf@curie.anarc.at
This commit is contained in:
parent
ed92816fdb
commit
5b9256f5dc
|
@ -44,52 +44,82 @@ copy_msg_convert( int in_cr, int out_cr, copy_vars_t *vars )
|
||||||
uint in_len = vars->data.len;
|
uint in_len = vars->data.len;
|
||||||
uint idx = 0, sbreak = 0, ebreak = 0, break2 = UINT_MAX;
|
uint idx = 0, sbreak = 0, ebreak = 0, break2 = UINT_MAX;
|
||||||
uint lines = 0, hdr_crs = 0, bdy_crs = 0, app_cr = 0, extra = 0;
|
uint lines = 0, hdr_crs = 0, bdy_crs = 0, app_cr = 0, extra = 0;
|
||||||
uint add_subj = 0;
|
uint add_subj = 0, fix_tuid = 0, fix_subj = 0, fix_hdr = 0, end_hdr = 0;
|
||||||
|
|
||||||
if (vars->srec) {
|
if (vars->srec) {
|
||||||
nloop: ;
|
for (;;) {
|
||||||
uint start = idx;
|
uint start = idx;
|
||||||
uint line_cr = 0;
|
uint line_cr = 0;
|
||||||
char pc = 0;
|
uint got_line = 0;
|
||||||
while (idx < in_len) {
|
char pc = 0;
|
||||||
char c = in_buf[idx++];
|
while (idx < in_len) {
|
||||||
if (c == '\n') {
|
char c = in_buf[idx++];
|
||||||
if (pc == '\r')
|
if (c == '\n') {
|
||||||
line_cr = 1;
|
if (pc == '\r')
|
||||||
if (!ebreak && starts_with_upper( in_buf + start, (int)(in_len - start), "X-TUID: ", 8 )) {
|
line_cr = 1;
|
||||||
extra = (sbreak = start) - (ebreak = idx);
|
got_line = 1;
|
||||||
if (!vars->minimal)
|
break;
|
||||||
goto oke;
|
|
||||||
} else {
|
|
||||||
if (break2 == UINT_MAX && vars->minimal &&
|
|
||||||
starts_with_upper( in_buf + start, (int)(in_len - start), "SUBJECT:", 8 )) {
|
|
||||||
break2 = start + 8;
|
|
||||||
if (break2 < in_len && in_buf[break2] == ' ')
|
|
||||||
break2++;
|
|
||||||
}
|
|
||||||
lines++;
|
|
||||||
hdr_crs += line_cr;
|
|
||||||
}
|
}
|
||||||
if (idx - line_cr - 1 == start) {
|
pc = c;
|
||||||
if (!ebreak)
|
|
||||||
sbreak = ebreak = start;
|
|
||||||
if (vars->minimal) {
|
|
||||||
in_len = idx;
|
|
||||||
if (break2 == UINT_MAX) {
|
|
||||||
break2 = start;
|
|
||||||
add_subj = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
goto oke;
|
|
||||||
}
|
|
||||||
goto nloop;
|
|
||||||
}
|
}
|
||||||
pc = c;
|
if (!ebreak && starts_with_upper( in_buf + start, (int)(in_len - start), "X-TUID: ", 8 )) {
|
||||||
|
extra = (sbreak = start) - (ebreak = idx);
|
||||||
|
if (!vars->minimal)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (break2 == UINT_MAX && vars->minimal &&
|
||||||
|
starts_with_upper( in_buf + start, (int)(in_len - start), "SUBJECT:", 8 )) {
|
||||||
|
break2 = start + 8;
|
||||||
|
if (break2 < in_len && in_buf[break2] == ' ')
|
||||||
|
break2++;
|
||||||
|
}
|
||||||
|
hdr_crs += line_cr;
|
||||||
|
if (got_line) {
|
||||||
|
lines++;
|
||||||
|
if (idx - line_cr - 1 != start)
|
||||||
|
continue;
|
||||||
|
// Empty line => end of headers
|
||||||
|
} else {
|
||||||
|
// The line is incomplete.
|
||||||
|
if (pc == '\r')
|
||||||
|
idx--; // For simplicity, move back before trailing CR
|
||||||
|
if (idx != start) {
|
||||||
|
// The line is non-empty, so schedule completing it
|
||||||
|
fix_hdr = 1;
|
||||||
|
// ... and put our headers after it. (It would seem easier
|
||||||
|
// to prepend them, as then we could avoid the fixing - but
|
||||||
|
// the line might be a continuation. We could also prepend
|
||||||
|
// it to _all_ pre-exiting headers, but then we would risk
|
||||||
|
// masking an (incorrectly present) leading 'From ' header.)
|
||||||
|
start = idx;
|
||||||
|
}
|
||||||
|
end_hdr = 1;
|
||||||
|
}
|
||||||
|
if (!ebreak) {
|
||||||
|
sbreak = ebreak = start;
|
||||||
|
fix_tuid = fix_hdr;
|
||||||
|
fix_hdr = 0;
|
||||||
|
}
|
||||||
|
if (vars->minimal) {
|
||||||
|
in_len = idx;
|
||||||
|
if (break2 == UINT_MAX) {
|
||||||
|
break2 = start;
|
||||||
|
add_subj = 1;
|
||||||
|
fix_subj = fix_hdr;
|
||||||
|
fix_hdr = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fix_hdr = 0;
|
||||||
|
end_hdr = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
free( in_buf );
|
|
||||||
return "has incomplete header";
|
|
||||||
oke:
|
|
||||||
app_cr = out_cr && (!in_cr || hdr_crs);
|
app_cr = out_cr && (!in_cr || hdr_crs);
|
||||||
|
if (fix_tuid || fix_subj || fix_hdr)
|
||||||
|
extra += app_cr + 1;
|
||||||
|
if (end_hdr)
|
||||||
|
extra += app_cr + 1;
|
||||||
extra += 8 + TUIDL + app_cr + 1;
|
extra += 8 + TUIDL + app_cr + 1;
|
||||||
}
|
}
|
||||||
if (out_cr != in_cr) {
|
if (out_cr != in_cr) {
|
||||||
|
@ -157,6 +187,8 @@ copy_msg_convert( int in_cr, int out_cr, copy_vars_t *vars )
|
||||||
}
|
}
|
||||||
copy_msg_bytes( &out_buf, in_buf, &idx, sbreak, in_cr, out_cr );
|
copy_msg_bytes( &out_buf, in_buf, &idx, sbreak, in_cr, out_cr );
|
||||||
|
|
||||||
|
if (fix_tuid)
|
||||||
|
ADD_NL();
|
||||||
memcpy( out_buf, "X-TUID: ", 8 );
|
memcpy( out_buf, "X-TUID: ", 8 );
|
||||||
out_buf += 8;
|
out_buf += 8;
|
||||||
memcpy( out_buf, vars->srec->tuid, TUIDL );
|
memcpy( out_buf, vars->srec->tuid, TUIDL );
|
||||||
|
@ -170,6 +202,8 @@ copy_msg_convert( int in_cr, int out_cr, copy_vars_t *vars )
|
||||||
memcpy( out_buf, dummy_pfx, strlen(dummy_pfx) );
|
memcpy( out_buf, dummy_pfx, strlen(dummy_pfx) );
|
||||||
out_buf += strlen(dummy_pfx);
|
out_buf += strlen(dummy_pfx);
|
||||||
} else {
|
} else {
|
||||||
|
if (fix_subj)
|
||||||
|
ADD_NL();
|
||||||
memcpy( out_buf, dummy_subj, strlen(dummy_subj) );
|
memcpy( out_buf, dummy_subj, strlen(dummy_subj) );
|
||||||
out_buf += strlen(dummy_subj);
|
out_buf += strlen(dummy_subj);
|
||||||
ADD_NL();
|
ADD_NL();
|
||||||
|
@ -178,8 +212,14 @@ copy_msg_convert( int in_cr, int out_cr, copy_vars_t *vars )
|
||||||
}
|
}
|
||||||
copy_msg_bytes( &out_buf, in_buf, &idx, in_len, in_cr, out_cr );
|
copy_msg_bytes( &out_buf, in_buf, &idx, in_len, in_cr, out_cr );
|
||||||
|
|
||||||
if (vars->minimal)
|
if (vars->minimal) {
|
||||||
|
if (end_hdr) {
|
||||||
|
if (fix_hdr)
|
||||||
|
ADD_NL();
|
||||||
|
ADD_NL();
|
||||||
|
}
|
||||||
memcpy( out_buf, dummy_msg_buf, dummy_msg_len );
|
memcpy( out_buf, dummy_msg_buf, dummy_msg_len );
|
||||||
|
}
|
||||||
|
|
||||||
free( in_buf );
|
free( in_buf );
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -131,10 +131,13 @@ mintests( const char *name, const char *in, const char *out, int flagged )
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FROM "From: de\rvil\r\n"
|
#define FROM "From: de\rvil\r\n"
|
||||||
#define TO "To: me\r\n"
|
#define R_TO "To: me"
|
||||||
#define IN_TUID "X-TUID: garbage\r\n"
|
#define TO R_TO "\r\n"
|
||||||
|
#define R_IN_TUID "X-TUID: garbage"
|
||||||
|
#define IN_TUID R_IN_TUID "\r\n"
|
||||||
#define OUT_TUID "X-TUID: " TUID "\r\n"
|
#define OUT_TUID "X-TUID: " TUID "\r\n"
|
||||||
#define SUBJECT "Subject: hell\r\n"
|
#define R_SUBJECT "Subject: hell"
|
||||||
|
#define SUBJECT R_SUBJECT "\r\n"
|
||||||
#define PH_SUBJECT "Subject: [placeholder] hell\r\n"
|
#define PH_SUBJECT "Subject: [placeholder] hell\r\n"
|
||||||
#define NO_SUBJECT "Subject: [placeholder] (No Subject)\r\n"
|
#define NO_SUBJECT "Subject: [placeholder] (No Subject)\r\n"
|
||||||
#define BODY "\r\nHi,\r\n\r\n...\r\n"
|
#define BODY "\r\nHi,\r\n\r\n...\r\n"
|
||||||
|
@ -177,5 +180,79 @@ main( void )
|
||||||
scc out_tuid_from_subj_to[] = OUT_TUID FROM PH_SUBJECT TO PH_BODY;
|
scc out_tuid_from_subj_to[] = OUT_TUID FROM PH_SUBJECT TO PH_BODY;
|
||||||
mintests( "tuid / from / subject / to", in_tuid_from_subj_to, out_tuid_from_subj_to, REGULAR );
|
mintests( "tuid / from / subject / to", in_tuid_from_subj_to, out_tuid_from_subj_to, REGULAR );
|
||||||
|
|
||||||
|
|
||||||
|
scc in_from_to_b1[] = FROM TO;
|
||||||
|
fulltests( "from / to w/o end", in_from_to_b1, in_from_to_b1, AS_IS );
|
||||||
|
scc out_from_to_b1[] = FROM TO OUT_TUID;
|
||||||
|
fulltests( "from / to w/o end", in_from_to_b1, out_from_to_b1, ADD_TUID );
|
||||||
|
scc in_from_tuid_to_b1[] = FROM IN_TUID TO;
|
||||||
|
scc out_from_tuid_to_b1[] = FROM OUT_TUID TO;
|
||||||
|
fulltests( "from / tuid / to w/o end", in_from_tuid_to_b1, out_from_tuid_to_b1, ADD_TUID );
|
||||||
|
scc in_from_to_tuid_b1[] = FROM TO IN_TUID;
|
||||||
|
scc out_from_to_tuid_b1[] = FROM TO OUT_TUID;
|
||||||
|
fulltests( "from / to / tuid w/o end", in_from_to_tuid_b1, out_from_to_tuid_b1, ADD_TUID );
|
||||||
|
|
||||||
|
mintests( "from / to w/o end", in_from_to_b1, out_from_to_ph, REGULAR );
|
||||||
|
mintests( "from / tuid / to w/o end", in_from_tuid_to_b1, out_from_tuid_to_ph, REGULAR );
|
||||||
|
scc in_from_subj_to_b1[] = FROM SUBJECT TO;
|
||||||
|
mintests( "from / subject / to w/o end", in_from_subj_to_b1, out_from_subj_to, REGULAR );
|
||||||
|
scc in_from_subj_tuid_to_b1[] = FROM SUBJECT IN_TUID TO;
|
||||||
|
mintests( "from / subject / tuid / to w/o end", in_from_subj_tuid_to_b1, out_from_subj_tuid_to, REGULAR );
|
||||||
|
scc in_from_subj_to_tuid_b1[] = FROM SUBJECT TO IN_TUID;
|
||||||
|
scc out_from_subj_to_tuid_b1[] = FROM PH_SUBJECT TO OUT_TUID PH_BODY;
|
||||||
|
mintests( "from / subject / to / tuid w/o end", in_from_subj_to_tuid_b1, out_from_subj_to_tuid_b1, REGULAR );
|
||||||
|
scc in_from_tuid_subj_to_b1[] = FROM IN_TUID SUBJECT TO;
|
||||||
|
mintests( "from / tuid / subject / to w/o end", in_from_tuid_subj_to_b1, out_from_tuid_subj_to, REGULAR );
|
||||||
|
scc in_from_tuid_to_subj_b1[] = FROM IN_TUID TO SUBJECT;
|
||||||
|
scc out_from_tuid_to_subj_b1[] = FROM OUT_TUID TO PH_SUBJECT PH_BODY;
|
||||||
|
mintests( "from / tuid / to / subject w/o end", in_from_tuid_to_subj_b1, out_from_tuid_to_subj_b1, REGULAR );
|
||||||
|
|
||||||
|
|
||||||
|
scc in_from_to_b2[] = FROM R_TO "\r";
|
||||||
|
fulltests( "from / to w/o lf", in_from_to_b2, in_from_to_b2, AS_IS );
|
||||||
|
scc out_from_to_b2[] = FROM TO OUT_TUID "\r";
|
||||||
|
fulltests( "from / to w/o lf", in_from_to_b2, out_from_to_b2, ADD_TUID );
|
||||||
|
scc in_from_tuid_to_b2[] = FROM IN_TUID R_TO "\r";
|
||||||
|
scc out_from_tuid_to_b2[] = FROM OUT_TUID R_TO "\r";
|
||||||
|
fulltests( "from / tuid / to w/o lf", in_from_tuid_to_b2, out_from_tuid_to_b2, ADD_TUID );
|
||||||
|
scc in_from_to_tuid_b2[] = FROM TO R_IN_TUID "\r";
|
||||||
|
fulltests( "from / to / tuid w/o lf", in_from_to_tuid_b2, out_from_to_tuid_b1, ADD_TUID );
|
||||||
|
|
||||||
|
mintests( "from / to w/o lf", in_from_to_b2, out_from_to_ph, REGULAR );
|
||||||
|
mintests( "from / tuid / to w/o lf", in_from_tuid_to_b2, out_from_tuid_to_ph, REGULAR );
|
||||||
|
scc in_from_subj_to_b2[] = FROM SUBJECT R_TO "\r";
|
||||||
|
mintests( "from / subject / to w/o lf", in_from_subj_to_b2, out_from_subj_to, REGULAR );
|
||||||
|
scc in_from_subj_tuid_to_b2[] = FROM SUBJECT IN_TUID R_TO "\r";
|
||||||
|
mintests( "from / subject / tuid / to w/o lf", in_from_subj_tuid_to_b2, out_from_subj_tuid_to, REGULAR );
|
||||||
|
scc in_from_subj_to_tuid_b2[] = FROM SUBJECT TO R_IN_TUID "\r";
|
||||||
|
mintests( "from / subject / to / tuid w/o lf", in_from_subj_to_tuid_b2, out_from_subj_to_tuid_b1, REGULAR );
|
||||||
|
scc in_from_tuid_subj_to_b2[] = FROM IN_TUID SUBJECT R_TO "\r";
|
||||||
|
mintests( "from / tuid / subject / to w/o lf", in_from_tuid_subj_to_b2, out_from_tuid_subj_to, REGULAR );
|
||||||
|
scc in_from_tuid_to_subj_b2[] = FROM IN_TUID TO R_SUBJECT "\r";
|
||||||
|
mintests( "from / tuid / to / subject w/o lf", in_from_tuid_to_subj_b2, out_from_tuid_to_subj_b1, REGULAR );
|
||||||
|
|
||||||
|
|
||||||
|
scc in_from_to_b3[] = FROM R_TO;
|
||||||
|
fulltests( "from / to w/o crlf", in_from_to_b3, in_from_to_b3, AS_IS );
|
||||||
|
fulltests( "from / to w/o crlf", in_from_to_b3, out_from_to_b1, ADD_TUID );
|
||||||
|
scc in_from_tuid_to_b3[] = FROM IN_TUID R_TO;
|
||||||
|
scc out_from_tuid_to_b3[] = FROM OUT_TUID R_TO;
|
||||||
|
fulltests( "from / tuid / to w/o crlf", in_from_tuid_to_b3, out_from_tuid_to_b3, ADD_TUID );
|
||||||
|
scc in_from_to_tuid_b3[] = FROM TO R_IN_TUID;
|
||||||
|
fulltests( "from / to / tuid w/o crlf", in_from_to_tuid_b3, out_from_to_tuid_b1, ADD_TUID );
|
||||||
|
|
||||||
|
mintests( "from / to w/o crlf", in_from_to_b3, out_from_to_ph, REGULAR );
|
||||||
|
mintests( "from / tuid / to w/o crlf", in_from_tuid_to_b3, out_from_tuid_to_ph, REGULAR );
|
||||||
|
scc in_from_subj_to_b3[] = FROM SUBJECT R_TO;
|
||||||
|
mintests( "from / subject / to w/o crlf", in_from_subj_to_b3, out_from_subj_to, REGULAR );
|
||||||
|
scc in_from_subj_tuid_to_b3[] = FROM SUBJECT IN_TUID R_TO;
|
||||||
|
mintests( "from / subject / tuid / to w/o crlf", in_from_subj_tuid_to_b3, out_from_subj_tuid_to, REGULAR );
|
||||||
|
scc in_from_subj_to_tuid_b3[] = FROM SUBJECT TO R_IN_TUID;
|
||||||
|
mintests( "from / subject / to / tuid w/o crlf", in_from_subj_to_tuid_b3, out_from_subj_to_tuid_b1, REGULAR );
|
||||||
|
scc in_from_tuid_subj_to_b3[] = FROM IN_TUID SUBJECT R_TO;
|
||||||
|
mintests( "from / tuid / subject / to w/o crlf", in_from_tuid_subj_to_b3, out_from_tuid_subj_to, REGULAR );
|
||||||
|
scc in_from_tuid_to_subj_b3[] = FROM IN_TUID TO R_SUBJECT;
|
||||||
|
mintests( "from / tuid / to / subject w/o crlf", in_from_tuid_to_subj_b3, out_from_tuid_to_subj_b1, REGULAR );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user