sup 0.20.0 → 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -1
  3. data/.travis.yml +11 -6
  4. data/CONTRIBUTORS +27 -15
  5. data/Gemfile +2 -1
  6. data/History.txt +84 -0
  7. data/README.md +26 -5
  8. data/Rakefile +0 -1
  9. data/ReleaseNotes +7 -0
  10. data/bin/sup +17 -30
  11. data/bin/sup-add +15 -16
  12. data/bin/sup-config +30 -45
  13. data/bin/sup-dump +2 -3
  14. data/bin/sup-import-dump +5 -6
  15. data/bin/sup-sync +3 -4
  16. data/bin/sup-sync-back-maildir +3 -4
  17. data/bin/sup-tweak-labels +6 -7
  18. data/contrib/colorpicker.rb +0 -2
  19. data/contrib/completion/_sup.bash +102 -0
  20. data/devel/profile.rb +0 -1
  21. data/ext/mkrf_conf_xapian.rb +1 -1
  22. data/lib/sup.rb +8 -8
  23. data/lib/sup/colormap.rb +5 -2
  24. data/lib/sup/contact.rb +4 -2
  25. data/lib/sup/crypto.rb +58 -16
  26. data/lib/sup/draft.rb +8 -8
  27. data/lib/sup/hook.rb +9 -9
  28. data/lib/sup/index.rb +20 -7
  29. data/lib/sup/label.rb +1 -1
  30. data/lib/sup/logger.rb +1 -1
  31. data/lib/sup/maildir.rb +2 -2
  32. data/lib/sup/mbox.rb +2 -2
  33. data/lib/sup/message.rb +26 -10
  34. data/lib/sup/message_chunks.rb +7 -4
  35. data/lib/sup/mode.rb +34 -28
  36. data/lib/sup/modes/contact_list_mode.rb +1 -0
  37. data/lib/sup/modes/edit_message_mode.rb +1 -1
  38. data/lib/sup/modes/forward_mode.rb +22 -3
  39. data/lib/sup/modes/line_cursor_mode.rb +1 -1
  40. data/lib/sup/modes/reply_mode.rb +3 -1
  41. data/lib/sup/modes/text_mode.rb +6 -1
  42. data/lib/sup/modes/thread_index_mode.rb +6 -2
  43. data/lib/sup/modes/thread_view_mode.rb +63 -18
  44. data/lib/sup/person.rb +68 -61
  45. data/lib/sup/search.rb +1 -1
  46. data/lib/sup/sent.rb +1 -1
  47. data/lib/sup/source.rb +1 -1
  48. data/lib/sup/util.rb +15 -94
  49. data/lib/sup/util/axe.rb +17 -0
  50. data/lib/sup/util/locale_fiddler.rb +24 -0
  51. data/lib/sup/util/ncurses.rb +3 -3
  52. data/lib/sup/version.rb +10 -1
  53. data/sup.gemspec +12 -10
  54. data/test/{messages → fixtures}/bad-content-transfer-encoding-1.eml +0 -0
  55. data/test/{messages → fixtures}/binary-content-transfer-encoding-2.eml +0 -0
  56. data/test/fixtures/blank-header-fields.eml +71 -0
  57. data/test/fixtures/contacts.txt +1 -0
  58. data/test/fixtures/mailing-list-header.eml +80 -0
  59. data/test/fixtures/malicious-attachment-names.eml +55 -0
  60. data/test/fixtures/missing-from-to.eml +18 -0
  61. data/test/{messages → fixtures}/missing-line.eml +0 -0
  62. data/test/fixtures/multi-part-2.eml +72 -0
  63. data/test/fixtures/multi-part.eml +61 -0
  64. data/test/fixtures/no-body.eml +18 -0
  65. data/test/fixtures/simple-message.eml +29 -0
  66. data/test/fixtures/text-attachments-with-charset.eml +46 -0
  67. data/test/fixtures/zimbra-quote-with-bottom-post.eml +27 -0
  68. data/test/gnupg_test_home/gpg.conf +2 -1
  69. data/test/gnupg_test_home/private-keys-v1.d/306D2EE90FF0014B5B9FD07E265C751791674140.key +0 -0
  70. data/test/gnupg_test_home/pubring.gpg +0 -0
  71. data/test/gnupg_test_home/receiver_pubring.gpg +0 -0
  72. data/test/gnupg_test_home/receiver_secring.gpg +0 -0
  73. data/test/gnupg_test_home/regen_keys.sh +70 -16
  74. data/test/gnupg_test_home/secring.gpg +0 -0
  75. data/test/gnupg_test_home/sup-test-2@foo.bar.asc +20 -22
  76. data/test/integration/test_maildir.rb +1 -1
  77. data/test/integration/test_mbox.rb +1 -1
  78. data/test/test_crypto.rb +14 -2
  79. data/test/test_header_parsing.rb +1 -1
  80. data/test/test_helper.rb +6 -3
  81. data/test/test_message.rb +115 -341
  82. data/test/test_messages_dir.rb +4 -28
  83. data/test/test_yaml_regressions.rb +1 -1
  84. data/test/unit/test_contact.rb +33 -0
  85. data/test/unit/test_locale_fiddler.rb +15 -0
  86. data/test/unit/test_person.rb +37 -0
  87. data/test/unit/util/test_query.rb +10 -4
  88. data/test/unit/util/test_string.rb +6 -0
  89. metadata +107 -43
  90. data/test/gnupg_test_home/key1.gen +0 -15
  91. data/test/gnupg_test_home/key2.gen +0 -15
