rfc-822-validator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.README.md.swp ADDED
Binary file
data/.bnsignore ADDED
@@ -0,0 +1,18 @@
1
+ # The list of files that should be ignored by Mr Bones.
2
+ # Lines that start with '#' are comments.
3
+ #
4
+ # A .gitignore file can be used instead by setting it as the ignore
5
+ # file in your Rakefile:
6
+ #
7
+ # Bones {
8
+ # ignore_file '.gitignore'
9
+ # }
10
+ #
11
+ # For a project with a C extension, the following would be a good set of
12
+ # exclude patterns (uncomment them if you want to use them):
13
+ # *.[oa]
14
+ # *~
15
+ announcement.txt
16
+ coverage
17
+ doc
18
+ pkg
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 1.0.0 / 2011-03-22
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ rfc-822
2
+ ===========
3
+
4
+ Implementation of RFC-822
5
+
6
+ Features
7
+ --------
8
+
9
+ Validates RFC-822 Addresses
10
+
11
+ More usefully, it validates the addr_spec portion of the addresses
12
+
13
+ Examples
14
+ --------
15
+
16
+ # Validate an address as per the RFC
17
+ RFC822.validate('example@example.net')
18
+
19
+ # Validate an address per the addr_spec portion of the RFC
20
+ # This is what most people actually expect in an address
21
+ RFC822.validate_addr('example@example.net')
22
+
23
+ A note on the RFC
24
+ -----------------
25
+ RFC 822 has some oddities, it does things most people don't expect, such as
26
+
27
+ * It does not validate domains
28
+ * It supports groups, multiple labeled lists of addresses. ex: MyGroup: "John Higgins" <john@example.net>, mark mark@example.net;
29
+ * It supports routes, a sequence of mailservers the message is supposed to travel. ex: test@mymailserver@othermailserver.com
30
+ * It support sdouble quoted strings as the local part of an address, with crazy chars in them. ex: "my@funkyaddress"@example.net
31
+ * It supports phrases before angle bracketed addresses. ex: "Test" <test@example.net>.
32
+
33
+
34
+ Authors
35
+ ------
36
+
37
+ Evan Phoenix (evanphx)
38
+ Andrew Cholakian (andrewvc)
39
+
40
+ License
41
+ -------
42
+
43
+ (The MIT License) FIXME (different license?)
44
+
45
+ Copyright (c) 2011 FIXME (author's name)
46
+
47
+ Permission is hereby granted, free of charge, to any person obtaining
48
+ a copy of this software and associated documentation files (the
49
+ 'Software'), to deal in the Software without restriction, including
50
+ without limitation the rights to use, copy, modify, merge, publish,
51
+ distribute, sublicense, and/or sell copies of the Software, and to
52
+ permit persons to whom the Software is furnished to do so, subject to
53
+ the following conditions:
54
+
55
+ The above copyright notice and this permission notice shall be
56
+ included in all copies or substantial portions of the Software.
57
+
58
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
59
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
60
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
61
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
62
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
63
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
64
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+
2
+ begin
3
+ require 'bones'
4
+ rescue LoadError
5
+ abort '### Please install the "bones" gem ###'
6
+ end
7
+
8
+ task :default => 'test:run'
9
+ task 'gem:release' => 'test:run'
10
+
11
+ task "parser" do
12
+ sh "kpeg -s -o lib/rfc-822/parser.rb -f email.kpeg"
13
+ end
14
+
15
+ Bones {
16
+ name 'rfc-822-validator'
17
+ authors 'Evan Phoenix, Andrew Cholakian'
18
+ email 'andrew@andrewvc.com'
19
+ url 'https://github.com/andrewvc/rfc-822'
20
+ }
21
+
data/bin/rfc-822 ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), %w[.. lib rfc-822]))
5
+
6
+ # Put your code here
7
+
data/email.kpeg ADDED
@@ -0,0 +1,72 @@
1
+ %% name = RFC822::Parser
2
+
3
+ HTAB = /\x09/
4
+ LF = /\x0A/
5
+ CR = /\x0D/
6
+ SPACE = " "
7
+ - = SPACE*
8
+ AT = "@"
9
+
10
+ LWSP_char = SPACE | HTAB
11
+ CHAR = /[\x00-\x7f]/
12
+ CTL = /[\x00-\x1f\x7f]/
13
+
14
+ special = /[\]()<>@,;:\\".\[]/
15
+
16
+ CRLF = CR LF
17
+
18
+ linear_white_space = (CRLF? LWSP_char)+
19
+
20
+ atom = /[^\]\x00-\x20 \x7F\x80-\xFF()<>@,;:\\".\[]+/
21
+
22
+ ctext = /[^)\\\x0D\x80-\xFF(]+/
23
+ | linear_white_space
24
+
25
+
26
+ dtext = /[^\]\\\x0D\x80-\xFF\[]+/
27
+ | linear_white_space
28
+
29
+ qtext = /[^"\\\x0D\x80-\xFF]+/
30
+ | linear_white_space
31
+
32
+
33
+ quoted_pair = "\\" CHAR
34
+
35
+ quoted_string = "\"" (qtext | quoted_pair)* "\""
36
+
37
+ domain_literal = "[" (dtext | quoted_pair)* "]"
38
+
39
+ comment = "(" (ctext | quoted_pair | comment)* ")"
40
+
41
+ ocms = comment*
42
+
43
+ word = atom | quoted_string
44
+
45
+ phrase = (word -)+
46
+
47
+ valid = ocms address ocms
48
+
49
+ address = mailbox | group
50
+
51
+ group = phrase ocms ":" ocms mailbox (ocms "," ocms mailbox)* ocms ";"
52
+
53
+ mailbox = addr_spec
54
+ | phrase - ocms - angle_addr
55
+
56
+ angle_addr = "<" ocms route? ocms addr_spec ">"
57
+
58
+ route = (AT ocms domain)+ ":"
59
+
60
+ addr_spec = local_part ocms "@" ocms domain
61
+
62
+ local_part = word ocms ("." ocms word)*
63
+
64
+ domain = sub_domain ocms ("." ocms sub_domain)*
65
+
66
+ sub_domain = domain_ref | domain_literal
67
+
68
+ domain_ref = atom
69
+
70
+ root = valid !.
71
+
72
+ only_addr_spec = addr_spec !.
data/lib/rfc-822.rb ADDED
@@ -0,0 +1,72 @@
1
+
2
+ module RFC822
3
+
4
+ # :stopdoc:
5
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
+ VERSION = ::File.read(PATH + 'version.txt').strip
8
+ # :startdoc:
9
+
10
+ # Returns the library path for the module. If any arguments are given,
11
+ # they will be joined to the end of the libray path using
12
+ # <tt>File.join</tt>.
13
+ #
14
+ def self.libpath( *args )
15
+ rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
16
+ if block_given?
17
+ begin
18
+ $LOAD_PATH.unshift LIBPATH
19
+ rv = yield
20
+ ensure
21
+ $LOAD_PATH.shift
22
+ end
23
+ end
24
+ return rv
25
+ end
26
+
27
+ # Returns the lpath for the module. If any arguments are given,
28
+ # they will be joined to the end of the path using
29
+ # <tt>File.join</tt>.
30
+ #
31
+ def self.path( *args )
32
+ rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
33
+ if block_given?
34
+ begin
35
+ $LOAD_PATH.unshift PATH
36
+ rv = yield
37
+ ensure
38
+ $LOAD_PATH.shift
39
+ end
40
+ end
41
+ return rv
42
+ end
43
+
44
+ # Utility method used to require all files ending in .rb that lie in the
45
+ # directory below this file that has the same name as the filename passed
46
+ # in. Optionally, a specific _directory_ name can be passed in such that
47
+ # the _filename_ does not have to be equivalent to the directory.
48
+ #
49
+ def self.require_all_libs_relative_to( fname, dir = nil )
50
+ dir ||= ::File.basename(fname, '.*')
51
+ search_me = ::File.expand_path(
52
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
53
+
54
+ Dir.glob(search_me).sort.each {|rb| require rb}
55
+ end
56
+
57
+
58
+ def self.validate(addr)
59
+ parser = Parser.new(addr)
60
+ parser.parse
61
+ end
62
+
63
+ def self.validate_addr(addr)
64
+ parser = Parser.new(addr, "only_addr_spec")
65
+ parser.parse
66
+ end
67
+
68
+
69
+ end # module RFC822
70
+
71
+ RFC822.require_all_libs_relative_to(__FILE__)
72
+
@@ -0,0 +1,1292 @@
1
+ class RFC822::Parser
2
+ # STANDALONE START
3
+ def setup_parser(str, debug=false)
4
+ @string = str
5
+ @pos = 0
6
+ @memoizations = Hash.new { |h,k| h[k] = {} }
7
+ @result = nil
8
+ @failed_rule = nil
9
+ @failing_rule_offset = -1
10
+
11
+ setup_foreign_grammar
12
+ end
13
+
14
+ def setup_foreign_grammar
15
+ end
16
+
17
+ # This is distinct from setup_parser so that a standalone parser
18
+ # can redefine #initialize and still have access to the proper
19
+ # parser setup code.
20
+ #
21
+ def initialize(str, debug=false)
22
+ setup_parser(str, debug)
23
+ end
24
+
25
+ attr_reader :string
26
+ attr_reader :result, :failing_rule_offset
27
+ attr_accessor :pos
28
+
29
+ # STANDALONE START
30
+ def current_column(target=pos)
31
+ if c = string.rindex("\n", target-1)
32
+ return target - c - 1
33
+ end
34
+
35
+ target + 1
36
+ end
37
+
38
+ def current_line(target=pos)
39
+ cur_offset = 0
40
+ cur_line = 0
41
+
42
+ string.each_line do |line|
43
+ cur_line += 1
44
+ cur_offset += line.size
45
+ return cur_line if cur_offset >= target
46
+ end
47
+
48
+ -1
49
+ end
50
+
51
+ def lines
52
+ lines = []
53
+ string.each_line { |l| lines << l }
54
+ lines
55
+ end
56
+
57
+ #
58
+
59
+ def get_text(start)
60
+ @string[start..@pos-1]
61
+ end
62
+
63
+ def show_pos
64
+ width = 10
65
+ if @pos < width
66
+ "#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")"
67
+ else
68
+ "#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")"
69
+ end
70
+ end
71
+
72
+ def failure_info
73
+ l = current_line @failing_rule_offset
74
+ c = current_column @failing_rule_offset
75
+
76
+ if @failed_rule.kind_of? Symbol
77
+ info = self.class::Rules[@failed_rule]
78
+ "line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'"
79
+ else
80
+ "line #{l}, column #{c}: failed rule '#{@failed_rule}'"
81
+ end
82
+ end
83
+
84
+ def failure_caret
85
+ l = current_line @failing_rule_offset
86
+ c = current_column @failing_rule_offset
87
+
88
+ line = lines[l-1]
89
+ "#{line}\n#{' ' * (c - 1)}^"
90
+ end
91
+
92
+ def failure_character
93
+ l = current_line @failing_rule_offset
94
+ c = current_column @failing_rule_offset
95
+ lines[l-1][c-1, 1]
96
+ end
97
+
98
+ def failure_oneline
99
+ l = current_line @failing_rule_offset
100
+ c = current_column @failing_rule_offset
101
+
102
+ char = lines[l-1][c-1, 1]
103
+
104
+ if @failed_rule.kind_of? Symbol
105
+ info = self.class::Rules[@failed_rule]
106
+ "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'"
107
+ else
108
+ "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'"
109
+ end
110
+ end
111
+
112
+ class ParseError < RuntimeError
113
+ end
114
+
115
+ def raise_error
116
+ raise ParseError, failure_oneline
117
+ end
118
+
119
+ def show_error(io=STDOUT)
120
+ error_pos = @failing_rule_offset
121
+ line_no = current_line(error_pos)
122
+ col_no = current_column(error_pos)
123
+
124
+ io.puts "On line #{line_no}, column #{col_no}:"
125
+
126
+ if @failed_rule.kind_of? Symbol
127
+ info = self.class::Rules[@failed_rule]
128
+ io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')"
129
+ else
130
+ io.puts "Failed to match rule '#{@failed_rule}'"
131
+ end
132
+
133
+ io.puts "Got: #{string[error_pos,1].inspect}"
134
+ line = lines[line_no-1]
135
+ io.puts "=> #{line}"
136
+ io.print(" " * (col_no + 3))
137
+ io.puts "^"
138
+ end
139
+
140
+ def set_failed_rule(name)
141
+ if @pos > @failing_rule_offset
142
+ @failed_rule = name
143
+ @failing_rule_offset = @pos
144
+ end
145
+ end
146
+
147
+ attr_reader :failed_rule
148
+
149
+ def match_string(str)
150
+ len = str.size
151
+ if @string[pos,len] == str
152
+ @pos += len
153
+ return str
154
+ end
155
+
156
+ return nil
157
+ end
158
+
159
+ def scan(reg)
160
+ if m = reg.match(@string[@pos..-1])
161
+ width = m.end(0)
162
+ @pos += width
163
+ return true
164
+ end
165
+
166
+ return nil
167
+ end
168
+
169
+ if "".respond_to? :getbyte
170
+ def get_byte
171
+ if @pos >= @string.size
172
+ return nil
173
+ end
174
+
175
+ s = @string.getbyte @pos
176
+ @pos += 1
177
+ s
178
+ end
179
+ else
180
+ def get_byte
181
+ if @pos >= @string.size
182
+ return nil
183
+ end
184
+
185
+ s = @string[@pos]
186
+ @pos += 1
187
+ s
188
+ end
189
+ end
190
+
191
+ def parse(rule=nil)
192
+ if !rule
193
+ _root ? true : false
194
+ else
195
+ # This is not shared with code_generator.rb so this can be standalone
196
+ method = rule.gsub("-","_hyphen_")
197
+ __send__("_#{method}") ? true : false
198
+ end
199
+ end
200
+
201
+ class LeftRecursive
202
+ def initialize(detected=false)
203
+ @detected = detected
204
+ end
205
+
206
+ attr_accessor :detected
207
+ end
208
+
209
+ class MemoEntry
210
+ def initialize(ans, pos)
211
+ @ans = ans
212
+ @pos = pos
213
+ @uses = 1
214
+ @result = nil
215
+ end
216
+
217
+ attr_reader :ans, :pos, :uses, :result
218
+
219
+ def inc!
220
+ @uses += 1
221
+ end
222
+
223
+ def move!(ans, pos, result)
224
+ @ans = ans
225
+ @pos = pos
226
+ @result = result
227
+ end
228
+ end
229
+
230
+ def external_invoke(other, rule, *args)
231
+ old_pos = @pos
232
+ old_string = @string
233
+
234
+ @pos = other.pos
235
+ @string = other.string
236
+
237
+ begin
238
+ if val = __send__(rule, *args)
239
+ other.pos = @pos
240
+ else
241
+ other.set_failed_rule "#{self.class}##{rule}"
242
+ end
243
+ val
244
+ ensure
245
+ @pos = old_pos
246
+ @string = old_string
247
+ end
248
+ end
249
+
250
+ def apply(rule)
251
+ if m = @memoizations[rule][@pos]
252
+ m.inc!
253
+
254
+ prev = @pos
255
+ @pos = m.pos
256
+ if m.ans.kind_of? LeftRecursive
257
+ m.ans.detected = true
258
+ return nil
259
+ end
260
+
261
+ @result = m.result
262
+
263
+ return m.ans
264
+ else
265
+ lr = LeftRecursive.new(false)
266
+ m = MemoEntry.new(lr, @pos)
267
+ @memoizations[rule][@pos] = m
268
+ start_pos = @pos
269
+
270
+ ans = __send__ rule
271
+
272
+ m.move! ans, @pos, @result
273
+
274
+ # Don't bother trying to grow the left recursion
275
+ # if it's failing straight away (thus there is no seed)
276
+ if ans and lr.detected
277
+ return grow_lr(rule, start_pos, m)
278
+ else
279
+ return ans
280
+ end
281
+
282
+ return ans
283
+ end
284
+ end
285
+
286
+ def grow_lr(rule, start_pos, m)
287
+ while true
288
+ @pos = start_pos
289
+ @result = m.result
290
+
291
+ ans = __send__ rule
292
+ return nil unless ans
293
+
294
+ break if @pos <= m.pos
295
+
296
+ m.move! ans, @pos, @result
297
+ end
298
+
299
+ @result = m.result
300
+ @pos = m.pos
301
+ return m.ans
302
+ end
303
+
304
+ class RuleInfo
305
+ def initialize(name, rendered)
306
+ @name = name
307
+ @rendered = rendered
308
+ end
309
+
310
+ attr_reader :name, :rendered
311
+ end
312
+
313
+ def self.rule_info(name, rendered)
314
+ RuleInfo.new(name, rendered)
315
+ end
316
+
317
+ #
318
+ def setup_foreign_grammar; end
319
+
320
+ # HTAB = /\x09/
321
+ def _HTAB
322
+ _tmp = scan(/\A(?-mix:\x09)/)
323
+ set_failed_rule :_HTAB unless _tmp
324
+ return _tmp
325
+ end
326
+
327
+ # LF = /\x0A/
328
+ def _LF
329
+ _tmp = scan(/\A(?-mix:\x0A)/)
330
+ set_failed_rule :_LF unless _tmp
331
+ return _tmp
332
+ end
333
+
334
+ # CR = /\x0D/
335
+ def _CR
336
+ _tmp = scan(/\A(?-mix:\x0D)/)
337
+ set_failed_rule :_CR unless _tmp
338
+ return _tmp
339
+ end
340
+
341
+ # SPACE = " "
342
+ def _SPACE
343
+ _tmp = match_string(" ")
344
+ set_failed_rule :_SPACE unless _tmp
345
+ return _tmp
346
+ end
347
+
348
+ # - = SPACE*
349
+ def __hyphen_
350
+ while true
351
+ _tmp = apply(:_SPACE)
352
+ break unless _tmp
353
+ end
354
+ _tmp = true
355
+ set_failed_rule :__hyphen_ unless _tmp
356
+ return _tmp
357
+ end
358
+
359
+ # AT = "@"
360
+ def _AT
361
+ _tmp = match_string("@")
362
+ set_failed_rule :_AT unless _tmp
363
+ return _tmp
364
+ end
365
+
366
+ # LWSP_char = (SPACE | HTAB)
367
+ def _LWSP_char
368
+
369
+ _save = self.pos
370
+ while true # choice
371
+ _tmp = apply(:_SPACE)
372
+ break if _tmp
373
+ self.pos = _save
374
+ _tmp = apply(:_HTAB)
375
+ break if _tmp
376
+ self.pos = _save
377
+ break
378
+ end # end choice
379
+
380
+ set_failed_rule :_LWSP_char unless _tmp
381
+ return _tmp
382
+ end
383
+
384
+ # CHAR = /[\x00-\x7f]/
385
+ def _CHAR
386
+ _tmp = scan(/\A(?-mix:[\x00-\x7f])/)
387
+ set_failed_rule :_CHAR unless _tmp
388
+ return _tmp
389
+ end
390
+
391
+ # CTL = /[\x00-\x1f\x7f]/
392
+ def _CTL
393
+ _tmp = scan(/\A(?-mix:[\x00-\x1f\x7f])/)
394
+ set_failed_rule :_CTL unless _tmp
395
+ return _tmp
396
+ end
397
+
398
+ # special = /[\]()<>@,;:\\".\[]/
399
+ def _special
400
+ _tmp = scan(/\A(?-mix:[\]()<>@,;:\\".\[])/)
401
+ set_failed_rule :_special unless _tmp
402
+ return _tmp
403
+ end
404
+
405
+ # CRLF = CR LF
406
+ def _CRLF
407
+
408
+ _save = self.pos
409
+ while true # sequence
410
+ _tmp = apply(:_CR)
411
+ unless _tmp
412
+ self.pos = _save
413
+ break
414
+ end
415
+ _tmp = apply(:_LF)
416
+ unless _tmp
417
+ self.pos = _save
418
+ end
419
+ break
420
+ end # end sequence
421
+
422
+ set_failed_rule :_CRLF unless _tmp
423
+ return _tmp
424
+ end
425
+
426
+ # linear_white_space = (CRLF? LWSP_char)+
427
+ def _linear_white_space
428
+ _save = self.pos
429
+
430
+ _save1 = self.pos
431
+ while true # sequence
432
+ _save2 = self.pos
433
+ _tmp = apply(:_CRLF)
434
+ unless _tmp
435
+ _tmp = true
436
+ self.pos = _save2
437
+ end
438
+ unless _tmp
439
+ self.pos = _save1
440
+ break
441
+ end
442
+ _tmp = apply(:_LWSP_char)
443
+ unless _tmp
444
+ self.pos = _save1
445
+ end
446
+ break
447
+ end # end sequence
448
+
449
+ if _tmp
450
+ while true
451
+
452
+ _save3 = self.pos
453
+ while true # sequence
454
+ _save4 = self.pos
455
+ _tmp = apply(:_CRLF)
456
+ unless _tmp
457
+ _tmp = true
458
+ self.pos = _save4
459
+ end
460
+ unless _tmp
461
+ self.pos = _save3
462
+ break
463
+ end
464
+ _tmp = apply(:_LWSP_char)
465
+ unless _tmp
466
+ self.pos = _save3
467
+ end
468
+ break
469
+ end # end sequence
470
+
471
+ break unless _tmp
472
+ end
473
+ _tmp = true
474
+ else
475
+ self.pos = _save
476
+ end
477
+ set_failed_rule :_linear_white_space unless _tmp
478
+ return _tmp
479
+ end
480
+
481
+ # atom = /[^\]\x00-\x20 \x7F\x80-\xFF()<>@,;:\\".\[]+/
482
+ def _atom
483
+ _tmp = scan(/\A(?-mix:[^\]\x00-\x20 \x7F\x80-\xFF()<>@,;:\\".\[]+)/)
484
+ set_failed_rule :_atom unless _tmp
485
+ return _tmp
486
+ end
487
+
488
+ # ctext = (/[^)\\\x0D\x80-\xFF(]+/ | linear_white_space)
489
+ def _ctext
490
+
491
+ _save = self.pos
492
+ while true # choice
493
+ _tmp = scan(/\A(?-mix:[^)\\\x0D\x80-\xFF(]+)/)
494
+ break if _tmp
495
+ self.pos = _save
496
+ _tmp = apply(:_linear_white_space)
497
+ break if _tmp
498
+ self.pos = _save
499
+ break
500
+ end # end choice
501
+
502
+ set_failed_rule :_ctext unless _tmp
503
+ return _tmp
504
+ end
505
+
506
+ # dtext = (/[^\]\\\x0D\x80-\xFF\[]+/ | linear_white_space)
507
+ def _dtext
508
+
509
+ _save = self.pos
510
+ while true # choice
511
+ _tmp = scan(/\A(?-mix:[^\]\\\x0D\x80-\xFF\[]+)/)
512
+ break if _tmp
513
+ self.pos = _save
514
+ _tmp = apply(:_linear_white_space)
515
+ break if _tmp
516
+ self.pos = _save
517
+ break
518
+ end # end choice
519
+
520
+ set_failed_rule :_dtext unless _tmp
521
+ return _tmp
522
+ end
523
+
524
+ # qtext = (/[^"\\\x0D\x80-\xFF]+/ | linear_white_space)
525
+ def _qtext
526
+
527
+ _save = self.pos
528
+ while true # choice
529
+ _tmp = scan(/\A(?-mix:[^"\\\x0D\x80-\xFF]+)/)
530
+ break if _tmp
531
+ self.pos = _save
532
+ _tmp = apply(:_linear_white_space)
533
+ break if _tmp
534
+ self.pos = _save
535
+ break
536
+ end # end choice
537
+
538
+ set_failed_rule :_qtext unless _tmp
539
+ return _tmp
540
+ end
541
+
542
+ # quoted_pair = "\\" CHAR
543
+ def _quoted_pair
544
+
545
+ _save = self.pos
546
+ while true # sequence
547
+ _tmp = match_string("\\")
548
+ unless _tmp
549
+ self.pos = _save
550
+ break
551
+ end
552
+ _tmp = apply(:_CHAR)
553
+ unless _tmp
554
+ self.pos = _save
555
+ end
556
+ break
557
+ end # end sequence
558
+
559
+ set_failed_rule :_quoted_pair unless _tmp
560
+ return _tmp
561
+ end
562
+
563
+ # quoted_string = "\"" (qtext | quoted_pair)* "\""
564
+ def _quoted_string
565
+
566
+ _save = self.pos
567
+ while true # sequence
568
+ _tmp = match_string("\"")
569
+ unless _tmp
570
+ self.pos = _save
571
+ break
572
+ end
573
+ while true
574
+
575
+ _save2 = self.pos
576
+ while true # choice
577
+ _tmp = apply(:_qtext)
578
+ break if _tmp
579
+ self.pos = _save2
580
+ _tmp = apply(:_quoted_pair)
581
+ break if _tmp
582
+ self.pos = _save2
583
+ break
584
+ end # end choice
585
+
586
+ break unless _tmp
587
+ end
588
+ _tmp = true
589
+ unless _tmp
590
+ self.pos = _save
591
+ break
592
+ end
593
+ _tmp = match_string("\"")
594
+ unless _tmp
595
+ self.pos = _save
596
+ end
597
+ break
598
+ end # end sequence
599
+
600
+ set_failed_rule :_quoted_string unless _tmp
601
+ return _tmp
602
+ end
603
+
604
+ # domain_literal = "[" (dtext | quoted_pair)* "]"
605
+ def _domain_literal
606
+
607
+ _save = self.pos
608
+ while true # sequence
609
+ _tmp = match_string("[")
610
+ unless _tmp
611
+ self.pos = _save
612
+ break
613
+ end
614
+ while true
615
+
616
+ _save2 = self.pos
617
+ while true # choice
618
+ _tmp = apply(:_dtext)
619
+ break if _tmp
620
+ self.pos = _save2
621
+ _tmp = apply(:_quoted_pair)
622
+ break if _tmp
623
+ self.pos = _save2
624
+ break
625
+ end # end choice
626
+
627
+ break unless _tmp
628
+ end
629
+ _tmp = true
630
+ unless _tmp
631
+ self.pos = _save
632
+ break
633
+ end
634
+ _tmp = match_string("]")
635
+ unless _tmp
636
+ self.pos = _save
637
+ end
638
+ break
639
+ end # end sequence
640
+
641
+ set_failed_rule :_domain_literal unless _tmp
642
+ return _tmp
643
+ end
644
+
645
+ # comment = "(" (ctext | quoted_pair | comment)* ")"
646
+ def _comment
647
+
648
+ _save = self.pos
649
+ while true # sequence
650
+ _tmp = match_string("(")
651
+ unless _tmp
652
+ self.pos = _save
653
+ break
654
+ end
655
+ while true
656
+
657
+ _save2 = self.pos
658
+ while true # choice
659
+ _tmp = apply(:_ctext)
660
+ break if _tmp
661
+ self.pos = _save2
662
+ _tmp = apply(:_quoted_pair)
663
+ break if _tmp
664
+ self.pos = _save2
665
+ _tmp = apply(:_comment)
666
+ break if _tmp
667
+ self.pos = _save2
668
+ break
669
+ end # end choice
670
+
671
+ break unless _tmp
672
+ end
673
+ _tmp = true
674
+ unless _tmp
675
+ self.pos = _save
676
+ break
677
+ end
678
+ _tmp = match_string(")")
679
+ unless _tmp
680
+ self.pos = _save
681
+ end
682
+ break
683
+ end # end sequence
684
+
685
+ set_failed_rule :_comment unless _tmp
686
+ return _tmp
687
+ end
688
+
689
+ # ocms = comment*
690
+ def _ocms
691
+ while true
692
+ _tmp = apply(:_comment)
693
+ break unless _tmp
694
+ end
695
+ _tmp = true
696
+ set_failed_rule :_ocms unless _tmp
697
+ return _tmp
698
+ end
699
+
700
+ # word = (atom | quoted_string)
701
+ def _word
702
+
703
+ _save = self.pos
704
+ while true # choice
705
+ _tmp = apply(:_atom)
706
+ break if _tmp
707
+ self.pos = _save
708
+ _tmp = apply(:_quoted_string)
709
+ break if _tmp
710
+ self.pos = _save
711
+ break
712
+ end # end choice
713
+
714
+ set_failed_rule :_word unless _tmp
715
+ return _tmp
716
+ end
717
+
718
+ # phrase = (word -)+
719
+ def _phrase
720
+ _save = self.pos
721
+
722
+ _save1 = self.pos
723
+ while true # sequence
724
+ _tmp = apply(:_word)
725
+ unless _tmp
726
+ self.pos = _save1
727
+ break
728
+ end
729
+ _tmp = apply(:__hyphen_)
730
+ unless _tmp
731
+ self.pos = _save1
732
+ end
733
+ break
734
+ end # end sequence
735
+
736
+ if _tmp
737
+ while true
738
+
739
+ _save2 = self.pos
740
+ while true # sequence
741
+ _tmp = apply(:_word)
742
+ unless _tmp
743
+ self.pos = _save2
744
+ break
745
+ end
746
+ _tmp = apply(:__hyphen_)
747
+ unless _tmp
748
+ self.pos = _save2
749
+ end
750
+ break
751
+ end # end sequence
752
+
753
+ break unless _tmp
754
+ end
755
+ _tmp = true
756
+ else
757
+ self.pos = _save
758
+ end
759
+ set_failed_rule :_phrase unless _tmp
760
+ return _tmp
761
+ end
762
+
763
+ # valid = ocms address ocms
764
+ def _valid
765
+
766
+ _save = self.pos
767
+ while true # sequence
768
+ _tmp = apply(:_ocms)
769
+ unless _tmp
770
+ self.pos = _save
771
+ break
772
+ end
773
+ _tmp = apply(:_address)
774
+ unless _tmp
775
+ self.pos = _save
776
+ break
777
+ end
778
+ _tmp = apply(:_ocms)
779
+ unless _tmp
780
+ self.pos = _save
781
+ end
782
+ break
783
+ end # end sequence
784
+
785
+ set_failed_rule :_valid unless _tmp
786
+ return _tmp
787
+ end
788
+
789
+ # address = (mailbox | group)
790
+ def _address
791
+
792
+ _save = self.pos
793
+ while true # choice
794
+ _tmp = apply(:_mailbox)
795
+ break if _tmp
796
+ self.pos = _save
797
+ _tmp = apply(:_group)
798
+ break if _tmp
799
+ self.pos = _save
800
+ break
801
+ end # end choice
802
+
803
+ set_failed_rule :_address unless _tmp
804
+ return _tmp
805
+ end
806
+
807
+ # group = phrase ocms ":" ocms mailbox (ocms "," ocms mailbox)* ocms ";"
808
+ def _group
809
+
810
+ _save = self.pos
811
+ while true # sequence
812
+ _tmp = apply(:_phrase)
813
+ unless _tmp
814
+ self.pos = _save
815
+ break
816
+ end
817
+ _tmp = apply(:_ocms)
818
+ unless _tmp
819
+ self.pos = _save
820
+ break
821
+ end
822
+ _tmp = match_string(":")
823
+ unless _tmp
824
+ self.pos = _save
825
+ break
826
+ end
827
+ _tmp = apply(:_ocms)
828
+ unless _tmp
829
+ self.pos = _save
830
+ break
831
+ end
832
+ _tmp = apply(:_mailbox)
833
+ unless _tmp
834
+ self.pos = _save
835
+ break
836
+ end
837
+ while true
838
+
839
+ _save2 = self.pos
840
+ while true # sequence
841
+ _tmp = apply(:_ocms)
842
+ unless _tmp
843
+ self.pos = _save2
844
+ break
845
+ end
846
+ _tmp = match_string(",")
847
+ unless _tmp
848
+ self.pos = _save2
849
+ break
850
+ end
851
+ _tmp = apply(:_ocms)
852
+ unless _tmp
853
+ self.pos = _save2
854
+ break
855
+ end
856
+ _tmp = apply(:_mailbox)
857
+ unless _tmp
858
+ self.pos = _save2
859
+ end
860
+ break
861
+ end # end sequence
862
+
863
+ break unless _tmp
864
+ end
865
+ _tmp = true
866
+ unless _tmp
867
+ self.pos = _save
868
+ break
869
+ end
870
+ _tmp = apply(:_ocms)
871
+ unless _tmp
872
+ self.pos = _save
873
+ break
874
+ end
875
+ _tmp = match_string(";")
876
+ unless _tmp
877
+ self.pos = _save
878
+ end
879
+ break
880
+ end # end sequence
881
+
882
+ set_failed_rule :_group unless _tmp
883
+ return _tmp
884
+ end
885
+
886
+ # mailbox = (addr_spec | phrase - ocms - angle_addr)
887
+ def _mailbox
888
+
889
+ _save = self.pos
890
+ while true # choice
891
+ _tmp = apply(:_addr_spec)
892
+ break if _tmp
893
+ self.pos = _save
894
+
895
+ _save1 = self.pos
896
+ while true # sequence
897
+ _tmp = apply(:_phrase)
898
+ unless _tmp
899
+ self.pos = _save1
900
+ break
901
+ end
902
+ _tmp = apply(:__hyphen_)
903
+ unless _tmp
904
+ self.pos = _save1
905
+ break
906
+ end
907
+ _tmp = apply(:_ocms)
908
+ unless _tmp
909
+ self.pos = _save1
910
+ break
911
+ end
912
+ _tmp = apply(:__hyphen_)
913
+ unless _tmp
914
+ self.pos = _save1
915
+ break
916
+ end
917
+ _tmp = apply(:_angle_addr)
918
+ unless _tmp
919
+ self.pos = _save1
920
+ end
921
+ break
922
+ end # end sequence
923
+
924
+ break if _tmp
925
+ self.pos = _save
926
+ break
927
+ end # end choice
928
+
929
+ set_failed_rule :_mailbox unless _tmp
930
+ return _tmp
931
+ end
932
+
933
+ # angle_addr = "<" ocms route? ocms addr_spec ">"
934
+ def _angle_addr
935
+
936
+ _save = self.pos
937
+ while true # sequence
938
+ _tmp = match_string("<")
939
+ unless _tmp
940
+ self.pos = _save
941
+ break
942
+ end
943
+ _tmp = apply(:_ocms)
944
+ unless _tmp
945
+ self.pos = _save
946
+ break
947
+ end
948
+ _save1 = self.pos
949
+ _tmp = apply(:_route)
950
+ unless _tmp
951
+ _tmp = true
952
+ self.pos = _save1
953
+ end
954
+ unless _tmp
955
+ self.pos = _save
956
+ break
957
+ end
958
+ _tmp = apply(:_ocms)
959
+ unless _tmp
960
+ self.pos = _save
961
+ break
962
+ end
963
+ _tmp = apply(:_addr_spec)
964
+ unless _tmp
965
+ self.pos = _save
966
+ break
967
+ end
968
+ _tmp = match_string(">")
969
+ unless _tmp
970
+ self.pos = _save
971
+ end
972
+ break
973
+ end # end sequence
974
+
975
+ set_failed_rule :_angle_addr unless _tmp
976
+ return _tmp
977
+ end
978
+
979
+ # route = (AT ocms domain)+ ":"
980
+ def _route
981
+
982
+ _save = self.pos
983
+ while true # sequence
984
+ _save1 = self.pos
985
+
986
+ _save2 = self.pos
987
+ while true # sequence
988
+ _tmp = apply(:_AT)
989
+ unless _tmp
990
+ self.pos = _save2
991
+ break
992
+ end
993
+ _tmp = apply(:_ocms)
994
+ unless _tmp
995
+ self.pos = _save2
996
+ break
997
+ end
998
+ _tmp = apply(:_domain)
999
+ unless _tmp
1000
+ self.pos = _save2
1001
+ end
1002
+ break
1003
+ end # end sequence
1004
+
1005
+ if _tmp
1006
+ while true
1007
+
1008
+ _save3 = self.pos
1009
+ while true # sequence
1010
+ _tmp = apply(:_AT)
1011
+ unless _tmp
1012
+ self.pos = _save3
1013
+ break
1014
+ end
1015
+ _tmp = apply(:_ocms)
1016
+ unless _tmp
1017
+ self.pos = _save3
1018
+ break
1019
+ end
1020
+ _tmp = apply(:_domain)
1021
+ unless _tmp
1022
+ self.pos = _save3
1023
+ end
1024
+ break
1025
+ end # end sequence
1026
+
1027
+ break unless _tmp
1028
+ end
1029
+ _tmp = true
1030
+ else
1031
+ self.pos = _save1
1032
+ end
1033
+ unless _tmp
1034
+ self.pos = _save
1035
+ break
1036
+ end
1037
+ _tmp = match_string(":")
1038
+ unless _tmp
1039
+ self.pos = _save
1040
+ end
1041
+ break
1042
+ end # end sequence
1043
+
1044
+ set_failed_rule :_route unless _tmp
1045
+ return _tmp
1046
+ end
1047
+
1048
+ # addr_spec = local_part ocms "@" ocms domain
1049
+ def _addr_spec
1050
+
1051
+ _save = self.pos
1052
+ while true # sequence
1053
+ _tmp = apply(:_local_part)
1054
+ unless _tmp
1055
+ self.pos = _save
1056
+ break
1057
+ end
1058
+ _tmp = apply(:_ocms)
1059
+ unless _tmp
1060
+ self.pos = _save
1061
+ break
1062
+ end
1063
+ _tmp = match_string("@")
1064
+ unless _tmp
1065
+ self.pos = _save
1066
+ break
1067
+ end
1068
+ _tmp = apply(:_ocms)
1069
+ unless _tmp
1070
+ self.pos = _save
1071
+ break
1072
+ end
1073
+ _tmp = apply(:_domain)
1074
+ unless _tmp
1075
+ self.pos = _save
1076
+ end
1077
+ break
1078
+ end # end sequence
1079
+
1080
+ set_failed_rule :_addr_spec unless _tmp
1081
+ return _tmp
1082
+ end
1083
+
1084
+ # local_part = word ocms ("." ocms word)*
1085
+ def _local_part
1086
+
1087
+ _save = self.pos
1088
+ while true # sequence
1089
+ _tmp = apply(:_word)
1090
+ unless _tmp
1091
+ self.pos = _save
1092
+ break
1093
+ end
1094
+ _tmp = apply(:_ocms)
1095
+ unless _tmp
1096
+ self.pos = _save
1097
+ break
1098
+ end
1099
+ while true
1100
+
1101
+ _save2 = self.pos
1102
+ while true # sequence
1103
+ _tmp = match_string(".")
1104
+ unless _tmp
1105
+ self.pos = _save2
1106
+ break
1107
+ end
1108
+ _tmp = apply(:_ocms)
1109
+ unless _tmp
1110
+ self.pos = _save2
1111
+ break
1112
+ end
1113
+ _tmp = apply(:_word)
1114
+ unless _tmp
1115
+ self.pos = _save2
1116
+ end
1117
+ break
1118
+ end # end sequence
1119
+
1120
+ break unless _tmp
1121
+ end
1122
+ _tmp = true
1123
+ unless _tmp
1124
+ self.pos = _save
1125
+ end
1126
+ break
1127
+ end # end sequence
1128
+
1129
+ set_failed_rule :_local_part unless _tmp
1130
+ return _tmp
1131
+ end
1132
+
1133
+ # domain = sub_domain ocms ("." ocms sub_domain)+
1134
+ def _domain
1135
+
1136
+ _save = self.pos
1137
+ while true # sequence
1138
+ _tmp = apply(:_sub_domain)
1139
+ unless _tmp
1140
+ self.pos = _save
1141
+ break
1142
+ end
1143
+ _tmp = apply(:_ocms)
1144
+ unless _tmp
1145
+ self.pos = _save
1146
+ break
1147
+ end
1148
+ _save1 = self.pos
1149
+
1150
+ _save2 = self.pos
1151
+ while true # sequence
1152
+ _tmp = match_string(".")
1153
+ unless _tmp
1154
+ self.pos = _save2
1155
+ break
1156
+ end
1157
+ _tmp = apply(:_ocms)
1158
+ unless _tmp
1159
+ self.pos = _save2
1160
+ break
1161
+ end
1162
+ _tmp = apply(:_sub_domain)
1163
+ unless _tmp
1164
+ self.pos = _save2
1165
+ end
1166
+ break
1167
+ end # end sequence
1168
+
1169
+ if _tmp
1170
+ while true
1171
+
1172
+ _save3 = self.pos
1173
+ while true # sequence
1174
+ _tmp = match_string(".")
1175
+ unless _tmp
1176
+ self.pos = _save3
1177
+ break
1178
+ end
1179
+ _tmp = apply(:_ocms)
1180
+ unless _tmp
1181
+ self.pos = _save3
1182
+ break
1183
+ end
1184
+ _tmp = apply(:_sub_domain)
1185
+ unless _tmp
1186
+ self.pos = _save3
1187
+ end
1188
+ break
1189
+ end # end sequence
1190
+
1191
+ break unless _tmp
1192
+ end
1193
+ _tmp = true
1194
+ else
1195
+ self.pos = _save1
1196
+ end
1197
+ unless _tmp
1198
+ self.pos = _save
1199
+ end
1200
+ break
1201
+ end # end sequence
1202
+
1203
+ set_failed_rule :_domain unless _tmp
1204
+ return _tmp
1205
+ end
1206
+
1207
+ # sub_domain = (domain_ref | domain_literal)
1208
+ def _sub_domain
1209
+
1210
+ _save = self.pos
1211
+ while true # choice
1212
+ _tmp = apply(:_domain_ref)
1213
+ break if _tmp
1214
+ self.pos = _save
1215
+ _tmp = apply(:_domain_literal)
1216
+ break if _tmp
1217
+ self.pos = _save
1218
+ break
1219
+ end # end choice
1220
+
1221
+ set_failed_rule :_sub_domain unless _tmp
1222
+ return _tmp
1223
+ end
1224
+
1225
+ # domain_ref = atom
1226
+ def _domain_ref
1227
+ _tmp = apply(:_atom)
1228
+ set_failed_rule :_domain_ref unless _tmp
1229
+ return _tmp
1230
+ end
1231
+
1232
+ # root = valid !.
1233
+ def _root
1234
+
1235
+ _save = self.pos
1236
+ while true # sequence
1237
+ _tmp = apply(:_valid)
1238
+ unless _tmp
1239
+ self.pos = _save
1240
+ break
1241
+ end
1242
+ _save1 = self.pos
1243
+ _tmp = get_byte
1244
+ _tmp = _tmp ? nil : true
1245
+ self.pos = _save1
1246
+ unless _tmp
1247
+ self.pos = _save
1248
+ end
1249
+ break
1250
+ end # end sequence
1251
+
1252
+ set_failed_rule :_root unless _tmp
1253
+ return _tmp
1254
+ end
1255
+
1256
+ Rules = {}
1257
+ Rules[:_HTAB] = rule_info("HTAB", "/\\x09/")
1258
+ Rules[:_LF] = rule_info("LF", "/\\x0A/")
1259
+ Rules[:_CR] = rule_info("CR", "/\\x0D/")
1260
+ Rules[:_SPACE] = rule_info("SPACE", "\" \"")
1261
+ Rules[:__hyphen_] = rule_info("-", "SPACE*")
1262
+ Rules[:_AT] = rule_info("AT", "\"@\"")
1263
+ Rules[:_LWSP_char] = rule_info("LWSP_char", "(SPACE | HTAB)")
1264
+ Rules[:_CHAR] = rule_info("CHAR", "/[\\x00-\\x7f]/")
1265
+ Rules[:_CTL] = rule_info("CTL", "/[\\x00-\\x1f\\x7f]/")
1266
+ Rules[:_special] = rule_info("special", "/[\\]()<>@,;:\\\\\".\\[]/")
1267
+ Rules[:_CRLF] = rule_info("CRLF", "CR LF")
1268
+ Rules[:_linear_white_space] = rule_info("linear_white_space", "(CRLF? LWSP_char)+")
1269
+ Rules[:_atom] = rule_info("atom", "/[^\\]\\x00-\\x20 \\x7F\\x80-\\xFF()<>@,;:\\\\\".\\[]+/")
1270
+ Rules[:_ctext] = rule_info("ctext", "(/[^)\\\\\\x0D\\x80-\\xFF(]+/ | linear_white_space)")
1271
+ Rules[:_dtext] = rule_info("dtext", "(/[^\\]\\\\\\x0D\\x80-\\xFF\\[]+/ | linear_white_space)")
1272
+ Rules[:_qtext] = rule_info("qtext", "(/[^\"\\\\\\x0D\\x80-\\xFF]+/ | linear_white_space)")
1273
+ Rules[:_quoted_pair] = rule_info("quoted_pair", "\"\\\\\" CHAR")
1274
+ Rules[:_quoted_string] = rule_info("quoted_string", "\"\\\"\" (qtext | quoted_pair)* \"\\\"\"")
1275
+ Rules[:_domain_literal] = rule_info("domain_literal", "\"[\" (dtext | quoted_pair)* \"]\"")
1276
+ Rules[:_comment] = rule_info("comment", "\"(\" (ctext | quoted_pair | comment)* \")\"")
1277
+ Rules[:_ocms] = rule_info("ocms", "comment*")
1278
+ Rules[:_word] = rule_info("word", "(atom | quoted_string)")
1279
+ Rules[:_phrase] = rule_info("phrase", "(word -)+")
1280
+ Rules[:_valid] = rule_info("valid", "ocms address ocms")
1281
+ Rules[:_address] = rule_info("address", "(mailbox | group)")
1282
+ Rules[:_group] = rule_info("group", "phrase ocms \":\" ocms mailbox (ocms \",\" ocms mailbox)* ocms \";\"")
1283
+ Rules[:_mailbox] = rule_info("mailbox", "(addr_spec | phrase - ocms - angle_addr)")
1284
+ Rules[:_angle_addr] = rule_info("angle_addr", "\"<\" ocms route? ocms addr_spec \">\"")
1285
+ Rules[:_route] = rule_info("route", "(AT ocms domain)+ \":\"")
1286
+ Rules[:_addr_spec] = rule_info("addr_spec", "local_part ocms \"@\" ocms domain")
1287
+ Rules[:_local_part] = rule_info("local_part", "word ocms (\".\" ocms word)*")
1288
+ Rules[:_domain] = rule_info("domain", "sub_domain ocms (\".\" ocms sub_domain)+")
1289
+ Rules[:_sub_domain] = rule_info("sub_domain", "(domain_ref | domain_literal)")
1290
+ Rules[:_domain_ref] = rule_info("domain_ref", "atom")
1291
+ Rules[:_root] = rule_info("root", "valid !.")
1292
+ end