imapcli 2.1.0 → 3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0736f0dbe2cb473770fb5f92f0f37546b9f26a6e892bbca3c69b072c1f06db9f
4
- data.tar.gz: '0609a383ac74799eb2aade3d52fa0c5c811fc5cb4b253f1607e0b6f2dbe7cf01'
3
+ metadata.gz: 5a1983fc995c34ea7b3a8d03cdbc45d644090aa0cc60527fe824cd7ae5227300
4
+ data.tar.gz: f688ac2337ae9c3f0cb5d6d62df60a345bb5fabc0dab771d518be5d1ce1b18a1
5
5
  SHA512:
6
- metadata.gz: 69d818a1780fda1549bbd83581c2d0abbc4ecda7274cb411bedd450a8365e322153263c1f5b490b03a183e7c8cb02e5d382c82c8628ee43e1c1c1294f6e76afa
7
- data.tar.gz: e664577a0949609bebd90a7bc08b94e4559001fcb7b26429958fe38801acd835089b030cad3d3b1fa09a95ccc51b400f6cb8f66befc4903ebe1cb9b4bb56746d
6
+ metadata.gz: 23e6aaf015e5ffb731e4f5a6e6d926ff0b8988ba3ea92503df7615aff9217e1b1b55a4c5236a9aabade45dffe53f7bf2912e6084886c25ec0f0d83202fc220f9
7
+ data.tar.gz: 5cae5a577598c723f2c9621ad5ad173aa246bf93ffaff740f57e5ab6ce4f3c21b0d124daddf55b801f22b60e677a37a93ae1d20a913da82eff3d644818899833
data/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Version 3.0.0 (2025-04-21)][v3.0.0]
9
+
10
+ ### Changed
11
+
12
+ - **BREAKING:** Removed the `-v`/`--verbose` switch which was not functional
13
+ anyway and added a new option `-O`/`--log-output` flag to write IMAP responses
14
+ to a file in JSON format.
15
+
8
16
  ## [Version 2.1.0 (2025-03-16)][v2.1.0]
9
17
 
10
18
  ### Added
@@ -79,6 +87,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
79
87
  - Fix: Docker image.
80
88
  - Fix: Options error message.
81
89
 
90
+ [v3.0.0]: https://github.com/bovender/imapcli/releases/tag/v3.0.0
82
91
  [v2.1.0]: https://github.com/bovender/imapcli/releases/tag/v2.1.0
83
92
  [v2.0.1]: https://github.com/bovender/imapcli/releases/tag/v2.0.1
84
93
  [v2.0.0]: https://github.com/bovender/imapcli/releases/tag/v2.0.0
data/Gemfile.lock CHANGED
@@ -1,13 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- imapcli (2.0.1)
4
+ imapcli (2.1.0)
5
5
  activesupport (~> 8.0)
6
6
  csv
7
7
  descriptive_statistics (~> 2.5)
8
8
  dotenv (~> 3.1)
9
9
  gli (~> 2.22)
10
+ multi_json (~> 1.15)
10
11
  net-imap
12
+ oj (~> 3.16)
11
13
  tty-progressbar (~> 0.18)
12
14
  tty-prompt (~> 0.23)
13
15
  tty-table (~> 0.12)
@@ -93,6 +95,7 @@ GEM
93
95
  lumberjack (1.2.10)
94
96
  method_source (1.1.0)
95
97
  minitest (5.25.5)
98
+ multi_json (1.15.0)
96
99
  nenv (0.3.0)
97
100
  net-imap (0.5.6)
98
101
  date
@@ -102,6 +105,9 @@ GEM
102
105
  notiffany (0.1.3)
103
106
  nenv (~> 0.1)
104
107
  shellany (~> 0.0)
108
+ oj (3.16.10)
109
+ bigdecimal (>= 3.0)
110
+ ostruct (>= 0.2)
105
111
  ostruct (0.6.1)
106
112
  parallel (1.26.3)
