notes-structured-text-json-messages 0.1.1 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.4
|
@@ -16,6 +16,10 @@ OptionParser.new do |opts|
|
|
16
16
|
opts.on("-v", "--[no-]verbose", "Run verbosely (default: true)") do |v|
|
17
17
|
options[:verbose] = v
|
18
18
|
end
|
19
|
+
|
20
|
+
opts.on("-m", "--mapping-file FILE", "output notes-distinguished-name <=> internet-email-address mappings to FILE") do |f|
|
21
|
+
options[:mapping_file] = f
|
22
|
+
end
|
19
23
|
end.parse!
|
20
24
|
|
21
25
|
NotesStructuredTextJsonMessages.logger = Logger.new($stderr)
|
@@ -5,6 +5,7 @@ module NotesStructuredTextJsonMessages
|
|
5
5
|
class << self
|
6
6
|
attr_accessor :logger
|
7
7
|
attr_accessor :stats
|
8
|
+
attr_accessor :mappings
|
8
9
|
end
|
9
10
|
|
10
11
|
module_function
|
@@ -13,26 +14,50 @@ module NotesStructuredTextJsonMessages
|
|
13
14
|
yield logger if logger
|
14
15
|
end
|
15
16
|
|
16
|
-
def reset_stats
|
17
|
-
self.stats={}
|
18
|
-
end
|
19
|
-
|
20
17
|
def increment_stats(key)
|
21
18
|
self.stats[key] = (self.stats[key]||0) + 1
|
22
19
|
end
|
23
20
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
21
|
+
def collect_mapping(addr1, addr2)
|
22
|
+
self.mappings << [addr1, addr2] if self.mappings
|
23
|
+
end
|
24
|
+
|
25
|
+
def with_mappings(options)
|
26
|
+
mapping_file = options[:mapping_file]
|
27
|
+
log{|logger| logger.info "using mapping_file: #{options[:mapping_file]}"} if mapping_file
|
28
|
+
self.mappings=[]
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
if mapping_file
|
32
|
+
File.open(mapping_file, "w") do |output|
|
33
|
+
output << "[\n"
|
34
|
+
output << self.mappings.map(&:to_json).join(",\n")
|
35
|
+
output << "\n]"
|
29
36
|
end
|
30
37
|
end
|
31
|
-
|
38
|
+
end
|
39
|
+
|
40
|
+
def with_stats
|
41
|
+
self.stats={}
|
42
|
+
yield
|
43
|
+
ensure
|
44
|
+
self.stats.each do |k,v|
|
32
45
|
log{|logger| logger.info("#{k}: #{v}")}
|
33
46
|
end
|
34
47
|
end
|
35
48
|
|
49
|
+
def json_messages(output_dir, input_files, options={})
|
50
|
+
with_stats do
|
51
|
+
with_mappings(options) do
|
52
|
+
[*input_files].each do |input_file|
|
53
|
+
File.open(input_file, "r") do |input|
|
54
|
+
json_messages_from_stream(output_dir, input, options)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
36
61
|
def json_messages_from_stream(output_dir, input, options={})
|
37
62
|
block = nil
|
38
63
|
process_block(output_dir, block, options) while block=read_block(input)
|
@@ -138,35 +163,42 @@ module NotesStructuredTextJsonMessages
|
|
138
163
|
def process_address(addr)
|
139
164
|
if is_distinguished_name?(addr)
|
140
165
|
name = addr[/CN=([^\/]*)/, 1]
|
141
|
-
{
|
142
|
-
|
166
|
+
h = {:notes_dn=>addr}
|
167
|
+
h[:name] = name if name
|
168
|
+
h
|
143
169
|
else
|
144
170
|
ta = TMail::Address.parse(addr)
|
145
171
|
if ta.is_a?(TMail::Address)
|
146
|
-
{
|
147
|
-
|
172
|
+
h = {:email_address=>ta.address.downcase}
|
173
|
+
h[:name] = ta.name if ta.name
|
174
|
+
h
|
148
175
|
else
|
149
176
|
log{|logger| logger.warn("addr does not parse to a TMail::Address: #{addr}")}
|
150
177
|
end
|
151
178
|
end
|
152
179
|
end
|
153
180
|
|
154
|
-
def process_address_pair(inet_addr, notes_addr)
|
181
|
+
def process_address_pair(inet_addr, notes_addr, options)
|
155
182
|
if inet_addr == "."
|
156
183
|
process_address(notes_addr)
|
157
184
|
else
|
158
|
-
process_address(inet_addr)
|
185
|
+
inet_addr = process_address(inet_addr)
|
186
|
+
notes_addr = process_address(notes_addr)
|
187
|
+
|
188
|
+
collect_mapping(notes_addr, inet_addr)
|
189
|
+
|
190
|
+
inet_addr
|
159
191
|
end
|
160
192
|
end
|
161
193
|
|
162
|
-
def process_addresses(block, inet_field, notes_field)
|
194
|
+
def process_addresses(block, inet_field, notes_field, options)
|
163
195
|
inet_h = header_values(block, inet_field, :split_rfc822_addresses)
|
164
196
|
notes_h = header_values(block, notes_field, :split_rfc822_addresses)
|
165
197
|
|
166
198
|
if inet_h && notes_h
|
167
199
|
if inet_h.length == notes_h.length
|
168
200
|
inet_h.zip(notes_h).map do |inet_addr, notes_addr|
|
169
|
-
process_address_pair(inet_addr, notes_addr)
|
201
|
+
process_address_pair(inet_addr, notes_addr, options)
|
170
202
|
end
|
171
203
|
else
|
172
204
|
raise "#{inet_field}: does not match #{notes_field}:"
|
@@ -188,11 +220,17 @@ module NotesStructuredTextJsonMessages
|
|
188
220
|
|
189
221
|
def extract_json_message(block, options={})
|
190
222
|
message_id_h = header_value(block, MESSAGE_ID)
|
191
|
-
|
223
|
+
if !message_id_h
|
224
|
+
increment_stats(:failure_no_message_id)
|
225
|
+
raise "no #{MESSAGE_ID}"
|
226
|
+
end
|
192
227
|
message_id = strip_angles(message_id_h)
|
193
228
|
|
194
229
|
posted_date_h = header_value(block, POSTED_DATE)
|
195
|
-
|
230
|
+
if !posted_date_h
|
231
|
+
increment_stats(:failure_no_posted_date)
|
232
|
+
raise "no #{POSTED_DATE}"
|
233
|
+
end
|
196
234
|
posted_date = parse_date(posted_date_h, options)
|
197
235
|
|
198
236
|
in_reply_to_h = header_value(block, IN_REPLY_TO)
|
@@ -201,14 +239,20 @@ module NotesStructuredTextJsonMessages
|
|
201
239
|
references_h = header_values(block, REFERENCES, " ")
|
202
240
|
references = references_h.map{|r| strip_angles(r)} if references_h
|
203
241
|
|
204
|
-
froms = process_addresses(block, INET_FROM, FROM)
|
205
|
-
|
242
|
+
froms = process_addresses(block, INET_FROM, FROM, options)
|
243
|
+
if !froms || froms.size>1
|
244
|
+
increment_stats(:failure_from)
|
245
|
+
raise "no From:, or more than one From:"
|
246
|
+
end
|
206
247
|
from = froms[0]
|
207
|
-
to = process_addresses(block, INET_TO, TO)
|
208
|
-
cc = process_addresses(block, INET_CC, CC)
|
209
|
-
bcc = process_addresses(block, INET_BCC, BCC)
|
248
|
+
to = process_addresses(block, INET_TO, TO, options)
|
249
|
+
cc = process_addresses(block, INET_CC, CC, options)
|
250
|
+
bcc = process_addresses(block, INET_BCC, BCC, options)
|
210
251
|
|
211
|
-
|
252
|
+
if (to||[]).size + (cc||[]).size + (bcc||[]).size == 0
|
253
|
+
increment_stats(:failure_no_recipients)
|
254
|
+
raise "no recipients"
|
255
|
+
end
|
212
256
|
|
213
257
|
{ :message_type=>"email",
|
214
258
|
:message_id=>message_id,
|
@@ -222,7 +266,8 @@ module NotesStructuredTextJsonMessages
|
|
222
266
|
end
|
223
267
|
|
224
268
|
def output_json_message(output_dir, json_message)
|
225
|
-
fname = File.join(output_dir, MD5.hexdigest(json_message[:message_id]))
|
269
|
+
fname = File.join(output_dir, "#{MD5.hexdigest(json_message[:message_id])}.json")
|
226
270
|
File.open(fname, "w"){|out| out << json_message.to_json}
|
227
271
|
end
|
272
|
+
|
228
273
|
end
|
@@ -5,7 +5,7 @@ describe NotesStructuredTextJsonMessages do
|
|
5
5
|
it "should open each file and call json_messages_from_stream with it" do
|
6
6
|
output_dir = Object.new
|
7
7
|
input_files = [Object.new, Object.new]
|
8
|
-
options =
|
8
|
+
options = {}
|
9
9
|
|
10
10
|
input0 = Object.new
|
11
11
|
input1 = Object.new
|
@@ -34,6 +34,27 @@ describe NotesStructuredTextJsonMessages do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
describe "with_mappings" do
|
38
|
+
it "should write mapping JSON if mapping_file option is given" do
|
39
|
+
opts = Object.new
|
40
|
+
mf = Object.new
|
41
|
+
mfs = StringIO.new
|
42
|
+
stub(opts).[](:mapping_file){mf}
|
43
|
+
mock(File).open(mf, "w"){|f,m,block| block.call(mfs)}
|
44
|
+
|
45
|
+
NotesStructuredTextJsonMessages.with_mappings(opts) do
|
46
|
+
NotesStructuredTextJsonMessages.collect_mapping({:notes_dn=>"CN=foo mcfoo/OU=foofoo/O=foo"},
|
47
|
+
{:email_address=>"foo.mcfoo@foo.com"})
|
48
|
+
NotesStructuredTextJsonMessages.collect_mapping({:notes_dn=>"CN=bar mcbar/OU=barbar/O=bar"},
|
49
|
+
{:email_address=>"bar.mcbar@bar.com"})
|
50
|
+
end
|
51
|
+
|
52
|
+
j = JSON.parse(mfs.string)
|
53
|
+
j.should == [[{"notes_dn"=>"CN=foo mcfoo/OU=foofoo/O=foo"}, {"email_address"=>"foo.mcfoo@foo.com"}],
|
54
|
+
[{"notes_dn"=>"CN=bar mcbar/OU=barbar/O=bar"}, {"email_address"=>"bar.mcbar@bar.com"}]]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
37
58
|
describe "readblock" do
|
38
59
|
it "should return lines read from a stream until the first empty line" do
|
39
60
|
input = <<-EOF
|
@@ -240,12 +261,12 @@ EOF
|
|
240
261
|
|
241
262
|
describe "process_address_pair" do
|
242
263
|
it "should process_address the notes_address if the inet_address is '.'" do
|
243
|
-
NotesStructuredTextJsonMessages.process_address_pair(".", "CN=foo bar/OU=here/O=there").should ==
|
264
|
+
NotesStructuredTextJsonMessages.process_address_pair(".", "CN=foo bar/OU=here/O=there", {}).should ==
|
244
265
|
{:name=>"foo bar", :notes_dn=>"CN=foo bar/OU=here/O=there"}
|
245
266
|
end
|
246
267
|
|
247
268
|
it "should process_address the inet_addr if the inet_address is not '.'" do
|
248
|
-
NotesStructuredTextJsonMessages.process_address_pair('"foo bar" <foo@bar.com>', "CN=foo bar/OU=here/O=there").should ==
|
269
|
+
NotesStructuredTextJsonMessages.process_address_pair('"foo bar" <foo@bar.com>', "CN=foo bar/OU=here/O=there", {}).should ==
|
249
270
|
{:name=>"foo bar", :email_address=>"foo@bar.com"}
|
250
271
|
end
|
251
272
|
end
|
@@ -255,12 +276,13 @@ EOF
|
|
255
276
|
inet_field = Object.new
|
256
277
|
notes_field = Object.new
|
257
278
|
block = Object.new
|
279
|
+
options = {}
|
258
280
|
|
259
281
|
stub(NotesStructuredTextJsonMessages).header_values(block, inet_field, :split_rfc822_addresses){["foo", "bar"]}
|
260
282
|
stub(NotesStructuredTextJsonMessages).header_values(block, notes_field, :split_rfc822_addresses){["foo"]}
|
261
283
|
|
262
284
|
lambda {
|
263
|
-
NotesStructuredTextJsonMessages.process_addresses(block, inet_field, notes_field)
|
285
|
+
NotesStructuredTextJsonMessages.process_addresses(block, inet_field, notes_field, options)
|
264
286
|
}.should raise_error(/does not match/)
|
265
287
|
end
|
266
288
|
|
@@ -268,20 +290,22 @@ EOF
|
|
268
290
|
inet_field = Object.new
|
269
291
|
notes_field = Object.new
|
270
292
|
block = Object.new
|
293
|
+
options={}
|
271
294
|
|
272
295
|
stub(NotesStructuredTextJsonMessages).header_values(block, inet_field, :split_rfc822_addresses){["foo.mcfoo@foo.com", "bar.mcbar@bar.com"]}
|
273
296
|
stub(NotesStructuredTextJsonMessages).header_values(block, notes_field, :split_rfc822_addresses){["CN=foo mcfoo/OU=main/O=foo", "CN=bar mcbar/OU=main/O=bar"]}
|
274
297
|
|
275
|
-
mock(NotesStructuredTextJsonMessages).process_address_pair("foo.mcfoo@foo.com", "CN=foo mcfoo/OU=main/O=foo")
|
276
|
-
mock(NotesStructuredTextJsonMessages).process_address_pair("bar.mcbar@bar.com", "CN=bar mcbar/OU=main/O=bar")
|
298
|
+
mock(NotesStructuredTextJsonMessages).process_address_pair("foo.mcfoo@foo.com", "CN=foo mcfoo/OU=main/O=foo", options)
|
299
|
+
mock(NotesStructuredTextJsonMessages).process_address_pair("bar.mcbar@bar.com", "CN=bar mcbar/OU=main/O=bar", options)
|
277
300
|
|
278
|
-
NotesStructuredTextJsonMessages.process_addresses(block, inet_field, notes_field)
|
301
|
+
NotesStructuredTextJsonMessages.process_addresses(block, inet_field, notes_field, options)
|
279
302
|
end
|
280
303
|
|
281
304
|
it "should call process_address if an inet header is present" do
|
282
305
|
inet_field = Object.new
|
283
306
|
notes_field = Object.new
|
284
307
|
block = Object.new
|
308
|
+
options={}
|
285
309
|
|
286
310
|
stub(NotesStructuredTextJsonMessages).header_values(block, inet_field, :split_rfc822_addresses){["foo.mcfoo@foo.com", "bar.mcbar@bar.com"]}
|
287
311
|
stub(NotesStructuredTextJsonMessages).header_values(block, notes_field, :split_rfc822_addresses){nil}
|
@@ -289,13 +313,14 @@ EOF
|
|
289
313
|
mock(NotesStructuredTextJsonMessages).process_address("foo.mcfoo@foo.com")
|
290
314
|
mock(NotesStructuredTextJsonMessages).process_address("bar.mcbar@bar.com")
|
291
315
|
|
292
|
-
NotesStructuredTextJsonMessages.process_addresses(block, inet_field, notes_field)
|
316
|
+
NotesStructuredTextJsonMessages.process_addresses(block, inet_field, notes_field, options)
|
293
317
|
end
|
294
318
|
|
295
319
|
it "should call process_address if a notes header is present" do
|
296
320
|
inet_field = Object.new
|
297
321
|
notes_field = Object.new
|
298
322
|
block = Object.new
|
323
|
+
options={}
|
299
324
|
|
300
325
|
stub(NotesStructuredTextJsonMessages).header_values(block, inet_field, :split_rfc822_addresses){nil}
|
301
326
|
stub(NotesStructuredTextJsonMessages).header_values(block, notes_field, :split_rfc822_addresses){["CN=foo mcfoo/OU=main/O=foo", "CN=bar mcbar/OU=main/O=bar"]}
|
@@ -303,7 +328,7 @@ EOF
|
|
303
328
|
mock(NotesStructuredTextJsonMessages).process_address("CN=foo mcfoo/OU=main/O=foo")
|
304
329
|
mock(NotesStructuredTextJsonMessages).process_address("CN=bar mcbar/OU=main/O=bar")
|
305
330
|
|
306
|
-
NotesStructuredTextJsonMessages.process_addresses(block, inet_field, notes_field)
|
331
|
+
NotesStructuredTextJsonMessages.process_addresses(block, inet_field, notes_field, options)
|
307
332
|
end
|
308
333
|
|
309
334
|
end
|
@@ -320,7 +345,7 @@ EOF
|
|
320
345
|
output_stream = Object.new
|
321
346
|
mock(output_stream).<<(json_struct.to_json){output_stream}
|
322
347
|
|
323
|
-
mock(File).open("/a/b/c/d/#{MD5.hexdigest("foo123@foo.com")}", "w") do |fn,m,block|
|
348
|
+
mock(File).open("/a/b/c/d/#{MD5.hexdigest("foo123@foo.com")}.json", "w") do |fn,m,block|
|
324
349
|
block.call(output_stream)
|
325
350
|
end
|
326
351
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: notes-structured-text-json-messages
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 4
|
10
|
+
version: 0.1.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- craig mcmillan
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-04-
|
18
|
+
date: 2011-04-27 00:00:00 +01:00
|
19
19
|
default_executable: notes_structured_text_json_messages
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|