hermeneutics 1.21 → 1.23

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
  SHA256:
3
- metadata.gz: 26e095f585149d4c8a07af7a415cfcc003a3958cc45f4611490b3a018f19b94b
4
- data.tar.gz: 20e963ec38f9c4dbace27a15c6c39097ab6bbf6a52528a2b5d4e40aaba15c193
3
+ metadata.gz: 81d01a3292ca2c19c8a0a7f285262c44584bb7d91d658dc5650774f9828bcd92
4
+ data.tar.gz: 92bf5d6e7c81f27da58666bba8e5df0716bafcefef2daec6b0dca1f716f2b20d
5
5
  SHA512:
6
- metadata.gz: 760bea637b51c7852ee0b6678af340f60e98fcab925f3376ff5e7ff147106a3d4532b1e7f8e3a3d0eada210826fa26467adb50c99a4c81978bdb08b795b819bf
7
- data.tar.gz: 1e34626ab27cb6210a20d57f0e30bab31475b8d4040406fcab0636ca97f5a69c4edce39c8f3e9ceee5ddeb425b7e32816680c3c0f9fb6a2149a1a8181e5a0856
6
+ metadata.gz: b97a17139583cd4955b413e09affd7349544d36ff0228d9c4238879567e9ed83c922f5f0d2a5cb41009afc7ebe94330ff7187d8d75c0452dc7e17b5e3bb23757
7
+ data.tar.gz: 198822fd194ff176303b2d05ab599d662458e6e9100ee0d1c711ce819ddb7da324c6b86377a148fce0ff0a1e16492e8947eed8e894d88512a73fef9d2cf120b4
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  = Hermeneutics -- Ruby mail and CGI handling
2
2
 
3
- Copyright (c) 2011-2013, Bertram Scharpf <software@bertram-scharpf.de>.
3
+ Copyright (c) 2011-2024, Bertram Scharpf <software@bertram-scharpf.de>.
4
4
  All rights reserved.
5
5
 
6
6
  Redistribution and use in source and binary forms, with or without
@@ -16,7 +16,6 @@ module Hermeneutics
16
16
 
17
17
  PORT, PORT_SSL = 143, 993
18
18
 
19
- class Error < StandardError ; end
20
19
  class UnspecResponse < Error ; end
21
20
  class ServerBye < Error ; end
22
21
  class ServerError < Error ; end
@@ -37,7 +36,7 @@ module Hermeneutics
37
36
 
38
37
  def initialize *args
39
38
  super
40
- @tag = "H%04d" % 0
39
+ @tag = "%s%04d" % [ TAG_PREFIX, 0]
41
40
  @info = [ get_response]
42
41
  start_watch
43
42
  end