107
113
  parser (3.3.7.1)
data/README.md CHANGED
@@ -280,6 +280,17 @@ Use case: Say you have a very large IMAP account, and you would like to know the
280
280
 
281
281
  Use the `--csv` flag.
282
282
 
283
+ ### Writing IMAP responses to file
284
+
285
+ Using the `-O`/`--log-output` flag, you can have `imapcli` write the IMAP responses
286
+ to a file in JSON format:
287
+
288
+ ```bash
289
+ imapcli -s yourserver.example.com -u username -P -O output_file.json stats Inbox
290
+ ```
291
+
292
+ **WARNING:** The output file will be overwritten without notice!
293
+
283
294
  ## Alternative resources
284
295
 
285
296
  While researching command-line tools for IMAP servers, I came across the
data/imapcli.gemspec CHANGED
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
28
28
  s.add_dependency('dotenv', '~> 3.1')
29
29
  s.add_dependency('gli', '~> 2.22')
30
30
  s.add_dependency('net-imap')
31
+ s.add_dependency('oj', '~> 3.16')
31
32
  s.add_dependency('tty-progressbar', '~> 0.18')
32
33
  s.add_dependency('tty-prompt', '~> 0.23')
33
34
  s.add_dependency('tty-table', '~> 0.12')
data/lib/imapcli/cli.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'multi_json'
4
+ require 'oj'
5
+
3
6
  module Imapcli
4
7
  class Cli # rubocop:disable Metrics/ClassLength,Style/Documentation
5
8
  extend GLI::App
@@ -31,8 +34,8 @@ module Imapcli
31
34
  desc 'Prompt for password'
32
35
  switch %i[P prompt], negatable: false
33
36
 
34
- desc 'Verbose output (e.g., response values from Rubys Net::IMAP)'
35
- switch %i[v verbose], negatable: false
37
+ desc 'Output responses from Rubys Net::IMAP to file in JSON format. File will be overwritten if it exists!'
38
+ flag %i[O log-output]
36
39
 
37
40
  desc 'Tests if the server is available and log-in succeeds with the credentials'
38
41
  command :check do |c|
@@ -89,7 +92,7 @@ module Imapcli
89
92
  if progress_bar
90
93
  progress_bar.advance
91
94
  else