@@ -0,0 +1,29 @@
1
+ Return-path: <fake_sender@example.invalid>
2
+ Envelope-to: fake_receiver@localhost
3
+ Delivery-date: Sun, 09 Dec 2007 21:48:19 +0200
4
+ Received: from fake_sender by localhost.localdomain with local (Exim 4.67)
5
+ (envelope-from <fake_sender@example.invalid>)
6
+ id 1J1S8R-0006lA-MJ
7
+ for fake_receiver@localhost; Sun, 09 Dec 2007 21:48:19 +0200
8
+ Date: Sun, 9 Dec 2007 21:48:19 +0200
9
+ Mailing-List: contact example-help@example.invalid; run by ezmlm
10
+ Precedence: bulk
11
+ List-Id: <example.list-id.example.invalid>
12
+ List-Post: <mailto:example@example.invalid>
13
+ List-Help: <mailto:example-help@example.invalid>
14
+ List-Unsubscribe: <mailto:example-unsubscribe@example.invalid>
15
+ List-Subscribe: <mailto:example-subscribe@example.invalid>
16
+ Delivered-To: mailing list example@example.invalid
17
+ Delivered-To: moderator for example@example.invalid
18
+ From: Fake Sender <fake_sender@example.invalid>
19
+ To: Fake Receiver <fake_receiver@localhost>
20
+ Subject: Re: Test message subject
21
+ Message-ID: <20071209194819.GA25972@example.invalid>
22
+ References: <E1J1Rvb-0006k2-CE@localhost.localdomain>
23
+ MIME-Version: 1.0
24
+ Content-Type: text/plain; charset=us-ascii
25
+ Content-Disposition: inline
26
+ In-Reply-To: <E1J1Rvb-0006k2-CE@localhost.localdomain>
27
+ User-Agent: Sup/0.3
28
+
29
+ Test message!
@@ -0,0 +1,46 @@
1
+ From: Fake Sender <fake_sender@example.invalid>
2
+ To: Fake Receiver <fake_receiver@localhost>
3
+ Date: Sun, 21 Jun 2020 06:25:49 -0000
4
+ Subject: Attachments with charset
5
+ MIME-Version: 1.0
6
+ Content-Type: multipart/mixed; boundary="===============2385509127900810307=="
7
+
8
+ --===============2385509127900810307==
9
+ Content-Type: text/plain; charset="utf-8"
10
+ Content-Transfer-Encoding: 7bit
11
+
12
+ This is the body.
13
+
14
+ --===============2385509127900810307==
15
+ Content-Type: text/plain; charset="us-ascii"
16
+ Content-Transfer-Encoding: 7bit
17
+ MIME-Version: 1.0
18
+ Content-Disposition: attachment; filename="ascii.txt"
19
+
20
+ This is ASCII
21
+
22
+ --===============2385509127900810307==
23
+ Content-Type: text/plain; charset="koi8-r"
24
+ Content-Transfer-Encoding: quoted-printable
25
+ MIME-Version: 1.0
26
+ Content-Disposition: attachment; filename="cyrillic.txt"
27
+
28
+ =F0=D2=C9=D7=C5=D4
29
+
30
+ --===============2385509127900810307==
31
+ Content-Type: text/plain; charset="utf-8"
32
+ Content-Transfer-Encoding: base64
33
+ MIME-Version: 1.0
34
+ Content-Disposition: attachment; filename="emoji.txt"
35
+
36
+ 8J+Yggo=
37
+
38
+ --===============2385509127900810307==
39
+ Content-Type: text/plain
40
+ Content-Transfer-Encoding: quoted-printable
41
+ Content-Disposition: attachment; filename="bad.txt"
42
+ MIME-Version: 1.0
43
+
44
+ Embedded=F0garbage
45
+ --===============2385509127900810307==--
46
+
@@ -0,0 +1,27 @@
1
+ Return-Path: <zimbra.user@example.invalid>
2
+ Delivered-To: <recipient@example.invalid>
3
+ Received: from zmail16.collab.prod.int.phx2.redhat.com (zmail16.collab.prod.int.phx2.redhat.com [10.5.83.18])
4
+ by mx4-phx2.redhat.com (8.13.8/8.13.8) with ESMTP id q3A5xQ06025053
5
+ for <recipient@example.invalid>; Tue, 10 Apr 2012 01:59:26 -0400
6
+ Date: Tue, 10 Apr 2012 01:59:26 -0400 (EDT)
7
+ From: Zimbra User <zimbra.user@example.invalid>
8
+ To: Recipient <recipient@example.invalid>
9
+ Subject: Re: Zimbra
10
+ Message-ID: <0fe105df-e67b-419e-8599-50aaff7260e8@zmail16.collab.prod.int.phx2.redhat.com>
11
+ In-Reply-To: <1334037315-sup-8577@example.invalid>
12
+ Content-Type: text/plain; charset=utf-8
13
+ Content-Transfer-Encoding: 7bit
14
+ MIME-Version: 1.0
15
+ X-Mailer: Zimbra 7.1.2_GA_3268 (ZimbraWebClient - FF3.0 (Linux)/7.1.2_GA_3268)
16
+
17
+ ----- Original Message -----
18
+ > From: "Recipient" <recipient@example.invalid>
19
+ > To: "Zimbra User" <zimbra.user@example.invalid>
20
+ > Sent: Tuesday, April 10, 2012 3:56:15 PM
21
+ > Subject: Re: Zimbra
22
+ >
23
+ > This is the quoted original message.
24
+ >
25
+
26
+
27
+ This is the reply from the Zimbra user.
@@ -1,2 +1,3 @@
1
1
  trust-model always
2
-
2
+ # Set preferred hash algo to the one expected in the test suite
3
+ personal-digest-preferences sha256
@@ -1,35 +1,89 @@
1
- #! /bin/bash
1
+ #!/bin/bash
2
2
  #
3
3
  # re-generate test keys for the sup test base
4
4
  #
5
5
  # https://github.com/sup-heliotrope/sup/wiki/Development%3A-Crypto
6
+ #
7
+ # Requires GPG 2.1+ installed as "gpg2"
8
+ #
9
+ # GPG 2.1+ by default uses pubring.kbx - but this isn't backwards compatible
10
+ # with GPG 1 or GPG 2.0.
11
+ # Workaround:
12
+ # - Create empty pubring.gpg file, which causes GPG 2.1+ to use this
13
+ # backwards-compatible store.
14
+ # - Manually export private key copy to secring.gpg, which would be used
15
+ # by GPG 1.
16
+
17
+ set -e -u -o pipefail
6
18
 
7
19
  pushd $(dirname $0)
8
20
 
9
- export GNUPGHOME="$(pwd)"
21
+ echo "Generating keys in: $(pwd)..."
10
22
 
11
- echo "genrating keys in: $GNUPGHOME.."
23
+ echo "Checking gpg2 version"
24
+ gpg2 --version | head -1
12
25
 
