imap-backup 6.0.0.rc2 → 6.0.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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/imap-backup.gemspec +5 -1
  3. data/lib/cli_coverage.rb +11 -11
  4. data/lib/email/provider/base.rb +2 -0
  5. data/lib/email/provider/unknown.rb +2 -0
  6. data/lib/email/provider.rb +2 -0
  7. data/lib/imap/backup/account/connection/backup_folders.rb +27 -0
  8. data/lib/imap/backup/account/connection/client_factory.rb +54 -0
  9. data/lib/imap/backup/account/connection/folder_names.rb +26 -0
  10. data/lib/imap/backup/account/connection.rb +11 -95
  11. data/lib/imap/backup/account/folder.rb +9 -6
  12. data/lib/imap/backup/account.rb +3 -5
  13. data/lib/imap/backup/cli/backup.rb +1 -3
  14. data/lib/imap/backup/cli/helpers.rb +24 -22
  15. data/lib/imap/backup/cli/local.rb +20 -13
  16. data/lib/imap/backup/cli/migrate.rb +4 -10
  17. data/lib/imap/backup/cli/restore.rb +8 -7
  18. data/lib/imap/backup/cli/setup.rb +10 -8
  19. data/lib/imap/backup/cli/stats.rb +78 -0
  20. data/lib/imap/backup/cli/status.rb +2 -2
  21. data/lib/imap/backup/cli/utils.rb +4 -6
  22. data/lib/imap/backup/cli.rb +24 -3
  23. data/lib/imap/backup/configuration.rb +9 -11
  24. data/lib/imap/backup/downloader.rb +48 -30
  25. data/lib/imap/backup/migrator.rb +5 -5
  26. data/lib/imap/backup/sanitizer.rb +3 -2
  27. data/lib/imap/backup/serializer/appender.rb +49 -0
  28. data/lib/imap/backup/serializer/message_enumerator.rb +29 -0
  29. data/lib/imap/backup/serializer/unused_name_finder.rb +27 -0
  30. data/lib/imap/backup/serializer.rb +24 -78
  31. data/lib/imap/backup/setup/account/header.rb +75 -0
  32. data/lib/imap/backup/setup/account.rb +14 -91
  33. data/lib/imap/backup/setup/asker.rb +4 -15
  34. data/lib/imap/backup/setup/backup_path.rb +41 -0
  35. data/lib/imap/backup/setup/email.rb +45 -0
  36. data/lib/imap/backup/setup/folder_chooser.rb +3 -3
  37. data/lib/imap/backup/setup/helpers.rb +1 -1
  38. data/lib/imap/backup/setup.rb +5 -4
  39. data/lib/imap/backup/thunderbird/mailbox_exporter.rb +39 -20
  40. data/lib/imap/backup/uploader.rb +46 -8
  41. data/lib/imap/backup/utils.rb +1 -1
  42. data/lib/imap/backup/version.rb +1 -1
  43. data/lib/imap/backup.rb +0 -1
  44. metadata +31 -134
  45. data/spec/features/backup_spec.rb +0 -100
  46. data/spec/features/configuration/minimal_configuration.rb +0 -15
  47. data/spec/features/configuration/missing_configuration.rb +0 -14
  48. data/spec/features/folders_spec.rb +0 -36
  49. data/spec/features/helper.rb +0 -2
  50. data/spec/features/local/list_accounts_spec.rb +0 -12
  51. data/spec/features/local/list_emails_spec.rb +0 -21
  52. data/spec/features/local/list_folders_spec.rb +0 -21
  53. data/spec/features/local/show_an_email_spec.rb +0 -34
  54. data/spec/features/migrate_spec.rb +0 -35
  55. data/spec/features/remote/list_account_folders_spec.rb +0 -16
  56. data/spec/features/restore_spec.rb +0 -162
  57. data/spec/features/status_spec.rb +0 -43
  58. data/spec/features/support/aruba.rb +0 -78
  59. data/spec/features/support/backup_directory.rb +0 -43
  60. data/spec/features/support/email_server.rb +0 -110
  61. data/spec/features/support/shared/connection_context.rb +0 -14
  62. data/spec/features/support/shared/message_fixtures.rb +0 -16
  63. data/spec/fixtures/connection.yml +0 -7
  64. data/spec/spec_helper.rb +0 -15
  65. data/spec/support/fixtures.rb +0 -11
  66. data/spec/support/higline_test_helpers.rb +0 -8
  67. data/spec/support/silence_logging.rb +0 -7
  68. data/spec/unit/email/mboxrd/message_spec.rb +0 -177
  69. data/spec/unit/email/provider/apple_mail_spec.rb +0 -7
  70. data/spec/unit/email/provider/base_spec.rb +0 -11
  71. data/spec/unit/email/provider/fastmail_spec.rb +0 -7
  72. data/spec/unit/email/provider/gmail_spec.rb +0 -7
  73. data/spec/unit/email/provider_spec.rb +0 -27
  74. data/spec/unit/imap/backup/account/connection_spec.rb +0 -433
  75. data/spec/unit/imap/backup/account/folder_spec.rb +0 -261
  76. data/spec/unit/imap/backup/account_spec.rb +0 -246
  77. data/spec/unit/imap/backup/cli/accounts_spec.rb +0 -58
  78. data/spec/unit/imap/backup/cli/backup_spec.rb +0 -19
  79. data/spec/unit/imap/backup/cli/folders_spec.rb +0 -39
  80. data/spec/unit/imap/backup/cli/helpers_spec.rb +0 -87
  81. data/spec/unit/imap/backup/cli/local_spec.rb +0 -100
  82. data/spec/unit/imap/backup/cli/migrate_spec.rb +0 -80
  83. data/spec/unit/imap/backup/cli/restore_spec.rb +0 -67
  84. data/spec/unit/imap/backup/cli/setup_spec.rb +0 -17
  85. data/spec/unit/imap/backup/cli/utils_spec.rb +0 -125
  86. data/spec/unit/imap/backup/cli_spec.rb +0 -93
  87. data/spec/unit/imap/backup/client/apple_mail_spec.rb +0 -9
  88. data/spec/unit/imap/backup/client/default_spec.rb +0 -22
  89. data/spec/unit/imap/backup/configuration_spec.rb +0 -238
  90. data/spec/unit/imap/backup/downloader_spec.rb +0 -96
  91. data/spec/unit/imap/backup/logger_spec.rb +0 -48
  92. data/spec/unit/imap/backup/migrator_spec.rb +0 -58
  93. data/spec/unit/imap/backup/sanitizer_spec.rb +0 -42
  94. data/spec/unit/imap/backup/serializer/directory_spec.rb +0 -37
  95. data/spec/unit/imap/backup/serializer/imap_spec.rb +0 -218
  96. data/spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb +0 -45
  97. data/spec/unit/imap/backup/serializer/mbox_spec.rb +0 -101
  98. data/spec/unit/imap/backup/serializer_spec.rb +0 -296
  99. data/spec/unit/imap/backup/setup/account_spec.rb +0 -461
  100. data/spec/unit/imap/backup/setup/asker_spec.rb +0 -137
  101. data/spec/unit/imap/backup/setup/connection_tester_spec.rb +0 -51
  102. data/spec/unit/imap/backup/setup/folder_chooser_spec.rb +0 -146
  103. data/spec/unit/imap/backup/setup/helpers_spec.rb +0 -15
  104. data/spec/unit/imap/backup/setup_spec.rb +0 -301
  105. data/spec/unit/imap/backup/thunderbird/mailbox_exporter_spec.rb +0 -116
  106. data/spec/unit/imap/backup/uploader_spec.rb +0 -54
  107. data/spec/unit/imap/backup/utils_spec.rb +0 -92
  108. data/spec/unit/retry_on_error_spec.rb +0 -34
