hermeneutics 1.11 → 1.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,218 @@
1
+ #
2
+ # hermeneutics/cli/smtp.rb -- SMTP client
3
+ #
4
+
5
+ require "hermeneutics/cli/protocol"
6
+
7
+ module Hermeneutics
8
+
9
+ module Cli
10
+
11
+ class SMTP < Protocol
12
+
13
+ CRLF = true
14
+
15
+ PORT, PORT_SSL = 25, 465
16
+
17
+ class Error < StandardError ; end
18
+ class UnspecError < Error ; end
19
+ class ServerNotReady < Error ; end
20
+ class NotOk < Error ; end
21
+ class NotReadyForData < Error ; end
22
+ class Unused < Error ; end
23
+ class Uncaught < Error ; end
24
+
25
+ class <<self
26
+ private :new
27
+ def open host, port = nil, timeout: nil, ssl: false
28
+ port ||= ssl ? PORT_SSL : PORT
29
+ super host, port, timeout: timeout, ssl: ssl
30
+ end
31
+ end
32
+
33
+ attr_reader :domain, :greet
34
+ attr_reader :advertised
35
+ attr_reader :last_response
36
+
37
+ def initialize *args
38
+ super
39
+ get_response.ok? or raise ServerNotReady, @last_response.msg
40
+ end
41
+
42
+ def size
43
+ @advertised && @advertised[ :SIZE]
44
+ end
45
+
46
+ def auth
47
+ @advertised && @advertised[ :AUTH]
48
+ end
49
+
50
+ def has_auth? meth
51
+ a = auth
52
+ a and a.include? meth
53
+ end
54
+
55
+
56
+ def helo host = nil
57
+ cmd_hello "HELO", host
58
+ end
59
+
60
+ def ehlo host = nil
61
+ @advertised = {}
62
+ cmd_hello "EHLO", host do |code,msg|
63
+ unless @domain then
64
+ @domain, @greet = msg.split nil, 2
65
+ next
66
+ end
67
+ keyword, param = msg.split nil, 2
68
+ keyword.upcase!
69
+ keyword = keyword.to_sym
70
+ case keyword
71
+ when :SIZE then param = Integer param
72
+ when :AUTH then param = param.split.map { |p| p.upcase! ; p.to_sym }
73
+ end
74
+ @advertised[ keyword] = param || true
75
+ end
76
+ end
77
+
78
+ def mail_from from
79
+ cmd "MAIL", "FROM:<#{from}>"
80
+ end
81
+
82
+ def rcpt_to to
83
+ cmd "RCPT", "TO:<#{to}>"
84
+ end
85
+
86
+ def data reader
87
+ write_cmd "DATA"
88
+ get_response.waiting? or raise NotReadyForData, @last_response.msg
89
+ reader.each_line { |l|
90
+ l =~ /\A\./ and l = ".#{l}"
91
+ writeline l
92
+ }
93
+ writeline "."
94
+ get_response_ok
95
+ end
96
+
97
+ def bdat data
98
+ data.each { |d|
99
+ write_cmd "BDAT", d.bytesize
100
+ write d
101
+ get_response_ok
102
+ }
103
+ write_cmd "BDAT", 0, "LAST"
104
+ get_response_ok do |code,msg|
105
+ yield msg if block_given?
106
+ end
107
+ end
108
+
109
+ def rset
110
+ cmd "RSET"
111
+ end
112
+
113
+ def help str = nil, &block
114
+ cmd "HELP", str, &block
115
+ end
116
+
117
+ def noop str = nil
118
+ cmd "NOOP"
119
+ end
120
+
121
+ def quit
122
+ cmd "QUIT"
123
+ end
124
+
125
+
126
+ def plain user, password
127
+ write_cmd "AUTH", "PLAIN"
128
+ get_response.waiting? or raise NotReadyForData, @last_response.msg
129
+ l = ["\0#{user}\0#{password}"].pack "m0"
130
+ writeline l
131
+ get_response_ok
132
+ end
133
+
134
+
135
+ def login user, password
136
+ write_cmd "AUTH", "LOGIN"
137
+ get_response.waiting? or raise NotReadyForData, @last_response.msg
138
+ writeline [user].pack "m0"
139
+ get_response.waiting? or raise NotReadyForData, @last_response.msg
140
+ writeline [password].pack "m0"
141
+ get_response_ok
142
+ end
143
+
144
+
145
+ private
146
+
147
+ def cmd_hello name, host, &block
148
+ host ||= Socket.gethostname
149
+ write_cmd name, host
150
+ get_response_ok &block
151
+ unless @domain then
152
+ @domain, @greet = @last_response.msg.split nil, 2
153
+ end
154
+ end
155
+
156
+ def cmd name, *args, &block
157
+ write_cmd name, *args
158
+ get_response_ok &block
159
+ end
160
+
161
+ def write_cmd name, *args
162
+ l = [ name, *args].join " "
163
+ writeline l
164
+ end
165
+
166
+ class Response
167
+
168
+ attr_reader :code, :msg
169
+
170
+ def initialize code, msg
171
+ @code, @msg = code, msg
172
+ end
173
+
174
+ def kat ; code / 100 ; end
175
+
176
+ def to_s ; "%03d %s" % [ @code, @msg] ; end
177
+
178
+ def prelim? ; kat == 1 ; end
179
+ def ok? ; kat == 2 ; end
180
+ def waiting? ; kat == 3 ; end
181
+ def error? ; kat == 4 ; end
182
+ def fatal? ; kat == 5 ; end
183
+
184
+ end
185
+
186
+ def get_response_ok &block
187
+ get_response &block
188
+ @last_response.ok? or raise NotOk, @last_response.msg
189
+ true
190
+ end
191
+
192
+ def get_response
193
+ loop do
194
+ r = readline
195
+ if r =~ /\A(\d\d\d) / then
196
+ @last_response = Response.new $1.to_i, $'
197
+ break
198
+ elsif r =~ /\A(\d\d\d)-/ then
199
+ block_given? or raise Uncaught, r
200
+ yield $1.to_i, $'
201
+ else
202
+ raise UnspecError, r
203
+ end
204
+ 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
+ end
212
+
213
+ end
214
+
215
+ end
216
+
217
+ end
218
+
@@ -8,7 +8,7 @@
8
8
 
