imap-backup 16.0.0 → 16.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ac22de1cd99aab34b9d478d2ad8727faf67bbac635cf6ef80335d27012328a29
4
- data.tar.gz: 7b74833c6e1752c1a25a201d3e3f40a05f8b966bebe38796843ee4f133191aff
3
+ metadata.gz: bf6997d289ca5babbecd35e683ede921273300779f3f7dac95e247c0478f1814
4
+ data.tar.gz: '009892c47699a0cc94ff28c2d3ea7346915732b7dc86c7231b7e606302219888'
5
5
  SHA512:
6
- metadata.gz: b0147bfef559ef12c9f6b3e41eced66cade0de85fa418bafb81eed6cfa06bd6e751d818cb8d058768a8259e69526c2a90aa504389a188146722f66f2d2671b2c
7
- data.tar.gz: 6b48724665aa1383094053164de511e2bcfd1b3bf2b32d28bf659740e96e1e5f32a9dc37af32ec6cb0fd23fb06bd863d567ca78135bac27bb2662d6b6b6f5118
6
+ metadata.gz: 46bdbccf9be3efade25e500f6c67f37de4fc0a0aa8514b55f8eabf7e1171042b5be87d029f37d9cb449c23d1fcf0d5fd2a20c2e8595c6149eff0c20f89e6b3d3
7
+ data.tar.gz: d507a668897c325e2cc771d69b083f9929247b839b55d1fe86bfaeac3ee8be40df43b9f634d4f97c0188fe3bcbfba666456a9131236103455020fb45ecec9d61
@@ -1,9 +1,7 @@
1
1
  require "socket"
2
2
 
3
- require "imap/backup/client/apple_mail"
4
3
  require "imap/backup/client/automatic_login_wrapper"
5
4
  require "imap/backup/client/default"
6
- require "imap/backup/email/provider"
7
5
 
8
6
  module Imap; end
9
7
 
@@ -14,39 +12,17 @@ module Imap::Backup
14
12
  class Account::ClientFactory
15
13
  def initialize(account:)
16
14
  @account = account
17
- @provider = nil
18
- @server = nil
19
15
  end
20
16
 
21
17
  # @return [Client::AutomaticLoginWrapper] a client for the account
22
18
  def run
23
- options = provider_options
24
- Logger.logger.debug(
25
- "Creating IMAP instance: #{server}, options: #{options.inspect}"
26
- )
27
- client =
28
- if provider.is_a?(Email::Provider::AppleMail)
29
- Client::AppleMail.new(server, account, options)
30
- else
31
- Client::Default.new(server, account, options)
32
- end
19
+ Logger.logger.debug("Creating IMAP instance")
20
+ client = Client::Default.new(account)
33
21
  Client::AutomaticLoginWrapper.new(client: client)
34
22
  end
35
23
 
36
24
  private
37
25
 
38
26
  attr_reader :account
39
-
40
- def provider
41
- @provider ||= Email::Provider.for_address(account.username)
42
- end
43
-
44
- def provider_options
45
- provider.options.merge(account.connection_options || {})
46
- end
47
-
48
- def server
49
- @server ||= account.server || provider.host
50
- end
51
27
  end
52
28
  end
@@ -38,7 +38,6 @@ module Imap::Backup
38
38
  Logger.logger.debug "Folder '#{name}' exists"
39
39
  true
40
40
  rescue FolderNotFound
41
- Logger.logger.debug "Folder '#{name}' does not exist"
42
41
  false
43
42
  end
44
43
 
@@ -189,9 +188,9 @@ module Imap::Backup
189
188
  def examine
190
189
  client.examine(utf7_encoded_name)
191
190
  rescue Net::IMAP::NoResponseError
192
- Imap::Backup::Logger.logger.warn "Folder '#{name}' does not exist on server"
193
- Imap::Backup::Logger.logger.warn caller.join("\n")
194
- raise FolderNotFound, "Folder '#{name}' does not exist on server"
191
+ message = "Folder '#{name}' does not exist on server"
192
+ Imap::Backup::Logger.logger.warn message
193
+ raise FolderNotFound, message
195
194
  end
196
195
 
197
196
  def extract_uid(response)
@@ -211,11 +211,7 @@ module Imap::Backup
211
211
  def multi_fetch_size
212
212
  @multi_fetch_size ||= begin
213
213
  int = @multi_fetch_size_orignal.to_i