@@ -0,0 +1,183 @@
1
+ #
2
+ # lib/hermeneutics/cli/lmtp.rb -- LMTP client
3
+ #
4
+
5
+ require "hermeneutics/cli/protocol"
6
+
7
+ module Hermeneutics
8
+
9
+ module Cli
10
+
11
+ class LMTP < Protocol
12
+
13
+ CRLF = true
14
+
15
+ class UnspecError < Error ; end
16
+ class ServerNotReady < Error ; end
17
+ class NotOk < Error ; end
18
+ class NotReadyForData < Error ; end
19
+ class Unused < Error ; end
20
+ class Uncaught < Error ; end
21
+
22
+ class <<self
23
+ private :new
24
+ def open socketfile
25
+ UNIXSocket.open socketfile do |s|
26
+ i = new s, nil
27
+ yield i
28
+ end
29
+ end
30
+ end
31
+
32
+ attr_reader :domain, :greet
33
+ attr_reader :advertised
34
+ attr_reader :last_response
35
+
36
+ def initialize *args
37
+ super
38
+ get_response.ok? or raise ServerNotReady, @last_response.msg
39
+ @rcpt = 0
40
+ end
41
+
42
+ def size
43
+ @advertised && @advertised[ :SIZE]
44
+ end
45
+
46
+
47
+ def lhlo host = nil
48
+ @advertised = {}
49
+ write_cmd "LHLO", host||Socket.gethostname
50
+ get_response_ok do |code,msg|
51
+ unless @domain then
52
+ @domain, @greet = msg.split nil, 2
53
+ next
54
+ end
55
+ keyword, param = msg.split nil, 2
56
+ keyword.upcase!
57
+ keyword = keyword.to_sym
58
+ case keyword
59
+ when :SIZE then param = Integer param
60
+ when :AUTH then param = param.split.map { |p| p.upcase! ; p.to_sym }
61
+ end
62
+ @advertised[ keyword] = param || true
63
+ end
64
+ unless @domain then
65
+ @domain, @greet = @last_response.msg.split nil, 2
66
+ end
67
+ end
68
+
69
+ def mail_from from
70
+ cmd "MAIL", "FROM:<#{from}>"
71
+ end
72
+
73
+ def rcpt_to to
74
+ cmd "RCPT", "TO:<#{to}>"
75
+ @rcpt += 1
76
+ end
77
+
78
+ def data reader
79
+ write_cmd "DATA"
80
+ get_response.waiting? or raise NotReadyForData, @last_response.msg
81
+ reader.each_line { |l|
82
+ l =~ /\A\./ and l = ".#{l}"
83
+ writeline l
84
+ }
85
+ writeline "."
86
+ get_response_rcpts
87
+ end
88
+
89
+ def bdat data
90
+ data.each { |d|
91
+ write_cmd "BDAT", d.bytesize
92
+ write d
93
+ get_response_ok
94
+ }
95
+ write_cmd "BDAT", 0, "LAST"
96
+ get_response_rcpts
97
+ end
98
+
99
+ def rset
100
+ cmd "RSET"
101
+ ensure
102
+ @rcpt = 0
103
+ end
104
+
105
+ def noop str = nil
106
+ cmd "NOOP"
107
+ end
108
+
109
+ def quit
110
+ cmd "QUIT"
111
+ end
112
+
113
+
114
+ private
115
+
116
+ def cmd name, *args, &block
117
+ write_cmd name, *args
118
+ get_response_ok &block
119
+ end
120
+
121
+ def write_cmd name, *args
122
+ l = [ name, *args].join " "
123
+ writeline l
124
+ end
125
+
126
+ class Response
127
+
128
+ attr_reader :code, :msg
129
+
130
+ def initialize code, msg
131
+ @code, @msg = code, msg
132
+ end
133
+
134
+ def kat ; code / 100 ; end
135
+
136
+ def to_s ; "%03d %s" % [ @code, @msg] ; end
137
+
138
+ def prelim? ; kat == 1 ; end
139
+ def ok? ; kat == 2 ; end
140
+ def waiting? ; kat == 3 ; end
141
+ def error? ; kat == 4 ; end
142
+ def fatal? ; kat == 5 ; end
143
+
144
+ end
145
+
146
+ def get_response_ok &block
147
+ get_response &block
148
+ @last_response.ok? or raise NotOk, @last_response.msg
149
+ true
150
+ end
151
+
152
+ def get_response
153
+ loop do
154
+ r = readline
155
+ if r =~ /\A(\d\d\d) / then
156
+ @last_response = Response.new $1.to_i, $'
157
+ break @last_response
158
+ elsif r =~ /\A(\d\d\d)-/ then
159
+ block_given? or raise Uncaught, r
160
+ yield $1.to_i, $'
161
+ else
162
+ raise UnspecError, r
163
+ end
164
+ end
165
+ end
166
+
167
+ def get_response_rcpts
168
+ r = []
169
+ @rcpt.times {
170
+ r.push get_response
171
+ @last_response.ok? or raise NotOk, @last_response.msg
172
+ }
173
+ r
174
+ ensure
175
+ @rcpt = 0
176
+ end
177
+
178
+ end
179
+
180
+ end
181
+
182
+ end
183
+
@@ -14,7 +14,6 @@ module Hermeneutics
14
14
 
15
15
  PORT, PORT_SSL = 110, 995
16
16
 
17
- class Error < StandardError ; end
18
17
  class UnspecError < Error ; end
19
18
  class AuthFail < Error ; end
20
19
  class Check < Error ; end
@@ -22,8 +22,12 @@ module Hermeneutics
22
22
 
23
23
  module Cli
24
24
 
25
+
25
26
  class Protocol
26
27
 
28
+ class Error < StandardError ; end
29
+ class Timeout < Error ; end
30
+
27
31
  class <<self
28
32
  private :new
29
33
  def open host, port, timeout: nil, ssl: false
@@ -80,7 +84,7 @@ module Hermeneutics
80
84
  end
81
85
 
82
86
  def readline
83
- @socket.wait @timeout||0
87
+ wait
84
88
  r = @socket.readline
85
89
  r.chomp!
86
90
  @trace and $stderr.puts "S: #{r}"
@@ -94,7 +98,7 @@ module Hermeneutics
94
98
  end
95
99
 
96
100
  def read bytes
97
- @socket.wait @timeout||0
101
+ wait
98
102
  r = @socket.read bytes
99
103
  @trace and $stderr.puts "S- #{r.inspect}"
100
104
  r
@@ -105,6 +109,12 @@ module Hermeneutics
105
109
  not @socket.ready?
106
110
  end
107
111
 
112
+ def wait
113
+ if @timeout then
114
+ raise Timeout unless @socket.wait @timeout
115
+ end
116
+ end
117
+
108
118
  end
109
119
 
110
120
 
@@ -14,7 +14,6 @@ module Hermeneutics
14
14
 
