Skip to content

Commit

Permalink
write Content-Disposition->filename* wrt RFC 2231 and RFC 5987, tackles
Browse files Browse the repository at this point in the history
  • Loading branch information
r10s committed May 29, 2018
1 parent 52c16b0 commit d40e85f
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 7 deletions.
7 changes: 7 additions & 0 deletions cmdline/stress.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,13 @@ void stress_functions(mrmailbox_t* mailbox)
assert( strcmp(buf1, "") == 0 );
free(buf1);

assert( mr_needs_ext_header("Björn") );
assert( !mr_needs_ext_header("Bjoern") );
assert( !mr_needs_ext_header("") );
assert( mr_needs_ext_header(" ") );
assert( mr_needs_ext_header("a b") );
assert( !mr_needs_ext_header(NULL) );

buf1 = mr_encode_modified_utf7("Björn Petersen", 1);
assert( strcmp(buf1, "Bj&APY-rn_Petersen")==0 );
buf2 = mr_decode_modified_utf7(buf1, 1);
Expand Down
32 changes: 28 additions & 4 deletions src/mrmimefactory.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,20 +391,44 @@ static struct mailmime* build_body_file(const mrmsg_t* msg, const char* base_nam
/* create mime part, for Content-Disposition, see RFC 2183.
`Content-Disposition: attachment` seems not to make a difference to `Content-Disposition: inline` at least on tested Thunderbird and Gma'l in 2017.
But I've heard about problems with inline and outl'k, so we just use the attachment-type until we run into other problems ... */
int needs_ext = mr_needs_ext_header(filename_to_send);

mime_fields = mailmime_fields_new_filename(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
mr_encode_header_words(filename_to_send), MAILMIME_MECHANISM_BASE64);
needs_ext? NULL : safe_strdup(filename_to_send), MAILMIME_MECHANISM_BASE64);

if( ret_file_name_as_sent ) {
*ret_file_name_as_sent = safe_strdup(filename_to_send);
if( needs_ext ) {
for( clistiter* cur1 = clist_begin(mime_fields->fld_list); cur1 != NULL; cur1 = clist_next(cur1) ) {
struct mailmime_field* field = (struct mailmime_field*)clist_content(cur1);
if( field && field->fld_type == MAILMIME_FIELD_DISPOSITION && field->fld_data.fld_disposition )
{
struct mailmime_disposition* file_disposition = field->fld_data.fld_disposition;
if( file_disposition )
{
struct mailmime_disposition_parm* parm = mailmime_disposition_parm_new(
MAILMIME_DISPOSITION_PARM_PARAMETER, NULL, NULL, NULL, NULL, 0,
mailmime_parameter_new(strdup("filename*"), mr_encode_ext_header(filename_to_send)));
if( parm ) {
clist_append(file_disposition->dsp_parms, parm);
}
}

break;
}
}
}

content = mailmime_content_new_with_str(mimetype);
clist_append(content->ct_parameters, mailmime_param_new_with_data("name", (filename_encoded=mr_encode_header_words(filename_to_send))));
clist_append(content->ct_parameters, mailmime_param_new_with_data("name",
(filename_encoded=mr_encode_header_words(filename_to_send))));

mime_sub = mailmime_new_empty(content, mime_fields);

mailmime_set_body_file(mime_sub, safe_strdup(pathNfilename));

if( ret_file_name_as_sent ) {
*ret_file_name_as_sent = safe_strdup(filename_to_send);
}

cleanup:
free(pathNfilename);
free(mimetype);
Expand Down
3 changes: 1 addition & 2 deletions src/mrmimeparser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1140,13 +1140,12 @@ static int mrmimeparser_add_single_part_if_known(mrmimeparser_t* ths, struct mai
or `Content-Disposition: ... filename=...` */
mrstrbuilder_t filename_parts;
mrstrbuilder_init(&filename_parts, 0);
struct mailmime_disposition* file_disposition = NULL; /* must not be free()'d */
for( clistiter* cur1 = clist_begin(mime->mm_mime_fields->fld_list); cur1 != NULL; cur1 = clist_next(cur1) )
{
struct mailmime_field* field = (struct mailmime_field*)clist_content(cur1);
if( field && field->fld_type == MAILMIME_FIELD_DISPOSITION && field->fld_data.fld_disposition )
{
file_disposition = field->fld_data.fld_disposition;
struct mailmime_disposition* file_disposition = field->fld_data.fld_disposition;
if( file_disposition )
{
for( clistiter* cur2 = clist_begin(file_disposition->dsp_parms); cur2 != NULL; cur2 = clist_next(cur2) )
Expand Down
27 changes: 26 additions & 1 deletion src/mrstrencode.c
Original file line number Diff line number Diff line change
Expand Up @@ -751,12 +751,37 @@ char* mr_decode_modified_utf7(const char *to_decode, int change_spaces)
******************************************************************************/


/**
* Check if extended header format is needed for a given string.
*
* @param to_check Null-terminated UTF-8 string to check.
*
* @return 0=extended header encoding is not needed,
* 1=extended header encoding is needed,
* use mr_encode_ext_header() for this purpose.
*/
int mr_needs_ext_header(const char* to_check)
{
if( to_check ) {
while( *to_check )
{
if( !isalnum(*to_check) && *to_check!='-' && *to_check!='_' && *to_check!='.' && *to_check!='~' ) {
return 1;
}
to_check++;
}
}

return 0;
}


/**
* Encode an UTF-8 string to the extended header format.
*
* Example: `Björn Petersen` gets encoded to `utf-8''Bj%C3%B6rn%20Petersen`
*
* @param to_encode Null-terminated UTF-8 string to encode
* @param to_encode Null-terminated UTF-8 string to encode.
*
* @return Null-terminated encoded string. Must be free()'d after usage.
* Halts the program on memory allocation errors,
Expand Down
1 change: 1 addition & 0 deletions src/mrstrencode.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ char* mr_decode_header_words (const char*);
char* mr_encode_modified_utf7 (const char*, int change_spaces);
char* mr_decode_modified_utf7 (const char*, int change_spaces);

int mr_needs_ext_header (const char*);
char* mr_encode_ext_header (const char*);
char* mr_decode_ext_header (const char*);

Expand Down

0 comments on commit d40e85f

Please sign in to comment.