notes-structured-text-json-messages 0.1.1 → 0.1.4
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.
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
|