15
15
  PORT, PORT_SSL = 25, 465
16
16
 
17
- class Error < StandardError ; end
18
17
  class UnspecError < Error ; end
19
18
  class ServerNotReady < Error ; end
20
19
  class NotOk < Error ; end
@@ -194,7 +193,7 @@ module Hermeneutics
194
193
  r = readline
195
194
  if r =~ /\A(\d\d\d) / then
196
195
  @last_response = Response.new $1.to_i, $'
197
- break
196
+ break @last_response
198
197
  elsif r =~ /\A(\d\d\d)-/ then
199
198
  block_given? or raise Uncaught, r
200
199
  yield $1.to_i, $'
@@ -202,12 +201,6 @@ module Hermeneutics
202
201
  raise UnspecError, r
203
202
  end
204
203
  end
205
- @last_response
206
- ensure
207
- unless done? then
208
- r = readline
209
- r and raise Unused, "Unexpected data: #{r.inspect}"
210
- end
211
204
  end
212
205
 
213
206
  end
@@ -235,7 +235,7 @@ module Hermeneutics
235
235
  # representing the ASCII code. Eight bit characters should be masked the
236
236
  # same way.
237
237
  #
238
- # An URL line does not store encoding information by itself. A locator may
238
+ # A URL line does not store encoding information by itself. A locator may
239
239
  # either say one of these:
240
240
  #
241
241
  # http://www.example.com/subdir/index.html?umlfield=%C3%BCber+alles
@@ -248,7 +248,7 @@ module Hermeneutics
248
248
  }
249
249
  open_smtp conn do |smtp|
250
250
  log :INF, "Sending to", *tos
251
- smtp.mail_from headers.from.first.plain
251
+ headers.from.empty? or smtp.mail_from headers.from.first.plain
252
252
  tos.each { |t| smtp.rcpt_to t }
253
253
  smtp.data m
254
254
  end
@@ -261,22 +261,22 @@ module Hermeneutics
261
261
  def open_smtp arg, &block
262
262
  if [ :mail_from, :rcpt_to, :data].map { |m| arg.respond_to? m }.all? then
263
263
  yield arg
264
- return
265
- end
266
- a = {}
267
- case arg
268
- when nil then h, p = "localhost", nil
269
- when String then h, p = arg.split ":" ; p &&= Integer p
270
- when Array then h, p = *arg
271
- when Hash then a = arg.clone ; h, p = (a.delete :host), (a.delete :port)
272
- else h, p = arg.host, arg.port ; arg.scheme == "smtps" and a[ :ssl] = true
273
- end
274
- require "hermeneutics/cli/smtp"
275
- Cli::SMTP.open h, p, **a do |smtp|
276
- smtp.helo
277
- yield smtp
278
- ensure
279
- smtp.quit
264
+ else
265
+ a = {}
266
+ case arg
267
+ when nil then h, p = "localhost", nil
268
+ when String then h, p = arg.split ":" ; p &&= Integer p
269
+ when Array then h, p = *arg
270
+ when Hash then a = arg.clone ; h, p = (a.delete :host), (a.delete :port)
271
+ else h, p = arg.host, arg.port ; arg.scheme == "smtps" and a[ :ssl] = true
272
+ end
273
+ require "hermeneutics/cli/smtp"
274
+ Cli::SMTP.open h, p, **a do |smtp|
275
+ smtp.helo
276
+ yield smtp
277
+ ensure
278
+ smtp.quit
279
+ end
280
280
  end
281
281
  end
282
282
 
@@ -13,7 +13,7 @@
13
13
  module Hermeneutics
14
14
 
15
15
  NAME = "hermeneutics"
16
- VERSION = "1.21".freeze
16
+ VERSION = "1.23".freeze
17
17
  SUMMARY = "CGI and mail handling"
18
18
 
19
19
  DESCRIPTION = <<~EOT
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hermeneutics
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.21'
4
+ version: '1.23'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bertram Scharpf
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-04 00:00:00.000000000 Z
11
+ date: 2024-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: supplement
@@ -59,6 +59,7 @@ files:
59
59
  - lib/hermeneutics/cli/imap/commands.rb
60
60
  - lib/hermeneutics/cli/imap/parser.rb
61
61
  - lib/hermeneutics/cli/imap/utf7imap.rb
62
+ - lib/hermeneutics/cli/lmtp.rb
62
63
  - lib/hermeneutics/cli/openssl.rb
63
64
  - lib/hermeneutics/cli/pop3.rb
64
65
  - lib/hermeneutics/cli/protocol.rb
@@ -97,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
98
  version: '0'
98
99
  requirements:
99
100
  - Ruby, at least 3.0
100
- rubygems_version: 3.5.6
101
+ rubygems_version: 3.5.21
101
102
  signing_key:
102
103
  specification_version: 4
103
104
  summary: CGI and mail handling