13
- rm *.gpg *.asc
26
+ echo "Deleting all existing test keys"
27
+ rm -f \
28
+ *.gpg \
29
+ *.asc \
30
+ private-keys-v1.d/*.key \
31
+ .gpg-v21-migrated
14
32
 
15
- echo "generate receiver key.."
16
- gpg --batch --gen-key key2.gen
33
+ echo "Generating key pair for test receiver (email sup-test-2@foo.bar.asc)"
34
+ touch pubring.gpg # So GPG 2.1+ writes to pubring.gpg instead of pubring.kbx
35
+ gpg2 \
36
+ --homedir . \
37
+ --batch \
38
+ --pinentry-mode loopback \
39
+ --passphrase '' \
40
+ --quick-generate-key sup-test-2@foo.bar rsa encrypt,sign 0
17
41
 
18
- echo "export receiver key.."
42
+ echo "Exporting public key only for test receiver (file sup-test-2@foo.bar.asc)"
43
+ gpg2 \
44
+ --homedir . \
45
+ --armor \
46
+ --output sup-test-2@foo.bar.asc \
47
+ --export sup-test-2@foo.bar
19
48
 
20
- gpg --output sup-test-2@foo.bar.asc --armor --export sup-test-2@foo.bar
49
+ echo "Backing up secret key for test receiver (file receiver_secring.gpg)"
50
+ gpg2 \
51
+ --homedir . \
52
+ --export-secret-keys \
53
+ >receiver_secring.gpg
21
54
 
22
- mv trustdb.gpg receiver_trustdb.gpg
23
- mv secring.gpg receiver_secring.gpg
24
- mv pubring.gpg receiver_pubring.gpg
55
+ echo "Backing up pubring.gpg for test receiver (file receiver_pubring.gpg)"
56
+ cp -a pubring.gpg receiver_pubring.gpg
25
57
 
26
- echo "generate sender key.."
27
- gpg --batch --gen-key key1.gen
58
+ echo "Clearing key store, so we can start from a blank slate for next key(s)"
59
+ rm -f pubring.gpg trustdb.gpg private-keys-v1.d/*.key .gpg-v21-migrated
28
60
 
29
- echo "import receiver key.."
30
- gpg --import sup-test-2@foo.bar.asc
61
+ echo "Generating key pair for sender (email sup-test-1@foo.bar)"
62
+ touch pubring.gpg # So GPG 2.1+ writes to pubring.gpg instead of pubring.kbx
63
+ gpg2 \
64
+ --homedir . \
65
+ --batch \
66
+ --pinentry-mode loopback \
67
+ --passphrase '' \
68
+ --quick-generate-key sup-test-1@foo.bar rsa encrypt,sign 0
31
69
 
70
+ echo "Importing public key for receiver, into sender's key store"
71
+ gpg2 \
72
+ --homedir . \
73
+ --import sup-test-2@foo.bar.asc
32
74
 
75
+ echo "Copy private key also to secring.gpg (old format used by GPG 1)"
76
+ gpg2 \
77
+ --homedir . \
78
+ --export-secret-keys \
79
+ >secring.gpg
33
80
 
34
- popd
81
+ echo "Done."
82
+
83
+ echo "We now have two non-expiring public keys (receiver & sender):"
84
+ gpg2 --homedir . --list-keys
35
85
 
86
+ echo "And we also have only *one* corresponding private key (sender only):"
87
+ gpg2 --homedir . --list-secret-keys
88
+
89
+ popd
@@ -1,25 +1,23 @@
1
1
  -----BEGIN PGP PUBLIC KEY BLOCK-----
2
- Version: GnuPG v2
3
2
 
4
- mQGiBFP3VogRBADVBEkaZQXj728C1HUIaTRDCFoKzojwC79Z1BLsD72qQYE8z1ic
5
- 5P9CJpJU5wbhQFDTGBjw+i1nNTWy01z4q5bfFqok+KorT3XNp5IJRcRIEOkj+Twq
6
- 7ZaSODwXGsUmdzSoOVDYmtUpVzRQe0IM0rPQQV4vGzgw55FdJBe7a63nIwCg+WvR
7
- iQN09PlhpGG7SIEmx0psEqUEAL/t1c5oC9RC7L4a0GM+2AcgFRBMXvzpdnytrzgt
8
- 73Ud6CcUplQp6WODrUYhX0RLzSJPO4zWDsBmkBad/iQCwbCKpFPfAFdBMArJpknx
9
- rc6vRED4a9dLfCNTT1g86CkiElge9t36juZgOoFT3xt/XP7BxhU1fCFshZNR6VK6
10
- tN9eA/9G4fUX6XvEGIrNiBYKyU4QvM1nyMXCBujm7vYF6KfSlYyAvVXxG4h+mvUy
11
- ZXQ/WHMQJSbPTY3dd4hmo0p0GUMlSvXU8JLf7qienW1IccD9Pv88J1XjkbFd+wgw
12
- feoSx1sAfc36gH+aE17lvsU+PPAP4Bc9CSiScNo0iQv7v/KZjrQ+U3VwIFRlc3Qg
13
- UmVjZWl2ZXIgKFRlc3QgcmVjZWl2ZXIgZm9yIFN1cCkgPHN1cC10ZXN0LTJAZm9v
14
- LmJhcj6IaQQTEQIAKQUCU/dWiAIbIwUJAeEzgAcLCQgHAwIBBhUIAgkKCwQWAgMB
15
- Ah4BAheAAAoJEKfs+g8ACvQGPxIAnj1CSZCzjwyIFLgNEQnIhntU+b28AKDsMEVN
16
- gf9mHqwhabN+UKgBwX0U3LkBDQRT91aIEAQAjQZEnDK++SKp/l2Oiku6H9IuCsi4
17
- lv+MhLQP0bMuD4DrPk3mauZNc8BB+U0wgAMh/kZoCKySEdMK1mcf2iOsd5yOCrK+
18
- sJQAMsALAnrYjCE9QA2xIQs8gHF4PrKopycF55iRHQMDNa1QWfs+j4WJaXderlGQ
19
- S0dGfLyoqtZsFusAAwUEAIi0+aDZlAVVIdDO2cvR0lu6eDW2Mr2ExZzuwTfAI6dS
20
- tJLoPzoA2OAVW7cFVVpCOHcVLiF2GOHvtJPw1MgpxaNjzpNdJPTiP2sYZg253dfR
21
- v66Cw9IuWKgZcElWXmIy5vFWqWWbLyTBOuwEQxCsFnjN9UUZauSADOJSPFy1sekf
22
- iE8EGBECAA8FAlP3VogCGwwFCQHhM4AACgkQp+z6DwAK9Ab/swCg8LWNwfMwNk+H
23
- gLgnS1LVsesZ8D4An2Ie2P0/oYuSmPPFV44kbWySX9wW
24
- =Jo82
3
+ mQGNBF7leTkBDAC3auy8xodH6jxoISylFZTpVqy/0L2ul879YUb/QbC58+F/H36S
4
+ CjLfPxFlq0FAOXHelOvktxaybg+BG5UpSvTgBLbcArq5nctee+04TMXCzQzrG2V1
5
+ zb9gIRT665fX3+WYncSIXdr4LAp7r8Jw3RT3tTOZqbaencumCWaJblnvfFwPrMKf
6
+ AXWa/NVndNMAXmJ5uBf1MRr45KXaQ2tczPIeHqSOKhKNnKZPRqPs0fg4i3d0Vb6G
7
+ yItgtJapfBo50FV+PvtodMHo3LDlz/BBjdEJHSvghqEjb1S7xGo+hdXs+lfCMfa0
8
+ 3PAWoj+OeHNorbK0YbVKOtS0E0xYvScbyC7bfwtA9yb3LZYmy7VHsKJmQfygCNQ6
9
+ wIKQGAVN1NcQcJsvWyAwk9+WMN5oqB5lb76u40beoWlUjSJRlph2VvWvkGuh/huU
10
+ sVGqcN7EO4SFkwi2YQLoWfQRGur3mids/PQTBywpGE1SyziPZK76pT6SqP8b+OpI
11
+ CG1QbcTZzYpbv6kAEQEAAbQSc3VwLXRlc3QtMkBmb28uYmFyiQHOBBMBCgA4FiEE
12
+ e0oXvVeqMzUcfd1s2bF8xbTizW8FAl7leTkCGw8FCwkIBwIGFQoJCAsCBBYCAwEC
13
+ HgECF4AACgkQ2bF8xbTizW92TAv/WGlYfDTKNEmJ0K+kxt33T2ldmZXaJKL04Mft
14
+ h5s5KlRZWDNpkCC/L55uyaeEg+Uy+BEEQKLAEeJrrLMV8UMJwMPDOizSTT9uLyiz
15
+ b8RjnQw4iMT8wt9TQboXGaTMslwdXvFPii7w44KgCimE7VuPetJuLMLMbnl147G8
16
+ +QhkNUsrB51TuPS8xZJ4qjbH+K/Y2NlvwLtJrxNE3SRQuy2ApYJxKPZIj1KpUL8M
17
+ 7Jy/2hI8DaRm/0Fpu8HwRIVsd6/dgdkqdj1uVyLj+wyhgdzqV5WrPLFCRVhd3icd
18
+ lPNRIDjg8YKCh353LVHjKwefOW4SnkOPn4uVMdCP9gUFd9zpMP9lMFpjk0o0tcYO
19
+ NiFrOclS4q5qZ5jrj1MnBF0NaGhuC83DDgRfKV+p5noVeJxg0nXYZSlsSMfAT/K7
20
+ FbdNEg0XUsrLgWVzhvWv/ebMetFPSfGHIveZ7lhiq1qpA5hLBNfSSBb1JJsFmtQt
21
+ cEUluymdNe5W7Y6UGs1CpvcIvbj+
22
+ =Cy9S
25
23
  -----END PGP PUBLIC KEY BLOCK-----
@@ -1,6 +1,6 @@
1
1
  require "test_helper"
2
2
 
3
- class TestMaildir < MiniTest::Unit::TestCase
3
+ class TestMaildir < Minitest::Test
4
4
 
5
5
  def setup
6
6
  @path = Dir.mktmpdir
@@ -1,6 +1,6 @@
1
1
  require "test_helper"
2
2
 
3
- class TestMbox < MiniTest::Unit::TestCase
3
+ class TestMbox < MiniTest::Test
4
4
 
5
5
  def setup
6
6
  @path = Dir.mktmpdir
@@ -25,10 +25,11 @@ require 'tmpdir'
25
25
 
26
26
  module Redwood
27
27
 
28
- class TestCryptoManager < ::Minitest::Unit::TestCase
28
+ class TestCryptoManager < Minitest::Test
29
29
 
30
30
  def setup
31
31
  @from_email = 'sup-test-1@foo.bar'
32
+ @from_email_ecc = 'sup-fake-ecc@fake.fake'
32
33
  @to_email = 'sup-test-2@foo.bar'
33
34
  # Use test gnupg setup
34
35
  @orig_gnupghome = ENV['GNUPGHOME']
@@ -37,7 +38,7 @@ class TestCryptoManager < ::Minitest::Unit::TestCase
37
38
  @path = Dir.mktmpdir
38
39
  Redwood::HookManager.init File.join(@path, 'hooks')
39
40
 
40
- am = {:default=> {:name => "test", :email=> 'sup-test-1@foo.bar'}}
41
+ am = {:default=> {name: "test", email: @from_email, alternates: [@from_email_ecc]}}
41
42
  Redwood::AccountManager.init am
42
43
 
43
44
  Redwood::CryptoManager.init
@@ -60,6 +61,8 @@ class TestCryptoManager < ::Minitest::Unit::TestCase
60
61
  if CryptoManager.have_crypto? then
61
62
  signed = CryptoManager.sign @from_email,@to_email,"ABCDEFG"
62
63
  assert_instance_of RMail::Message, signed
64
+ assert_equal("multipart/signed; protocol=application/pgp-signature; micalg=pgp-sha256",
65
+ signed.header["Content-Type"])
63
66
  assert_equal "ABCDEFG", signed.body[0]
64
67
  assert signed.body[1].body.length > 0 , "signature length must be > 0"
65
68
  assert (signed.body[1].body.include? "-----BEGIN PGP SIGNATURE-----") , "Expecting PGP armored data"
@@ -104,6 +107,15 @@ class TestCryptoManager < ::Minitest::Unit::TestCase
104
107
  CryptoManager.verify signed.body[0], signed.body[1], true
105
108
  end
106
109
  end
110
+
111
+ def test_verify_unknown_keytype
112
+ if CryptoManager.have_crypto?
113
+ signed = CryptoManager.sign @from_email_ecc, @to_email, "ABCDEFG"
114
+ assert_instance_of RMail::Message, signed
115
+ assert_instance_of String, (signed.body[1].body)
116
+ CryptoManager.verify signed.body[0], signed.body[1], true
117
+ end
118
+ end
107
119
  end
108
120
 
109
121
  end
@@ -6,7 +6,7 @@ require 'stringio'
6
6
 
7
7
  include Redwood
8
8
 
9
- class TestMBoxParsing < Minitest::Unit::TestCase
9
+ class TestMBoxParsing < Minitest::Test
10
10
 
11
11
  def setup
12
12
  @path = Dir.mktmpdir
@@ -2,6 +2,9 @@ require "rubygems" rescue nil
2
2
  require 'minitest/autorun'
3
3
  require "rr"
4
4
 
5
- class Minitest::Unit::TestCase
6
- include ::RR::Adapters::MiniTest
7
- end
5
+ def fixture(filename)
6
+ file = ''
7
+ path = File.expand_path("../fixtures/#{filename}", __FILE__)
8
+ File.open(path) { |io| file = io.read }
9
+ file
10
+ end
@@ -6,27 +6,9 @@ require 'stringio'
6
6
 
7
7
  require 'dummy_source'
8
8
 
9
- # override File.exists? to make it work with StringIO for testing.
10
- # FIXME: do aliasing to avoid breaking this when sup moves from
11
- # File.exists? to File.exist?
12
-
13
- class File
14
-
15
- def File.exists? file
16
- # puts "fake File::exists?"
17
-
18
- if file.is_a?(StringIO)
19
- return false
20
- end
21
- # use the different function
22
- File.exist?(file)
23
- end
24
-
25
- end
26
-
27
9
  module Redwood
28
10
 
29
- class TestMessage < ::Minitest::Unit::TestCase
11
+ class TestMessage < Minitest::Test
30
12
 
31
13
  def setup
32
14
  @path = Dir.mktmpdir
@@ -39,38 +21,7 @@ class TestMessage < ::Minitest::Unit::TestCase
39
21
  end
40
22
 
41
23
  def test_simple_message
42
-
43
- message = <<EOS
44
- Return-path: <fake_sender@example.invalid>
45
- Envelope-to: fake_receiver@localhost
46
- Delivery-date: Sun, 09 Dec 2007 21:48:19 +0200
47
- Received: from fake_sender by localhost.localdomain with local (Exim 4.67)
48
- (envelope-from <fake_sender@example.invalid>)
49
- id 1J1S8R-0006lA-MJ
50
- for fake_receiver@localhost; Sun, 09 Dec 2007 21:48:19 +0200
51
- Date: Sun, 9 Dec 2007 21:48:19 +0200
52
- Mailing-List: contact example-help@example.invalid; run by ezmlm
53
- Precedence: bulk
54
- List-Id: <example.list-id.example.invalid>
55
- List-Post: <mailto:example@example.invalid>
56
- List-Help: <mailto:example-help@example.invalid>
57
- List-Unsubscribe: <mailto:example-unsubscribe@example.invalid>
58
- List-Subscribe: <mailto:example-subscribe@example.invalid>
59
- Delivered-To: mailing list example@example.invalid
60
- Delivered-To: moderator for example@example.invalid
61
- From: Fake Sender <fake_sender@example.invalid>
62
- To: Fake Receiver <fake_receiver@localhost>
63
- Subject: Re: Test message subject
64
- Message-ID: <20071209194819.GA25972@example.invalid>
65
- References: <E1J1Rvb-0006k2-CE@localhost.localdomain>
66
- MIME-Version: 1.0
67
- Content-Type: text/plain; charset=us-ascii
68
- Content-Disposition: inline
69
- In-Reply-To: <E1J1Rvb-0006k2-CE@localhost.localdomain>
70
- User-Agent: Sup/0.3
71
-
72
- Test message!
73
- EOS
24
+ message = fixture('simple-message.eml')
74
25
 
75
26
  source = DummySource.new("sup-test://test_simple_message")
76
27
  source.messages = [ message ]
@@ -80,11 +31,9 @@ EOS
80
31
  sup_message.load_from_source!
81
32
 
82
33
  # see how well parsing the header went
83
-
84
34
  to = sup_message.to
85
- # "to" is an Array containing person items
86
-
87
- # there should be only one item
35
+ assert(to.is_a? Array)
36
+ assert(to.first.is_a? Person)
88
37
  assert_equal(1, to.length)
89
38
 
90
39
  # sup doesn't do capitalized letters in email addresses
@@ -92,8 +41,7 @@ EOS
92
41
  assert_equal("Fake Receiver", to[0].name)
93
42
 
94
43
  from = sup_message.from
95
- # "from" is just a simple person item
96
-
44
+ assert(from.is_a? Person)
97
45
  assert_equal("fake_sender@example.invalid", from.email)
98
46
  assert_equal("Fake Sender", from.name)
99
47
 
@@ -124,13 +72,8 @@ EOS
124
72
  assert_equal(1, replytos.length)
125
73
  assert_equal("E1J1Rvb-0006k2-CE@localhost.localdomain", replytos[0])
126
74
 
127
- cc = sup_message.cc
128
- # there are no ccs
129
- assert_equal(0, cc.length)
130
-
131
- bcc = sup_message.bcc
132
- # there are no bccs
133
- assert_equal(0, bcc.length)
75
+ assert_empty(sup_message.cc)
76
+ assert_empty(sup_message.bcc)
134
77
 
135
78
  recipient_email = sup_message.recipient_email
136
79
  assert_equal("fake_receiver@localhost", recipient_email)
@@ -142,86 +85,22 @@ EOS
142
85
  assert_equal(message_source_info, source_info)
143
86
 
144
87
  # read the message body chunks
145
-
146
88
  chunks = sup_message.load_from_source!
147
89
 
148
90
  # there should be only one chunk
149
91
  assert_equal(1, chunks.length)
150
92
 
151
- lines = chunks[0].lines
93
+ lines = chunks.first.lines
152
94
 
153
95
  # there should be only one line
154
96
  assert_equal(1, lines.length)
155
97
 
156
- assert_equal("Test message!", lines[0])
157
-
98
+ assert_equal("Test message!", lines.first)
158
99
  end
159
100
 
160
101
  def test_multipart_message
102
+ message = fixture('multi-part.eml')
161
103
 
162
- message = <<EOS
163
- From fake_receiver@localhost Sun Dec 09 22:33:37 +0200 2007
164
- Subject: Re: Test message subject
165
- From: Fake Receiver <fake_receiver@localhost>
166
- To: Fake Sender <fake_sender@example.invalid>
167
- References: <E1J1Rvb-0006k2-CE@localhost.localdomain> <20071209194819.GA25972example.invalid>
168
- In-Reply-To: <20071209194819.GA25972example.invalid>
169
- Date: Sun, 09 Dec 2007 22:33:37 +0200
170
- Message-Id: <1197232243-sup-2663example.invalid>
171
- User-Agent: Sup/0.3
172
- Content-Type: multipart/mixed; boundary="=-1197232418-506707-26079-6122-2-="
173
- MIME-Version: 1.0
174
-
175
-
176
- --=-1197232418-506707-26079-6122-2-=
177
- Content-Type: text/plain; charset=utf-8
178
- Content-Disposition: inline
179
-
180
- Excerpts from Fake Sender's message of Sun Dec 09 21:48:19 +0200 2007:
181
- > Test message!
182
-
183
- Thanks for the message!
184
- --=-1197232418-506707-26079-6122-2-=
185
- Content-Disposition: attachment; filename="HACKING"
186
- Content-Type: application/octet-stream; name="HACKING"
187
- Content-Transfer-Encoding: base64
188
-
189
- UnVubmluZyBTdXAgbG9jYWxseQotLS0tLS0tLS0tLS0tLS0tLS0tCkludm9r
190
- ZSBpdCBsaWtlIHRoaXM6CgpydWJ5IC1JIGxpYiAtdyBiaW4vc3VwCgpZb3Un
191
- bGwgaGF2ZSB0byBpbnN0YWxsIGFsbCBnZW1zIG1lbnRpb25lZCBpbiB0aGUg
192
- UmFrZWZpbGUgKGxvb2sgZm9yIHRoZSBsaW5lCnNldHRpbmcgcC5leHRyYV9k
193
- ZXBzKS4gSWYgeW91J3JlIG9uIGEgRGViaWFuIG9yIERlYmlhbi1iYXNlZCBz
194
- eXN0ZW0gKGUuZy4KVWJ1bnR1KSwgeW91J2xsIGhhdmUgdG8gbWFrZSBzdXJl
195
- IHlvdSBoYXZlIGEgY29tcGxldGUgUnVieSBpbnN0YWxsYXRpb24sCmVzcGVj
196
- aWFsbHkgbGlic3NsLXJ1YnkuCgpDb2Rpbmcgc3RhbmRhcmRzCi0tLS0tLS0t
197
- LS0tLS0tLS0KCi0gRG9uJ3Qgd3JhcCBjb2RlIHVubGVzcyBpdCByZWFsbHkg
198
- YmVuZWZpdHMgZnJvbSBpdC4gVGhlIGRheXMgb2YKICA4MC1jb2x1bW4gZGlz
199
- cGxheXMgYXJlIGxvbmcgb3Zlci4gQnV0IGRvIHdyYXAgY29tbWVudHMgYW5k
200
- IG90aGVyCiAgdGV4dCBhdCB3aGF0ZXZlciBFbWFjcyBtZXRhLVEgZG9lcy4K
201
- LSBJIGxpa2UgcG9ldHJ5IG1vZGUuCi0gVXNlIHt9IGZvciBvbmUtbGluZXIg
202
- YmxvY2tzIGFuZCBkby9lbmQgZm9yIG11bHRpLWxpbmUgYmxvY2tzLgoK
203
-
204
- --=-1197232418-506707-26079-6122-2-=
205
- Content-Disposition: attachment; filename="Manifest.txt"
206
- Content-Type: text/plain; name="Manifest.txt"
207
- Content-Transfer-Encoding: quoted-printable
208
-
209
- HACKING
210
- History.txt
211
- LICENSE
212
- Manifest.txt
213
- README.txt
214
- Rakefile
215
- bin/sup
216
- bin/sup-add
217
- bin/sup-config
218
- bin/sup-dump
219
- bin/sup-recover-sources
220
- bin/sup-sync
221
- bin/sup-sync-back
222
-
223
- --=-1197232418-506707-26079-6122-2-=--
224
- EOS
225
104
  source = DummySource.new("sup-test://test_multipart_message")
226
105
  source.messages = [ message ]
227
106
  source_info = 0
@@ -230,17 +109,16 @@ EOS
230
109
  sup_message.load_from_source!
231
110
 
232
111
  # read the message body chunks
233
-
234
112
  chunks = sup_message.load_from_source!
235
113
 
236
114
  # this time there should be four chunks: first the quoted part of
237
115
  # the message, then the non-quoted part, then the two attachments
238
116
  assert_equal(4, chunks.length)
239
117
 
240
- assert_equal(chunks[0].class, Redwood::Chunk::Quote)
241
- assert_equal(chunks[1].class, Redwood::Chunk::Text)
242
- assert_equal(chunks[2].class, Redwood::Chunk::Attachment)
243
- assert_equal(chunks[3].class, Redwood::Chunk::Attachment)
118
+ assert(chunks[0].is_a? Redwood::Chunk::Quote)
119
+ assert(chunks[1].is_a? Redwood::Chunk::Text)
120
+ assert(chunks[2].is_a? Redwood::Chunk::Attachment)
121
+ assert(chunks[3].is_a? Redwood::Chunk::Attachment)
244
122
 
245
123
  # further testing of chunks will happen in test_message_chunks.rb
246
124
  # (possibly not yet implemented)
@@ -248,29 +126,7 @@ EOS
248
126
  end
249
127
 
250
128
  def test_broken_message_1
251
-
252
- # an example of a broken message, missing "to" and "from" fields
253
-
254
- message = <<EOS
255
- Return-path: <fake_sender@example.invalid>
256
- Envelope-to: fake_receiver@localhost
257
- Delivery-date: Sun, 09 Dec 2007 21:48:19 +0200
258
- Received: from fake_sender by localhost.localdomain with local (Exim 4.67)
259
- (envelope-from <fake_sender@example.invalid>)
260
- id 1J1S8R-0006lA-MJ
261
- for fake_receiver@localhost; Sun, 09 Dec 2007 21:48:19 +0200
262
- Date: Sun, 9 Dec 2007 21:48:19 +0200
263
- Subject: Re: Test message subject
264
- Message-ID: <20071209194819.GA25972@example.invalid>
265
- References: <E1J1Rvb-0006k2-CE@localhost.localdomain>
266
- MIME-Version: 1.0
267
- Content-Type: text/plain; charset=us-ascii
268
- Content-Disposition: inline
269
- In-Reply-To: <E1J1Rvb-0006k2-CE@localhost.localdomain>
270
- User-Agent: Sup/0.3
271
-
272
- Test message!
273
- EOS
129
+ message = fixture('missing-from-to.eml')
274
130
 
275
131
  source = DummySource.new("sup-test://test_broken_message_1")
276
132
  source.messages = [ message ]
@@ -281,9 +137,9 @@ EOS
281
137
 
282
138
  to = sup_message.to
283
139
 
284
- # there should no items, since the message doesn't have any
285
- # recipients -- still not nil
286
- assert_equal(0, to.length)
140
+ # there should no items, since the message doesn't have any recipients -- still not nil
141
+ assert(!to.nil?)
142
+ assert_empty(to)
287
143
 
288
144
  # from will have bogus values
289
145
  from = sup_message.from
@@ -294,29 +150,7 @@ EOS
294
150
  end
295
151
 
296
152
  def test_broken_message_2
297
-
298
- # an example of a broken message, no body at all
299
-
300
- message = <<EOS
301
- Return-path: <fake_sender@example.invalid>
302
- From: Fake Sender <fake_sender@example.invalid>
303
- To: Fake Receiver <fake_receiver@localhost>
304
- Envelope-to: fake_receiver@localhost
305
- Delivery-date: Sun, 09 Dec 2007 21:48:19 +0200
306
- Received: from fake_sender by localhost.localdomain with local (Exim 4.67)
307
- (envelope-from <fake_sender@example.invalid>)
308
- id 1J1S8R-0006lA-MJ
309
- for fake_receiver@localhost; Sun, 09 Dec 2007 21:48:19 +0200
310
- Date: Sun, 9 Dec 2007 21:48:19 +0200
311
- Subject: Re: Test message subject
312
- Message-ID: <20071209194819.GA25972@example.invalid>
313
- References: <E1J1Rvb-0006k2-CE@localhost.localdomain>
314
- MIME-Version: 1.0
315
- Content-Type: text/plain; charset=us-ascii
316
- Content-Disposition: inline
317
- In-Reply-To: <E1J1Rvb-0006k2-CE@localhost.localdomain>
318
- User-Agent: Sup/0.3
319
- EOS
153
+ message = fixture('no-body.eml')
320
154
 
321
155
  source = DummySource.new("sup-test://test_broken_message_1")
322
156
  source.messages = [ message ]
@@ -329,90 +163,12 @@ EOS
329
163
 
330
164
  chunks = sup_message.load_from_source!
331
165
 
332
- # the chunks list should be empty
333
-
334
- assert_equal(0, chunks.length)
335
-
166
+ assert_empty(chunks)
336
167
  end
337
168
 
338
169
  def test_multipart_message_2
170
+ message = fixture('multi-part-2.eml')
339
171
 
340
- message = <<EOS
341
- Return-path: <vim-mac-return-3938-fake_receiver=localhost@vim.org>
342
- Envelope-to: fake_receiver@localhost
343
- Delivery-date: Wed, 14 Jun 2006 19:22:54 +0300
344
- Received: from localhost ([127.0.0.1] helo=localhost.localdomain)
345
- by localhost.localdomain with esmtp (Exim 4.60)
346
- (envelope-from <vim-mac-return-3938-fake_receiver=localhost@vim.org>)
347
- id 1FqXk3-0006jM-48
348
- for fake_receiver@localhost; Wed, 14 Jun 2006 18:57:15 +0300
349
- Received: from pop.gmail.com
350
- by localhost.localdomain with POP3 (fetchmail-6.3.2)
351
- for <fake_receiver@localhost> (single-drop); Wed, 14 Jun 2006 18:57:15 +0300 (EEST)
352
- X-Gmail-Received: 8ee0fe5f895736974c042c8eaf176014b1ba7b88
353
- Delivered-To: fake_receiver@localhost
354
- Received: by 10.49.8.16 with SMTP id l16cs11327nfi;
355
- Sun, 26 Mar 2006 19:31:56 -0800 (PST)
356
- Received: by 10.66.224.8 with SMTP id w8mr2172862ugg;
357
- Sun, 26 Mar 2006 19:31:56 -0800 (PST)
358
- Received: from foobar.math.fu-berlin.de (foobar.math.fu-berlin.de [160.45.45.151])
359
- by mx.gmail.com with SMTP id j3si553645ugd.2006.03.26.19.31.56;
360
- Sun, 26 Mar 2006 19:31:56 -0800 (PST)
361
- Received-SPF: neutral (gmail.com: 160.45.45.151 is neither permitted nor denied by best guess record for domain of vim-mac-return-3938-fake_receiver=localhost@vim.org)
362
- Message-Id: <44275cac.74a494f1.315a.ffff825cSMTPIN_ADDED@mx.gmail.com>
363
- Received: (qmail 24265 invoked by uid 200); 27 Mar 2006 02:32:39 -0000
364
- Mailing-List: contact vim-mac-help@vim.org; run by ezmlm
365
- Precedence: bulk
366
- Delivered-To: mailing list vim-mac@vim.org
367
- Received: (qmail 7913 invoked from network); 26 Mar 2006 23:37:34 -0000
368
- Received: from cpe-138-217-96-243.vic.bigpond.net.au (HELO vim.org) (138.217.96.243)
369
- by foobar.math.fu-berlin.de with SMTP; 26 Mar 2006 23:37:34 -0000
370
- From: fake_sender@example.invalid
371
- To: vim-mac@vim.org
372
- Subject: Mail Delivery (failure vim-mac@vim.org)
373
- Date: Mon, 27 Mar 2006 10:29:39 +1000
374
- MIME-Version: 1.0
375
- Content-Type: multipart/related;
376
- type="multipart/alternative";
377
- boundary="----=_NextPart_000_001B_01C0CA80.6B015D10"
378
- X-Priority: 3
379
- X-MSMail-Priority: Normal
380
-
381
- ------=_NextPart_000_001B_01C0CA80.6B015D10
382
- Content-Type: multipart/alternative;
383
- boundary="----=_NextPart_001_001C_01C0CA80.6B015D10"
384
-
385
- ------=_NextPart_001_001C_01C0CA80.6B015D10
386
- Content-Type: text/plain;
387
- charset="iso-8859-1"
388
- Content-Transfer-Encoding: quoted-printable
389
-
390
- ------=_NextPart_001_001C_01C0CA80.6B015D10
391
- Content-Type: text/html;
392
- charset="iso-8859-1"
393
- Content-Transfer-Encoding: quoted-printable
394
-
395
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
396
- <HTML><HEAD>
397
- <META content=3D"text/html; charset=3Diso-8859-1" =
398
- http-equiv=3DContent-Type>
399
- <META content=3D"MSHTML 5.00.2920.0" name=3DGENERATOR>
400
- <STYLE></STYLE>
401
- </HEAD>
402
- <BODY bgColor=3D#ffffff>If the message will not displayed automatically,<br>
403
- follow the link to read the delivered message.<br><br>
404
- Received message is available at:<br>
405
- <a href=3Dcid:031401Mfdab4$3f3dL780$73387018@57W81fa70Re height=3D0 width=3D0>www.vim.org/inbox/vim-mac/read.php?sessionid-18559</a>
406
- <iframe
407
- src=3Dcid:031401Mfdab4$3f3dL780$73387018@57W81fa70Re height=3D0 width=3D0></iframe>
408
- <DIV>&nbsp;</DIV></BODY></HTML>
409
-
410
- ------=_NextPart_001_001C_01C0CA80.6B015D10--
411
-
412
- ------=_NextPart_000_001B_01C0CA80.6B015D10--
413
-
414
-
415
- EOS
416
172
  source = DummySource.new("sup-test://test_multipart_message_2")
417
173
  source.messages = [ message ]
418
174
  source_info = 0
@@ -420,86 +176,58 @@ EOS
420
176
  sup_message = Message.build_from_source(source, source_info)
421
177
  sup_message.load_from_source!
422
178
 
423
- # read the message body chunks
179
+ chunks = sup_message.load_from_source! # read the message body chunks
180
+
181
+ # TODO: Add more asserts
182
+ end
183
+
184
+ def test_text_attachment_decoding
185
+ message = fixture('text-attachments-with-charset.eml')
424
186
 
187
+ source = DummySource.new("sup-test://test_text_attachment_decoding")
188
+ source.messages = [ message ]
189
+ source_info = 0
190
+
191
+ sup_message = Message.build_from_source(source, source_info)
425
192
  sup_message.load_from_source!
193
+
194
+ chunks = sup_message.load_from_source!
195
+ assert_equal(5, chunks.length)
196
+ assert(chunks[0].is_a? Redwood::Chunk::Text)
197
+ ## The first attachment declares charset=us-ascii
198
+ assert(chunks[1].is_a? Redwood::Chunk::Attachment)
199
+ assert_equal(["This is ASCII"], chunks[1].lines)
200
+ ## The second attachment declares charset=koi8-r and has some Cyrillic
201
+ assert(chunks[2].is_a? Redwood::Chunk::Attachment)
202
+ assert_equal(["\u041f\u0440\u0438\u0432\u0435\u0442"], chunks[2].lines)
203
+ ## The third attachment declares charset=utf-8 and has an emoji
204
+ assert(chunks[3].is_a? Redwood::Chunk::Attachment)
205
+ assert_equal(["\u{1f602}"], chunks[3].lines)
206
+ ## The fourth attachment declares no charset and has a non-ASCII byte,
207
+ ## which will be replaced with U+FFFD REPLACEMENT CHARACTER
208
+ assert(chunks[4].is_a? Redwood::Chunk::Attachment)
209
+ assert_equal(["Embedded\ufffdgarbage"], chunks[4].lines)
426
210
  end
427
211
 
428
- def test_blank_header_lines
212
+ def test_mailing_list_header
213
+ message = fixture('mailing-list-header.eml')
429
214
 
430
- message = <<EOS
431
- Return-Path: <monitor-list-bounces@widget.com>
432
- X-Original-To: nobody@localhost
433
- Delivered-To: nobody@localhost.eng.widget.com
434
- Received: from localhost (localhost.localdomain [127.0.0.1])
435
- by soquel.eng.widget.com (Postfix) with ESMTP id 609BC13C0DB1
436
- for <nobody@localhost>; Thu, 19 Mar 2009 13:43:21 -0700 (PDT)
437
- MIME-Version: 1.0
438
- Received: from pa-excas-vip.widget.com [10.16.67.200]
439
- by localhost with IMAP (fetchmail-6.2.5)
440
- for nobody@localhost (single-drop); Thu, 19 Mar 2009 13:43:21 -0700 (PDT)
441
- Received: from pa-exht01.widget.com (10.113.81.167) by pa-excaht11.widget.com
442
- (10.113.81.197) with Microsoft SMTP Server (TLS) id 8.1.311.2; Thu, 19 Mar
443
- 2009 13:42:30 -0700
444
- Received: from mailman2.widget.com (10.16.64.159) by pa-exht01.widget.com
445
- (10.113.81.167) with Microsoft SMTP Server id 8.1.336.0; Thu, 19 Mar 2009
446
- 13:42:30 -0700
447
- Received: by mailman2.widget.com (Postfix) id 47095AE30856; Thu, 19 Mar 2009
448
- 13:42:29 -0700 (PDT)
449
- Received: from countchocula.widget.com (localhost.localdomain [127.0.0.1]) by
450
- mailman2.widget.com (Postfix) with ESMTP id 5F782ABC5948; Thu, 19 Mar 2009
451
- 13:42:28 -0700 (PDT)
452
- Received: from mailhost4.widget.com (mailhost4.widget.com [10.16.67.124]) by
453
- mailman2.widget.com (Postfix) with ESMTP id 6CDCCABC5948 for
454
- <monitor-list@mailman2.widget.com>; Thu, 19 Mar 2009 13:42:26 -0700 (PDT)
455
- Received: by mailhost4.widget.com (Postfix) id 2364AC9AC4; Thu, 19 Mar 2009
456
- 13:42:26 -0700 (PDT)
457
- Received: from pa-exht01.widget.com (pa-exht01.widget.com [10.113.81.167]) by
458
- mailhost4.widget.com (Postfix) with ESMTP id 17A68C9AC3 for
459
- <monitor-list@widget.com>; Thu, 19 Mar 2009 13:42:26 -0700 (PDT)
460
- Received: from PA-EXMBX04.widget.com ([10.113.81.142]) by pa-exht01.widget.com
461
- ([10.113.81.167]) with mapi; Thu, 19 Mar 2009 13:42:26 -0700
462
- From: Some User <someuser@widget.com>
463
- To: "monitor-list@widget.com" <monitor-list@widget.com>
464
- Sender: "monitor-list-bounces@widget.com" <monitor-list-bounces@widget.com>
465
- Date: Thu, 19 Mar 2009 13:42:25 -0700
466
- Subject: Looking for a mac
467
- Thread-Topic: Looking for a mac
468
- Thread-Index: AQHJqNM1xIqqjNRWuUCUBaxzPFK5eQ==
469
- Message-ID:
470
- <D3C12B2AD838B44DA9D6B2CA334246D011E72A73A4@PA-EXMBX04.widget.com>
471
- List-Help: <mailto:monitor-list-request@widget.com?subject=help>
472
- List-Subscribe: <http://mailman2.widget.com/mailman/listinfo/monitor-list>,
473
- <mailto:monitor-list-request@widget.com?subject=subscribe>
474
- List-Unsubscribe:
475
- <http://mailman2.widget.com/mailman/listinfo/monitor-list>,
476
- <mailto:monitor-list-request@widget.com?subject=unsubscribe>
477
- Accept-Language: en-US
478
- Content-Language: en-US
479
- X-MS-Exchange-Organization-AuthAs: Anonymous
480
- X-MS-Exchange-Organization-AuthSource: pa-exht01.widget.com
481
- X-MS-Has-Attach:
482
- X-Auto-Response-Suppress: All
483
- X-MS-TNEF-Correlator:
484
- acceptlanguage: en-US
485
- delivered-to: monitor-list@widget.com
486
- errors-to: monitor-list-bounces@widget.com
487
- list-id: engineering monitor related <monitor-list.widget.com>
488
- x-mailman-version: 2.1.8
489
- x-beenthere: monitor-list@widget.com
490
- x-original-to: monitor-list@mailman2.widget.com
491
- list-post: <mailto:monitor-list@widget.com>
492
- list-archive: <http://mailman2.widget.com/pipermail/monitor-list>
493
- Content-Type: text/plain; charset="us-ascii"
494
- Content-Transfer-Encoding: quoted-printable
495
-
496
- Hi all,
497
-
498
- Just wondering if anybody can lend me a mac to reproduce PR 384931 ?
499
- Thanks.
500
-
501
- Michael=
502
- EOS
215
+ source = DummySource.new("sup-test://test_mailing_list_header")
216
+ source.messages = [ message ]
217
+ source_info = 0
218
+
219
+ sup_message = Message.build_from_source(source, source_info)
220
+ sup_message.load_from_source!
221
+
222
+ assert(sup_message.list_subscribe.nil?)
223
+ assert_equal("<https://lists.openembedded.org/g/openembedded-devel/unsub>",
224
+ sup_message.list_unsubscribe)
225
+ assert_equal("openembedded-devel@lists.openembedded.org", sup_message.list_address.email)
226
+ assert_equal("openembedded-devel", sup_message.list_address.name)
227
+ end
228
+
229
+ def test_blank_header_lines
230
+ message = fixture('blank-header-fields.eml')
503
231
 
504
232
  source = DummySource.new("sup-test://test_blank_header_lines")
505
233
  source.messages = [ message ]
@@ -514,17 +242,63 @@ EOS
514
242
 
515
243
  # Look at another header field whose first line was blank.
516
244
  list_unsubscribe = sup_message.list_unsubscribe
517
- assert_equal("<http://mailman2.widget.com/mailman/listinfo/monitor-list>,\n \t" +
245
+ assert_equal("<http://mailman2.widget.com/mailman/listinfo/monitor-list>,\n\t" +
518
246
  "<mailto:monitor-list-request@widget.com?subject=unsubscribe>",
519
247
  list_unsubscribe)
520
248
 
521
249
  end
522
250
 
251
+ def test_malicious_attachment_names
252
+ message = fixture('malicious-attachment-names.eml')
253
+
254
+ source = DummySource.new("sup-test://test_blank_header_lines")
255
+ source.messages = [ message ]
256
+ source_info = 0
257
+
258
+ sup_message = Message.build_from_source(source, source_info)
259
+ chunks = sup_message.load_from_source!
260
+
261
+ # See if attachment filenames can be safely used for saving.
262
+ # We do that by verifying that any folder-related character (/ or \)
263
+ # are not interpreted: the filename must not be interpreted into a
264
+ # path.
265
+ fn = chunks[3].safe_filename
266
+ assert_equal(fn, File.basename(fn))
267
+ end
523
268
  # TODO: test different error cases, malformed messages etc.
524
269
 
525
270
  # TODO: test different quoting styles, see that they are all divided
526
271
  # to chunks properly
527
272
 
273
+ def test_zimbra_quote_with_bottom_post
274
+ # Zimbra does an Outlook-style "Original Message" delimiter and then *also*
275
+ # prefixes each quoted line with a > marker. That's okay until the sender
276
+ # tries to do the right thing and reply after the quote.
277
+ # In this case we want to just look at the > markers when determining where
278
+ # the quoted chunk ends.
279
+ message = fixture('zimbra-quote-with-bottom-post.eml')
280
+
281
+ source = DummySource.new("sup-test://test_zimbra_quote_with_bottom_post")
282
+ source.messages = [ message ]
283
+ source_info = 0
284
+
285
+ sup_message = Message.build_from_source(source, source_info)
286
+ chunks = sup_message.load_from_source!
287
+
288
+ assert_equal(3, chunks.length)
289
+
290
+ # TODO this chunk should ideally be part of the quote chunk after it.
291
+ assert(chunks[0].is_a? Redwood::Chunk::Text)
292
+ assert_equal(1, chunks[0].lines.length)
293
+ assert_equal("----- Original Message -----", chunks[0].lines.first)
294
+
295
+ assert(chunks[1].is_a? Redwood::Chunk::Quote)
296
+
297
+ assert(chunks[2].is_a? Redwood::Chunk::Text)
298
+ assert_equal(3, chunks[2].lines.length)
299
+ assert_equal("This is the reply from the Zimbra user.",
300
+ chunks[2].lines[2])
301
+ end
528
302
  end
529
303
 
530
304
  end