imapcli 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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)