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
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 json_messages(output_dir, input_files, options={})
25
- reset_stats
26
- [*input_files].each do |input_file|
27
- File.open(input_file, "r") do |input|
28
- json_messages_from_stream(output_dir, input, options)
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
- stats.each do |k,v|
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
- { :name=>name,
142
- :notes_dn=>addr}
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
- { :name=>ta.name,
147
- :email_address=>ta.address.downcase}
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
- raise "no #{MESSAGE_ID}" if !message_id_h
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
- raise "no #{POSTED_DATE}" if !posted_date_h
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
- raise "no From:, or more than one From:" if !froms || froms.size>1
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
- raise "no recipients" if (to||[]).size + (cc||[]).size + (bcc||[]).size == 0
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 = Object.new
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: 25
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 1
10
- version: 0.1.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-26 00:00:00 +01:00
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