9
9
  Hermeneutics::Color handles 24-bit colors.
10
10
 
11
- Hermeneutics::Colour is an alias for <code>Hermeneutics::Color</code>.
11
+ Hermeneutics::Colour is an alias for +Hermeneutics::Color+.
12
12
 
13
13
  =end
14
14
 
@@ -41,7 +41,7 @@ module Hermeneutics
41
41
  # new( r, g, b) -> clr
42
42
  #
43
43
  # Create a color with red, green and blue values. They are in range
44
- # <code>0..255</code>.
44
+ # +0..255+.
45
45
  #
46
46
  def initialize r, *gb
47
47
  if gb.any? then
@@ -79,8 +79,8 @@ module Hermeneutics
79
79
  # :call-seq:
80
80
  # gray( num) -> clr
81
81
  #
82
- # Create a gray color (r=b=g). <code>num</code> is in range
83
- # <code>0..255</code>.
82
+ # Create a gray color (r=b=g). +num+ is in range
83
+ # +0..255+.
84
84
  #
85
85
  def gray i
86
86
  new i, i, i
@@ -96,7 +96,7 @@ module Hermeneutics
96
96
  #
97
97
  def to_s ; "#" + tuple.map { |x| "%02x" % x }.join ; end
98
98
 
99
- def inspect ; "#<#{cls}:#{'0x%08x' % (object_id << 1)} #{to_s}>" ; end
99
+ def inspect ; "#<#{self.class}:#{'0x%08x' % (object_id << 1)} #{to_s}>" ; end
100
100
 
101
101
  class <<self
102
102
 
@@ -224,8 +224,8 @@ module Hermeneutics
224
224
  # :call-seq:
225
225
  # edit_hsv() { |h,s,v| ... } -> clr
226
226
  #
227
- # Convert it to an HSV triple, yield that to the block and build a
228
- # new <code>Color</code> from the blocks result.
227
+ # Convert it to an HSV triple, yield that to the block and build a new
228
+ # +Color+ from the blocks result.
229
229
  #
