IMAPCleanse 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.DS_Store +0 -0
- data/CVS/Entries +6 -0
- data/CVS/Repository +1 -0
- data/CVS/Root +1 -0
- data/LICENSE +27 -0
- data/Manifest.txt +16 -0
- data/README +80 -0
- data/Rakefile +58 -0
- data/bin/CVS/Entries +2 -0
- data/bin/CVS/Repository +1 -0
- data/bin/CVS/Root +1 -0
- data/bin/imap_cleanse +6 -0
- data/lib/CVS/Entries +2 -0
- data/lib/CVS/Repository +1 -0
- data/lib/CVS/Root +1 -0
- data/lib/imap_cleanse.rb +347 -0
- metadata +61 -0
data/.DS_Store
ADDED
Binary file
|
data/CVS/Entries
ADDED
data/CVS/Repository
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby/imap_cleanse
|
data/CVS/Root
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
:ext:drbrain@ziz:/home/cvs/
|
data/LICENSE
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Copyright 2005 Eric Hodel. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
4
|
+
modification, are permitted provided that the following conditions
|
5
|
+
are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright
|
10
|
+
notice, this list of conditions and the following disclaimer in the
|
11
|
+
documentation and/or other materials provided with the distribution.
|
12
|
+
3. Neither the names of the authors nor the names of their contributors
|
13
|
+
may be used to endorse or promote products derived from this software
|
14
|
+
without specific prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
|
17
|
+
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
|
20
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
21
|
+
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
22
|
+
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
23
|
+
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
24
|
+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
25
|
+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
26
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
|
data/Manifest.txt
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
.DS_Store
|
2
|
+
CVS/Entries
|
3
|
+
CVS/Repository
|
4
|
+
CVS/Root
|
5
|
+
LICENSE
|
6
|
+
Manifest.txt
|
7
|
+
README
|
8
|
+
Rakefile
|
9
|
+
bin/CVS/Entries
|
10
|
+
bin/CVS/Repository
|
11
|
+
bin/CVS/Root
|
12
|
+
bin/imap_cleanse
|
13
|
+
lib/CVS/Entries
|
14
|
+
lib/CVS/Repository
|
15
|
+
lib/CVS/Root
|
16
|
+
lib/imap_cleanse.rb
|
data/README
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
= IMAPCleanse
|
2
|
+
|
3
|
+
Rubyforge Project:
|
4
|
+
|
5
|
+
http://rubyforge.org/projects/seattlerb/
|
6
|
+
|
7
|
+
Documentation:
|
8
|
+
|
9
|
+
http://seattlerb.rubyforge.org/IMAPCleanse/
|
10
|
+
|
11
|
+
== About
|
12
|
+
|
13
|
+
IMAPCleanse removes old, read, unflagged messages from your IMAP mailboxes.
|
14
|
+
|
15
|
+
== Why?
|
16
|
+
|
17
|
+
I'm lazy. I don't delete read messages from my mailboxes because I like to
|
18
|
+
have context when reading threads. Since I'm lazy my more-trafficed mailboxes
|
19
|
+
can end up with tens of thousands of read messages. Deleting this many
|
20
|
+
messages with Mail.app is time consuming and boring.
|
21
|
+
|
22
|
+
So I wrote IMAPCleanse to clean out my old mailboxes for me. If I want to keep
|
23
|
+
a message around for forever I'll just flag it and IMAPCleanse won't touch it.
|
24
|
+
|
25
|
+
== Installing IMAPCleanse
|
26
|
+
|
27
|
+
Just install the gem:
|
28
|
+
|
29
|
+
$ sudo gem install IMAPCleanse
|
30
|
+
|
31
|
+
== Using IMAPCleanse
|
32
|
+
|
33
|
+
In short:
|
34
|
+
|
35
|
+
imap_cleanse -H mail.example.com -p mypassword -b Lists/FreeBSD/current,Lists/Ruby -a 30
|
36
|
+
|
37
|
+
The help for IMAPCleanse should be sufficiently verbose, but here's a couple of
|
38
|
+
tips:
|
39
|
+
|
40
|
+
=== --noop and --verbose
|
41
|
+
|
42
|
+
The --noop flag tells IMAPCleanse not to delete anything. When combined with
|
43
|
+
the --verbose flag you can see how many messages IMAPCleanse would have deleted
|
44
|
+
from which mailboxes.
|
45
|
+
|
46
|
+
$ ruby -Ilib bin/imap_cleanse -nv
|
47
|
+
# Connected to mail.example.com:993
|
48
|
+
# Logged in as drbrain
|
49
|
+
# Cleansing read, unflagged messages older than 26-Feb-2006 17:04 PST
|
50
|
+
# Found 23 mailboxes to cleanse:
|
51
|
+
# mail/Lists/FreeBSD/current
|
52
|
+
[...]
|
53
|
+
# mail/Lists/Ruby/ZineBoard
|
54
|
+
# Selected mail/Lists/FreeBSD/current
|
55
|
+
# Scanning for messages
|
56
|
+
# Found 0 messages
|
57
|
+
[...]
|
58
|
+
# Selected mail/Lists/Ruby/ZineBoard
|
59
|
+
# Scanning for messages
|
60
|
+
# Found 0 messages
|
61
|
+
# Done. Found 0 messages in 23 mailboxes
|
62
|
+
|
63
|
+
(Since I just ran IMAPCleanse it didn't have anything to do.)
|
64
|
+
|
65
|
+
=== ~/.imap_cleanse
|
66
|
+
|
67
|
+
The ~/.imap_cleanse file can hold your password and other options so you don't
|
68
|
+
have to type them in on the command line every time. The format is simple,
|
69
|
+
just the options file name followed by '=' followed by the argument.
|
70
|
+
|
71
|
+
No whitespace is stripped from options, so be sure to do that yourself. Mine
|
72
|
+
looks something like this:
|
73
|
+
|
74
|
+
Host=mail.example.com
|
75
|
+
SSL=true
|
76
|
+
Username=drbrain
|
77
|
+
Boxes=Lists/FreeBSD/current,Lists/FreeBSD/performance,Lists/FreeBSD/Soekris,Lists/FreeBSD/stable,Lists/Ruby
|
78
|
+
Age=30
|
79
|
+
Password=my password
|
80
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
$VERBOSE = nil
|
8
|
+
|
9
|
+
spec = Gem::Specification.new do |s|
|
10
|
+
s.name = 'IMAPCleanse'
|
11
|
+
s.version = '1.0.0'
|
12
|
+
s.summary = 'Cleanses your IMAP mailboxes of oldness'
|
13
|
+
s.description = 'IMAPCleanse removes old, read, unflagged messages from your IMAP mailboxes so you don\'t have to!'
|
14
|
+
s.author = 'Eric Hodel'
|
15
|
+
s.email = 'drbrain@segment7.net'
|
16
|
+
|
17
|
+
s.has_rdoc = true
|
18
|
+
s.files = File.read('Manifest.txt').split($/)
|
19
|
+
s.require_path = 'lib'
|
20
|
+
s.executables = 'imap_cleanse'
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'Run tests'
|
24
|
+
task :default => [ :test ]
|
25
|
+
|
26
|
+
Rake::TestTask.new('test') do |t|
|
27
|
+
t.libs << 'test'
|
28
|
+
t.pattern = 'test/test_*.rb'
|
29
|
+
t.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'Update Manifest.txt'
|
33
|
+
task :update_manifest do
|
34
|
+
sh "find . -type f | sed -e 's%./%%' | egrep -v 'svn|swp|~' | egrep -v '^(doc|pkg)/' | sort > Manifest.txt"
|
35
|
+
end
|
36
|
+
|
37
|
+
desc 'Generate RDoc'
|
38
|
+
Rake::RDocTask.new :rdoc do |rd|
|
39
|
+
rd.rdoc_dir = 'doc'
|
40
|
+
rd.rdoc_files.add 'lib', 'README', 'LICENSE'
|
41
|
+
rd.main = 'README'
|
42
|
+
rd.options << '-d' if `which dot` =~ /\/dot/
|
43
|
+
rd.options << '-t IMAPCreate'
|
44
|
+
end
|
45
|
+
|
46
|
+
desc 'Build Gem'
|
47
|
+
Rake::GemPackageTask.new spec do |pkg|
|
48
|
+
pkg.need_tar = true
|
49
|
+
end
|
50
|
+
|
51
|
+
desc 'Clean up'
|
52
|
+
task :clean => [ :clobber_rdoc, :clobber_package ]
|
53
|
+
|
54
|
+
desc 'Clean up'
|
55
|
+
task :clobber => [ :clean ]
|
56
|
+
|
57
|
+
# vim: syntax=Ruby
|
58
|
+
|
data/bin/CVS/Entries
ADDED
data/bin/CVS/Repository
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby/imap_cleanse/bin
|
data/bin/CVS/Root
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
:ext:drbrain@ziz:/home/cvs/
|
data/bin/imap_cleanse
ADDED
data/lib/CVS/Entries
ADDED
data/lib/CVS/Repository
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby/imap_cleanse/lib
|
data/lib/CVS/Root
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
:ext:drbrain@ziz:/home/cvs/
|
data/lib/imap_cleanse.rb
ADDED
@@ -0,0 +1,347 @@
|
|
1
|
+
require 'net/imap'
|
2
|
+
require 'optparse'
|
3
|
+
require 'pp'
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
class Time
|
7
|
+
|
8
|
+
##
|
9
|
+
# Formats this Time as an IMAP-style date.
|
10
|
+
#
|
11
|
+
# RFC 2060 doesn't specify the format of its times. Unfortunately it is
|
12
|
+
# almost but not quite RFC 822 dates.
|
13
|
+
|
14
|
+
def imapdate
|
15
|
+
strftime '%d-%b-%Y %H:%M %Z'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# RFC 2595 PLAIN Authenticator for Net::IMAP. Only for use with SSL (but not
|
21
|
+
# enforced).
|
22
|
+
|
23
|
+
class Net::IMAP::PlainAuthenticator
|
24
|
+
|
25
|
+
##
|
26
|
+
# From RFC 2595 Section 6. PLAIN SASL Authentication
|
27
|
+
#
|
28
|
+
# The mechanism consists of a single message from the client to the
|
29
|
+
# server. The client sends the authorization identity (identity to
|
30
|
+
# login as), followed by a US-ASCII NUL character, followed by the
|
31
|
+
# authentication identity (identity whose password will be used),
|
32
|
+
# followed by a US-ASCII NUL character, followed by the clear-text
|
33
|
+
# password. The client may leave the authorization identity empty to
|
34
|
+
# indicate that it is the same as the authentication identity.
|
35
|
+
|
36
|
+
def process(data)
|
37
|
+
return [@user, @user, @password].join("\0")
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
##
|
43
|
+
# Creates a new PlainAuthenticator that will authenticate with +user+ and
|
44
|
+
# +password+.
|
45
|
+
|
46
|
+
def initialize(user, password)
|
47
|
+
@user = user
|
48
|
+
@password = password
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
if defined? OpenSSL then
|
54
|
+
Net::IMAP.add_authenticator 'PLAIN', Net::IMAP::PlainAuthenticator
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# IMAPCleanse removes old messages from your IMAP mailboxes so you don't have
|
59
|
+
# to!
|
60
|
+
|
61
|
+
class IMAPCleanse
|
62
|
+
|
63
|
+
##
|
64
|
+
# Handles processing of +args+.
|
65
|
+
|
66
|
+
def self.process_args(args)
|
67
|
+
opts_file = File.expand_path '~/.imap_cleanse'
|
68
|
+
|
69
|
+
unless File.stat(opts_file).mode & 077 == 0 then
|
70
|
+
STDERR.puts "WARNING! #{opts_file} is group/other readable or writable!"
|
71
|
+
STDERR.puts "WARNING! I'm not doing a thing until you fix it!"
|
72
|
+
exit 1
|
73
|
+
end
|
74
|
+
|
75
|
+
options = {}
|
76
|
+
|
77
|
+
File.readlines(opts_file).map { |l| l.chomp.split '=', 2 }.each do |k,v|
|
78
|
+
v = true if v == 'true'
|
79
|
+
v = false if v == 'false'
|
80
|
+
v = Integer(v) rescue v
|
81
|
+
options[k.intern] = v
|
82
|
+
end
|
83
|
+
|
84
|
+
options[:SSL] ||= true
|
85
|
+
options[:Username] ||= ENV['USER']
|
86
|
+
options[:Root] ||= 'mail'
|
87
|
+
options[:Noop] ||= false
|
88
|
+
options[:Verbose] ||= false
|
89
|
+
|
90
|
+
opts = OptionParser.new do |opts|
|
91
|
+
opts.banner = 'Usage: imap_cleanse [options]'
|
92
|
+
opts.separator ''
|
93
|
+
opts.separator 'Options may also be set in the options file ~/.imap_cleanse.'
|
94
|
+
opts.separator ''
|
95
|
+
opts.separator 'Example ~/.imap_cleanse:'
|
96
|
+
opts.separator "\tHost=mail.example.com"
|
97
|
+
opts.separator "\tPassword=my password"
|
98
|
+
|
99
|
+
opts.separator ''
|
100
|
+
opts.separator 'Connection options:'
|
101
|
+
|
102
|
+
opts.on("-H", "--host HOST",
|
103
|
+
"IMAP server host",
|
104
|
+
"Default: #{options[:Host].inspect}",
|
105
|
+
"Options file name: Host") do |host|
|
106
|
+
options[:Host] = host
|
107
|
+
end
|
108
|
+
|
109
|
+
opts.on("-P", "--port PORT",
|
110
|
+
"IMAP server port",
|
111
|
+
"Default: The correct port SSL/non-SSL mode",
|
112
|
+
"Options file name: Port") do |port|
|
113
|
+
options[:Port] = port
|
114
|
+
end
|
115
|
+
|
116
|
+
opts.on("-s", "--[no-]ssl",
|
117
|
+
"Use SSL for IMAP connection",
|
118
|
+
"Default: #{options[:SSL].inspect}",
|
119
|
+
"Options file name: SSL") do |ssl|
|
120
|
+
options[:SSL] = ssl
|
121
|
+
end
|
122
|
+
|
123
|
+
opts.separator ''
|
124
|
+
opts.separator 'Login options:'
|
125
|
+
|
126
|
+
opts.on("-u", "--username USERNAME",
|
127
|
+
"IMAP username",
|
128
|
+
"Default: #{options[:Username].inspect}",
|
129
|
+
"Options file name: Username") do |username|
|
130
|
+
options[:Username] = username
|
131
|
+
end
|
132
|
+
|
133
|
+
opts.on("-p", "--password PASSWORD",
|
134
|
+
"IMAP password",
|
135
|
+
"Default: Read from ~/.imap_cleanse",
|
136
|
+
"Options file name: Password") do |password|
|
137
|
+
options[:Password] = password
|
138
|
+
end
|
139
|
+
|
140
|
+
opts.separator ''
|
141
|
+
opts.separator 'Cleansing options:'
|
142
|
+
|
143
|
+
opts.on("-r", "--root ROOT",
|
144
|
+
"Root of mailbox hierarchy",
|
145
|
+
"Default: #{options[:Root].inspect}",
|
146
|
+
"Options file name: Root") do |root|
|
147
|
+
options[:Root] = root
|
148
|
+
end
|
149
|
+
|
150
|
+
opts.on("-b", "--boxes BOXES",
|
151
|
+
"Comma-separated list of mailbox name",
|
152
|
+
"prefixes to cleanse",
|
153
|
+
"Default: #{options[:Boxes].inspect}",
|
154
|
+
"Options file name: Boxes") do |boxes|
|
155
|
+
options[:Boxes] = boxes
|
156
|
+
end
|
157
|
+
|
158
|
+
opts.on("-a", "--age AGE",
|
159
|
+
"Delete messages more than AGE days old",
|
160
|
+
"Default: #{options[:Age].inspect}",
|
161
|
+
"Options file name: Age", Integer) do |age|
|
162
|
+
options[:Age] = age
|
163
|
+
end
|
164
|
+
|
165
|
+
opts.on("-n", "--noop",
|
166
|
+
"Perform no destructive operations",
|
167
|
+
"Best used with the verbose option",
|
168
|
+
"Default: #{options[:Noop].inspect}",
|
169
|
+
"Options file name: Noop") do |noop|
|
170
|
+
options[:Noop] = noop
|
171
|
+
end
|
172
|
+
|
173
|
+
opts.on("-v", "--[no-]verbose",
|
174
|
+
"Be verbose",
|
175
|
+
"Default: #{options[:Verbose].inspect}",
|
176
|
+
"Options file name: Verbose") do |verbose|
|
177
|
+
options[:Verbose] = verbose
|
178
|
+
end
|
179
|
+
|
180
|
+
opts.separator ''
|
181
|
+
|
182
|
+
opts.on("-h", "--help",
|
183
|
+
"You're looking at it") do
|
184
|
+
STDERR.puts opts
|
185
|
+
exit 1
|
186
|
+
end
|
187
|
+
|
188
|
+
opts.separator ''
|
189
|
+
end
|
190
|
+
|
191
|
+
opts.parse! args
|
192
|
+
|
193
|
+
options[:Port] ||= options[:SSL] ? 993 : 143
|
194
|
+
|
195
|
+
if options[:Host].nil? or
|
196
|
+
options[:Password].nil? or
|
197
|
+
options[:Boxes].nil? or
|
198
|
+
options[:Age].nil? then
|
199
|
+
STDERR.puts opts
|
200
|
+
STDERR.puts
|
201
|
+
STDERR.puts "Host name not set" if options[:Host].nil?
|
202
|
+
STDERR.puts "Password not set" if options[:Password].nil?
|
203
|
+
STDERR.puts "Boxes option not set" if options[:Boxes].nil?
|
204
|
+
STDERR.puts "Age option not set" if options[:Age].nil?
|
205
|
+
exit 1
|
206
|
+
end
|
207
|
+
|
208
|
+
return options
|
209
|
+
end
|
210
|
+
|
211
|
+
##
|
212
|
+
# Sets up IMAPCleanse options then cleanses mailboxes.
|
213
|
+
|
214
|
+
def self.run(args = ARGV)
|
215
|
+
options = process_args args
|
216
|
+
cleanser = new options
|
217
|
+
cleanser.cleanse
|
218
|
+
end
|
219
|
+
|
220
|
+
##
|
221
|
+
# Creates a new IMAPCleanse from +options+.
|
222
|
+
#
|
223
|
+
# Options include:
|
224
|
+
# +:Verbose+:: Verbose flag
|
225
|
+
# +:Noop+:: Don't delete anything flag
|
226
|
+
# +:Root+:: IMAP root path
|
227
|
+
# +:Boxes+:: Comma-separated list of mailbox prefixes to cleanse
|
228
|
+
# +:Age+:: Delete messages older than this many days ago
|
229
|
+
# +:Host+:: IMAP server
|
230
|
+
# +:Port+:: IMAP server port
|
231
|
+
# +:SSL+:: SSL flag
|
232
|
+
# +:Username+:: IMAP username
|
233
|
+
# +:Password+:: IMAP password
|
234
|
+
|
235
|
+
def initialize(options)
|
236
|
+
@verbose = options[:Verbose]
|
237
|
+
@noop = options[:Noop]
|
238
|
+
@root = options[:Root]
|
239
|
+
|
240
|
+
boxes = options[:Boxes].split(',').map { |b| Regexp.escape b }
|
241
|
+
@box_re = /^#{Regexp.escape @root}\/#{Regexp.union(*boxes)}/
|
242
|
+
|
243
|
+
@before_date = (Time.now - 86400 * options[:Age]).imapdate
|
244
|
+
|
245
|
+
connect options[:Host], options[:Port], options[:SSL],
|
246
|
+
options[:Username], options[:Password]
|
247
|
+
end
|
248
|
+
|
249
|
+
##
|
250
|
+
# Removes read, unflagged messages from all selected mailboxes...
|
251
|
+
#
|
252
|
+
# Unless :Noop was set, then it just prints out what it would do.
|
253
|
+
|
254
|
+
def cleanse
|
255
|
+
log "Cleansing read, unflagged messages older than #{@before_date}"
|
256
|
+
|
257
|
+
message_count = 0
|
258
|
+
mailboxes = find_mailboxes
|
259
|
+
|
260
|
+
mailboxes.each do |mailbox|
|
261
|
+
@imap.select mailbox
|
262
|
+
log "Selected #{mailbox}"
|
263
|
+
|
264
|
+
messages = old_messages_in_curr
|
265
|
+
next if messages.empty?
|
266
|
+
|
267
|
+
message_count += messages.length
|
268
|
+
|
269
|
+
if @noop then
|
270
|
+
log "Noop - nothing deleted"
|
271
|
+
next
|
272
|
+
end
|
273
|
+
|
274
|
+
purge messages
|
275
|
+
end
|
276
|
+
|
277
|
+
log "Done. Found #{message_count} messages in #{mailboxes.length} mailboxes"
|
278
|
+
end
|
279
|
+
|
280
|
+
private
|
281
|
+
|
282
|
+
##
|
283
|
+
# Connects to IMAP server +host+ at +port+ using ssl if +ssl+ is true then
|
284
|
+
# logs in as +username+ with +password+. IMAPCleanse will really only work
|
285
|
+
# with PLAIN auth on SSL sockets, sorry.
|
286
|
+
|
287
|
+
def connect(host, port, ssl, username, password)
|
288
|
+
@imap = Net::IMAP.new host, port, ssl
|
289
|
+
log "Connected to #{host}:#{port}"
|
290
|
+
@imap.authenticate 'PLAIN', username, password
|
291
|
+
log "Logged in as #{username}"
|
292
|
+
end
|
293
|
+
|
294
|
+
##
|
295
|
+
# Finds mailboxes with messages that were selected by the :Boxes option.
|
296
|
+
|
297
|
+
def find_mailboxes
|
298
|
+
mailboxes = @imap.list(@root, "*")
|
299
|
+
mailboxes.reject! { |mailbox| mailbox.attr.include? :Noselect }
|
300
|
+
mailboxes.map! { |mailbox| mailbox.name }
|
301
|
+
mailboxes.reject! { |mailbox| mailbox !~ @box_re }
|
302
|
+
mailboxes = mailboxes.sort_by { |m| m.downcase }
|
303
|
+
log "Found #{mailboxes.length} mailboxes to cleanse:"
|
304
|
+
mailboxes.each { |mailbox| log "\t#{mailbox}" } if @verbose
|
305
|
+
return mailboxes
|
306
|
+
end
|
307
|
+
|
308
|
+
##
|
309
|
+
# Logs +message+ to STDERR if :Verbose was selected.
|
310
|
+
|
311
|
+
def log(message)
|
312
|
+
return unless @verbose
|
313
|
+
STDERR.puts "# #{message}"
|
314
|
+
end
|
315
|
+
|
316
|
+
##
|
317
|
+
# Searches for read, unflagged messages older than :Age in the currently
|
318
|
+
# selected mailbox (see Net::IMAP#select).
|
319
|
+
|
320
|
+
def old_messages_in_curr
|
321
|
+
log "Scanning for messages"
|
322
|
+
messages = @imap.search [
|
323
|
+
'NOT', 'NEW',
|
324
|
+
'NOT', 'FLAGGED',
|
325
|
+
'BEFORE', @before_date
|
326
|
+
]
|
327
|
+
log "Found #{messages.length} messages"
|
328
|
+
return messages
|
329
|
+
end
|
330
|
+
|
331
|
+
##
|
332
|
+
# Marks +messages+ in the currently selected mailbox for deletion then
|
333
|
+
# expunges the mailbox (see Net::IMAP#store and Net::IMAP#expunge).
|
334
|
+
|
335
|
+
def purge(messages)
|
336
|
+
until messages.empty? do
|
337
|
+
chunk = messages.slice! 0, 500
|
338
|
+
@imap.store chunk, '+FLAGS', [:Deleted]
|
339
|
+
end
|
340
|
+
log "Marked messages for deletion"
|
341
|
+
|
342
|
+
@imap.expunge
|
343
|
+
log "Expunged deleted messages"
|
344
|
+
end
|
345
|
+
|
346
|
+
end
|
347
|
+
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11.6
|
3
|
+
specification_version: 1
|
4
|
+
name: IMAPCleanse
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2006-03-28 00:00:00 -08:00
|
8
|
+
summary: Cleanses your IMAP mailboxes of oldness
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: drbrain@segment7.net
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description: IMAPCleanse removes old, read, unflagged messages from your IMAP mailboxes so you don't have to!
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Eric Hodel
|
31
|
+
files:
|
32
|
+
- .DS_Store
|
33
|
+
- CVS/Entries
|
34
|
+
- CVS/Repository
|
35
|
+
- CVS/Root
|
36
|
+
- LICENSE
|
37
|
+
- Manifest.txt
|
38
|
+
- README
|
39
|
+
- Rakefile
|
40
|
+
- bin/CVS/Entries
|
41
|
+
- bin/CVS/Repository
|
42
|
+
- bin/CVS/Root
|
43
|
+
- bin/imap_cleanse
|
44
|
+
- lib/CVS/Entries
|
45
|
+
- lib/CVS/Repository
|
46
|
+
- lib/CVS/Root
|
47
|
+
- lib/imap_cleanse.rb
|
48
|
+
test_files: []
|
49
|
+
|
50
|
+
rdoc_options: []
|
51
|
+
|
52
|
+
extra_rdoc_files: []
|
53
|
+
|
54
|
+
executables:
|
55
|
+
- imap_cleanse
|
56
|
+
extensions: []
|
57
|
+
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
dependencies: []
|
61
|
+
|