@@ -302,18 +302,22 @@ defmodule Mail.Parsers.RFC2822 do
302
302
end )
303
303
end
304
304
305
- defp parse_headers ( message , [ ] , _opts ) , do: message
305
+ defp parse_headers ( message , headers , opts ) do
306
+ headers =
307
+ Enum . reduce ( headers , message . headers , fn header , headers ->
308
+ { key , value } = parse_header ( header , opts )
309
+ put_header ( headers , key , value )
310
+ end )
311
+
312
+ Map . put ( message , :headers , headers )
313
+ end
306
314
307
- defp parse_headers ( message , [ header | tail ] , opts ) do
315
+ def parse_header ( header , opts ) do
308
316
[ name , body ] = String . split ( header , ":" , parts: 2 )
309
317
key = String . downcase ( name )
310
- decoded = parse_encoded_word ( body , opts )
311
-
312
- headers =
313
- put_header ( message . headers , key , String . downcase ( name ) |> parse_header_value ( decoded ) )
314
-
315
- message = % { message | headers: headers }
316
- parse_headers ( message , tail , opts )
318
+ value = parse_header_value ( key , body )
319
+ decoded = decode_header_value ( key , value , opts )
320
+ { key , decoded }
317
321
end
318
322
319
323
defp put_header ( headers , "received" = key , value ) ,
@@ -372,6 +376,48 @@ defmodule Mail.Parsers.RFC2822 do
372
376
defp parse_header_value ( _key , value ) ,
373
377
do: value
374
378
379
+ defp decode_header_value ( _key , nil , _opts ) ,
380
+ do: nil
381
+
382
+ defp decode_header_value ( _key , % DateTime { } = datetime , _opts ) ,
383
+ do: datetime
384
+
385
+ defp decode_header_value ( "received" , value , _opts ) ,
386
+ do: value
387
+
388
+ defp decode_header_value ( _key , [ value | [ param | _params ] = params ] , opts )
389
+ when is_binary ( value ) and is_tuple ( param ) do
390
+ decoded = parse_encoded_word ( value , opts )
391
+ params = Enum . map ( params , fn { param , value } -> { param , parse_encoded_word ( value , opts ) } end )
392
+ [ decoded | params ]
393
+ end
394
+
395
+ defp decode_header_value ( _key , { name , email } , opts ) do
396
+ decoded = parse_encoded_word ( name , opts )
397
+ { decoded , email }
398
+ end
399
+
400
+ defp decode_header_value ( key , addresses , opts )
401
+ when key in [ "to" , "cc" , "from" , "reply-to" ] and is_list ( addresses ) do
402
+ addresses =
403
+ Enum . map ( addresses , fn
404
+ { name , email } ->
405
+ decoded = parse_encoded_word ( name , opts )
406
+ { decoded , email }
407
+
408
+ email ->
409
+ email
410
+ end )
411
+
412
+ addresses
413
+ end
414
+
415
+ defp decode_header_value ( "from" , value , _opts ) , do: value
416
+
417
+ defp decode_header_value ( _key , value , opts ) do
418
+ parse_encoded_word ( value , opts )
419
+ end
420
+
375
421
# See https://tools.ietf.org/html/rfc2047
376
422
defp parse_encoded_word ( "" , _opts ) , do: ""
377
423
@@ -404,39 +450,59 @@ defmodule Mail.Parsers.RFC2822 do
404
450
defp parse_encoded_word ( << char :: utf8 , rest :: binary >> , opts ) ,
405
451
do: << char :: utf8 , parse_encoded_word ( rest , opts ) :: binary >>
406
452
407
- defp parse_structured_header_value ( string , value \\ nil , sub_types \\ [ ] , acc \\ "" )
453
+ defp parse_structured_header_value (
454
+ string ,
455
+ value \\ nil ,
456
+ sub_types \\ [ ] ,
457
+ part \\ :value ,
458
+ acc \\ ""
459
+ )
408
460
409
- defp parse_structured_header_value ( "" , value , [ { key , nil } | sub_types ] , acc ) ,
461
+ defp parse_structured_header_value ( "" , value , [ { key , nil } | sub_types ] , _part , acc ) ,
410
462
do: [ value | Enum . reverse ( [ { key , acc } | sub_types ] ) ]
411
463
412
- defp parse_structured_header_value ( "" , nil , [ ] , acc ) ,
464
+ defp parse_structured_header_value ( "" , nil , [ ] , _part , acc ) ,
413
465
do: acc
414
466
415
- defp parse_structured_header_value ( "" , value , sub_types , "" ) ,
467
+ defp parse_structured_header_value ( "" , value , sub_types , _part , "" ) ,
416
468
do: [ value | Enum . reverse ( sub_types ) ]
417
469
418
- defp parse_structured_header_value ( "" , value , [ ] , acc ) ,
470
+ defp parse_structured_header_value ( "" , value , [ ] , _part , acc ) ,
419
471
do: [ value , String . trim ( acc ) ]
420
472
421
- defp parse_structured_header_value ( "" , value , sub_types , acc ) ,
422
- do: parse_structured_header_value ( "" , value , sub_types , String . trim ( acc ) )
473
+ defp parse_structured_header_value ( "" , value , sub_types , part , acc ) ,
474
+ do: parse_structured_header_value ( "" , value , sub_types , part , String . trim ( acc ) )
423
475
424
- defp parse_structured_header_value ( << "\" " , rest :: binary >> , value , sub_types , acc ) do
476
+ defp parse_structured_header_value ( << "\" " , rest :: binary >> , value , sub_types , part , acc ) do
425
477
{ string , rest } = parse_quoted_string ( rest )
426
- parse_structured_header_value ( rest , value , sub_types , << acc :: binary , string :: binary >> )
478
+ parse_structured_header_value ( rest , value , sub_types , part , << acc :: binary , string :: binary >> )
427
479
end
428
480
429
- defp parse_structured_header_value ( << ";" , rest :: binary >> , nil , sub_types , acc ) ,
430
- do: parse_structured_header_value ( rest , acc , sub_types , "" )
431
-
432
- defp parse_structured_header_value ( << ";" , rest :: binary >> , value , [ { key , nil } | sub_types ] , acc ) ,
433
- do: parse_structured_header_value ( rest , value , [ { key , acc } | sub_types ] , "" )
481
+ defp parse_structured_header_value ( << ";" , rest :: binary >> , nil , sub_types , part , acc )
482
+ when part in [ :value , :param_value ] ,
483
+ do: parse_structured_header_value ( rest , acc , sub_types , :param_name , "" )
434
484
435
- defp parse_structured_header_value ( << "=" , rest :: binary >> , value , sub_types , acc ) ,
436
- do: parse_structured_header_value ( rest , value , [ { key_to_atom ( acc ) , nil } | sub_types ] , "" )
485
+ defp parse_structured_header_value (
486
+ << ";" , rest :: binary >> ,
487
+ value ,
488
+ [ { key , nil } | sub_types ] ,
489
+ :param_value ,
490
+ acc
491
+ ) ,
492
+ do: parse_structured_header_value ( rest , value , [ { key , acc } | sub_types ] , :param_name , "" )
437
493
438
- defp parse_structured_header_value ( << char :: utf8 , rest :: binary >> , value , sub_types , acc ) ,
439
- do: parse_structured_header_value ( rest , value , sub_types , << acc :: binary , char :: utf8 >> )
494
+ defp parse_structured_header_value ( << "=" , rest :: binary >> , value , sub_types , :param_name , acc ) ,
495
+ do:
496
+ parse_structured_header_value (
497
+ rest ,
498
+ value ,
499
+ [ { key_to_atom ( acc ) , nil } | sub_types ] ,
500
+ :param_value ,
501
+ ""
502
+ )
503
+
504
+ defp parse_structured_header_value ( << char :: utf8 , rest :: binary >> , value , sub_types , part , acc ) ,
505
+ do: parse_structured_header_value ( rest , value , sub_types , part , << acc :: binary , char :: utf8 >> )
440
506
441
507
defp parse_quoted_string ( string , acc \\ "" )
442
508
0 commit comments