mailparser 0.4.22a

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.
@@ -0,0 +1,54 @@
1
+ # Copyright (C) 2006-2010 TOMITA Masahiro
2
+ # mailto:tommy@tmtm.org
3
+
4
+ require "mailparser/error"
5
+ require "mailparser/rfc2822"
6
+ require "mailparser/rfc2045/parser"
7
+
8
+ module MailParser::RFC2045
9
+ HEADER_TYPE = {
10
+ "content-type" => :CONTENT_TYPE,
11
+ # "content-description" => :UNSTRUCTURED,
12
+ "content-transfer-encoding" => :CONTENT_TRANSFER_ENCODING,
13
+ "content-id" => [MailParser::RFC2822, :MSG_ID],
14
+ "mime-version" => :MIME_VERSION,
15
+ }
16
+
17
+ class ContentType
18
+ def initialize(type, subtype, params)
19
+ @type, @subtype, @params = type.downcase, subtype.downcase, params
20
+ end
21
+
22
+ attr_reader :type, :subtype, :params
23
+ end
24
+
25
+ class ContentTransferEncoding
26
+ def initialize(mechanism)
27
+ @mechanism = mechanism.downcase
28
+ end
29
+
30
+ attr_reader :mechanism
31
+ end
32
+
33
+ module_function
34
+
35
+ def parse(name, value, opt={})
36
+ htype = HEADER_TYPE[name.downcase]
37
+ unless htype then
38
+ return value.chomp
39
+ end
40
+ if htype.is_a? Array then
41
+ htype[0]::Parser.new.parse(htype[1], value)
42
+ else
43
+ Parser.new.parse(htype, value)
44
+ end
45
+ end
46
+
47
+ def qp_decode(str)
48
+ return str.gsub(/=\s*?$/,"=").unpack("M")[0]
49
+ end
50
+
51
+ def b64_decode(str)
52
+ return str.gsub(/[^A-Z0-9\+\/=]/i,"").unpack("m")[0]
53
+ end
54
+ end
@@ -0,0 +1,245 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by racc 1.4.5
4
+ # from racc grammer file "lib/mailparser/rfc2045/parser.y".
5
+ #
6
+
7
+ require 'racc/parser'
8
+
9
+
10
+ module MailParser
11
+
12
+ module RFC2045
13
+
14
+ class Parser < Racc::Parser
15
+
16
+ module_eval <<'..end lib/mailparser/rfc2045/parser.y modeval..idcdf01fc9ea', 'lib/mailparser/rfc2045/parser.y', 62
17
+
18
+ require "mailparser/rfc2045/scanner"
19
+
20
+ def parse(header_type, value)
21
+ @header_type = header_type
22
+ @value = value
23
+ @scanner = Scanner.new(header_type, value)
24
+ ret = yyparse(self, :parse_sub)
25
+ class << ret
26
+ attr_accessor :comments
27
+ end
28
+ ret.comments = @scanner.comments
29
+ ret
30
+ end
31
+
32
+ def parse_sub(&block)
33
+ yield @header_type, nil
34
+ @scanner.scan(&block)
35
+ end
36
+
37
+ def on_error(t, val, vstack)
38
+ # p t, val, vstack
39
+ # p racc_token2str(t)
40
+ raise MailParser::ParseError, val+@scanner.rest
41
+ end
42
+ ..end lib/mailparser/rfc2045/parser.y modeval..idcdf01fc9ea
43
+
44
+ ##### racc 1.4.5 generates ###
45
+
46
+ racc_reduce_table = [
47
+ 0, 0, :racc_error,
48
+ 2, 13, :_reduce_1,
49
+ 2, 13, :_reduce_2,
50
+ 2, 13, :_reduce_3,
51
+ 4, 14, :_reduce_4,
52
+ 1, 15, :_reduce_5,
53
+ 3, 16, :_reduce_6,
54
+ 1, 20, :_reduce_none,
55
+ 1, 17, :_reduce_none,
56
+ 1, 18, :_reduce_none,
57
+ 0, 19, :_reduce_10,
58
+ 3, 19, :_reduce_11,
59
+ 3, 21, :_reduce_12,
60
+ 1, 22, :_reduce_none,
61
+ 1, 23, :_reduce_none,
62
+ 1, 23, :_reduce_none ]
63
+
64
+ racc_reduce_n = 16
65
+
66
+ racc_shift_n = 29
67
+
68
+ racc_action_table = [
69
+ 28, 8, 10, 26, 1, 3, 4, 13, 14, 15,
70
+ 7, 18, 19, 21, 23, 25, 16 ]
71
+
72
+ racc_action_check = [
73
+ 25, 2, 3, 25, 0, 0, 0, 4, 6, 8,
74
+ 1, 14, 16, 20, 21, 22, 13 ]
75
+
76
+ racc_action_pointer = [
77
+ 2, 2, 1, -6, 1, nil, 3, nil, 9, nil,
78
+ nil, nil, nil, 9, 3, nil, 6, nil, nil, nil,
79
+ 4, 6, 5, nil, nil, -8, nil, nil, nil ]
80
+
81
+ racc_action_default = [
82
+ -16, -16, -16, -16, -16, -1, -16, -8, -16, -2,
83
+ -7, -5, -3, -16, -16, 29, -16, -10, -9, -6,
84
+ -4, -16, -16, -13, -11, -16, -15, -12, -14 ]
85
+
86
+ racc_goto_table = [
87
+ 2, 5, 9, 12, 6, 17, 20, 11, 24, 22,
88
+ 27 ]
89
+
90
+ racc_goto_check = [
91
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
92
+ 11 ]
93
+
94
+ racc_goto_pointer = [
95
+ nil, 0, 0, -1, -1, 3, -9, -11, 4, -13,
96
+ -12, -15 ]
97
+
98
+ racc_goto_default = [
99
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
100
+ nil, nil ]
101
+
102
+ racc_token_table = {
103
+ false => 0,
104
+ Object.new => 1,
105
+ :CONTENT_TYPE => 2,
106
+ :CONTENT_TRANSFER_ENCODING => 3,
107
+ :MIME_VERSION => 4,
108
+ "/" => 5,
109
+ :DIGIT => 6,
110
+ "." => 7,
111
+ :TOKEN => 8,
112
+ ";" => 9,
113
+ "=" => 10,
114
+ :QUOTED_STRING => 11 }
115
+
116
+ racc_use_result_var = false
117
+
118
+ racc_nt_base = 12
119
+
120
+ Racc_arg = [
121
+ racc_action_table,
122
+ racc_action_check,
123
+ racc_action_default,
124
+ racc_action_pointer,
125
+ racc_goto_table,
126
+ racc_goto_check,
127
+ racc_goto_default,
128
+ racc_goto_pointer,
129
+ racc_nt_base,
130
+ racc_reduce_table,
131
+ racc_token_table,
132
+ racc_shift_n,
133
+ racc_reduce_n,
134
+ racc_use_result_var ]
135
+
136
+ Racc_token_to_s_table = [
137
+ '$end',
138
+ 'error',
139
+ 'CONTENT_TYPE',
140
+ 'CONTENT_TRANSFER_ENCODING',
141
+ 'MIME_VERSION',
142
+ '"/"',
143
+ 'DIGIT',
144
+ '"."',
145
+ 'TOKEN',
146
+ '";"',
147
+ '"="',
148
+ 'QUOTED_STRING',
149
+ '$start',
150
+ 'all',
151
+ 'content_type',
152
+ 'content_transfer_encoding',
153
+ 'mime_version',
154
+ 'type',
155
+ 'subtype',
156
+ 'parameter_list',
157
+ 'mechanism',
158
+ 'parameter',
159
+ 'attribute',
160
+ 'value']
161
+
162
+ Racc_debug_parser = false
163
+
164
+ ##### racc system variables end #####
165
+
166
+ # reduce 0 omitted
167
+
168
+ module_eval <<'.,.,', 'lib/mailparser/rfc2045/parser.y', 9
169
+ def _reduce_1( val, _values)
170
+ val[1]
171
+ end
172
+ .,.,
173
+
174
+ module_eval <<'.,.,', 'lib/mailparser/rfc2045/parser.y', 11
175
+ def _reduce_2( val, _values)
176
+ val[1]
177
+ end
178
+ .,.,
179
+
180
+ module_eval <<'.,.,', 'lib/mailparser/rfc2045/parser.y', 13
181
+ def _reduce_3( val, _values)
182
+ val[1]
183
+ end
184
+ .,.,
185
+
186
+ module_eval <<'.,.,', 'lib/mailparser/rfc2045/parser.y', 19
187
+ def _reduce_4( val, _values)
188
+ ContentType.new(val[0], val[2], val[3])
189
+ end
190
+ .,.,
191
+
192
+ module_eval <<'.,.,', 'lib/mailparser/rfc2045/parser.y', 24
193
+ def _reduce_5( val, _values)
194
+ ContentTransferEncoding.new(val[0])
195
+ end
196
+ .,.,
197
+
198
+ module_eval <<'.,.,', 'lib/mailparser/rfc2045/parser.y', 31
199
+ def _reduce_6( val, _values)
200
+ val.join
201
+ end
202
+ .,.,
203
+
204
+ # reduce 7 omitted
205
+
206
+ # reduce 8 omitted
207
+
208
+ # reduce 9 omitted
209
+
210
+ module_eval <<'.,.,', 'lib/mailparser/rfc2045/parser.y', 42
211
+ def _reduce_10( val, _values)
212
+ {}
213
+ end
214
+ .,.,
215
+
216
+ module_eval <<'.,.,', 'lib/mailparser/rfc2045/parser.y', 49
217
+ def _reduce_11( val, _values)
218
+ pn, pv = val[2]
219
+ pv = $1 if pv =~ /\A\"(.*)\"\Z/m
220
+ val[0][pn] = pv.gsub(/\s*\n\s*/, " ")
221
+ val[0]
222
+ end
223
+ .,.,
224
+
225
+ module_eval <<'.,.,', 'lib/mailparser/rfc2045/parser.y', 54
226
+ def _reduce_12( val, _values)
227
+ [val[0].downcase, val[2]]
228
+ end
229
+ .,.,
230
+
231
+ # reduce 13 omitted
232
+
233
+ # reduce 14 omitted
234
+
235
+ # reduce 15 omitted
236
+
237
+ def _reduce_none( val, _values)
238
+ val[0]
239
+ end
240
+
241
+ end # class Parser
242
+
243
+ end # module RFC2045
244
+
245
+ end # module MailParser
@@ -0,0 +1,54 @@
1
+ # Copyright (C) 2006-2010 TOMITA Masahiro
2
+ # mailto:tommy@tmtm.org
3
+
4
+ require "mailparser/rfc2822"
5
+
6
+ class MailParser::RFC2045::Scanner < MailParser::RFC2822::Scanner
7
+ TOKEN_RE = '\x21\x23-\x27\x2a\x2b\x2d\x2e\x30-\x39\x41-\x5a\x5e-\x7f'
8
+
9
+ def scan(&block)
10
+ case @header_type
11
+ when :MIME_VERSION
12
+ scan_mime_version(&block)
13
+ else
14
+ scan_structured(&block)
15
+ end
16
+ end
17
+
18
+ def scan_structured()
19
+ until @ss.eos?
20
+ case
21
+ when s = @ss.scan(/\s*\(/nmo)
22
+ s << cfws(@ss)
23
+ next
24
+ when s = @ss.scan(/\s+/nmo)
25
+ next
26
+ when s = @ss.scan(/\"(\s*(\\[#{TEXT_RE}]|[#{QTEXT_RE}]))*\s*\"/nmo)
27
+ yield :QUOTED_STRING, s
28
+ when s = @ss.scan(/[#{TOKEN_RE}]+/no)
29
+ yield :TOKEN, s
30
+ when s = @ss.scan(/./no)
31
+ yield s, s
32
+ end
33
+ end
34
+ yield nil
35
+ end
36
+
37
+ def scan_mime_version()
38
+ until @ss.eos?
39
+ case
40
+ when s = @ss.scan(/\s*\(/nmo)
41
+ s << cfws(@ss)
42
+ next
43
+ when s = @ss.scan(/\s+/nmo)
44
+ next
45
+ when s = @ss.scan(/\d+/no)
46
+ yield :DIGIT, s
47
+ when s = @ss.scan(/./no)
48
+ yield s, s
49
+ end
50
+ end
51
+ yield nil
52
+ end
53
+
54
+ end
@@ -0,0 +1,82 @@
1
+ # Copyright (C) 2006-2010 TOMITA Masahiro
2
+ # mailto:tommy@tmtm.org
3
+
4
+ require "strscan"
5
+ require "iconv"
6
+ require "nkf"
7
+ require "mailparser/conv_charset"
8
+
9
+ module MailParser
10
+ end
11
+
12
+ module MailParser::RFC2047
13
+
14
+ class String < ::String
15
+ @@charset_converter = Proc.new{|f,t,s| MailParser::ConvCharset.conv_charset(f,t,s)}
16
+ def initialize(str, charset=nil, raw=nil, charset_converter=nil)
17
+ super(str)
18
+ @charset = charset
19
+ @raw = raw || str
20
+ @charset_converter = charset_converter || @@charset_converter
21
+ end
22
+ attr_reader :charset
23
+ attr_reader :raw
24
+
25
+ def conv_charset(to_charset)
26
+ if @charset and to_charset
27
+ @charset_converter.call @charset, to_charset, self
28
+ else
29
+ self
30
+ end
31
+ end
32
+ end
33
+
34
+ module_function
35
+
36
+ def decode(str, opt=nil)
37
+ if opt.is_a? Hash
38
+ charset = opt[:output_charset]
39
+ charset_converter = opt[:charset_converter]
40
+ else
41
+ charset = opt
42
+ end
43
+ last_charset = nil
44
+ ret = ""
45
+ split_decode(str, charset_converter).each do |s|
46
+ begin
47
+ s2 = charset && s.charset ? s.conv_charset(charset) : s
48
+ cs = s.charset
49
+ rescue Iconv::Failure
50
+ s2 = s.raw
51
+ cs = nil
52
+ end
53
+ ret << " " if last_charset.nil? or cs.nil?
54
+ ret << s2
55
+ last_charset = cs
56
+ end
57
+ return ret.strip
58
+ end
59
+
60
+ def split_decode(str, charset_converter=nil)
61
+ ret = []
62
+ while str =~ /\=\?([^\(\)\<\>\@\,\;\:\"\/\[\]\?\.\=]+)\?([QB])\?([^\? ]+)\?\=/ni do
63
+ raw = $&
64
+ pre, charset, encoding, enc_text, after = $`, $1.downcase, $2.downcase, $3, $'
65
+ ret << String.new(pre.strip) unless pre.strip.empty?
66
+ s = encoding == "q" ? q_decode(enc_text) : b_decode(enc_text)
67
+ ret << String.new(s, charset, raw, charset_converter)
68
+ str = after
69
+ end
70
+ ret << String.new(str.strip) unless str.empty?
71
+ return ret
72
+ end
73
+
74
+ def q_decode(str)
75
+ return str.gsub(/_/," ").gsub(/=\s*?$/,"=").unpack("M")[0]
76
+ end
77
+
78
+ def b_decode(str)
79
+ return str.gsub(/[^A-Z0-9\+\/=]/i,"").unpack("m")[0]
80
+ end
81
+
82
+ end
@@ -0,0 +1,33 @@
1
+ # Copyright (C) 2006-2010 TOMITA Masahiro
2
+ # mailto:tommy@tmtm.org
3
+
4
+ require "mailparser/error"
5
+ require "mailparser/rfc2183/parser"
6
+
7
+ module MailParser::RFC2183
8
+ HEADER_TYPE = {
9
+ "content-disposition" => :CONTENT_DISPOSITION,
10
+ }
11
+
12
+ class ContentDisposition
13
+ def initialize(type, params)
14
+ @type, @params = type.downcase, params
15
+ end
16
+
17
+ attr_reader :type, :params
18
+ end
19
+
20
+ module_function
21
+
22
+ def parse(name, value, opt={})
23
+ htype = HEADER_TYPE[name.downcase]
24
+ unless htype then
25
+ return value.chomp
26
+ end
27
+ if htype.is_a? Array then
28
+ htype[0]::Parser.new.parse(htype[1], value)
29
+ else
30
+ Parser.new.parse(htype, value)
31
+ end
32
+ end
33
+ end