230
230
  def edit_hsv
231
231
  hsv = yield *to_hsv
@@ -241,7 +241,7 @@ module Hermeneutics
241
241
 
242
242
  end
243
243
 
244
- # Alias for class <code>Hermeneutics::Color</code> in British English.
244
+ # Alias for class +Hermeneutics::Color+ in British English.
245
245
  Colour = Color
246
246
 
247
247
  end
@@ -115,6 +115,9 @@ module Hermeneutics
115
115
  end
116
116
  end
117
117
 
118
+ def empty? ; @hash.empty? ; end
119
+ def notempty? ; self if @hash.notempty? ; end
120
+
118
121
  # :call-seq:
119
122
  # []( key) -> str or nil
120
123
  #
@@ -256,6 +259,9 @@ module Hermeneutics
256
259
  super hash
257
260
  end
258
261
 
262
+ def empty? ; @caption.empty? and super ; end
263
+ def notempty? ; self if @caption.notempty? or super ; end
264
+
259
265
  def =~ re
260
266
  @caption =~ re
261
267
  end
@@ -26,7 +26,7 @@ module Hermeneutics
26
26
  # a ":visited", ATTR_COL2, ATTR_DECON
27
27
  # a ":active", ATTR_COL1, ATTR_DECON
28
28
  # a ":focus", ATTR_COL1, ATTR_DECOU
29
- # space
29
+ # skip
30
30
  #
31
31
  # body "#dummy" do
32
32
  # properties background_color: "f7f7f7".to_rgb
@@ -145,22 +145,22 @@ module Hermeneutics
145
145
  def comment str
146
146
  @out << "/*"
147
147
  str = mask_comment str
