hermeneutics 1.11 → 1.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README +11 -0
- data/bin/hermesmail +93 -58
- data/lib/hermeneutics/addrs.rb +6 -4
- data/lib/hermeneutics/boxes.rb +134 -119
- data/lib/hermeneutics/cgi.rb +16 -6
- data/lib/hermeneutics/cli/imap/commands.rb +283 -0
- data/lib/hermeneutics/cli/imap/parser.rb +245 -0
- data/lib/hermeneutics/cli/imap/utf7imap.rb +75 -0
- data/lib/hermeneutics/cli/imap.rb +240 -0
- data/lib/hermeneutics/cli/openssl.rb +11 -0
- data/lib/hermeneutics/cli/pop3.rb +257 -0
- data/lib/hermeneutics/cli/protocol.rb +141 -0
- data/lib/hermeneutics/cli/smtp.rb +218 -0
- data/lib/hermeneutics/color.rb +8 -8
- data/lib/hermeneutics/contents.rb +6 -0
- data/lib/hermeneutics/css.rb +10 -10
- data/lib/hermeneutics/escape.rb +30 -34
- data/lib/hermeneutics/html.rb +4 -4
- data/lib/hermeneutics/mail.rb +248 -63
- data/lib/hermeneutics/message.rb +237 -254
- data/lib/hermeneutics/types.rb +8 -7
- data/lib/hermeneutics/version.rb +3 -4
- metadata +26 -5
- data/lib/hermeneutics/cli/pop.rb +0 -102
- data/lib/hermeneutics/transports.rb +0 -230
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d06afea9e09641e4c0c05bc3fca3590c3b4002047092034a379ab9a096867a57
|
4
|
+
data.tar.gz: 21944a76c2279a66b7de8ea9d32ad6db9328898c7ff944a2b736e0c3500dd61c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 399dd807c48582880089a94580b1c939ad57fc5da148b9987dff1f77729e731b62863f2f44a8a7540aefc4edc9dd211ab8dfe5a759d654ab6f9de682c968f9e7
|
7
|
+
data.tar.gz: 61514f34f392828df42f4123e49c6d7af7aecaf0dd3a503241ee60d5ee811e5e8fecb957cebee7bca4a407afab656ce96922f5ebf7d6c683e584acc3c56bf70f
|
data/README
ADDED
data/bin/hermesmail
CHANGED
@@ -11,8 +11,7 @@ rescue LoadError
|
|
11
11
|
end
|
12
12
|
|
13
13
|
require "hermeneutics/version"
|
14
|
-
require "hermeneutics/
|
15
|
-
require "hermeneutics/cli/pop"
|
14
|
+
require "hermeneutics/mail"
|
16
15
|
|
17
16
|
|
18
17
|
module Hermeneutics
|
@@ -38,7 +37,7 @@ module Hermeneutics
|
|
38
37
|
|
39
38
|
# Forward by SMTP
|
40
39
|
def forward_smtp to
|
41
|
-
send nil, to
|
40
|
+
send! nil, to
|
42
41
|
done
|
43
42
|
end
|
44
43
|
|
@@ -50,45 +49,26 @@ module Hermeneutics
|
|
50
49
|
alias forward forward_smtp
|
51
50
|
|
52
51
|
|
53
|
-
self.logfile = "hermesmail.log"
|
54
|
-
self.loglevel = :ERR
|
55
|
-
|
56
52
|
@failed_process = "=failed-process"
|
53
|
+
@failed_parse = "=failed-parse"
|
57
54
|
|
58
55
|
class <<self
|
59
|
-
attr_accessor :failed_process
|
56
|
+
attr_accessor :failed_process, :failed_parse
|
60
57
|
def process input, debug = false
|
61
58
|
i = parse input
|
62
59
|
i.debug = debug
|
63
60
|
i.execute
|
64
61
|
rescue
|
65
62
|
raise if debug
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
63
|
+
log_exception "Error while parsing mail"
|
64
|
+
b = box @failed_parse
|
65
|
+
log :INF, "Saving to", b.path
|
66
|
+
b.store_raw input, nil, nil
|
70
67
|
end
|
71
68
|
def log_exception msg, *args
|
72
69
|
log :ERR, "#{msg}: #$! (#{$!.class})", *args
|
73
70
|
$!.backtrace.each { |b| log :INF, " #{b}" }
|
74
71
|
end
|
75
|
-
private
|
76
|
-
def open_failed
|
77
|
-
i = 0
|
78
|
-
d = expand_sysdir
|
79
|
-
w = Time.now.strftime "%Y%m%d%H%M%S"
|
80
|
-
begin
|
81
|
-
p = File.join d, "failed-#{w}-%05d" % i
|
82
|
-
File.open p, File::CREAT|File::EXCL|File::WRONLY do |f|
|
83
|
-
yield f
|
84
|
-
end
|
85
|
-
rescue Errno::ENOENT
|
86
|
-
Dir.mkdir! d and retry
|
87
|
-
rescue Errno::EEXIST
|
88
|
-
i +=1
|
89
|
-
retry
|
90
|
-
end
|
91
|
-
end
|
92
72
|
end
|
93
73
|
|
94
74
|
def execute
|
@@ -98,12 +78,12 @@ module Hermeneutics
|
|
98
78
|
rescue
|
99
79
|
raise if @debug
|
100
80
|
log_exception "Error while processing mail"
|
101
|
-
b =
|
81
|
+
b = self.class.box self.class.failed_process
|
102
82
|
save b
|
103
83
|
end
|
104
84
|
|
105
85
|
def log_exception msg, *args
|
106
|
-
|
86
|
+
self.class.log_exception msg, *args
|
107
87
|
end
|
108
88
|
|
109
89
|
end
|
@@ -112,44 +92,99 @@ module Hermeneutics
|
|
112
92
|
class Fetch
|
113
93
|
|
114
94
|
class <<self
|
95
|
+
|
115
96
|
private :new
|
116
97
|
def create *args, &block
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
98
|
+
@list = []
|
99
|
+
class_eval *args, &block
|
100
|
+
new @list
|
101
|
+
ensure
|
102
|
+
@list = nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def pop *args, **kwargs
|
106
|
+
access Pop, *args, **kwargs do yield end
|
107
|
+
end
|
108
|
+
def login *args
|
109
|
+
@access[ :logins].push args
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
def access type, *args, **kwargs
|
115
|
+
@access and raise "Access methods must not be nested."
|
116
|
+
@access = { type: type, args: args, kwargs: kwargs, logins: [] }
|
117
|
+
yield
|
118
|
+
@list.push @access
|
119
|
+
nil
|
120
|
+
ensure
|
121
|
+
@access = nil
|
128
122
|
end
|
129
|
-
end
|
130
123
|
|
131
|
-
def initialize
|
132
|
-
@list = []
|
133
124
|
end
|
134
125
|
|
135
|
-
def
|
136
|
-
|
126
|
+
def initialize list
|
127
|
+
@list = list
|
128
|
+
end
|
137
129
|
|
138
|
-
def
|
139
|
-
@
|
140
|
-
|
130
|
+
def each
|
131
|
+
@list.each { |a|
|
132
|
+
c = a[ :type].new *a[ :args], **a[ :kwargs]
|
133
|
+
a[ :logins].each { |l|
|
134
|
+
c.login *l do yield c end
|
135
|
+
}
|
136
|
+
}
|
141
137
|
end
|
142
138
|
|
139
|
+
class Keep < Exception ; end
|
140
|
+
|
143
141
|
private
|
144
142
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
143
|
+
|
144
|
+
class Pop
|
145
|
+
|
146
|
+
def initialize host, port = nil, ssl: nil
|
147
|
+
if not port and host =~ /:(\d+)\z/ then
|
148
|
+
host, port = $`, $1.to_i
|
149
|
+
end
|
150
|
+
@host, @port, @ssl = host, port, ssl
|
151
|
+
end
|
152
|
+
|
153
|
+
def login user, password
|
154
|
+
require "hermeneutics/cli/pop3"
|
155
|
+
Cli::POP3.open @host, @port, ssl: @ssl do |pop|
|
156
|
+
@user, @password, @pop = user, password, pop
|
157
|
+
@pop.authenticate @user, @password
|
158
|
+
yield
|
159
|
+
@pop.quit
|
160
|
+
end
|
161
|
+
ensure
|
162
|
+
@user, @password, @pop = nil, nil, nil
|
163
|
+
end
|
164
|
+
|
165
|
+
def name
|
166
|
+
@user or raise "Not logged in."
|
167
|
+
r = "#@user@#@host"
|
168
|
+
r << ":#@port" if @port
|
169
|
+
r
|
170
|
+
end
|
171
|
+
|
172
|
+
def count
|
173
|
+
c, = @pop.stat
|
174
|
+
c
|
175
|
+
end
|
176
|
+
|
177
|
+
def each
|
178
|
+
@pop.list.each { |k,|
|
179
|
+
text = @pop.retr k
|
180
|
+
begin
|
181
|
+
yield text
|
182
|
+
@pop.dele k
|
183
|
+
rescue Keep
|
184
|
+
end
|
185
|
+
}
|
186
|
+
end
|
187
|
+
|
153
188
|
end
|
154
189
|
|
155
190
|
end
|
@@ -231,7 +266,7 @@ module Hermeneutics
|
|
231
266
|
print "\r#{i}/#{c} " if @quiet < 1
|
232
267
|
i += 1
|
233
268
|
Processed.process m
|
234
|
-
raise
|
269
|
+
raise Fetch::Keep if @keep
|
235
270
|
}
|
236
271
|
puts "\rDone. " if @quiet < 1
|
237
272
|
}
|
data/lib/hermeneutics/addrs.rb
CHANGED
@@ -95,8 +95,6 @@ module Hermeneutics
|
|
95
95
|
|
96
96
|
end
|
97
97
|
|
98
|
-
attr_reader :mail, :real
|
99
|
-
|
100
98
|
def initialize mail, real
|
101
99
|
@mail, @real = mail, real
|
102
100
|
@mail.compact!
|
@@ -138,6 +136,8 @@ module Hermeneutics
|
|
138
136
|
tokenized.encode
|
139
137
|
end
|
140
138
|
|
139
|
+
private
|
140
|
+
|
141
141
|
def tokenized
|
142
142
|
r = Token[ :addr, [ Token[ :lang] , @mail, Token[ :rang]]]
|
143
143
|
if @real then
|
@@ -146,8 +146,6 @@ module Hermeneutics
|
|
146
146
|
r
|
147
147
|
end
|
148
148
|
|
149
|
-
private
|
150
|
-
|
151
149
|
def mk_plain
|
152
150
|
p = @mail.to_s
|
153
151
|
p.downcase!
|
@@ -592,6 +590,9 @@ module Hermeneutics
|
|
592
590
|
|
593
591
|
public
|
594
592
|
|
593
|
+
def empty? ; @list.empty? ; end
|
594
|
+
def notempty? ; self if @list.notempty? ; end
|
595
|
+
|
595
596
|
def push addrs
|
596
597
|
case addrs
|
597
598
|
when nil then
|
@@ -600,6 +601,7 @@ module Hermeneutics
|
|
600
601
|
else addrs.each { |a| push a }
|
601
602
|
end
|
602
603
|
end
|
604
|
+
alias << push
|
603
605
|
|
604
606
|
def inspect
|
605
607
|
"<#{self.class}: " + (@list.map { |a| a.inspect }.join ", ") + ">"
|
data/lib/hermeneutics/boxes.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
=begin rdoc
|
6
6
|
|
7
|
-
:section: Classes
|
7
|
+
:section: Classes defined here
|
8
8
|
|
9
9
|
Hermeneutics::Box is a general Mailbox.
|
10
10
|
|
@@ -18,7 +18,6 @@ Hermeneutics::Maildir is the maildir format.
|
|
18
18
|
|
19
19
|
|
20
20
|
require "supplement"
|
21
|
-
require "supplement/locked"
|
22
21
|
require "date"
|
23
22
|
|
24
23
|
|
@@ -31,15 +30,18 @@ module Hermeneutics
|
|
31
30
|
|
32
31
|
class <<self
|
33
32
|
|
33
|
+
attr_accessor :default_format
|
34
|
+
|
34
35
|
# :call-seq:
|
35
36
|
# Box.find( path, default = nil) -> box
|
36
37
|
#
|
37
38
|
# Create a Box object (some subclass of Box), depending on
|
38
|
-
# what type the box is found at
|
39
|
+
# what type the box is found at +path+.
|
39
40
|
#
|
40
41
|
def find path, default_format = nil
|
41
42
|
b = @boxes.find { |b| b.check path }
|
42
43
|
b ||= default_format
|
44
|
+
b ||= @default_format
|
43
45
|
b ||= if File.directory? path then
|
44
46
|
Maildir
|
45
47
|
elsif File.file? path then
|
@@ -71,7 +73,7 @@ module Hermeneutics
|
|
71
73
|
# :call-seq:
|
72
74
|
# Box.new( path) -> box
|
73
75
|
#
|
74
|
-
# Instantiate a Box object, just store the
|
76
|
+
# Instantiate a Box object, just store the +path+.
|
75
77
|
#
|
76
78
|
def initialize mailbox
|
77
79
|
@mailbox = mailbox
|
@@ -84,12 +86,39 @@ module Hermeneutics
|
|
84
86
|
# :call-seq:
|
85
87
|
# box.exists? -> true or false
|
86
88
|
#
|
87
|
-
# Test whether the
|
89
|
+
# Test whether the +Box+ exists.
|
88
90
|
#
|
89
91
|
def exists?
|
90
92
|
self.class.check @mailbox
|
91
93
|
end
|
92
94
|
|
95
|
+
# :call-seq:
|
96
|
+
# mbox.store( msg) -> nil
|
97
|
+
#
|
98
|
+
# Store the mail to the local +MBox+.
|
99
|
+
#
|
100
|
+
def store msg
|
101
|
+
store_raw msg.to_s, msg.plain_from, msg.created
|
102
|
+
end
|
103
|
+
|
104
|
+
# :call-seq:
|
105
|
+
# mbox.each { |mail| ... } -> nil
|
106
|
+
#
|
107
|
+
# Iterate through +MBox+.
|
108
|
+
# Alias for +MBox#each_mail+.
|
109
|
+
#
|
110
|
+
def each &block ; each_mail &block ; end
|
111
|
+
include Enumerable
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def local_from
|
116
|
+
require "etc"
|
117
|
+
require "socket"
|
118
|
+
s = File.stat @mailbox
|
119
|
+
lfrom = "#{(Etc.getpwuid s.uid).name}@#{Socket.gethostname}"
|
120
|
+
end
|
121
|
+
|
93
122
|
end
|
94
123
|
|
95
124
|
class MBox < Box
|
@@ -102,7 +131,7 @@ module Hermeneutics
|
|
102
131
|
# :call-seq:
|
103
132
|
# MBox.check( path) -> true or false
|
104
133
|
#
|
105
|
-
# Check whether path is a
|
134
|
+
# Check whether path is a +MBox+.
|
106
135
|
#
|
107
136
|
def check path
|
108
137
|
if File.file? path then
|
@@ -114,48 +143,10 @@ module Hermeneutics
|
|
114
143
|
|
115
144
|
end
|
116
145
|
|
117
|
-
# :stopdoc:
|
118
|
-
class Region
|
119
|
-
class <<self
|
120
|
-
private :new
|
121
|
-
def open file, start, stop
|
122
|
-
t = file.tell
|
123
|
-
begin
|
124
|
-
i = new file, start, stop
|
125
|
-
yield i
|
126
|
-
ensure
|
127
|
-
file.seek t
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
def initialize file, start, stop
|
132
|
-
@file, @start, @stop = file, start, stop
|
133
|
-
rewind
|
134
|
-
end
|
135
|
-
def rewind ; @file.seek @start ; end
|
136
|
-
def read n = nil
|
137
|
-
m = @stop - @file.tell
|
138
|
-
n = m if not n or n > m
|
139
|
-
@file.read n
|
140
|
-
end
|
141
|
-
def to_s
|
142
|
-
rewind
|
143
|
-
read
|
144
|
-
end
|
145
|
-
def each_line
|
146
|
-
@file.each_line { |l|
|
147
|
-
break if @file.tell > @stop
|
148
|
-
yield l
|
149
|
-
}
|
150
|
-
end
|
151
|
-
alias eat_lines each_line
|
152
|
-
end
|
153
|
-
# :startdoc:
|
154
|
-
|
155
146
|
# :call-seq:
|
156
147
|
# mbox.create -> self
|
157
148
|
#
|
158
|
-
# Create the
|
149
|
+
# Create the +MBox+.
|
159
150
|
#
|
160
151
|
def create
|
161
152
|
d = File.dirname @mailbox
|
@@ -165,65 +156,69 @@ module Hermeneutics
|
|
165
156
|
end
|
166
157
|
|
167
158
|
# :call-seq:
|
168
|
-
# mbox.
|
159
|
+
# mbox.store_raw( text, from, created) -> nil
|
169
160
|
#
|
170
|
-
# Store
|
161
|
+
# Store some text that appears like a mail to the local +MBox+.
|
171
162
|
#
|
172
|
-
def
|
173
|
-
|
174
|
-
|
163
|
+
def store_raw text, from, created
|
164
|
+
from ||= local_from
|
165
|
+
created ||= Time.now
|
166
|
+
File.open @mailbox, "r+", encoding: Encoding::ASCII_8BIT do |f|
|
175
167
|
f.seek [ f.size - 4, 0].max
|
176
|
-
last =
|
168
|
+
last = nil
|
177
169
|
f.read.each_line { |l| last = l }
|
178
|
-
f.puts
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
170
|
+
f.puts if last and not last =~ RE_N
|
171
|
+
|
172
|
+
f.puts "From #{from.gsub ' ', '_'} #{created.to_time.gmtime.asctime}"
|
173
|
+
text.each_line { |l|
|
174
|
+
l.chomp!
|
175
|
+
f.print ">" if l =~ RE_F
|
176
|
+
f.puts l
|
177
|
+
}
|
184
178
|
f.puts
|
185
179
|
end
|
186
|
-
|
180
|
+
nil
|
187
181
|
end
|
188
182
|
|
189
183
|
# :call-seq:
|
190
|
-
# mbox.
|
184
|
+
# mbox.each_mail { |mail| ... } -> nil
|
191
185
|
#
|
192
|
-
# Iterate through
|
186
|
+
# Iterate through +MBox+.
|
193
187
|
#
|
194
|
-
def
|
188
|
+
def each_mail
|
195
189
|
File.open @mailbox, encoding: Encoding::ASCII_8BIT do |f|
|
196
|
-
|
197
|
-
|
190
|
+
nl_seen = false
|
191
|
+
from, created, text = nil, nil, nil
|
198
192
|
f.each_line { |l|
|
199
|
-
|
200
|
-
if
|
193
|
+
l.chomp!
|
194
|
+
if l =~ RE_F then
|
195
|
+
l = $'
|
196
|
+
yield text, from, created if text
|
197
|
+
length_tried = false
|
198
|
+
from, created = l.split nil, 2
|
201
199
|
begin
|
202
|
-
|
203
|
-
|
204
|
-
|
200
|
+
created = DateTime.parse created
|
201
|
+
rescue Date::Error
|
202
|
+
unless length_tried then
|
203
|
+
from = $'
|
204
|
+
created = from.slice! from.length-Time.now.ctime.length, from.length
|
205
|
+
from.strip!
|
206
|
+
length_tried = true
|
207
|
+
retry
|
208
|
+
end
|
209
|
+
raise "#@mailbox does not seem to be a mailbox: From line '#{l}'."
|
205
210
|
end
|
211
|
+
text, nl_seen = "", false
|
206
212
|
else
|
207
|
-
|
208
|
-
|
213
|
+
from or raise "#@mailbox does not seem to be a mailbox. No 'From' line."
|
214
|
+
text << "\n" if nl_seen
|
215
|
+
nl_seen = l =~ RE_N
|
216
|
+
nl_seen or text << l << "\n"
|
209
217
|
end
|
210
218
|
}
|
211
|
-
|
212
|
-
e ||= f.tell
|
213
|
-
m and Region.open f, m, e, &block
|
219
|
+
text and yield text, from, created
|
214
220
|
end
|
215
221
|
end
|
216
|
-
include Enumerable
|
217
|
-
|
218
|
-
private
|
219
|
-
|
220
|
-
def is_from_line? l
|
221
|
-
l =~ RE_F or return
|
222
|
-
addr, time = $'.split nil, 2
|
223
|
-
DateTime.parse time
|
224
|
-
addr =~ /@/
|
225
|
-
rescue ArgumentError, TypeError
|
226
|
-
end
|
227
222
|
|
228
223
|
end
|
229
224
|
|
@@ -237,7 +232,7 @@ module Hermeneutics
|
|
237
232
|
# :call-seq:
|
238
233
|
# Maildir.check( path) -> true or false
|
239
234
|
#
|
240
|
-
# Check whether path is a
|
235
|
+
# Check whether path is a +Maildir+.
|
241
236
|
#
|
242
237
|
def check mailbox
|
243
238
|
if File.directory? mailbox then
|
@@ -254,7 +249,7 @@ module Hermeneutics
|
|
254
249
|
# :call-seq:
|
255
250
|
# maildir.create -> self
|
256
251
|
#
|
257
|
-
# Create the
|
252
|
+
# Create the +Maildir+.
|
258
253
|
#
|
259
254
|
def create
|
260
255
|
Dir.mkdir! @mailbox
|
@@ -266,53 +261,73 @@ module Hermeneutics
|
|
266
261
|
end
|
267
262
|
|
268
263
|
# :call-seq:
|
269
|
-
# maildir.
|
264
|
+
# maildir.store_raw( text, from, created) -> nil
|
270
265
|
#
|
271
|
-
# Store
|
266
|
+
# Store some text that appears like a mail to the local +MBox+.
|
272
267
|
#
|
273
|
-
def
|
274
|
-
|
275
|
-
File.
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
268
|
+
def store_raw text, from, created
|
269
|
+
filename = mkfilename from, created
|
270
|
+
tpath = File.join @mailbox, TMP, filename
|
271
|
+
File.open tpath, File::CREAT|File::EXCL|File::WRONLY do |f| f.puts text end
|
272
|
+
cpath = File.join @mailbox, NEW, filename
|
273
|
+
File.link tpath, cpath
|
274
|
+
filename
|
275
|
+
rescue Errno::EEXIST
|
276
|
+
File.unlink tpath rescue nil
|
277
|
+
retry
|
278
|
+
ensure
|
279
|
+
File.unlink tpath
|
280
|
+
end
|
281
|
+
|
282
|
+
# :call-seq:
|
283
|
+
# mbox.each_file { |filename| ... } -> nil
|
284
|
+
#
|
285
|
+
# Iterate through +Maildir+.
|
286
|
+
#
|
287
|
+
def each_file new = nil
|
288
|
+
p = File.join @mailbox, new ? NEW : CUR
|
289
|
+
(Dir.new p).sort.each { |fn|
|
290
|
+
next if fn.starts_with? "."
|
291
|
+
path = File.join p, fn
|
292
|
+
yield path
|
293
|
+
}
|
281
294
|
end
|
282
295
|
|
283
296
|
# :call-seq:
|
284
297
|
# mbox.each { |mail| ... } -> nil
|
285
298
|
#
|
286
|
-
# Iterate through
|
299
|
+
# Iterate through +Maildir+.
|
287
300
|
#
|
288
|
-
def
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
301
|
+
def each_mail new = nil
|
302
|
+
lfrom = local_from
|
303
|
+
each_file new do |fn|
|
304
|
+
created = Time.at fn[ /\A(\d+)/, 1].to_i + fn[ /M(\d+)/, 1].to_i*0.000001
|
305
|
+
File.open fn, encoding: Encoding::ASCII_8BIT do |f|
|
306
|
+
from_host = fn[ /\.([.a-z0-9_+-]+)/, 1]
|
307
|
+
text = f.read
|
308
|
+
from = text[ /[a-z0-9.+-]+@#{Regexp.quote from_host}/]
|
309
|
+
yield text, from||lfrom, created
|
295
310
|
end
|
296
|
-
|
311
|
+
end
|
297
312
|
end
|
298
|
-
include Enumerable
|
299
313
|
|
300
314
|
private
|
301
315
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
c += 1
|
314
|
-
retry
|
316
|
+
@seq = 0
|
317
|
+
class <<self
|
318
|
+
def seq! ; @seq += 1 ; end
|
319
|
+
end
|
320
|
+
|
321
|
+
def mkfilename from, created
|
322
|
+
host = if from =~ /@/ then
|
323
|
+
$'
|
324
|
+
else
|
325
|
+
require "socket"
|
326
|
+
Socket.gethostname
|
315
327
|
end
|
328
|
+
created ||= Time.now
|
329
|
+
created = created.to_time
|
330
|
+
"#{created.to_i}M#{created.usec}P#$$Q#{self.class.seq!}.#{host}"
|
316
331
|
end
|
317
332
|
|
318
333
|
end
|