imap_processor 1.3 → 1.5
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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gemtest +0 -0
- data/History.rdoc +83 -0
- data/Manifest.txt +11 -2
- data/{README.txt → README.rdoc} +13 -6
- data/Rakefile +6 -3
- data/bin/imap_cleanse +5 -0
- data/bin/imap_flag +5 -0
- data/bin/imap_learn +5 -0
- data/bin/imap_mkdir +5 -0
- data/lib/imap_processor.rb +206 -150
- data/lib/imap_processor/archive.rb +58 -13
- data/lib/imap_processor/cleanse.rb +67 -0
- data/lib/imap_processor/client.rb +145 -0
- data/lib/imap_processor/flag.rb +121 -0
- data/lib/imap_processor/learn.rb +231 -0
- data/lib/imap_processor/mkdir.rb +25 -0
- data/test/test_imap_processor.rb +37 -0
- metadata +121 -72
- metadata.gz.sig +0 -0
- data/History.txt +0 -43
@@ -0,0 +1,231 @@
|
|
1
|
+
require 'imap_processor/client'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'rbayes'
|
8
|
+
rescue LoadError
|
9
|
+
# ignoring
|
10
|
+
class RBayes
|
11
|
+
def initialize *args
|
12
|
+
# nothing to do
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# IMAPLearn flags messages per-folder based on what you've flagged before.
|
19
|
+
#
|
20
|
+
# aka part three of my Plan for Total Email Domination.
|
21
|
+
|
22
|
+
class IMAPProcessor::Learn < IMAPProcessor::Client
|
23
|
+
|
24
|
+
##
|
25
|
+
# IMAP keyword for learned messages
|
26
|
+
|
27
|
+
LEARN_KEYWORD = 'IMAPLEARN_FLAGGED'
|
28
|
+
|
29
|
+
##
|
30
|
+
# IMAP keyword for tasty messages
|
31
|
+
|
32
|
+
TASTY_KEYWORD = LEARN_KEYWORD + '_TASTY'
|
33
|
+
|
34
|
+
##
|
35
|
+
# IMAP keyword for bland messages
|
36
|
+
|
37
|
+
BLAND_KEYWORD = LEARN_KEYWORD + '_BLAND'
|
38
|
+
|
39
|
+
##
|
40
|
+
# Handles processing of +args+.
|
41
|
+
|
42
|
+
def self.process_args(args)
|
43
|
+
@@options[:Threshold] = [0.85, 'Tastiness threshold not set']
|
44
|
+
|
45
|
+
super __FILE__, args, {} do |opts, options|
|
46
|
+
opts.on("-t", "--threshold THRESHOLD",
|
47
|
+
"Flag messages more tasty than THRESHOLD",
|
48
|
+
"Default: #{options[:Threshold].inspect}",
|
49
|
+
"Options file name: Threshold", Float) do |threshold|
|
50
|
+
options[:Threshold] = threshold
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Creates a new IMAPLearn from +options+.
|
57
|
+
#
|
58
|
+
# Options include:
|
59
|
+
# +:Threshold+:: Tastiness threshold for flagging
|
60
|
+
#
|
61
|
+
# and all options from IMAPClient
|
62
|
+
|
63
|
+
def initialize(options)
|
64
|
+
super
|
65
|
+
|
66
|
+
@db_root = File.join '~', '.imap_learn',
|
67
|
+
"#{options[:User]}@#{options[:Host]}:#{options[:Port]}"
|
68
|
+
@db_root = File.expand_path @db_root
|
69
|
+
|
70
|
+
@threshold = options[:Threshold]
|
71
|
+
|
72
|
+
@classifiers = Hash.new do |h,k|
|
73
|
+
filter_db = File.join @db_root, "#{k}.db"
|
74
|
+
FileUtils.mkdir_p File.dirname(filter_db)
|
75
|
+
h[k] = RBayes.new filter_db
|
76
|
+
end
|
77
|
+
|
78
|
+
@unlearned_flagged = []
|
79
|
+
@tasty_unflagged = []
|
80
|
+
@bland_flagged = []
|
81
|
+
@tasty_unlearned = []
|
82
|
+
@bland_unlearned = []
|
83
|
+
|
84
|
+
@noop = false
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# Flags tasty messages from all selected mailboxes.
|
89
|
+
|
90
|
+
def run
|
91
|
+
log "Flagging tasty messages"
|
92
|
+
|
93
|
+
message_count = 0
|
94
|
+
mailboxes = find_mailboxes
|
95
|
+
|
96
|
+
mailboxes.each do |mailbox|
|
97
|
+
@mailbox = mailbox
|
98
|
+
@imap.select @mailbox
|
99
|
+
log "Selected #{@mailbox}"
|
100
|
+
|
101
|
+
message_count += process_unlearned_flagged
|
102
|
+
message_count += process_tasty_unflagged
|
103
|
+
message_count += process_bland_flagged
|
104
|
+
message_count += process_unlearned
|
105
|
+
end
|
106
|
+
|
107
|
+
log "Done. Found #{message_count} messages in #{mailboxes.length} mailboxes"
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
##
|
113
|
+
# Returns an Array of tasty message sequence numbers.
|
114
|
+
|
115
|
+
def unlearned_flagged_in_curr
|
116
|
+
log "Finding unlearned, flagged messages"
|
117
|
+
|
118
|
+
@unlearned_flagged = @imap.search [
|
119
|
+
'FLAGGED',
|
120
|
+
'NOT', 'KEYWORD', LEARN_KEYWORD
|
121
|
+
]
|
122
|
+
|
123
|
+
update_db @unlearned_flagged, :add_tasty
|
124
|
+
|
125
|
+
@unlearned_flagged.length
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Returns an Array of message sequence numbers that should be marked as
|
130
|
+
# bland.
|
131
|
+
|
132
|
+
def tasty_unflagged_in_curr
|
133
|
+
log "Finding messages re-marked bland"
|
134
|
+
|
135
|
+
@bland_flagged = @imap.search [
|
136
|
+
'NOT', 'FLAGGED',
|
137
|
+
'KEYWORD', TASTY_KEYWORD
|
138
|
+
]
|
139
|
+
|
140
|
+
update_db @tasty_unflagged, :remove_tasty, :add_bland
|
141
|
+
|
142
|
+
@bland_flagged.length
|
143
|
+
end
|
144
|
+
|
145
|
+
##
|
146
|
+
# Returns an Array of tasty message sequence numbers that should be marked
|
147
|
+
# as tasty.
|
148
|
+
|
149
|
+
def bland_flagged_in_curr
|
150
|
+
log "Finding messages re-marked tasty"
|
151
|
+
@bland_flagged = @imap.search [
|
152
|
+
'FLAGGED',
|
153
|
+
'KEYWORD', BLAND_KEYWORD
|
154
|
+
]
|
155
|
+
|
156
|
+
update_db @bland_flagged, :remove_bland, :add_tasty
|
157
|
+
|
158
|
+
@bland_flagged.length
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# Returns two Arrays, one of tasty message sequence numbers and one of bland
|
163
|
+
# message sequence numbers.
|
164
|
+
|
165
|
+
def unlearned_in_curr
|
166
|
+
log "Learning new, unmarked messages"
|
167
|
+
unlearned = @imap.search [
|
168
|
+
'NOT', 'KEYWORD', LEARN_KEYWORD
|
169
|
+
]
|
170
|
+
|
171
|
+
tasty = []
|
172
|
+
bland = []
|
173
|
+
|
174
|
+
chunk unlearned do |messages|
|
175
|
+
bodies = @imap.fetch messages, 'RFC822'
|
176
|
+
bodies.each do |body|
|
177
|
+
text = body.attr['RFC822']
|
178
|
+
bucket = classify(text) ? tasty : bland
|
179
|
+
bucket << body.seqno
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
update_db tasty, :add_tasty
|
184
|
+
update_db bland, :add_bland
|
185
|
+
|
186
|
+
tasty.length + bland.length
|
187
|
+
end
|
188
|
+
|
189
|
+
def chunk(messages, size = 20)
|
190
|
+
messages = messages.dup
|
191
|
+
|
192
|
+
until messages.empty? do
|
193
|
+
chunk = messages.slice! 0, size
|
194
|
+
yield chunk
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
##
|
199
|
+
# Returns true if +text+ is "tasty"
|
200
|
+
|
201
|
+
def classify(text)
|
202
|
+
rating = @classifiers[@mailbox].rate text
|
203
|
+
rating > @threshold
|
204
|
+
end
|
205
|
+
|
206
|
+
def update_db(messages, *actions)
|
207
|
+
chunk messages do |chunk|
|
208
|
+
bodies = @imap.fetch chunk, 'RFC822'
|
209
|
+
bodies.each do |body|
|
210
|
+
text = body.attr['RFC822']
|
211
|
+
actions.each do |action|
|
212
|
+
@classifiers[@mailbox].update_db_with text, action
|
213
|
+
case action
|
214
|
+
when :add_bland then
|
215
|
+
@imap.store body.seqno, '+FLAG.SILENT',
|
216
|
+
[LEARN_KEYWORD, BLAND_KEYWORD]
|
217
|
+
when :add_tasty then
|
218
|
+
@imap.store body.seqno, '+FLAG.SILENT',
|
219
|
+
[:Flagged, LEARN_KEYWORD, TASTY_KEYWORD]
|
220
|
+
when :remove_bland then
|
221
|
+
@imap.store body.seqno, '-FLAG.SILENT', [BLAND_KEYWORD]
|
222
|
+
when :remove_tasty then
|
223
|
+
@imap.store body.seqno, '-FLAG.SILENT', [TASTY_KEYWORD]
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'imap_processor'
|
2
|
+
|
3
|
+
##
|
4
|
+
# Creates folders in IMAP.
|
5
|
+
|
6
|
+
class IMAPProcessor::Mkdir < IMAPProcessor
|
7
|
+
attr_reader :sep
|
8
|
+
|
9
|
+
def self.process_args(args)
|
10
|
+
super __FILE__, args
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(options)
|
14
|
+
super
|
15
|
+
|
16
|
+
@imap = connect.imap
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
ARGV.each do |mailbox|
|
21
|
+
create_mailbox mailbox
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
data/test/test_imap_processor.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'rubygems'
|
1
2
|
require 'minitest/autorun'
|
2
3
|
require 'imap_processor'
|
3
4
|
require 'time'
|
@@ -41,6 +42,8 @@ class TestIMAPProcessor < MiniTest::Unit::TestCase
|
|
41
42
|
@ip.instance_variable_set :@imap, @imap
|
42
43
|
|
43
44
|
@delim = @imap.list('', 'INBOX').first.delim
|
45
|
+
|
46
|
+
@NI = Net::IMAP
|
44
47
|
end
|
45
48
|
|
46
49
|
def teardown
|
@@ -60,6 +63,40 @@ class TestIMAPProcessor < MiniTest::Unit::TestCase
|
|
60
63
|
test.setup
|
61
64
|
test.teardown
|
62
65
|
|
66
|
+
def test_capability
|
67
|
+
res =
|
68
|
+
@NI::UntaggedResponse.new('OK',
|
69
|
+
@NI::ResponseText.new(
|
70
|
+
@NI::ResponseCode.new('CAPABILITY',
|
71
|
+
'IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE AUTH=PLAIN'),
|
72
|
+
'Dovecot ready.'),
|
73
|
+
"OK [CAPABAILITY ...] Dovecot ready.\r\n")
|
74
|
+
|
75
|
+
cap = @ip.capability @imap, res
|
76
|
+
|
77
|
+
assert_equal \
|
78
|
+
%w[IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE AUTH=PLAIN],
|
79
|
+
cap
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_capability_no_cap
|
83
|
+
res =
|
84
|
+
@NI::TaggedResponse.new('RUBY0001', 'OK',
|
85
|
+
@NI::ResponseText.new(nil,
|
86
|
+
'User logged in'),
|
87
|
+
"RUBY0001 OK User logged in\r\n")
|
88
|
+
|
89
|
+
cap = @ip.capability @imap, res
|
90
|
+
|
91
|
+
assert_includes cap, 'IMAP4REV1'
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_capability_no_res
|
95
|
+
cap = @ip.capability @imap
|
96
|
+
|
97
|
+
assert_includes cap, 'IMAP4REV1'
|
98
|
+
end
|
99
|
+
|
63
100
|
def test_create_mailbox
|
64
101
|
@imap.create "directory#{@delim}"
|
65
102
|
|
metadata
CHANGED
@@ -1,114 +1,163 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: imap_processor
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.5'
|
5
5
|
platform: ruby
|
6
|
-
authors:
|
6
|
+
authors:
|
7
7
|
- Eric Hodel
|
8
|
+
- Ryan Davis
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
+
cert_chain:
|
11
12
|
- |
|
12
13
|
-----BEGIN CERTIFICATE-----
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
14
|
+
MIIDPjCCAiagAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMRMwEQYDVQQDDApyeWFu
|
15
|
+
ZC1ydWJ5MRkwFwYKCZImiZPyLGQBGRYJemVuc3BpZGVyMRMwEQYKCZImiZPyLGQB
|
16
|
+
GRYDY29tMB4XDTEzMDkxNjIzMDQxMloXDTE0MDkxNjIzMDQxMlowRTETMBEGA1UE
|
17
|
+
AwwKcnlhbmQtcnVieTEZMBcGCgmSJomT8ixkARkWCXplbnNwaWRlcjETMBEGCgmS
|
18
|
+
JomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALda
|
19
|
+
b9DCgK+627gPJkB6XfjZ1itoOQvpqH1EXScSaba9/S2VF22VYQbXU1xQXL/WzCkx
|
20
|
+
taCPaLmfYIaFcHHCSY4hYDJijRQkLxPeB3xbOfzfLoBDbjvx5JxgJxUjmGa7xhcT
|
21
|
+
oOvjtt5P8+GSK9zLzxQP0gVLS/D0FmoE44XuDr3iQkVS2ujU5zZL84mMNqNB1znh
|
22
|
+
GiadM9GHRaDiaxuX0cIUBj19T01mVE2iymf9I6bEsiayK/n6QujtyCbTWsAS9Rqt
|
23
|
+
qhtV7HJxNKuPj/JFH0D2cswvzznE/a5FOYO68g+YCuFi5L8wZuuM8zzdwjrWHqSV
|
24
|
+
gBEfoTEGr7Zii72cx+sCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAw
|
25
|
+
HQYDVR0OBBYEFEfFe9md/r/tj/Wmwpy+MI8d9k/hMA0GCSqGSIb3DQEBBQUAA4IB
|
26
|
+
AQCFZ7JTzoy1gcG4d8A6dmOJy7ygtO5MFpRIz8HuKCF5566nOvpy7aHhDDzFmQuu
|
27
|
+
FX3zDU6ghx5cQIueDhf2SGOncyBmmJRRYawm3wI0o1MeN6LZJ/3cRaOTjSFy6+S6
|
28
|
+
zqDmHBp8fVA2TGJtO0BLNkbGVrBJjh0UPmSoGzWlRhEVnYC33TpDAbNA+u39UrQI
|
29
|
+
ynwhNN7YbnmSR7+JU2cUjBFv2iPBO+TGuWC+9L2zn3NHjuc6tnmSYipA9y8Hv+As
|
30
|
+
Y4evBVezr3SjXz08vPqRO5YRdO3zfeMT8gBjRqZjWJGMZ2lD4XNfrs7eky74CyZw
|
31
|
+
xx3n58i0lQkBE1EpKE0lFu/y
|
31
32
|
-----END CERTIFICATE-----
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
date: 2014-08-07 00:00:00.000000000 Z
|
34
|
+
dependencies:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: minitest
|
37
|
+
requirement: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '5.4'
|
42
|
+
type: :development
|
43
|
+
prerelease: false
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ~>
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '5.4'
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rdoc
|
51
|
+
requirement: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '4.0'
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ~>
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '4.0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
37
64
|
name: hoe
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3.12'
|
38
70
|
type: :development
|
39
|
-
|
40
|
-
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
requirements:
|
42
|
-
- -
|
43
|
-
- !ruby/object:Gem::Version
|
44
|
-
version:
|
45
|
-
version:
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '3.12'
|
46
77
|
description: |-
|
47
78
|
IMAPProcessor is a client for processing messages on an IMAP server. It
|
48
79
|
provides some basic mechanisms for connecting to an IMAP server, determining
|
49
80
|
capabilities and handling messages.
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
81
|
+
|
82
|
+
|
83
|
+
IMAPProcessor ships with several executables which can query and
|
84
|
+
manipulate IMAP mailboxes in several different ways:
|
85
|
+
|
86
|
+
imap_archive :: Archives old messages to a new dated mailbox.
|
87
|
+
imap_cleanse :: Delete messages older than a certain age in specified mailboxes.
|
88
|
+
imap_flag :: Flag messages to/from certain people.
|
89
|
+
imap_idle :: Shows new messages in a mailbox.
|
90
|
+
imap_keywords :: Queries an IMAP server for keywords set on messages
|
91
|
+
imap_learn :: Flags messages based on what you've flagged before.
|
92
|
+
imap_mkdir :: Ensures that certain mailboxes exist.
|
93
|
+
email:
|
56
94
|
- drbrain@segment7.net
|
57
|
-
|
95
|
+
- ryand-ruby@zenspider.com
|
96
|
+
executables:
|
58
97
|
- imap_archive
|
98
|
+
- imap_cleanse
|
99
|
+
- imap_flag
|
59
100
|
- imap_idle
|
60
101
|
- imap_keywords
|
102
|
+
- imap_learn
|
103
|
+
- imap_mkdir
|
61
104
|
extensions: []
|
62
|
-
|
63
|
-
|
64
|
-
- History.txt
|
105
|
+
extra_rdoc_files:
|
106
|
+
- History.rdoc
|
65
107
|
- Manifest.txt
|
66
|
-
- README.
|
67
|
-
files:
|
108
|
+
- README.rdoc
|
109
|
+
files:
|
68
110
|
- .autotest
|
69
|
-
-
|
111
|
+
- .gemtest
|
112
|
+
- History.rdoc
|
70
113
|
- Manifest.txt
|
71
|
-
- README.
|
114
|
+
- README.rdoc
|
72
115
|
- Rakefile
|
73
116
|
- bin/imap_archive
|
117
|
+
- bin/imap_cleanse
|
118
|
+
- bin/imap_flag
|
74
119
|
- bin/imap_idle
|
75
120
|
- bin/imap_keywords
|
121
|
+
- bin/imap_learn
|
122
|
+
- bin/imap_mkdir
|
76
123
|
- lib/imap_processor.rb
|
77
124
|
- lib/imap_processor/archive.rb
|
125
|
+
- lib/imap_processor/cleanse.rb
|
126
|
+
- lib/imap_processor/client.rb
|
127
|
+
- lib/imap_processor/flag.rb
|
78
128
|
- lib/imap_processor/idle.rb
|
79
129
|
- lib/imap_processor/keywords.rb
|
130
|
+
- lib/imap_processor/learn.rb
|
131
|
+
- lib/imap_processor/mkdir.rb
|
80
132
|
- lib/imap_sasl_plain.rb
|
81
133
|
- lib/net/imap/date.rb
|
82
134
|
- lib/net/imap/idle.rb
|
83
135
|
- test/test_imap_processor.rb
|
84
|
-
has_rdoc: true
|
85
136
|
homepage: http://seattlerb.rubyforge.org/imap_processor
|
86
|
-
licenses:
|
87
|
-
|
137
|
+
licenses:
|
138
|
+
- MIT
|
139
|
+
metadata: {}
|
88
140
|
post_install_message:
|
89
|
-
rdoc_options:
|
141
|
+
rdoc_options:
|
90
142
|
- --main
|
91
|
-
- README.
|
92
|
-
require_paths:
|
143
|
+
- README.rdoc
|
144
|
+
require_paths:
|
93
145
|
- lib
|
94
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
-
requirements:
|
96
|
-
- -
|
97
|
-
- !ruby/object:Gem::Version
|
98
|
-
version:
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
version: "0"
|
105
|
-
version:
|
146
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - '>='
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
152
|
+
requirements:
|
153
|
+
- - '>='
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: '0'
|
106
156
|
requirements: []
|
107
|
-
|
108
|
-
|
109
|
-
rubygems_version: 1.3.5
|
157
|
+
rubyforge_project:
|
158
|
+
rubygems_version: 2.2.1
|
110
159
|
signing_key:
|
111
|
-
specification_version:
|
160
|
+
specification_version: 4
|
112
161
|
summary: IMAPProcessor is a client for processing messages on an IMAP server
|
113
|
-
test_files:
|
162
|
+
test_files:
|
114
163
|
- test/test_imap_processor.rb
|