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 +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +7 -1
- data/README.md +11 -0
- data/imapcli.gemspec +1 -0
- data/lib/imapcli/cli.rb +16 -15
- data/lib/imapcli/client.rb +37 -15
- data/lib/imapcli/version.rb +1 -1
- data/logoutput.json +527 -0
- metadata +18 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a1983fc995c34ea7b3a8d03cdbc45d644090aa0cc60527fe824cd7ae5227300
|
4
|
+
data.tar.gz: f688ac2337ae9c3f0cb5d6d62df60a345bb5fabc0dab771d518be5d1ce1b18a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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 '
|
35
|
-
|
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.
|
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.
|
117
|
+
@prompt.warn "notice: -H/--human flag present, message sizes are given with SI prefixes"
|
115
118
|
else
|
116
|
-
@prompt.
|
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[:
|
163
|
-
@prompt.
|
164
|
-
@client.responses
|
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
|
|
data/lib/imapcli/client.rb
CHANGED
@@ -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
|
-
|
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
|
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 <<
|
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
|
data/lib/imapcli/version.rb
CHANGED
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:
|
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-
|
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.
|
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: []
|