214
- if int.positive?
215
- int
216
- else
217
- DEFAULT_MULTI_FETCH_SIZE
218
- end
214
+ int.positive? ? int : DEFAULT_MULTI_FETCH_SIZE
219
215
  end
220
216
  end
221
217
 
@@ -1,6 +1,7 @@
1
1
  require "forwardable"
2
2
  require "net/imap"
3
3
 
4
+ require "imap/backup/email/provider"
4
5
  require "imap/backup/logger"
5
6
 
6
7
  module Imap; end
@@ -17,10 +18,8 @@ module Imap::Backup
17
18
  responses uid_fetch uid_search uid_store
18
19
  )
19
20
 
20
- def initialize(server, account, options)
21
+ def initialize(account)
21
22
  @account = account
22
- @options = options
23
- @server = server
24
23
  @state = nil
25
24
  end
26
25
 
@@ -32,7 +31,10 @@ module Imap::Backup
32
31
 
33
32
  return [] if mailbox_lists.nil?
34
33
 
35
- mailbox_lists.map { |ml| extract_name(ml) }
34
+ ignored_tags = provider.folder_ignore_tags
35
+ mailbox_lists.
36
+ select { |ml| ml.attr & ignored_tags == [] }.
37
+ map { |ml| extract_name(ml) }
36
38
  end
37
39
 
38
40
  # Logs in to the account on the IMAP server
@@ -83,8 +85,6 @@ module Imap::Backup
83
85
  private
84
86
 
85
87
  attr_reader :account
86
- attr_reader :options
87
- attr_reader :server
88
88
  attr_accessor :state
89
89
 
90
90
  def imap
@@ -100,17 +100,36 @@ module Imap::Backup
100
100
  account.password.gsub(/./, "x")
101
101
  end
102
102
 
103
+ def provider
104
+ @provider ||= Email::Provider.for_address(account.username)
105
+ end
106
+
107
+ def options
108
+ @options ||= provider.options.merge(account.connection_options || {})
109
+ end
110
+
111
+ def server
112
+ @server ||= account.server || provider.host
113
+ end
114
+
103
115
  # 6.3.8. LIST Command
104
116
  # An empty ("" string) mailbox name argument is a special request to
105
117
  # return the hierarchy delimiter and the root name of the name given
106
118
  # in the reference.
107
119
  def provider_root
108
- @provider_root ||= begin
109
- Logger.logger.debug "Fetching provider root"
110
- root_info = imap.list("", "")[0]
111
- Logger.logger.debug "Provider root is '#{root_info.name}'"
112
- root_info.name
113
- end
120
+ @provider_root ||=
121
+ if provider.root
122
+ Logger.logger.debug "Using fixed provider root '#{provider.root}'"
123
+ provider.root
124
+ else
125
+ Logger.logger.debug "Fetching provider root"
126
+ result = imap.list("", "")
127
+ raise "IMAP server did not return root folder for #{account.username}" if result.empty?
128
+
129
+ root_info = result[0]
130
+ Logger.logger.debug "Provider root is '#{root_info.name}'"
131
+ root_info.name
132
+ end
114
133
  end
115
134
  end
116
135
  end
@@ -13,13 +13,15 @@ module Imap::Backup
13
13
  @serializer = serializer
14
14
  @multi_fetch_size = multi_fetch_size
15
15
  @reset_seen_flags_after_fetch = reset_seen_flags_after_fetch
16
+ @folder_uids = nil
17
+ @serializer_uids = nil
16
18
  @uids = nil
17
19
  end
18
20
 
19
21
  # Runs the downloader
20
22
  # @return [void]
21
23
  def run
22
- debug("#{serializer_uids.count} already messages already downloaded")
24
+ debug("#{serializer_uids.count} messages already downloaded")
23
25
  debug("#{folder_uids.count} messages on server")
24
26
  local_only_count = (serializer_uids - folder_uids).count
25
27
  if local_only_count.positive?
@@ -33,15 +35,7 @@ module Imap::Backup
33
35
 
34
36
  info("#{uids.count} new messages")
35
37
 
36
- uids.each_slice(multi_fetch_size).with_index do |block, i|
37
- multifetch_failed = download_block(block, i)
38
- raise MultiFetchFailedError if multifetch_failed
39
- end
40
- rescue MultiFetchFailedError
41
- @count = nil
42
- @multi_fetch_size = 1
43
- @uids = nil
44
- retry
38
+ download
45
39
  rescue Net::IMAP::ByeResponseError
