imapcli 0.0.1 → 1.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
  SHA1:
3
- metadata.gz: a446b1918219fb961e61ddce7f63e260a05eefff
4
- data.tar.gz: 0d571a1f5c46a1edee07ef7381d10b26c6a1b511
3
+ metadata.gz: 0eea58453e11ea2b7a31df76ba5aa4d56152d1e6
4
+ data.tar.gz: 2c5d48c01d834adabd756cc6ea0c567ceb66eb2d
5
5
  SHA512:
6
- metadata.gz: 82a9caf9891f4814b4965f0c52d9c263d8cc33deab96f506c24918e1c91b2b29ccda53cb7e8d70d1ce873d4f1873c77930a0b20538e78a66773de64ba74e6d4d
7
- data.tar.gz: 76850a1c35393bba6997a7fde9bf9ad0075367c40c63cd78e6f3ea6a17b9754fddc140bbeff2e580f10f3580808aac47b8ced4d6f713d84e6629532488bb5515
6
+ metadata.gz: f7f5f2d62dcedb5e43dfa60b5b342bf7db7e7317f7e29809fcd6b5bac4c69e153bb8f7f5f1aef5040aca6802ec585faef16cf839a9d069621627b467ddc01d36
7
+ data.tar.gz: d5304ffda8cd1417592d9a9d5552ef969effd94c5d2d0a17ed68d0a93120495cbf206da27268a5e94223c7561d63959a07fd150ce4c83a0b1a4d07d8cc1a1fec
data/Gemfile CHANGED
@@ -6,6 +6,7 @@ gem 'dotenv'
6
6
  gem 'gli'
7
7
  gem 'tty-prompt'
8
8
  gem 'tty-table'
9
+ gem 'tty-progressbar'
9
10
  gem 'descriptive_statistics'
10
11
  gem 'filesize'
11
12
 
data/Gemfile.lock CHANGED
@@ -73,6 +73,9 @@ GEM
73
73
  hitimes
74
74
  tty-color (0.4.2)
75
75
  tty-cursor (0.5.0)
76
+ tty-progressbar (0.13.0)
77
+ tty-cursor (~> 0.5.0)
78
+ tty-screen (~> 0.6.0)
76
79
  tty-prompt (0.13.2)
77
80
  necromancer (~> 0.4.0)
78
81
  pastel (~> 0.7.0)
@@ -110,6 +113,7 @@ DEPENDENCIES
110
113
  rake
111
114
  rdoc
112
115
  rspec
116
+ tty-progressbar
113
117
  tty-prompt
114
118
  tty-table
115
119
 
data/NEWS ADDED
@@ -0,0 +1,9 @@
1
+
2
+ Version 0.0.1 (2017-11-16)
3
+ ------------------------------------------------------------------------
4
+
5
+ Initial alpha release. Stats working only for mailboxes that are
6
+ explicitly given on the command line.
7
+
8
+
9
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
data/README.md CHANGED
@@ -8,7 +8,7 @@ imapcli
8
8
 
9
9
  `imapcli` is a command-line tool that offers a convenient way to query an IMAP
10
10
  server for configuration details and e-mail statistics. It can be used to gather
11
- IMAP folder sizes.
11
+ IMAP mailbox sizes.
12
12
 
13
13
 
14
14
  Table of contents
