sup 0.20.0 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
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