46
40
  folder.client.reconnect
47
41
  retry
@@ -54,6 +48,21 @@ module Imap::Backup
54
48
  attr_reader :multi_fetch_size
55
49
  attr_reader :reset_seen_flags_after_fetch
56
50
 
51
+ def download
52
+ block_count = (uids.count / multi_fetch_size.to_f).ceil
53
+ uids.each_slice(multi_fetch_size).with_index do |block, i|
54
+ debug("Downloading #{block.count} messages (block #{i + 1}/#{block_count})")
55
+ multifetch_failed = download_block(block, i)
56
+ raise MultiFetchFailedError if multifetch_failed
57
+ end
58
+ rescue MultiFetchFailedError
59
+ @multi_fetch_size = 1
60
+ @uids = nil
61
+ @folder_uids = nil
62
+ @serializer_uids = nil
63
+ retry
64
+ end
65
+
57
66
  def download_block(block, index)
58
67
  uids_and_bodies =
59
68
  if reset_seen_flags_after_fetch
@@ -10,6 +10,11 @@ module Imap::Backup
10
10
  "imap.mail.me.com"
11
11
  end
12
12
 
13
+ # With Apple Mails's IMAP, passing "/" to list results in an empty list
14
+ def root
15
+ ""
16
+ end
17
+
13
18
  def sets_seen_flags_on_fetch?
14
19
  true
15
20
  end
@@ -6,11 +6,22 @@ module Imap::Backup
6
6
 
7
7
  # Supplies defaults for email provider behaviour
8
8
  class Email::Provider::Base
9
+ # @return [Array<Symbol>] tags to ignore when listing folders
10
+ def folder_ignore_tags
11
+ []
12
+ end
13
+
9
14
  # @return [Hash] defaults for the Net::IMAP connection
10
15
  def options
11
16
  {port: 993, ssl: {min_version: OpenSSL::SSL::TLS1_2_VERSION}}
12
17
  end
13
18
 
19
+ # By default, we query the server for this value.
20
+ # It is only fixed for Apple Mail accounts.
21
+ # @return [String, nil] any fixed value to use when requesting the list of account folders
22
+ def root
23
+ end
24
+
14
25
  def sets_seen_flags_on_fetch?
15
26
  false
16
27
  end
@@ -5,6 +5,11 @@ module Imap; end
5
5
  module Imap::Backup
6
6
  # Provides overrides for GMail accounts
7
7
  class Email::Provider::GMail < Email::Provider::Base
8
+ # https://imap-use.u.washington.narkive.com/RYMsOHTN/imap-protocol-status-on-a-noselect-mailbox
9
+ def folder_ignore_tags
10
+ [:Noselect]
11
+ end
12
+
8
13
  # @return [String] the GMail IMAP server host name
9
14
  def host
10
15
  "imap.gmail.com"
@@ -4,7 +4,7 @@ module Imap::Backup
4
4
  # @private
5
5
  MAJOR = 16
6
6
  # @private
7
- MINOR = 0
7
+ MINOR = 1
8
8
  # @private
9
9
  REVISION = 0
10
10
  # @private
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: imap-backup
3
3
  version: !ruby/object:Gem::Version
4
- version: 16.0.0
4
+ version: 16.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Yates
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-06-26 00:00:00.000000000 Z
11
+ date: 2025-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: highline
@@ -192,7 +192,6 @@ files:
192
192
  - lib/imap/backup/cli/stats.rb
193
193
  - lib/imap/backup/cli/transfer.rb
194
194
  - lib/imap/backup/cli/utils.rb
195
- - lib/imap/backup/client/apple_mail.rb
196
195
  - lib/imap/backup/client/automatic_login_wrapper.rb
197
196
  - lib/imap/backup/client/default.rb
198
197
  - lib/imap/backup/configuration.rb
@@ -1,15 +0,0 @@
1
- require "imap/backup/client/default"
2
-
3
- module Imap; end
4
-
5
- module Imap::Backup
6
- # Overrides default IMAP client behaviour for Apple Mail accounts
7
- class Client::AppleMail < Client::Default
8
- # With Apple Mails's IMAP, passing "/" to list
9
- # results in an empty list
10
- # @return [String] the value to use when requesting the list of account folders
11
- def provider_root
12
- ""
13
- end
14
- end
15
- end