@@ -18,7 +18,7 @@ Table of contents
18
18
  * [Warning](#warning)
19
19
  * [Installing and executing `imapcli`](#installing-and-executing-imapcli)
20
20
  * [Terminology](#terminology)
21
- * [Commands](#commands)
21
+ * [Usage](#usage)
22
22
  * [Alternative resources](#alternative-resources)
23
23
  * [State of the project](#state-of-the-project)
24
24
  * [Credits](#credits)
@@ -42,9 +42,10 @@ with the server by telnet or OpenSSL.
42
42
  Warning
43
43
  -------
44
44
 
45
- Some servers are configured to detect malicious login attempts by the frequency
46
- of connections from a given source. **It may happen that you get locked out of
47
- a server if you use `imapcli` to issue too many queries in too short a time!**
45
+ Some servers are configured to detect potentially malicious login attempts by
46
+ the frequency of repeat connections from a given source. **It may happen that
47
+ you get locked out of a server if you use `imapcli` to issue too many queries in
48
+ too short a time!**
48
49
 
49
50
  If you happen to be the server administrator yourself, have
50
51
  [fail2ban](https://www.fail2ban.org) running, and find your IP being denied
@@ -53,10 +54,10 @@ this:
53
54
 
54
55
  sudo fail2ban-client set dovecot unbanip <your-ip>
55
56
 
56
- If your IMAP server is not [Dovecot](https://www.dovecot.org), you need to change
57
- this command and provide the appropriate 'jail' name.
57
+ If your IMAP server is not [Dovecot](https://www.dovecot.org), you need to adjust
58
+ this command to provide the appropriate 'jail' name.
58
59
 
59
- To prevent `fail2ban` from blocking your IP, you may want to add a network and
60
+ To prevent `fail2ban` from blocking your IP, you may want to add your network and
60
61
  submask to `jail.local`:
61
62
 
62
63
  # /etc/fail2ban/jail.local
@@ -67,52 +68,67 @@ Do not forget to reload the `jail2ban` configuration afterwards:
67
68
 
68
69
  sudo service fail2ban reload
69
70
 
71
+ Of course this only works if your IP addresses do not change too much.
72
+
70
73
  (On Ubuntu Linux, the [indicator-ip](https://github.com/bovender/indicator-ip)
71
74
  applet may be useful to know your remote IP. Disclaimer: I am the author of this
72
75
  tool.)
73
76
 
77
+
74
78
  Installing and executing `imapcli`
75
79
  --------------------------------
76
80
 
77
- `imapcli` is a Ruby project and as such does not need to be compiled. You'll
78
- need Ruby on your system.
81
+ `imapcli` is a Ruby project and as such does not need to be compiled. To run it
82
+ on your machine, you can either pull the repository, install a Gem, or use a
83
+ Docker image.
79
84
 
85
+ Detailed usage instructions follow [below](#usage).
80
86
 
81
- ### Run in the repository
87
+ I don't currently provide a .deb package because Debian packaging done right
88
+ is kind of complicated.
82
89
 
83
- Just clone this repository and run
84
90
 
85
- bin/imapcli
91
+ ### Run in the repository
86
92
 
93
+ Requirements: git, a recent Ruby, and [bundler](http://bundler.io).
87
94
 
88
- ### Gem
95
+ Install:
89
96
 
90
- To follow.
97
+ git clone https://github.com/bovender/imapcli
91
98
 
92
99
  Run:
93
100
 
94
- imapcli
101
+ cd imapcli
102
+ bundle exec bin/imapcli
95
103
 
96
104
 
97
- ### .deb installer
105
+ ### Install the gem
98
106
 
99
- To follow.
107
+ Requirements: a recent Ruby and RubyGems.
108
+
109
+ Install:
110
+
111
+ gem install imapcli
112
+
113
+ Run:
114
+
115
+ imapcli
100
116
 
101
117
 
102
118
  ### Docker image
103
119
 
104
- To follow. This will be an option if you don't have Ruby installed.
120
+ To follow.
105
121
 
106
122
 
107
123
  Terminology
108
124
  -----------
109
125
 
110
126
  `imapcli` attempts to use the typical IMAP terminology. I guess most people
111
- have their mails organized in *folders*; in IMAP speak, a folder is a *maibox*.
127
+ have their mails organized in **folders**; in IMAP speak, a folder is a **maibox**.
112
128
 
113
129
 
114
- Commands
115
- --------
130
+ Usage
131
+ -----
116
132
 
117
133
  For basic usage instructions and possible options, run `imapcli` and examine
118
134
  the output. Please note that `imapcli` distinguishes between global and
@@ -120,45 +136,144 @@ command-specific options. Global options *precede* and command-specific options
120
136
  *follow* a `command`, see the output of `imapcli` (without command or options)
121
137
  for more information.
122
138
 
139
+ Note: The following examples use the command `imapcli`. Depending on how you
140
+ [installed](#installing-and-executing-imapcli) `imapcli`, you may need to use a
141
+ different command.
123
142
 
124
- ### Commands
125
143
 
126
- * `info`: Prints configuration information about the server.
127
- * `examine`: Examines a mailbox (i.e., folder) and returns statistics about it.
144
+ ### Setting your server and account information
128
145
 
146
+ Server and account information are given as *global options*:
129
147
 
130
- ### Command-line options
148
+ imapcli -s example.com -u username -p password
131
149
 
132
- * `-s SERVER`: Set the server domain name (e.g., `imap.example.com`). May be
133
- omitted if the information is given in the `IMAP_SERVER` environment variable
134
- (see below).
135
- * `-u USER`: Set the login (user) name (e.g., `john@example.com`). May be
136
- omitted if the information is given in the `IMAP_USER` environment variable
137
- (see below).
138
- * `-p PASSWORD`: Set the password. May be omitted if the `-P` option is used
139
- or if the information is given in the `IMAP_PASS` environment variable (see below).
140
- * `-P`: Prompt for the password.
150
+ Of course it is **not recommended** to type a password on the command line. If
151
+ you *must* give the password on the command line, and have the Bash shell,
152
+ precede the line with a space to prevent it from being saved in the shell history.
141
153
 
154
+ To have `imapcli` prompt you for a password, use the `-P` option:
142
155
 
143
- ### Using environment variables for the server and authentication details
156
+ imapcli -s example.com -u username -P
144
157
 
145
- You can set the following environment variables to avoid having to type the
146
- server information over and over again:
158
+ If you have one just IMAP server that you want to query, consider setting
159
+ environment variables:
147
160
 
148
161
  IMAP_SERVER="imap.example.com"
149
162
  IMAP_USER="your_imap_login"
150
- IMAP_PASS="your_imap_password"
163
+ IMAP_PASS="your_imap_password" # OPTIONAL, NOT RECOMMENDED, VERY INSECURE!
164
+
165
+ These variables can also be set in a `.env` file that resides in the root
166
+ directory of the repository. Never add this `.env` file to the repository!
167
+
168
+
169
+ ### Obtain general information about the IMAP server
170
+
171
+ $ bundle exec bin/imapcli -s yourserver.example.com -u myusername -P info
172
+ Enter password: ••••••••
173
+ server: yourserver.example.com
174
+ user: myusername
175
+ greeting: Dovecot ready.
176
+ capability: IMAP4REV1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SPECIAL-USE
177
+ hierarchy separator: /
178
+ quota: IMAP QUOTA extension not supported by this server
179
+
180
+
181
+ ### List all mailboxes (folders) without size information
182
+
183
+ $ bundle exec bin/imapcli -s yourserver.example.com -u myusername -P list
184
+ Enter password: ••••••••
185
+ server: yourserver.example.com
186
+ user: myusername
187
+ - Work
188
+ - Boss
189
+ - Project
190
+ - Family
191
+ - Sports
192
+ ...
193
+
194
+
195
+ ### Obtain size information about mailboxes
151
196
 
152
- If you put this in a file `.env` in the root directory of the repository, this
153
- information will be used. `.env` is git-ignored, so your credentials won't end up
154
- in the repository, but of course anyone on your system who has access to this file
155
- will be able to read the clear-text credentials.
197
+ To obtain mailbox sizes, the server has to be queried for the message sizes for
198
+ each mailbox of interest. Depending on the number of mailboxes and the number
199
+ of messages in them, this may take a little while.
156
200
 
157
- **Also, be aware that a clear-text password that is stored in an environment
158
- variable can be easily accessed by any other code running under your account.**
201
+ `imapcli` prints the following statistics about the message sizes in a mailbox:
159
202
 
160
- For best security, *never* store your clear-text password anywhere. Use the `-P`
161
- (prompt) global option to have `imapcli` prompt you for the password.
203
+ * `Count`: Number of individual messages
204
+ * `Total size`: Total size of all messages in the mailbox (in kiB)
205
+ * `Min`: Size of the smallest message in the mailbox (in kiB)
206
+ * `Q1`: First quartile of message sizes in the mailbox (in kiB)
207
+ * `Median`: Median of all message sizes in the mailbox (in kiB)
208
+ * `Q3`: First quartile of message sizes in the mailbox (in kiB)
209
+ * `Max`: Size of the largest message in the mailbox (in kiB)
210
+
211
+
212
+ #### All mailboxes
213
+
214
+ To obtain stats for all mailboxes, use the `stats` command without the optional
215
+ mailbox argument:
216
+
217
+ $ bundle exec bin/imapcli -s yourserver.example.com -u myusername -P stats
218
+ Enter password: ••••••••
219
+ server: yourserver.example.com
220
+ user: myusername
221
+ info: collecting stats for 109 folders
222
+ ┌────────────────────────────────┬─────┬─────────────┬──────┬───────┬─────────┬──────────┬──────────┐
223
+ │Mailbox │Count│ Total size│ Min│ Q1│ Median│ Q3│ Max│
224
+ ├────────────────────────────────┼─────┼─────────────┼──────┼───────┼─────────┼──────────┼──────────┤
225
+ ...
226
+ │Total │13168│2,498,517 kiB│ 0 kiB│ 4 kiB│ 7 kiB│ 25 kiB│33,681 kiB│
227
+ └────────────────────────────────┴─────┴─────────────┴──────┴───────┴─────────┴──────────┴──────────┘
228
+
229
+ #### Specific mailboxes without child mailboxes
230
+
231
+ $ bundle exec bin/imapcli -s yourserver.example.com -u myusername -P stats Archive Com
232
+ Enter password: ••••••••
233
+ server: yourserver.example.com
234
+ user: myusername
235
+ ┌───────┬─────┬──────────┬─────┬─────┬──────┬──────┬───────┐
236
+ │Mailbox│Count│Total size│ Min│ Q1│Median│ Q3│ Max│
237
+ ├───────┼─────┼──────────┼─────┼─────┼──────┼──────┼───────┤
238
+ │Archive│ 0│ 0 kiB│ NA│ NA│ NA│ NA│ NA│
239
+ │Com │ 60│ 3,276 kiB│2 kiB│5 kiB│13 kiB│65 kiB│478 kiB│
240
+ │Total │ 60│ 3,276 kiB│2 kiB│5 kiB│13 kiB│65 kiB│478 kiB│
241
+ └───────┴─────┴──────────┴─────┴─────┴──────┴──────┴───────┘
242
+
243
+ #### Specific mailboxes and child mailboxes
244
+
245
+ Use the `-r`/`--recurse` flag:
246
+
247
+ $ bundle exec bin/imapcli -s yourserver.example.com -u myusername -P stats -r Archive Com
248
+ Enter password: ••••••••
249
+ server: yourserver.example.com
250
+ user: myusername
251
+ info: collecting stats for 58 folders
252
+ ┌──────────────────────────┬─────┬──────────┬──────┬───────┬───────┬───────┬─────────┐
253
+ │Mailbox │Count│Total size│ Min│ Q1│ Median│ Q3│ Max│
254
+ ├──────────────────────────┼─────┼──────────┼──────┼───────┼───────┼───────┼─────────┤
255
+ ...
256
+
257
+ #### Sorting the output
258
+
259
+ By default, mailboxes are sorted alphabetically. To sort by a specific statistic,
260
+ use an `-o`/`--sort` option:
261
+
262
+ * `-o count`
263
+ * `-o total_size`
264
+ * `-o min_size`
265
+ * `-o q1`
266
+ * `-o median_size`
267
+ * `-o q3`
268
+ * `-o max_size`
269
+
270
+ Example:
271
+
272
+ $ bundle exec bin/imapcli -s yourserver.example.com -u myusername -P stats -r -o max_size Archive
273
+
274
+ #### Obtaining comma-separated values (CSV)
275
+
276
+ Use the `--csv` flag.
162
277
 
163
278
 
164
279
  Alternative resources
@@ -194,10 +309,11 @@ following:
194
309
  State of the project
195
310
  --------------------
196
311
 
197
- Please consider this an alpha version. It does what I needed it for most (collect
198
- information about the folder sizes), but that's pretty much it. I'll be happy
199
- to take **pull request**. Please issue those against the **develop** branch as
200
- I like to follow *[a successful Git branching model](http://nvie.com/git-model)*.
312
+ While `imapcli` does what I need it to do, there are a lot of things that could
313
+ be improved. I'll be happy to take **pull request**. Please issue those against
314
+ the **develop** branch as I like to follow *[a successful Git branching
315
+ model](http://nvie.com/git-model)*.
316
+
201
317
 
202
318
  ### Versioning
203
319
 
@@ -205,8 +321,10 @@ This project is [semantically versioned](https://semver.org).
205
321
 
206
322
  ### To do
207
323
 
324
+ - More human-friendly number formatting (e.g., MiB/GiB as appropriate)
325
+ - Output to file
326
+ - Deal with server-specific mailbox separator characters (e.g. '.' vs. '/')
208
327
  - Man page
209
- - .deb installer
210
328
  - More commands?
211
329
 
212
330
 
@@ -224,4 +342,14 @@ License
224
342
 
225
343
  &copy; 2017 Daniel Kraus (bovender)
226
344
 
227
- Apache license.
345
+ Licensed under the Apache License, Version 2.0 (the "License");
346
+ you may not use this file except in compliance with the License.
347
+ You may obtain a copy of the License at
348
+
349
+ http://www.apache.org/licenses/LICENSE-2.0
350
+
351
+ Unless required by applicable law or agreed to in writing, software
352
+ distributed under the License is distributed on an "AS IS" BASIS,
353
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
354
+ See the License for the specific language governing permissions and
355
+ limitations under the License.
data/bin/imapcli CHANGED
@@ -11,6 +11,9 @@ end
11
11
  require 'dotenv'
12
12
  require 'tty-prompt'
13
13
  require 'tty-table'
14
+ require 'tty-progressbar'
15
+ require 'csv'
16
+ # require 'pry'
14
17
  # require 'pp'
15
18
 
16
19
  Dotenv.load
@@ -70,30 +73,60 @@ end
70
73
 
71
74
  desc 'Collects mailbox statistics'
72
75
  arg_name :mailbox, optional: false, multiple: true
73
- command :examine do |c|
76
+ command :stats do |c|
77
+ c.switch [:r, :recurse], desc: 'Recurse into sub mailboxes', negatable: false
78
+ c.switch [:R, :no_recurse], desc: 'Do not recurse into sub mailboxes', negatable: false
79
+ c.flag [:o, :sort], desc: 'Order', arg_name: 'property'
80
+ c.switch [:O, :reverse], desc: 'Reverse sort order (largest first)', negatable: false
81
+ c.switch [:csv], desc: 'Output comma-separated values (CSV)'
82
+
74
83
  c.action do |global_options,options,args|
75
- body = @command.stats(args)
84
+ raise unless @validator.stats_options_valid?(options, args)
85
+
86
+ progress_bar = nil
87
+ body = @command.stats(args, @validator.options) do |n|
88
+ if progress_bar
89
+ progress_bar.advance
90
+ else
91
+ @prompt.say "info: collecting stats for #{n} folders" if n > 1
92
+ progress_bar = TTY::ProgressBar.new(
93
+ "collecting stats... :current/:total (:percent, :eta remaining)",
94
+ total: n, clear: true)
95
+ end
96
+ end
97
+
76
98
  head = [ 'Mailbox', 'Count', 'Total size', 'Min', 'Q1', 'Median', 'Q3', 'Max' ]
77
- table = TTY::Table.new(head, body)
78
- @prompt.say table.render(:unicode, alignments: [:left] + Array.new(7, :right) )
79
- if body.any? { |line| line[0].start_with? Imapcli::Command.unknown_mailbox_prefix }
80
- @prompt.warn "#{Imapcli::Command.unknown_mailbox_prefix}unknown mailbox"
99
+ if options[:csv]
100
+ @prompt.warn 'notice: messages sizes in CSV output are in kiB (1024 bytes)'
101
+ @prompt.say head.to_csv
102
+ last_mailbox_line = body.length == 1 ? -1 : -2 # skip grand total if present
103
+ body[0..last_mailbox_line].each { |row| @prompt.say row.to_csv }
104
+ else
105
+ nice_body = body.map do |row|
106
+ row[0..1] + row[2..-1].map { |cell| format_kib(cell) }
107
+ end
108
+ table = TTY::Table.new(head, nice_body)
109
+ @prompt.say table.render(:unicode, alignments: [:left] + Array.new(7, :right) )
110
+ if body.any? { |line| line[0].start_with? Imapcli::Command.unknown_mailbox_prefix }
111
+ @prompt.warn "#{Imapcli::Command.unknown_mailbox_prefix}unknown mailbox"
112
+ end
81
113
  end
82
114
  end
83
115
  end
84
116
 
117
+ def format_kib(kib)
118
+ if kib
119
+ kib.to_s.reverse.gsub(/...(?=.)/,'\&,').reverse + ' kiB'.freeze
120
+ else
121
+ 'NA'
122
+ end
123
+ end
124
+
85
125
  pre do |global,command,options,args|
86
126
  @prompt = TTY::Prompt.new
127
+ @validator = Imapcli::OptionValidator.new()
128
+ raise unless @validator.global_options_valid?(global)
87
129
 
88
- if global[:s].nil? || global[:s].empty?
89
- raise 'missing server name (use -s option or set IMAP_SERVER environment variable)'
90
- end
91
- if global[:s].nil? || global[:s].empty?
92
- raise 'missing server name (use -s option or set IMAP_SERVER environment variable)'
93
- end
94
- if global[:P] && global[:p]
95
- raise '-p and -P options do not agree'
96
- end
97
130
  if global[:P]
98
131
  global[:p] = @prompt.mask 'Enter password:'
99
132
  end
@@ -123,9 +156,16 @@ end
123
156
 
124
157
  on_error do |exception|
125
158
  @client.logout if @client
126
- # Error logic here
127
- # return false to skip default error handling
128
- true
159
+ if @validator && @validator.errors.any?
160
+ @validator.errors.each { |error| @prompt.error error }
161
+ else
162
+ @prompt&.error "error: #{exception}"
163
+ end
164
+ @prompt.nil? # if we do not have a prompt yet, let GLI handle the exception
165
+ end
166
+
167
+ def print_warnings
168
+ @validator.warnings.each { |warning| @prompt.warn warning }
129
169
  end
130
170
 
131
171
  exit run(ARGV)