148
- ml = str =~ %r(#$/)
148
+ ml = str =~ %r(\n)
149
149
  if ml then
150
- @out << $/
150
+ @out << "\n"
151
151
  str.each_line { |l|
152
152
  l.chomp!
153
- @out << " * " << l << $/
153
+ @out << " * " << l << "\n"
154
154
  }
155
155
  else
156
156
  @out << " " << str
157
157
  end
158
158
  @out << " */"
159
- ml and @out << $/
159
+ ml and @out << "\n"
160
160
  end
161
161
 
162
- def space
163
- @out << $/
162
+ def skip
163
+ @out << "\n"
164
164
  end
165
165
 
166
166
  def tag *args
@@ -232,15 +232,15 @@ module Hermeneutics
232
232
  args.each { |a| p.update a }
233
233
  @out << sel << " {"
234
234
  nl, ind = if p.size > 1 then
235
- @out << $/
236
- [ $/, INDENT]
235
+ @out << "\n"
236
+ [ "\n", INDENT]
237
237
  else
238
238
  [ " ", " "]
239
239
  end
240
240
  single p do |s|
241
241
  @out << ind << s << nl
242
242
  end
243
- @out << "}" << $/
243
+ @out << "}" << "\n"
244
244
  end
245
245
 
246
246
  def single hash
@@ -12,25 +12,25 @@ require "supplement"
12
12
  :section: Classes definied here
13
13
 
14
14
  Hermeneutics::Entities encodes to and decodes from HTML-Entities
15
- (<code>&amp;</code> etc.)
15
+ (+&amp;+ etc.)
16
16
 
17
17
  Hermeneutics::URLText encodes to and decodes from URLs
18
- (<code>%2d</code> etc.)
18
+ (+%2d+ etc.)
19
19
 
20
20
  Hermeneutics::HeaderExt encodes to and decodes from E-Mail Header fields
21
- (<code>=?UTF-8?Q?=C3=B6?=</code> etc.).
21
+ (+=?UTF-8?Q?=C3=B6?=+ etc.).
22
22
 
23
23
  =end
24
24
 
25
25
  module Hermeneutics
26
26
 
27
- # Translate HTML and XML character entities: <code>"&"</code> to
28
- # <code>"&amp;"</code> and vice versa.
27
+ # Translate HTML and XML character entities: +"&"+ to
28
+ # +"&amp;"+ and vice versa.
29
29
  #
30
30
  # == What actually happens
31
31
  #
32
- # HTML pages usually come in with characters encoded <code>&lt;</code>
33
- # for <code><</code> and <code>&euro;</code> for <code>€</code>.
32
+ # HTML pages usually come in with characters encoded +&lt;+ for +<+ and
33
+ # +&euro;+ for +€+.
34
34
  #
35
35
  # Further, they may contain a meta tag in the header like this:
36
36
  #
@@ -41,27 +41,25 @@ module Hermeneutics
41
41
  #
42
42
  # <?xml version="1.0" encoding="UTF-8" ?> (XHTML)
43
43
  #
44
- # When +charset+ is <code>utf-8</code> and the file contains the byte
45
- # sequence <code>"\303\244"</code>/<code>"\xc3\xa4"</code> then there will
46
- # be displayed a character <code>"ä"</code>.
44
+ # When +charset+ is +utf-8+ and the file contains the byte sequence
45
+ # +"\303\244"+/+"\xc3\xa4"+ then there will be displayed a character +"ä"+.
47
46
  #
48
- # When +charset+ is <code>iso8859-15</code> and the file contains the byte
49
- # sequence <code>"\344"</code>/<code>"\xe4"</code> then there will be
50
- # displayed a character <code>"ä"</code>, too.
47
+ # When +charset+ is +iso8859-15+ and the file contains the byte sequence
48
+ # +"\344"+/+"\xe4"+ then there will be displayed a character +"ä"+, too.
51
49
  #
52
- # The sequence <code>"&auml;"</code> will produce an <code>"ä"</code> in any
50
+ # The sequence +"&auml;"+ will produce an +"ä"+ in any
53
51
  # case.
54
52
  #
55
53
  # == What you should do
56
54
  #
57
55
  # Generating your own HTML pages you will always be safe when you only
58
- # produce entity tags as <code>&auml;</code> and <code>&euro;</code> or
59
- # <code>&#x00e4;</code> and <code>&#x20ac;</code> respectively.
56
+ # produce entity tags as +&auml;+ and +&euro;+ or +&#x00e4;+ and +&#x20ac;+
57
+ # respectively.
60
58
  #
61
59
  # == What this module does
62
60
  #
63
- # This module translates strings to a HTML-masked version. The encoding will
64
- # not be changed and you may demand to keep 8-bit-characters.
61
+ # This module translates strings to a HTML-masked version. The encoding
62
+ # will not be changed and you may demand to keep 8-bit-characters.
65
63
  #
66
64
  # == Examples
67
65
  #
@@ -118,7 +116,7 @@ module Hermeneutics
118
116
  # :call-seq:
119
117
  # new( keep_8bit: bool) -> ent
120
118
  #
121
- # Creates an <code>Entities</code> converter.
119
+ # Creates an +Entities+ converter.
122
120
  #
123
121
  # ent = Entities.new keep_8bit: true
124
122
  #
@@ -184,9 +182,8 @@ module Hermeneutics
184
182
  # Entities.decode "&lt;" #=> "<"
185
183
  # Entities.decode "&auml;&ouml;&uuml;" #=> "äöü"
186
184
  #
187
- # Unmasked 8-bit-characters (<code>"ä"</code> instead of
188
- # <code>"&auml;"</code>) will be kept but translated to
189
- # a unique encoding.
185
+ # Unmasked 8-bit-characters (+"ä"+ instead of +"&auml;"+) will be kept
186
+ # but translated to a unique encoding.
190
187
  #
191
188
  # s = "ä &ouml; ü"
192
189
  # s.encode! "utf-8"
@@ -259,7 +256,7 @@ module Hermeneutics
259
256
  # :call-seq:
260
257
  # new( hash) -> urltext
261
258
  #
262
- # Creates a <code>URLText</code> converter.
259
+ # Creates a +URLText+ converter.
263
260
  #
264
261
  # The parameters may be given as values or as a hash.
265
262
  #
@@ -276,7 +273,7 @@ module Hermeneutics
276
273
  # :call-seq:
277
274
  # encode( str) -> str
278
275
  #
279
- # Create a string that contains <code>%XX</code>-encoded bytes.
276
+ # Create a string that contains +%XX+-encoded bytes.
280
277
  #
281
278
  # utx = URLText.new
282
279
  # utx.encode "'Stop!' said Fred." #=> "%27Stop%21%27+said+Fred."
@@ -292,15 +289,14 @@ module Hermeneutics
292
289
  # s = "< ä >".encode "ISO-8859-1"
293
290
  # utx.encode s #=> "%3C+\xe4+%3E" in ISO-8859-1
294
291
  #
295
- # A space <code>" "</code> will not be replaced by a plus <code>"+"</code>
296
- # if +keep_space+ is set.
292
+ # A space +" "+ will not be replaced by a plus +"\+"+ if +keep_space+ is
293
+ # set.
297
294
  #
298
295
  # utx = URLText.new keep_space: true
299
296
  # s = "< x >"
300
297
  # utx.encode s #=> "%3C x %3E"
301
298
  #
302
- # When +mask_space+ is set, then a space will be represented as
303
- # <code>"%20"</code>,
299
+ # When +mask_space+ is set, then a space will be represented as +"%20"+,
304
300
  #
305
301
  def encode str
306
302
  r = str.new_string
@@ -370,7 +366,7 @@ module Hermeneutics
370
366
  # :call-seq:
371
367
  # encode_hash( hash) -> str
372
368
  #
373
- # Encode a <code>Hash</code> to a URL-style string.
369
+ # Encode a +Hash+ to a URL-style string.
374
370
  #
375
371
  # utx = URLText.new
376
372
  #
@@ -470,8 +466,8 @@ module Hermeneutics
470
466
  # decode_hash( str) -> hash
471
467
  # decode_hash( str) { |key,val| ... } -> nil or int
472
468
  #
473
- # Decode a URL-style encoded string to a <code>Hash</code>.
474
- # In case a block is given, the number of key-value pairs is returned.
469
+ # Decode a URL-style encoded string to a +Hash+. In case a block is
470
+ # given, the number of key-value pairs is returned.
475
471
  #
476
472
  # str = "a=%3B%3B%3B&x=%26auml%3B%26ouml%3B%26uuml%3B"
477
473
  # URLText.decode_hash str do |k,v|
@@ -528,7 +524,7 @@ module Hermeneutics
528
524
  # :call-seq:
529
525
  # new( [ parameters] ) -> con
530
526
  #
531
- # Creates a <code>HeaderExt</code> converter.
527
+ # Creates a +HeaderExt+ converter.
532
528
  #
533
529
  # See the +encode+ method for an explanation of the parameters.
534
530
  #
@@ -572,8 +568,8 @@ module Hermeneutics
572
568
  # The result will not contain any 8-bit characters. The encoding will
573
569
  # be kept although it won't have a meaning.
574
570
  #
575
- # The parameter <code>:mask</code> will have no influence on the masking
576
- # itself but will guarantee characters to be masked.
571
+ # The parameter +:mask+ will have no influence on the masking itself but
572
+ # will guarantee characters to be masked.
577
573
  #
578
574
  # == Examples
579
575
  #
@@ -151,7 +151,7 @@ module Hermeneutics
151
151
  @out << tag
152
152
  mkattrs attrs
153
153
  end
154
- if nls >3 then
154
+ if nls>3 then
155
155
  verbose_block yield
156
156
  else
157
157
  indent_if nls>2 do
@@ -213,9 +213,9 @@ module Hermeneutics
213
213
  @out << "/* "
214
214
  brace false do
215
215
  @out << "![CDATA["
216
- @out << " */" << $/
216
+ @out << " */\n"
217
217
  @out << str
218
- @out << $/ << "/* "
218
+ @out << "\n/* "
219
219
  @out << "]]"
220
220
  end
221
221
  @out << " */"
@@ -227,7 +227,7 @@ module Hermeneutics
227
227
  def brk
228
228
  unless @nl then
229
229
  @nl = true
230
- @out << $/
230
+ @out << "\n"
231
231
  end
232
232
  end
233
233
  def out_brk str