@@ -1,162 +0,0 @@
1
- require "features/helper"
2
-
3
- RSpec.describe "restore", type: :aruba, docker: true do
4
- include_context "imap-backup connection"
5
- include_context "message-fixtures"
6
-
7
- let(:local_backup_path) { File.expand_path("~/backup") }
8
- let(:folder) { "my-stuff" }
9
- let(:messages_as_mbox) do
10
- message_as_mbox_entry(msg1) + message_as_mbox_entry(msg2)
11
- end
12
- let(:messages_as_server_messages) do
13
- [message_as_server_message(msg1), message_as_server_message(msg2)]
14
- end
15
- let(:message_uids) { [msg1[:uid], msg2[:uid]] }
16
- let(:existing_imap_content) { imap_data(uid_validity, message_uids).to_json }
17
- let(:uid_validity) { 1234 }
18
-
19
- let!(:pre) {}
20
- let!(:setup) do
21
- create_directory local_backup_path
22
- File.write(imap_path(folder), existing_imap_content)
23
- File.write(mbox_path(folder), messages_as_mbox)
24
- create_config(accounts: [account.to_h])
25
-
26
- run_command_and_stop("imap-backup restore #{account.username}")
27
- end
28
- let(:cleanup) do
29
- server_delete_folder folder
30
- end
31
-
32
- after { cleanup }
33
-
34
- context "when the folder doesn't exist" do
35
- it "restores messages" do
36
- messages = server_messages(folder).map { |m| server_message_to_body(m) }
37
- expect(messages).to eq(messages_as_server_messages)
38
- end
39
-
40
- it "updates local uids to match the new server ones" do
41
- updated_imap_content = imap_parsed(folder)
42
- expect(server_uids(folder)).to eq(updated_imap_content[:uids])
43
- end
44
-
45
- it "sets the backup uid_validity to match the new folder" do
46
- updated_imap_content = imap_parsed(folder)
47
- expect(updated_imap_content[:uid_validity]).
48
- to eq(server_uid_validity(folder))
49
- end
50
- end
51
-
52
- context "when the folder exists" do
53
- let(:email3) { send_email folder, msg3 }
54
-
55
- context "when the uid_validity matches" do
56
- let(:pre) do
57
- server_create_folder folder
58
- email3
59
- uid_validity
60
- end
61
- let(:messages_as_server_messages) do
62
- [
63
- message_as_server_message(msg3),
64
- message_as_server_message(msg1),
65
- message_as_server_message(msg2)
66
- ]
67
- end
68
- let(:uid_validity) { server_uid_validity(folder) }
69
-
70
- it "appends to the existing folder" do
71
- messages = server_messages(folder).map { |m| server_message_to_body(m) }
72
- expect(messages).to eq(messages_as_server_messages)
73
- end
74
- end
75
-
76
- context "when the uid_validity doesn't match" do
77
- context "when the folder is empty" do
78
- let(:pre) do
79
- server_create_folder folder
80
- end
81
-
82
- it "sets the backup uid_validity to match the folder" do
83
- updated_imap_content = imap_parsed(folder)
84
- expect(updated_imap_content[:uid_validity]).
85
- to eq(server_uid_validity(folder))
86
- end
87
-
88
- it "uploads to the new folder" do
89
- messages = server_messages(folder).map do |m|
90
- server_message_to_body(m)
91
- end
92
- expect(messages).to eq(messages_as_server_messages)
93
- end
94
- end
95
-
96
- context "when the folder has content" do
97
- let(:new_folder) { "#{folder}-#{uid_validity}" }
98
- let(:cleanup) do
99
- server_delete_folder new_folder
100
- super()
101
- end
102
-
103
- let(:pre) do
104
- server_create_folder folder
105
- email3
106
- end
107
-
108
- it "renames the backup" do
109
- expect(mbox_content(new_folder)).to eq(messages_as_mbox)
110
- end
111
-
112
- it "leaves the existing folder as is" do
113
- messages = server_messages(folder).map do |m|
114
- server_message_to_body(m)
115
- end
116
- expect(messages).to eq([message_as_server_message(msg3)])
117
- end
118
-
119
- it "creates the new folder" do
120
- expect(server_folders.map(&:name)).to include(new_folder)
121
- end
122
-
123
- it "sets the backup uid_validity to match the new folder" do
124
- updated_imap_content = imap_parsed(new_folder)
125
- expect(updated_imap_content[:uid_validity]).
126
- to eq(server_uid_validity(new_folder))
127
- end
128
-
129
- it "uploads to the new folder" do
130
- messages = server_messages(new_folder).map do |m|
131
- server_message_to_body(m)
132
- end
133
- expect(messages).to eq(messages_as_server_messages)
134
- end
135
- end
136
- end
137
- end
138
-
139
- context "when non-Unicode encodings are used" do
140
- let(:server_message) do
141
- message_as_server_message(msg_iso8859)
142
- end
143
- let(:messages_as_mbox) do
144
- message_as_mbox_entry(msg_iso8859)
145
- end
146
- let(:message_uids) { [uid_iso8859] }
147
- let(:uid_validity) { server_uid_validity(folder) }
148
-
149
- let(:pre) do
150
- server_create_folder folder
151
- uid_validity
152
- end
153
-
154
- it "maintains encodings" do
155
- message =
156
- server_messages(folder).
157
- first["BODY[]"]
158
-
159
- expect(message).to eq(server_message)
160
- end
161
- end
162
- end
@@ -1,43 +0,0 @@
1
- require "features/helper"
2
- require "imap/backup/cli/status"
3
-
4
- RSpec.describe "status", type: :feature, docker: true do
5
- include_context "imap-backup connection"
6
- include_context "message-fixtures"
7
-
8
- context "when there are non-backed-up messages" do
9
- let(:options) do
10
- {accounts: "address@example.org"}
11
- end
12
- let(:folder) { "my-stuff" }
13
- let(:backup_folders) { [{name: folder}] }
14
- let(:email1) { send_email folder, msg1 }
15
- let(:output) { StringIO.new }
16
-
17
- before do
18
- allow(Imap::Backup::CLI::Accounts).to receive(:new) { [account] }
19
- server_create_folder folder
20
- email1
21
- end
22
-
23
- around do |example|
24
- stdout = $stdout
25
- $stdout = output
26
- example.run
27
- $stdout = stdout
28
- end
29
-
30
- after do
31
- FileUtils.rm_rf local_backup_path
32
- delete_emails folder
33
- server_delete_folder folder
34
- connection.disconnect
35
- end
36
-
37
- it "prints the number" do
38
- Imap::Backup::CLI::Status.new(options).run
39
-
40
- expect(output.string).to eq("address@example.org\nmy-stuff: 1\n")
41
- end
42
- end
43
- end
@@ -1,78 +0,0 @@
1
- require "aruba/rspec"
2
-
3
- require_relative "backup_directory"
4
- require "imap/backup/serializer/mbox"
5
-
6
- Aruba.configure do |config|
7
- config.home_directory = File.expand_path("./tmp/home")
8
- config.allow_absolute_paths = true
9
- end
10
-
11
- module ConfigurationHelpers
12
- def config_path
13
- File.expand_path("~/.imap-backup")
14
- end
15
-
16
- def create_config(accounts:, debug: false)
17
- pathname = File.join(config_path, "config.json")
18
- save_data = {
19
- version: Imap::Backup::Configuration::VERSION,
20
- accounts: accounts,
21
- debug: debug
22
- }
23
- FileUtils.mkdir_p config_path
24
- File.open(pathname, "w") { |f| f.write(JSON.pretty_generate(save_data)) }
25
- FileUtils.chmod(0o600, pathname)
26
- end
27
- end
28
-
29
- module StoreHelpers
30
- def store_email(
31
- email:, folder:,
32
- uid: 1,
33
- from: "sender@example.com",
34
- subject: "The Subject",
35
- body: "body"
36
- )
37
- account = config.accounts.find { |a| a.username == email }
38
- raise "Account not found" if !account
39
- FileUtils.mkdir_p account.local_path
40
- serializer = Imap::Backup::Serializer.new(account.local_path, folder)
41
- serializer.force_uid_validity("42") if !serializer.uid_validity
42
- serialized = to_serialized(from: from, subject: subject, body: body)
43
- serializer.append uid, serialized
44
- end
45
-
46
- def to_serialized(from:, subject:, body:)
47
- body_and_headers = <<~BODY
48
- From: #{from}
49
- Subject: #{subject}
50
-
51
- #{body}
52
- BODY
53
- end
54
-
55
- def config
56
- Imap::Backup::Configuration.new(
57
- File.expand_path("~/.imap-backup/config.json")
58
- )
59
- end
60
- end
61
-
62
- RSpec.configure do |config|
63
- config.include ConfigurationHelpers, type: :aruba
64
- config.include StoreHelpers, type: :aruba
65
- config.include BackupDirectoryHelpers, type: :aruba
66
-
67
- config.before(:suite) do
68
- FileUtils.rm_rf "./tmp/home"
69
- end
70
-
71
- config.before(:example, type: :aruba) do
72
- set_environment_variable("COVERAGE", "aruba")
73
- end
74
-
75
- config.after do
76
- FileUtils.rm_rf "./tmp/home"
77
- end
78
- end
@@ -1,43 +0,0 @@
1
- module BackupDirectoryHelpers
2
- def message_as_mbox_entry(options)
3
- from = fixture("connection")[:username]
4
- subject = options[:subject]
5
- body = options[:body]
6
- body_and_headers = <<~BODY
7
- From: #{from}
8
- Subject: #{subject}
9
-
10
- #{body}
11
- BODY
12
-
13
- "From #{from}\n#{body_and_headers}\n"
14
- end
15
-
16
- def imap_data(uid_validity, uids)
17
- {
18
- version: 2,
19
- uid_validity: uid_validity,
20
- uids: uids
21
- }
22
- end
23
-
24
- def mbox_content(name)
25
- File.read(mbox_path(name))
26
- end
27
-
28
- def mbox_path(name)
29
- File.join(local_backup_path, "#{name}.mbox")
30
- end
31
-
32
- def imap_path(name)
33
- File.join(local_backup_path, "#{name}.imap")
34
- end
35
-
36
- def imap_content(name)
37
- File.read(imap_path(name))
38
- end
39
-
40
- def imap_parsed(name)
41
- JSON.parse(imap_content(name), symbolize_names: true)
42
- end
43
- end
@@ -1,110 +0,0 @@
1
- module EmailServerHelpers
2
- REQUESTED_ATTRIBUTES = ["BODY[]"].freeze
3
- DEFAULT_EMAIL = "address@example.org".freeze
4
-
5
- def send_email(folder, options)
6
- message = message_as_server_message(options)
7
- imap.append(folder, message, nil, nil)
8
- end
9
-
10
- def message_as_server_message(options)
11
- from = options[:from] || DEFAULT_EMAIL
12
- subject = options[:subject]
13
- body = options[:body]
14
-
15
- <<~MESSAGE.gsub("\n", "\r\n")
16
- From: #{from}
17
- Subject: #{subject}
18
-
19
- #{body}
20
-
21
- MESSAGE
22
- end
23
-
24
- def server_messages(folder)
25
- server_uids(folder).map do |uid|
26
- server_fetch_email(folder, uid)
27
- end
28
- end
29
-
30
- def server_message_to_body(message)
31
- message["BODY[]"]
32
- end
33
-
34
- def server_fetch_email(folder, uid)
35
- examine folder
36
-
37
- fetch_data_items = imap.uid_fetch([uid.to_i], REQUESTED_ATTRIBUTES)
38
- return nil if fetch_data_items.nil?
39
-
40
- fetch_data_item = fetch_data_items[0]
41
- fetch_data_item.attr
42
- end
43
-
44
- def delete_emails(folder)
45
- imap.select(folder)
46
- uids = imap.uid_search(["ALL"]).sort
47
- imap.store(1..uids.size, "+FLAGS", [:Deleted])
48
- imap.expunge
49
- end
50
-
51
- def examine(folder)
52
- imap.examine(folder)
53
- end
54
-
55
- def server_uids(folder)
56
- examine(folder)
57
- imap.uid_search(["ALL"]).sort
58
- end
59
-
60
- def server_uid_validity(folder)
61
- examine(folder)
62
- imap.responses["UIDVALIDITY"][0]
63
- end
64
-
65
- def server_folders
66
- imap.list(root, "*")
67
- end
68
-
69
- def root
70
- root_info = imap.list("", "")[0]
71
- root_info.name
72
- end
73
-
74
- def server_create_folder(folder)
75
- imap.create(folder)
76
- imap.disconnect
77
- @imap = nil
78
- end
79
-
80
- def server_rename_folder(from, to)
81
- imap.rename(from, to)
82
- imap.disconnect
83
- @imap = nil
84
- end
85
-
86
- def server_delete_folder(folder)
87
- imap.delete folder
88
- imap.disconnect
89
- rescue StandardError => e
90
- ensure
91
- @imap = nil
92
- end
93
-
94
- def imap
95
- @imap ||=
96
- begin
97
- connection = fixture("connection")
98
- imap = Net::IMAP.new(
99
- connection[:server], connection[:connection_options]
100
- )
101
- imap.login(connection[:username], connection[:password])
102
- imap
103
- end
104
- end
105
- end
106
-
107
- RSpec.configure do |config|
108
- config.include EmailServerHelpers, type: :aruba
109
- config.include EmailServerHelpers, type: :feature
110
- end
@@ -1,14 +0,0 @@
1
- shared_context "imap-backup connection" do
2
- let(:local_backup_path) { Dir.mktmpdir(nil, "tmp") }
3
- let(:default_connection) { fixture("connection") }
4
- let(:backup_folders) { nil }
5
- let(:account) do
6
- Imap::Backup::Account.new(
7
- default_connection.merge(
8
- local_path: local_backup_path,
9
- folders: backup_folders
10
- )
11
- )
12
- end
13
- let(:connection) { Imap::Backup::Account::Connection.new(account) }
14
- end
@@ -1,16 +0,0 @@
1
- shared_context "message-fixtures" do
2
- let(:uid1) { 123 }
3
- let(:uid2) { 345 }
4
- let(:uid3) { 567 }
5
- let(:uid_iso8859) { 890 }
6
- let(:msg1) { {uid: uid1, subject: "Test 1", body: "body 1\nHi"} }
7
- let(:msg2) { {uid: uid2, subject: "Test 2", body: "body 2"} }
8
- let(:msg3) { {uid: uid3, subject: "Test 3", body: "body 3"} }
9
- let(:msg_iso8859) do
10
- {
11
- uid: uid_iso8859,
12
- subject: "iso8859 Body",
13
- body: "Ma, perchè?".encode(Encoding::ISO_8859_1).force_encoding("binary")
14
- }
15
- end
16
- end
@@ -1,7 +0,0 @@
1
- :server: 'localhost'
2
- :username: 'address@example.org'
3
- :password: 'pass'
4
- :connection_options:
5
- :port: <%= ENV.fetch("DOCKER_IMAP_SERVER", 8993) %>
6
- :ssl:
7
- :verify_mode: 0
data/spec/spec_helper.rb DELETED
@@ -1,15 +0,0 @@
1
- require "rspec"
2
-
3
- $LOAD_PATH << File.expand_path("../lib", __dir__)
4
-
5
- support_glob = File.join(__dir__, "support", "**", "*.rb")
6
- Dir[support_glob].sort.each { |f| require f }
7
-
8
- require "simplecov"
9
-
10
- SimpleCov.command_name "RSpec tests"
11
-
12
- require "imap/backup"
13
- require "imap/backup/cli"
14
-
15
- silence_logging
@@ -1,11 +0,0 @@
1
- require "erb"
2
- require "yaml"
3
-
4
- def fixture(name)
5
- spec_root = File.expand_path("..", File.dirname(__FILE__))
6
- fixture_path = File.join(spec_root, "fixtures", "#{name}.yml")
7
- content = File.read(fixture_path)
8
- template = ERB.new(content)
9
- yaml = template.result(binding)
10
- YAML.safe_load(yaml, [Symbol])
11
- end
@@ -1,8 +0,0 @@
1
- module HighLineTestHelpers
2
- def prepare_highline
3
- @input = instance_double(IO, eof?: false, gets: "q\n")
4
- @output = StringIO.new
5
- Imap::Backup::Setup.highline = HighLine.new(@input, @output)
6
- [@input, @output]
7
- end
8
- end
@@ -1,7 +0,0 @@
1
- def silence_logging
2
- RSpec.configure do |config|
3
- config.before(:suite) do
4
- Imap::Backup::Logger.logger.level = Logger::UNKNOWN
5
- end
6
- end
7
- end
@@ -1,177 +0,0 @@
1
- msg_no_from = <<~NO_FROM
2
- Delivered-To: you@example.com
3
- From: example <www.example.com>
4
- To: FirstName LastName <you@example.com>
5
- Subject: Re: no subject
6
- NO_FROM
7
-
8
- msg_bad_from = <<~BAD_FROM
9
- Delivered-To: you@example.com
10
- from: "FirstName LastName (TEXT)" <"TEXT*" <no-reply@example.com>>
11
- To: FirstName LastName <you@example.com>
12
- Subject: Re: no subject
13
- BAD_FROM
14
-
15
- msg_no_from_but_return_path = <<~RETURN_PATH
16
- Delivered-To: you@example.com
17
- From: example <www.example.com>
18
- To: FirstName LastName <you@example.com>
19
- Return-Path: <me@example.com>
20
- Subject: Re: no subject
21
- RETURN_PATH
22
-
23
- msg_no_from_but_sender = <<~NOT_SENDER
24
- Delivered-To: you@example.com
25
- To: FirstName LastName <you@example.com>
26
- Subject: Re: no subject
27
- Sender: FistName LastName <me@example.com>
28
- NOT_SENDER
29
-
30
- describe Email::Mboxrd::Message do
31
- subject { described_class.new(message_body) }
32
-
33
- let(:from) { "me@example.com" }
34
- let(:date) { DateTime.new(2012, 12, 13, 18, 23, 45) }
35
- let(:message_body) do
36
- instance_double(String, clone: cloned_message_body, force_encoding: nil)
37
- end
38
- let(:cloned_message_body) do
39
- "Foo\nBar\nFrom at the beginning of the line\n>>From quoted"
40
- end
41
- let(:msg_good) do
42
- <<~GOOD
43
- Delivered-To: you@example.com
44
- From: Foo <foo@example.com>
45
- To: FirstName LastName <you@example.com>
46
- Date: #{date.rfc822}
47
- Subject: Re: no subject
48
- GOOD
49
- end
50
-
51
- let(:msg_bad_date) do
52
- <<~BAD
53
- Delivered-To: you@example.com
54
- From: Foo <foo@example.com>
55
- To: FirstName LastName <you@example.com>
56
- Date: Mon,5 May 2014 08:97:99 GMT
57
- Subject: Re: no subject
58
- BAD
59
- end
60
-
61
- describe ".from_serialized" do
62
- let(:serialized_message) { "From foo@a.com\n#{imap_message}" }
63
- let(:imap_message) { "Delivered-To: me@example.com\nFrom Me\n" }
64
- let!(:result) { described_class.from_serialized(serialized_message) }
65
-
66
- it "returns the message" do
67
- expect(result).to be_a(described_class)
68
- end
69
-
70
- it "removes one level of > before From" do
71
- expect(result.supplied_body).to eq(imap_message)
72
- end
73
- end
74
-
75
- describe "#to_serialized" do
76
- let(:mail) { instance_double(Mail::Message, from: [from], date: date) }
77
-
78
- before do
79
- allow(Mail).to receive(:new).with(cloned_message_body) { mail }
80
- end
81
-
82
- it "adds a 'From ' line at the start" do
83
- expected = "From #{from} #{date.asctime}\n"
84
- expect(subject.to_serialized).to start_with(expected)
85
- end
86
-
87
- it "replaces existing 'From ' with '>From '" do
88
- expect(subject.to_serialized).to include("\n>From at the beginning")
89
- end
90
-
91
- it "appends > before '>+From '" do
92
- expect(subject.to_serialized).to include("\n>>>From quoted")
93
- end
94
-
95
- context "when date is missing" do
96
- let(:date) { nil }
97
-
98
- it "does no fail" do
99
- expect { subject.to_serialized }.to_not raise_error
100
- end
101
- end
102
- end
103
-
104
- describe "From" do
105
- before do
106
- # call original for these tests because we want to test the behaviour of
107
- # class-under-test given different behaviour of the Mail parser
108
- allow(Mail).to receive(:new).and_call_original
109
- end
110
-
111
- context "when original message 'from' is missing" do
112
- let(:message_body) { msg_no_from }
113
-
114
- it "'from' is empty string" do
115
- expect(subject.to_serialized).to start_with("From \n")
116
- end
117
- end
118
-
119
- context "when original message 'from' is not a well-formed address" do
120
- let(:message_body) { msg_bad_from }
121
-
122
- it "'from' is empty string" do
123
- expect(subject.to_serialized).to start_with("From \n")
124
- end
125
- end
126
-
127
- context "when original message 'from' is nil and " \
128
- "'envelope from' is nil and 'return path' is available" do
129
- let(:message_body) { msg_no_from_but_return_path }
130
-
131
- it "'return path' is used as 'from'" do
132
- expect(subject.to_serialized).to start_with("From #{from}\n")
133
- end
134
- end
135
-
136
- context "with no from and a 'Sender'" do
137
- let(:message_body) { msg_no_from_but_sender }
138
-
139
- it "Sender is used as 'from'" do
140
- expect(subject.to_serialized).to start_with("From #{from}\n")
141
- end
142
- end
143
- end
144
-
145
- describe "#date" do
146
- let(:message_body) { msg_good }
147
-
148
- it "returns the date" do
149
- expect(subject.date).to eq(date)
150
- end
151
-
152
- context "with incorrect minutes and seconds" do
153
- let(:message_body) { msg_bad_date }
154
-
155
- it "returns nil" do
156
- expect(subject.date).to be_nil
157
- end
158
- end
159
- end
160
-
161
- describe "#imap_body" do
162
- let(:message_body) { "Ciao" }
163
-
164
- it "returns the supplied body" do
165
- expect(subject.imap_body).to eq(message_body)
166
- end
167
-
168
- context "when newlines are not IMAP standard" do
169
- let(:message_body) { "Ciao\nHello" }
170
- let(:corrected) { "Ciao\r\nHello" }
171
-
172
- it "corrects them" do
173
- expect(subject.imap_body).to eq(corrected)
174
- end
175
- end
176
- end
177
- end