92
- @prompt.say "info: collecting stats for #{n} folders" if n > 1
95
+ @prompt.warn "info: collecting stats for #{n} folders" if n > 1
93
96
  progress_bar = TTY::ProgressBar.new(
94
97
  'collecting stats... :current/:total (:percent, :eta remaining)',
95
98
  total: n, clear: true
@@ -111,9 +114,9 @@ module Imapcli
111
114
  formatted_body = formatted_body.insert(0, :separator).insert(-2, :separator)
112
115
 
113
116
  if options[:human]
114
- @prompt.say "notice: -H/--human flag present, message sizes are given with SI prefixes"
117
+ @prompt.warn "notice: -H/--human flag present, message sizes are given with SI prefixes"
115
118
  else
116
- @prompt.say "notice: message sizes are given in bytes"
119
+ @prompt.warn "notice: message sizes are given in bytes"
117
120
  end
118
121
 
119
122
  table = TTY::Table.new(head, formatted_body)
@@ -143,27 +146,25 @@ module Imapcli
143
146
  global[:p] = @prompt.mask 'Enter password:' if global[:P]
144
147
  global[:p] ||= ENV.fetch('IMAP_PASS', nil)
145
148
 
146
- client = Imapcli::Client.new(global[:s], global[:u], global[:p])
149
+ @client = Imapcli::Client.new(global[:s], global[:u], global[:p])
147
150
  @prompt.say "server: #{global[:s]}"
148
151
  @prompt.say "user: #{global[:u]}"
149
- raise 'invalid server name' unless client.server_valid?
150
- raise 'invalid user name' unless client.user_valid?
152
+ raise 'invalid server name' unless @client.server_valid?
153
+ raise 'invalid user name' unless @client.user_valid?
151
154
 
152
155
  @prompt.warn 'warning: no password was provided (missing -p/-P option)' unless global[:p]
153
- raise 'unable to connect to server' unless client.connection
156
+ raise 'unable to connect to server' unless @client.connection
154
157
 
155
- @command = Imapcli::Command.new(client)
158
+ @command = Imapcli::Command.new(@client)
156
159
 
157
160
  true
158
161
  end
159
162
 
160
163
  post do |global, _command, _options, _args|
161
164
  @client&.logout
162
- if global[:v]
163
- @prompt.say "\n>>> --verbose switch on, listing server responses <<<"
164
- @client.responses.each do |response|
165
- @prompt.say response
166
- end
165
+ if file_name = global[:o]
166
+ @prompt.warn "notice: writing IMAP responses to #{file_name.dump}"
167
+ File.write(file_name, Oj.dump(@client.responses, mode: :object, indent: 2, escape: :unicode_xss, symbolize_names: false))
167
168
  end
168
169
  end
169
170
 
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+
3
5
  module Imapcli
4
6
  # Wrapper for Net::IMAP
5
7
  class Client # rubocop:disable Metrics/ClassLength
6
8
  attr_accessor :port, :user, :pass
7
- attr_reader :responses
8
9
 
9
10
  ## Initializs the Client class.
10
11
  ##
@@ -17,7 +18,7 @@ module Imapcli
17
18
  self.server = server_with_optional_port
18
19
  @user = user
19
20
  @pass = pass
20
- clear_log
21
+ clear_responses
21
22
  end
22
23
 
23
24
  # Attribute reader for the server domain name
@@ -57,10 +58,15 @@ module Imapcli
57
58
  end
58
59
 
59
60
  # Clears the server response log
60
- def clear_log
61
+ def clear_responses
61
62
  @log = []
62
63
  end
63
64
 
65
+ # Returns the IMAP server response log
66
+ def responses
67
+ @log
68
+ end
69
+
64
70
  # Returns the last response from the server
65
71
  def last_response
66
72
  @log.last
@@ -96,17 +102,17 @@ module Imapcli
96
102
  # Returns the server's greeting (which may reveal the server software name
97
103
  # such as 'Dovecot').
98
104
  def greeting
99
- query_server { connection.greeting.data.text.strip }
105
+ query_server('greeting') { connection.greeting.data.text.strip }
100
106
  end
101
107
 
102
108
  # Returns the server's capabilities.
103
109
  def capability
104
- @capability ||= query_server { connection.capability }
110
+ @capability ||= query_server('capability') { connection.capability }
105
111
  end
106
112
 
107
113
  # Returns the character that is used to separate nested mailbox names.
108
114
  def separator
109
- @separator ||= query_server { connection.list('', '')[0].delim }
115
+ @separator ||= query_server("list('')") { connection.list('', '')[0].delim }
110
116
  end
111
117
 
112
118
  # Returns true if the server supports the IMAP QUOTA extension.
@@ -120,7 +126,7 @@ module Imapcli
120
126
  return unless supports_quota
121
127
 
122
128
  @quota ||= begin
123
- info = query_server { @connection.getquotaroot('INBOX')[1] }
129
+ info = query_server("getquotaroot('INBOX')") { @connection.getquotaroot('INBOX')[1] }
124
130
  percent = info.quota.to_i.positive? ? info.usage.to_i.fdiv(info.quota.to_i) * 100 : nil
125
131
  [info.usage, info.quota, percent]
126
132
  end
@@ -130,8 +136,8 @@ module Imapcli
130
136
  #
131
137
  # The value is currently NOT cached.
132
138
  def messages(mailbox)
133
- query_server { connection.examine(mailbox) }
134
- query_server { connection.search('ALL') }
139
+ query_server("examine('#{mailbox}')") { connection.examine(mailbox) }
140
+ query_server("search('ALL')") { connection.search('ALL') }
135
141
  end
136
142
 
137
143
  # Examines a mailbox and returns statistics about the messages in it.
@@ -149,7 +155,7 @@ module Imapcli
149
155
  if messages.empty?
150
156
  []
151
157
  else
152
- query_server do
158
+ query_server('fetch(...)') do
153
159
  messages.each_slice(1000).map do |some_messages|
154
160
  connection.fetch(some_messages, 'RFC822.SIZE').map do |f|
155
161
  f.attr['RFC822.SIZE']
@@ -168,7 +174,7 @@ module Imapcli
168
174
  #
169
175
  # The value is cached.
170
176
  def mailboxes
171
- @mailboxes ||= query_server { @connection.list('', '*') }
177
+ @mailboxes ||= query_server('list') { @connection.list('', '*') }
172
178
  end
173
179
 
174
180
  # Returns a tree of +Imapcli::Mailbox+ objects.
@@ -188,12 +194,10 @@ module Imapcli
188
194
  private
189
195
 
190
196
  def response_ok?(response)
191
- @log << response
192
197
  response.name == 'OK'
193
198
  end
194
199
 
195
200
  def log_error(error)
196
- @log << error
197
201
  false
198
202
  end
199
203
 
@@ -203,13 +207,31 @@ module Imapcli
203
207
  # error if not. The code that queries the server must be contained in the
204
208
  # +block+, and the +block+'s return value is returned by this function.
205
209
  # The +connection+'s responses are logged.
206
- def query_server
210
+ def query_server(imap_command)
207
211
  raise('no connection to a server') unless connection
208
212
 
209
213
  result = yield
210
- @log << connection.responses
214
+ @log << {
215
+ 'imap_command': imap_command,
216
+ 'imap_response': connection.responses.to_h
217
+ }
211
218
  result
212
219
  end
213
220
 
221
+ # Recursively convert structs in an array of hashes to hashes
222
+ # Inspired by https://stackoverflow.com/a/62804063/270712
223
+ # and rephrased to improve readability a bit
224
+ def to_h_recursively(hash)
225
+ hash.map do |value|
226
+ if value.is_a?(Arry)
227
+ to_h_recursively(value)
228
+ elsif value.is_a?(Struct)
229
+ value.to_h
230
+ else
231
+ value
232
+ end
233
+ end
234
+ end
235
+
214
236
  end
215
237
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Imapcli
4
- VERSION = '2.1.0'
4
+ VERSION = '3.0.0'
5
5
  end
data/logoutput.json ADDED
@@ -0,0 +1,527 @@
1
+ [
2
+ {
3
+ ":imap_command":"list",
4
+ ":imap_response":{
5
+ "FLAGS":[
6
+ [
7
+ ":Answered",
8
+ ":Flagged",
9
+ ":Deleted",
10
+ ":Seen",
11
+ ":Draft",
12
+ "NonJunk",
13
+ "Junk",
14
+ "$label2",
15
+ "$forwarded",
16
+ "$label5",
17
+ "Old",
18
+ "$label4",
19
+ "$label3",
20
+ "$SIGNED",
21
+ "$JUNK",
22
+ "$ATTACHMENT",
23
+ "$NOTJUNK",
24
+ "$INVITATION",
25
+ "$label1",
26
+ "$TODO"
27
+ ]
28
+ ],
29
+ "OK":[
30
+ {
31
+ "^u":[
32
+ "Net::IMAP::ResponseText",
33
+ {
34
+ "^u":[
35
+ "Net::IMAP::ResponseCode",
36
+ "PERMANENTFLAGS",
37
+ []]},
38
+ "Read-only mailbox."]},
39
+ {
40
+ "^u":[
41
+ "Net::IMAP::ResponseText",
42
+ {
43
+ "^u":[
44
+ "Net::IMAP::ResponseCode",
45
+ "UNSEEN",
46
+ 6]},
47
+ "First unseen."]},
48
+ {
49
+ "^u":[
50
+ "Net::IMAP::ResponseText",
51
+ {
52
+ "^u":[
53
+ "Net::IMAP::ResponseCode",
54
+ "UIDVALIDITY",
55
+ 1435851445]},
56
+ "UIDs valid"]},
57
+ {
58
+ "^u":[
59
+ "Net::IMAP::ResponseText",
60
+ {
61
+ "^u":[
62
+ "Net::IMAP::ResponseCode",
63
+ "UIDNEXT",
64
+ 104489]},
65
+ "Predicted next UID"]},
66
+ {
67
+ "^u":[
68
+ "Net::IMAP::ResponseText",
69
+ {
70
+ "^u":[
71
+ "Net::IMAP::ResponseCode",
72
+ "HIGHESTMODSEQ",
73
+ 309489]},
74
+ "Highest"]}
75
+ ],
76
+ "PERMANENTFLAGS":[
77
+ []
78
+ ],
79
+ "EXISTS":[
80
+ 6
81
+ ],
82
+ "RECENT":[
83
+ 0
84
+ ],
85
+ "UNSEEN":[
86
+ 6
87
+ ],
88
+ "UIDVALIDITY":[
89
+ 1435851445
90
+ ],
91
+ "UIDNEXT":[
92
+ 104489
93
+ ],
94
+ "HIGHESTMODSEQ":[
95
+ 309489
96
+ ],
97
+ "ESEARCH":[],
98
+ "BYE":[
99
+ {
100
+ "^u":[
101
+ "Net::IMAP::ResponseText",
102
+ null,
103
+ "Logging out"]}
104
+ ]
105
+ }
106
+ },
107
+ {
108
+ ":imap_command":"list('')",
109
+ ":imap_response":{
110
+ "FLAGS":[
111
+ [
112
+ ":Answered",
113
+ ":Flagged",
114
+ ":Deleted",
115
+ ":Seen",
116
+ ":Draft",
117
+ "NonJunk",
118
+ "Junk",
119
+ "$label2",
120
+ "$forwarded",
121
+ "$label5",
122
+ "Old",
123
+ "$label4",
124
+ "$label3",
125
+ "$SIGNED",
126
+ "$JUNK",
127
+ "$ATTACHMENT",
128
+ "$NOTJUNK",
129
+ "$INVITATION",
130
+ "$label1",
131
+ "$TODO"
132
+ ]
133
+ ],
134
+ "OK":[
135
+ {
136
+ "^u":[
137
+ "Net::IMAP::ResponseText",
138
+ {
139
+ "^u":[
140
+ "Net::IMAP::ResponseCode",
141
+ "PERMANENTFLAGS",
142
+ []]},
143
+ "Read-only mailbox."]},
144
+ {
145
+ "^u":[
146
+ "Net::IMAP::ResponseText",
147
+ {
148
+ "^u":[
149
+ "Net::IMAP::ResponseCode",
150
+ "UNSEEN",
151
+ 6]},
152
+ "First unseen."]},
153
+ {
154
+ "^u":[
155
+ "Net::IMAP::ResponseText",
156
+ {
157
+ "^u":[
158
+ "Net::IMAP::ResponseCode",
159
+ "UIDVALIDITY",
160
+ 1435851445]},
161
+ "UIDs valid"]},
162
+ {
163
+ "^u":[
164
+ "Net::IMAP::ResponseText",
165
+ {
166
+ "^u":[
167
+ "Net::IMAP::ResponseCode",
168
+ "UIDNEXT",
169
+ 104489]},
170
+ "Predicted next UID"]},
171
+ {
172
+ "^u":[
173
+ "Net::IMAP::ResponseText",
174
+ {
175
+ "^u":[
176
+ "Net::IMAP::ResponseCode",
177
+ "HIGHESTMODSEQ",
178
+ 309489]},
179
+ "Highest"]}
180
+ ],
181
+ "PERMANENTFLAGS":[
182
+ []
183
+ ],
184
+ "EXISTS":[
185
+ 6
186
+ ],
187
+ "RECENT":[
188
+ 0
189
+ ],
190
+ "UNSEEN":[
191
+ 6
192
+ ],
193
+ "UIDVALIDITY":[
194
+ 1435851445
195
+ ],
196
+ "UIDNEXT":[
197
+ 104489
198
+ ],
199
+ "HIGHESTMODSEQ":[
200
+ 309489
201
+ ],
202
+ "ESEARCH":[],
203
+ "BYE":[
204
+ {
205
+ "^u":[
206
+ "Net::IMAP::ResponseText",
207
+ null,
208
+ "Logging out"]}
209
+ ]
210
+ }
211
+ },
212
+ {
213
+ ":imap_command":"examine('INBOX')",
214
+ ":imap_response":{
215
+ "FLAGS":[
216
+ [
217
+ ":Answered",
218
+ ":Flagged",
219
+ ":Deleted",
220
+ ":Seen",
221
+ ":Draft",
222
+ "NonJunk",
223
+ "Junk",
224
+ "$label2",
225
+ "$forwarded",
226
+ "$label5",
227
+ "Old",
228
+ "$label4",
229
+ "$label3",
230
+ "$SIGNED",
231
+ "$JUNK",
232
+ "$ATTACHMENT",
233
+ "$NOTJUNK",
234
+ "$INVITATION",
235
+ "$label1",
236
+ "$TODO"
237
+ ]
238
+ ],
239
+ "OK":[
240
+ {
241
+ "^u":[
242
+ "Net::IMAP::ResponseText",
243
+ {
244
+ "^u":[
245
+ "Net::IMAP::ResponseCode",
246
+ "PERMANENTFLAGS",
247
+ []]},
248
+ "Read-only mailbox."]},
249
+ {
250
+ "^u":[
251
+ "Net::IMAP::ResponseText",
252
+ {
253
+ "^u":[
254
+ "Net::IMAP::ResponseCode",
255
+ "UNSEEN",
256
+ 6]},
257
+ "First unseen."]},
258
+ {
259
+ "^u":[
260
+ "Net::IMAP::ResponseText",
261
+ {
262
+ "^u":[
263
+ "Net::IMAP::ResponseCode",
264
+ "UIDVALIDITY",
265
+ 1435851445]},
266
+ "UIDs valid"]},
267
+ {
268
+ "^u":[
269
+ "Net::IMAP::ResponseText",
270
+ {
271
+ "^u":[
272
+ "Net::IMAP::ResponseCode",
273
+ "UIDNEXT",
274
+ 104489]},
275
+ "Predicted next UID"]},
276
+ {
277
+ "^u":[
278
+ "Net::IMAP::ResponseText",
279
+ {
280
+ "^u":[
281
+ "Net::IMAP::ResponseCode",
282
+ "HIGHESTMODSEQ",
283
+ 309489]},
284
+ "Highest"]}
285
+ ],
286
+ "PERMANENTFLAGS":[
287
+ []
288
+ ],
289
+ "EXISTS":[
290
+ 6
291
+ ],
292
+ "RECENT":[
293
+ 0
294
+ ],
295
+ "UNSEEN":[
296
+ 6
297
+ ],
298
+ "UIDVALIDITY":[
299
+ 1435851445
300
+ ],
301
+ "UIDNEXT":[
302
+ 104489
303
+ ],
304
+ "HIGHESTMODSEQ":[
305
+ 309489
306
+ ],
307
+ "ESEARCH":[],
308
+ "BYE":[
309
+ {
310
+ "^u":[
311
+ "Net::IMAP::ResponseText",
312
+ null,
313
+ "Logging out"]}
314
+ ]
315
+ }
316
+ },
317
+ {
318
+ ":imap_command":"search('ALL')",
319
+ ":imap_response":{
320
+ "FLAGS":[
321
+ [
322
+ ":Answered",
323
+ ":Flagged",
324
+ ":Deleted",
325
+ ":Seen",
326
+ ":Draft",
327
+ "NonJunk",
328
+ "Junk",
329
+ "$label2",
330
+ "$forwarded",
331
+ "$label5",
332
+ "Old",
333
+ "$label4",
334
+ "$label3",
335
+ "$SIGNED",
336
+ "$JUNK",
337
+ "$ATTACHMENT",
338
+ "$NOTJUNK",
339
+ "$INVITATION",
340
+ "$label1",
341
+ "$TODO"
342
+ ]
343
+ ],
344
+ "OK":[
345
+ {
346
+ "^u":[
347
+ "Net::IMAP::ResponseText",
348
+ {
349
+ "^u":[
350
+ "Net::IMAP::ResponseCode",
351
+ "PERMANENTFLAGS",
352
+ []]},
353
+ "Read-only mailbox."]},
354
+ {
355
+ "^u":[
356
+ "Net::IMAP::ResponseText",
357
+ {
358
+ "^u":[
359
+ "Net::IMAP::ResponseCode",
360
+ "UNSEEN",
361
+ 6]},
362
+ "First unseen."]},
363
+ {
364
+ "^u":[
365
+ "Net::IMAP::ResponseText",
366
+ {
367
+ "^u":[
368
+ "Net::IMAP::ResponseCode",
369
+ "UIDVALIDITY",
370
+ 1435851445]},
371
+ "UIDs valid"]},
372
+ {
373
+ "^u":[
374
+ "Net::IMAP::ResponseText",
375
+ {
376
+ "^u":[
377
+ "Net::IMAP::ResponseCode",
378
+ "UIDNEXT",
379
+ 104489]},
380
+ "Predicted next UID"]},
381
+ {
382
+ "^u":[
383
+ "Net::IMAP::ResponseText",
384
+ {
385
+ "^u":[
386
+ "Net::IMAP::ResponseCode",
387
+ "HIGHESTMODSEQ",
388
+ 309489]},
389
+ "Highest"]}
390
+ ],
391
+ "PERMANENTFLAGS":[
392
+ []
393
+ ],
394
+ "EXISTS":[
395
+ 6
396
+ ],
397
+ "RECENT":[
398
+ 0
399
+ ],
400
+ "UNSEEN":[
401
+ 6
402
+ ],
403
+ "UIDVALIDITY":[
404
+ 1435851445
405
+ ],
406
+ "UIDNEXT":[
407
+ 104489
408
+ ],
409
+ "HIGHESTMODSEQ":[
410
+ 309489
411
+ ],
412
+ "ESEARCH":[],
413
+ "BYE":[
414
+ {
415
+ "^u":[
416
+ "Net::IMAP::ResponseText",
417
+ null,
418
+ "Logging out"]}
419
+ ]
420
+ }
421
+ },
422
+ {
423
+ ":imap_command":"fetch(...)",
424
+ ":imap_response":{
425
+ "FLAGS":[
426
+ [
427
+ ":Answered",
428
+ ":Flagged",
429
+ ":Deleted",
430
+ ":Seen",
431
+ ":Draft",
432
+ "NonJunk",
433
+ "Junk",
434
+ "$label2",
435
+ "$forwarded",
436
+ "$label5",
437
+ "Old",
438
+ "$label4",
439
+ "$label3",
440
+ "$SIGNED",
441
+ "$JUNK",
442
+ "$ATTACHMENT",
443
+ "$NOTJUNK",
444
+ "$INVITATION",
445
+ "$label1",
446
+ "$TODO"
447
+ ]
448
+ ],
449
+ "OK":[
450
+ {
451
+ "^u":[
452
+ "Net::IMAP::ResponseText",
453
+ {
454
+ "^u":[
455
+ "Net::IMAP::ResponseCode",
456
+ "PERMANENTFLAGS",
457
+ []]},
458
+ "Read-only mailbox."]},
459
+ {
460
+ "^u":[
461
+ "Net::IMAP::ResponseText",
462
+ {
463
+ "^u":[
464
+ "Net::IMAP::ResponseCode",
465
+ "UNSEEN",
466
+ 6]},
467
+ "First unseen."]},
468
+ {
469
+ "^u":[
470
+ "Net::IMAP::ResponseText",
471
+ {
472
+ "^u":[
473
+ "Net::IMAP::ResponseCode",
474
+ "UIDVALIDITY",
475
+ 1435851445]},
476
+ "UIDs valid"]},
477
+ {
478
+ "^u":[
479
+ "Net::IMAP::ResponseText",
480
+ {
481
+ "^u":[
482
+ "Net::IMAP::ResponseCode",
483
+ "UIDNEXT",
484
+ 104489]},
485
+ "Predicted next UID"]},
486
+ {
487
+ "^u":[
488
+ "Net::IMAP::ResponseText",
489
+ {
490
+ "^u":[
491
+ "Net::IMAP::ResponseCode",
492
+ "HIGHESTMODSEQ",
493
+ 309489]},
494
+ "Highest"]}
495
+ ],
496
+ "PERMANENTFLAGS":[
497
+ []
498
+ ],
499
+ "EXISTS":[
500
+ 6
501
+ ],
502
+ "RECENT":[
503
+ 0
504
+ ],
505
+ "UNSEEN":[
506
+ 6
507
+ ],
508
+ "UIDVALIDITY":[
509
+ 1435851445
510
+ ],
511
+ "UIDNEXT":[
512
+ 104489
513
+ ],
514
+ "HIGHESTMODSEQ":[
515
+ 309489
516
+ ],
517
+ "ESEARCH":[],
518
+ "BYE":[
519
+ {
520
+ "^u":[
521
+ "Net::IMAP::ResponseText",
522
+ null,
523
+ "Logging out"]}
524
+ ]
525
+ }
526
+ }
527
+ ]
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: imapcli
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Kraus (bovender)
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-03-16 00:00:00.000000000 Z
10
+ date: 2025-04-21 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -94,6 +93,20 @@ dependencies:
94
93
  - - ">="
95
94
  - !ruby/object:Gem::Version
96
95
  version: '0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: oj
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.16'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '3.16'
97
110
  - !ruby/object:Gem::Dependency
98
111
  name: tty-progressbar
99
112
  requirement: !ruby/object:Gem::Requirement
@@ -150,7 +163,6 @@ dependencies:
150
163
  - - "~>"
151
164
  - !ruby/object:Gem::Version
152
165
  version: 2.7.0
153
- description:
154
166
  email: bovender@bovender.de
155
167
  executables:
156
168
  - imapcli
@@ -186,6 +198,7 @@ files:
186
198
  - lib/imapcli/option_validator.rb
187
199
  - lib/imapcli/stats.rb
188
200
  - lib/imapcli/version.rb
201
+ - logoutput.json
189
202
  - spec/lib/imapcli/client_spec.rb
190
203
  - spec/lib/imapcli/command_spec.rb
191
204
  - spec/lib/imapcli/mailbox_spec.rb
@@ -195,7 +208,6 @@ homepage: https://github.com/bovender/imapcli
195
208
  licenses:
196
209
  - Apache-2.0
197
210
  metadata: {}
198
- post_install_message:
199
211
  rdoc_options:
200
212
  - "--title"
201
213
  - imapcli
@@ -215,8 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
227
  - !ruby/object:Gem::Version
216
228
  version: '0'
217
229
  requirements: []
218
- rubygems_version: 3.5.22
219
- signing_key:
230
+ rubygems_version: 3.6.2
220
231
  specification_version: 4
221
232
  summary: Command-line tool to query IMAP servers
222
233
  test_files: []