adhearsion-asterisk 0.1.0

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.
Files changed (33) hide show
  1. data/.gitignore +10 -0
  2. data/.rspec +3 -0
  3. data/CHANGELOG.md +14 -0
  4. data/Gemfile +6 -0
  5. data/Guardfile +5 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +143 -0
  8. data/Rakefile +23 -0
  9. data/adhearsion-asterisk.gemspec +35 -0
  10. data/lib/adhearsion-asterisk.rb +1 -0
  11. data/lib/adhearsion/asterisk.rb +12 -0
  12. data/lib/adhearsion/asterisk/config_generator.rb +103 -0
  13. data/lib/adhearsion/asterisk/config_generator/agents.rb +138 -0
  14. data/lib/adhearsion/asterisk/config_generator/queues.rb +247 -0
  15. data/lib/adhearsion/asterisk/config_generator/voicemail.rb +238 -0
  16. data/lib/adhearsion/asterisk/config_manager.rb +60 -0
  17. data/lib/adhearsion/asterisk/plugin.rb +464 -0
  18. data/lib/adhearsion/asterisk/queue_proxy.rb +177 -0
  19. data/lib/adhearsion/asterisk/queue_proxy/agent_proxy.rb +81 -0
  20. data/lib/adhearsion/asterisk/queue_proxy/queue_agents_list_proxy.rb +132 -0
  21. data/lib/adhearsion/asterisk/version.rb +5 -0
  22. data/spec/adhearsion/asterisk/config_generators/agents_spec.rb +258 -0
  23. data/spec/adhearsion/asterisk/config_generators/queues_spec.rb +322 -0
  24. data/spec/adhearsion/asterisk/config_generators/voicemail_spec.rb +306 -0
  25. data/spec/adhearsion/asterisk/config_manager_spec.rb +125 -0
  26. data/spec/adhearsion/asterisk/plugin_spec.rb +618 -0
  27. data/spec/adhearsion/asterisk/queue_proxy/agent_proxy_spec.rb +90 -0
  28. data/spec/adhearsion/asterisk/queue_proxy/queue_agents_list_proxy_spec.rb +145 -0
  29. data/spec/adhearsion/asterisk/queue_proxy_spec.rb +156 -0
  30. data/spec/adhearsion/asterisk_spec.rb +9 -0
  31. data/spec/spec_helper.rb +23 -0
  32. data/spec/support/the_following_code.rb +3 -0
  33. metadata +229 -0
@@ -0,0 +1,322 @@
1
+ require 'spec_helper'
2
+ require 'adhearsion/asterisk/config_generator/queues'
3
+
4
+ module QueuesConfigGeneratorTestHelper
5
+
6
+ def reset_queues!
7
+ @queues = Adhearsion::Asterisk::ConfigGenerator::Queues.new
8
+ end
9
+
10
+ def generated_config_should_have_pair(pair)
11
+ generated_config_has_pair(pair).should be true
12
+ end
13
+
14
+ def generated_config_has_pair(pair)
15
+ queues.to_s.split("\n").grep(/=[^>]/).each do |line|
16
+ key, value = line.strip.split('=')
17
+ return true if pair == {key.to_sym => value}
18
+ end
19
+ false
20
+ end
21
+ end
22
+
23
+ describe "The queues.conf config file generator" do
24
+
25
+ include QueuesConfigGeneratorTestHelper
26
+
27
+ attr_reader :queues
28
+ before(:each) do
29
+ reset_queues!
30
+ end
31
+
32
+ it 'should set autofill=yes by default' do
33
+ generated_config_should_have_pair :autofill => 'yes'
34
+ end
35
+
36
+ it 'should have a [general] section' do
37
+ queues.conf.should include "[general]\n"
38
+ end
39
+
40
+ it 'should yield a Queues object in its constructor' do
41
+ Adhearsion::Asterisk::ConfigGenerator::Queues.new do |config|
42
+ config.should be_a_kind_of Adhearsion::Asterisk::ConfigGenerator::Queues
43
+ end
44
+ end
45
+
46
+ it 'should add the warning message to the to_s output' do
47
+ queues.conf.should =~ /^\s*;.{10}/
48
+ end
49
+
50
+ end
51
+
52
+ describe "The queues.conf config file queues's QueueDefinition" do
53
+
54
+ include QueuesConfigGeneratorTestHelper
55
+
56
+ attr_reader :queues
57
+ before(:each) do
58
+ reset_queues!
59
+ end
60
+
61
+ it 'should include [queue_name]' do
62
+ name_of_queue = "leet_hax0rz"
63
+ queues.queue(name_of_queue).to_s.should include "[#{name_of_queue}]"
64
+ end
65
+
66
+ it '#member should create a valid Agent "channel driver" to the member definition list' do
67
+ sample_queue = queues.queue "sales" do |sales|
68
+ sales.member 123
69
+ sales.member "Jay"
70
+ sales.member 'SIP/jay-desk-650'
71
+ sales.member 'IAX2/12345@voipms/15554443333'
72
+ end
73
+ sample_queue.members.should == %w[Agent/123 Agent/Jay SIP/jay-desk-650 IAX2/12345@voipms/15554443333]
74
+ end
75
+
76
+ it 'should automatically enable the two AMI-related events' do
77
+ @queues = queues.queue 'name'
78
+ generated_config_should_have_pair :eventwhencalled => 'vars'
79
+ generated_config_should_have_pair :eventmemberstatus => 'yes'
80
+ end
81
+
82
+ it '#strategy should only allow the pre-defined settings' do
83
+ [:ringall, :roundrobin, :leastrecent, :fewestcalls, :random, :rrmemory].each do |strategy|
84
+ the_following_code {
85
+ q = queues.queue 'foobar'
86
+ q.strategy strategy
87
+ }.should_not raise_error
88
+ end
89
+
90
+ the_following_code {
91
+ queues.queue('qwerty').strategy :this_is_not_a_valid_strategy
92
+ }.should raise_error ArgumentError
93
+
94
+ end
95
+
96
+ it '#sound_files raises an argument error when it sees an unrecognized key' do
97
+ the_following_code {
98
+ queues.queue 'foobar' do |foobar|
99
+ foobar.sound_files \
100
+ :you_are_next => rand.to_s,
101
+ :there_are => rand.to_s,
102
+ :calls_waiting => rand.to_s,
103
+ :hold_time => rand.to_s,
104
+ :minutes => rand.to_s,
105
+ :seconds => rand.to_s,
106
+ :thank_you => rand.to_s,
107
+ :less_than => rand.to_s,
108
+ :report_hold => rand.to_s,
109
+ :periodic_announcement => rand.to_s
110
+ end
111
+ }.should_not raise_error
112
+
113
+ [:x_you_are_next, :x_there_are, :x_calls_waiting, :x_hold_time, :x_minutes,
114
+ :x_seconds, :x_thank_you, :x_less_than, :x_report_hold, :x_periodic_announcement].each do |bad_key|
115
+ the_following_code {
116
+ queues.queue("foobar") do |foobar|
117
+ foobar.sound_files bad_key => rand.to_s
118
+ end
119
+ }.should raise_error ArgumentError
120
+ end
121
+
122
+ end
123
+
124
+ end
125
+
126
+ describe "The private, helper methods in QueueDefinition" do
127
+
128
+ include QueuesConfigGeneratorTestHelper
129
+
130
+ attr_reader :queue
131
+ before(:each) do
132
+ reset_queues!
133
+ @queue = @queues.queue "doesn't matter"
134
+ end
135
+
136
+ it '#boolean should convert a boolean into "yes" or "no"' do
137
+ mock_of_properties = mock "mock of the properties instance variable of a QueueDefinition"
138
+ mock_of_properties.expects(:[]=).once.with("icanhascheezburger", "yes")
139
+ queue.expects(:properties).returns mock_of_properties
140
+ queue.send(:boolean, "icanhascheezburger" => true)
141
+ end
142
+
143
+ it '#int should raise an argument error when its argument is not Numeric' do
144
+ the_following_code {
145
+ queue.send(:int, "eisley" => :i_break_things!)
146
+ }.should raise_error ArgumentError
147
+ end
148
+
149
+ it '#int should coerce a String into a Numeric if possible' do
150
+ mock_of_properties = mock "mock of the properties instance variable of a QueueDefinition"
151
+ mock_of_properties.expects(:[]=).once.with("chimpanzee", 1337)
152
+ queue.expects(:properties).returns mock_of_properties
153
+ queue.send(:int, "chimpanzee" => "1337")
154
+ end
155
+
156
+ it '#string should add the argument directly to the properties' do
157
+ mock_of_properties = mock "mock of the properties instance variable of a QueueDefinition"
158
+ mock_of_properties.expects(:[]=).once.with("eins", "zwei")
159
+ queue.expects(:properties).returns mock_of_properties
160
+ queue.send(:string, "eins" => "zwei")
161
+ end
162
+
163
+ it '#one_of() should add its successful match to the properties attribute' do
164
+ mock_properties = mock "mock of the properties instance variable of a QueueDefinition"
165
+ mock_properties.expects(:[]=).once.with(:doesnt_matter, 5)
166
+ queue.expects(:properties).once.returns mock_properties
167
+ queue.send(:one_of, 1..100, :doesnt_matter => 5)
168
+ end
169
+
170
+ it "one_of() should convert booleans to yes/no" do
171
+ mock_properties = mock "mock of the properties instance variable of a QueueDefinition"
172
+ mock_properties.expects(:[]=).once.with(:doesnt_matter, 'yes')
173
+ queue.expects(:properties).once.returns mock_properties
174
+ queue.send(:one_of, [true, false, :strict], :doesnt_matter => true)
175
+
176
+ mock_properties = mock "mock of the properties instance variable of a QueueDefinition"
177
+ mock_properties.expects(:[]=).once.with(:doesnt_matter, :strict)
178
+ queue.expects(:properties).once.returns mock_properties
179
+ queue.send(:one_of, [true, false, :strict], :doesnt_matter => :strict)
180
+
181
+ mock_properties = mock "mock of the properties instance variable of a QueueDefinition"
182
+ mock_properties.expects(:[]=).once.with(:doesnt_matter, 'no')
183
+ queue.expects(:properties).once.returns mock_properties
184
+ queue.send(:one_of, [true, false, :strict], :doesnt_matter => false)
185
+ end
186
+
187
+ it '#one_of() should raise an ArgumentError if a value is not in the criteria' do
188
+ the_following_code {
189
+ queue.send(:one_of, [:jay, :thomas, :phillips], :sister => :jill)
190
+ }.should raise_error ArgumentError
191
+ end
192
+ end
193
+
194
+ describe 'The queues.conf config file generator when ran against a really big example' do
195
+
196
+ include QueuesConfigGeneratorTestHelper
197
+
198
+ attr_reader :queues, :default_config
199
+ before(:each) do
200
+ reset_queues!
201
+ @default_config = default_config = <<-CONFIG
202
+ [general]
203
+ persistentmembers=yes
204
+ autofill=yes
205
+ monitor-type=MixMonitor
206
+
207
+ [markq]
208
+ musicclass=default
209
+ announce=queue-markq
210
+ strategy=ringall
211
+ servicelevel=60
212
+ context=qoutcon
213
+ timeout=15
214
+ retry=5
215
+ weight=0
216
+ wrapuptime=15
217
+ autofill=yes
218
+ autopause=yes
219
+ maxlen=0
220
+ setinterfacevar=yes
221
+ announce-frequency=90
222
+ periodic-announce-frequency=60
223
+ announce-holdtime=once
224
+ announce-round-seconds=10
225
+ queue-youarenext=queue-youarenext
226
+ queue-thereare=queue-thereare
227
+ queue-callswaiting=queue-callswaiting
228
+ queue-holdtime=queue-holdtime
229
+ queue-minutes=queue-minutes
230
+ queue-seconds=queue-seconds
231
+ queue-thankyou=queue-thankyou
232
+ queue-lessthan=queue-less-than
233
+ queue-reporthold=queue-reporthold
234
+ periodic-announce=queue-periodic-announce
235
+ monitor-format=gsm
236
+ monitor-type=MixMonitor
237
+ joinempty=yes
238
+ leavewhenempty=yes
239
+ eventwhencalled=vars
240
+ eventmemberstatus=yes
241
+ reportholdtime=no
242
+ ringinuse=no
243
+ memberdelay=0
244
+ timeoutrestart=no
245
+
246
+ member => Zap/1
247
+ member => Agent/007
248
+ CONFIG
249
+ end
250
+
251
+ it "a sample config with multiple queues" do
252
+
253
+ generated = Adhearsion::Asterisk::ConfigGenerator::Queues.new do |config|
254
+ config.persistent_members true
255
+ config.monitor_type :mix_monitor
256
+
257
+ config.queue 'markq' do |markq|
258
+ markq.music_class :default
259
+ markq.play_on_connect 'queue-markq'
260
+ markq.strategy :ringall
261
+ markq.service_level 60
262
+ markq.exit_to_context_on_digit_press 'qoutcon'
263
+ markq.ring_timeout 15
264
+ markq.retry_after_waiting 5
265
+ markq.weight 0
266
+ markq.wrapup_time 15
267
+ markq.autopause true
268
+ markq.maximum_length 0
269
+ markq.queue_status_announce_frequency 90
270
+ markq.announce_hold_time :once
271
+ markq.announce_round_seconds 10
272
+ markq.sound_files \
273
+ :you_are_next => "queue-youarenext",
274
+ :there_are => "queue-thereare",
275
+ :calls_waiting => "queue-callswaiting",
276
+ :hold_time => "queue-holdtime",
277
+ :minutes => "queue-minutes",
278
+ :seconds => "queue-seconds",
279
+ :thank_you => "queue-thankyou",
280
+ :less_than => "queue-less-than",
281
+ :report_hold => "queue-reporthold"
282
+ markq.periodically_announce "queue-periodic-announce"
283
+ markq.monitor_format :gsm
284
+ markq.monitor_type :mix_monitor
285
+ markq.join_empty true
286
+ markq.leave_when_empty true
287
+ markq.report_hold_time false
288
+ markq.ring_in_use false
289
+ markq.delay_connection_by 0
290
+ markq.timeout_restart false
291
+
292
+ markq.member 'Zap/1'
293
+ markq.member '007'
294
+ end
295
+ end
296
+
297
+ cleaned_up_default_config =
298
+ Adhearsion::Asterisk::ConfigGenerator.create_sanitary_hash_from(default_config)
299
+
300
+ cleaned_up_generated_config = generated.to_sanitary_hash
301
+
302
+ cleaned_up_generated_config.should == cleaned_up_default_config
303
+ end
304
+
305
+ end
306
+
307
+ describe "ConfigGeneratorTestHelper" do
308
+
309
+ include QueuesConfigGeneratorTestHelper
310
+
311
+ attr_reader :queues
312
+
313
+ it "generated_config_has_pair() works properly" do
314
+ @queues = mock "A fake queues with just one pair", :to_s => "foo=bar"
315
+ generated_config_has_pair(:foo => "bar").should be true
316
+
317
+ @queues = mock "A fake queues with just one pair"
318
+ @queues.expects(:to_s).twice.returns("[general]\n\nqaz=qwerty\nagent => 1,2,3")
319
+ generated_config_has_pair(:qaz => "qwerty").should be true
320
+ generated_config_has_pair(:foo => "bar").should be false
321
+ end
322
+ end
@@ -0,0 +1,306 @@
1
+ require 'spec_helper'
2
+ require 'adhearsion/asterisk/config_generator/voicemail'
3
+
4
+ describe 'Basic requirements of the Voicemail config generator' do
5
+ attr_reader :config
6
+ before :each do
7
+ @config = Adhearsion::Asterisk::ConfigGenerator::Voicemail.new
8
+ end
9
+
10
+ it 'should have a [general] context' do
11
+ config.to_sanitary_hash.has_key?('[general]').should be true
12
+ end
13
+
14
+ it 'should set the format to "wav" by default in the general section' do
15
+ config.to_sanitary_hash['[general]'].should include 'format=wav'
16
+ end
17
+
18
+ it 'an exception should be raised if the context name is "general"' do
19
+ the_following_code {
20
+ config.context(:general) {|_|}
21
+ }.should raise_error ArgumentError
22
+ end
23
+
24
+ end
25
+
26
+ describe 'Defining recording-related settings of the Voicemail config file' do
27
+
28
+ attr_reader :recordings
29
+ before :each do
30
+ @recordings = Adhearsion::Asterisk::ConfigGenerator::Voicemail::RecordingDefinition.new
31
+ end
32
+
33
+ it 'the recordings setting setter' do
34
+ Adhearsion::Asterisk::ConfigGenerator::Voicemail.new.recordings.should be_a_kind_of recordings.class
35
+ end
36
+
37
+ it 'recordings format should only allow a few options' do
38
+ the_following_code {
39
+ recordings.format :wav
40
+ recordings.format :wav49
41
+ recordings.format :gsm
42
+ }.should_not raise_error
43
+
44
+ the_following_code {
45
+ recordings.format :lolcats
46
+ }.should raise_error ArgumentError
47
+ end
48
+
49
+ end
50
+
51
+ describe 'Defining email-related Voicemail settings' do
52
+
53
+ attr_reader :email
54
+ before :each do
55
+ @email = Adhearsion::Asterisk::ConfigGenerator::Voicemail::EmailDefinition.new
56
+ end
57
+
58
+ it 'the [] operator is overloaded to return conveniences for the body() and subject() methods' do
59
+ variables = %{#{email[:name]} #{email[:mailbox]} #{email[:date]} #{email[:duration]} } +
60
+ %{#{email[:message_number]} #{email[:caller_id]} #{email[:caller_id_number]} } +
61
+ %{#{email[:caller_id_name]}}
62
+ formatted = %{${VM_NAME} ${VM_MAILBOX} ${VM_DATE} ${VM_DUR} ${VM_MSGNUM} ${VM_CALLERID} ${VM_CIDNUM} ${VM_CIDNAME}}
63
+ email.body variables
64
+ email.subject variables
65
+ email.properties[:emailbody].should == formatted
66
+ email.properties[:emailsubject].should == formatted
67
+ end
68
+
69
+ it 'when defining a body, newlines should be escaped and carriage returns removed' do
70
+ unescaped, escaped = "one\ntwo\n\r\r\nthree\n\n\n", 'one\ntwo\n\nthree\n\n\n'
71
+ email.body unescaped
72
+ email.properties[:emailbody].should == escaped
73
+ end
74
+
75
+ it 'the body must not be allowed to exceed 512 characters' do
76
+ the_following_code {
77
+ email.body "X" * 512
78
+ }.should_not raise_error ArgumentError
79
+
80
+ the_following_code {
81
+ email.body "X" * 513
82
+ }.should raise_error ArgumentError
83
+
84
+ the_following_code {
85
+ email.body "X" * 1000
86
+ }.should raise_error ArgumentError
87
+ end
88
+
89
+ it 'should store away the email command properly' do
90
+ mail_command = "/usr/sbin/sendmail -f alice@wonderland.com -t"
91
+ email.command mail_command
92
+ email.properties[:mailcmd].should == mail_command
93
+ end
94
+
95
+ end
96
+
97
+ describe 'A mailbox definition' do
98
+ attr_reader :mailbox
99
+ before :each do
100
+ @mailbox = Adhearsion::Asterisk::ConfigGenerator::Voicemail::ContextDefinition::MailboxDefinition.new("123")
101
+ end
102
+
103
+ it 'setting the name should be reflected in the to_hash form of the definition' do
104
+ mailbox.name "Foobar"
105
+ mailbox.to_hash[:name].should == "Foobar"
106
+ end
107
+
108
+ it 'setting the pin_number should be reflected in the to_hash form of the definition' do
109
+ mailbox.pin_number 555
110
+ mailbox.to_hash[:pin_number].should == 555
111
+ end
112
+
113
+ it 'the mailbox number should be available in the mailbox_number getter' do
114
+ Adhearsion::Asterisk::ConfigGenerator::Voicemail::ContextDefinition::MailboxDefinition.new '123'
115
+ mailbox.mailbox_number.should == '123'
116
+ end
117
+
118
+ it 'an ArgumentError should be raised if the mailbox_number is not numeric' do
119
+ the_following_code {
120
+ Adhearsion::Asterisk::ConfigGenerator::Voicemail::ContextDefinition::MailboxDefinition.new("this is not numeric")
121
+ }.should raise_error ArgumentError
122
+ end
123
+
124
+ it 'an ArgumentError should be raised if the pin_number is not numeric' do
125
+ the_following_code {
126
+ mailbox.pin_number "this is not numeric"
127
+ }.should raise_error ArgumentError
128
+ end
129
+
130
+ it "the string representation should be valid" do
131
+ expected = "123 => 1337,Jay Phillips,ahn@adhearsion.com"
132
+ mailbox.pin_number 1337
133
+ mailbox.name "Jay Phillips"
134
+ mailbox.email "ahn@adhearsion.com"
135
+ mailbox.to_s.should == expected
136
+ end
137
+
138
+ it 'should not add a trailing comma when the email is left out' do
139
+ mailbox.pin_number 1337
140
+ mailbox.name "Jay Phillips"
141
+ mailbox.to_s.ends_with?(',').should be false
142
+ end
143
+
144
+ it 'should not add a trailing comma when the email and name is left out' do
145
+ mailbox.pin_number 1337
146
+ mailbox.to_s.ends_with?(',').should be false
147
+ end
148
+
149
+ end
150
+
151
+ describe "A Voicemail context definition" do
152
+
153
+ it "should ultimately add a [] context definition to the string output" do
154
+ voicemail = Adhearsion::Asterisk::ConfigGenerator::Voicemail.new
155
+ voicemail.context "monkeys" do |config|
156
+ config.should be_a_kind_of voicemail.class::ContextDefinition
157
+ config.mailbox 1234 do |mailbox|
158
+ mailbox.pin_number 3333
159
+ mailbox.email "alice@wonderland.com"
160
+ mailbox.name "Alice Little"
161
+ end
162
+ end
163
+ voicemail.to_sanitary_hash.has_key?('[monkeys]').should be true
164
+ end
165
+
166
+ it 'should raise a LocalJumpError if no block is given' do
167
+ the_following_code {
168
+ Adhearsion::Asterisk::ConfigGenerator::Voicemail.new.context('lols')
169
+ }.should raise_error LocalJumpError
170
+ end
171
+
172
+ it 'its string representation should begin with a context declaration' do
173
+ vm = Adhearsion::Asterisk::ConfigGenerator::Voicemail.new
174
+ vm.context("jay") {|_|}.to_s.starts_with?("[jay]").should be true
175
+ end
176
+
177
+ end
178
+
179
+ describe 'Defining Voicemail contexts with mailbox definitions' do
180
+
181
+ end
182
+
183
+ describe 'An expansive example of the Voicemail config generator' do
184
+
185
+ before :each do
186
+ @employees = [
187
+ {:name => "Tango", :pin_number => 7777, :mailbox_number => 10},
188
+ {:name => "Echo", :pin_number => 7777, :mailbox_number => 20},
189
+ {:name => "Sierra", :pin_number => 7777, :mailbox_number => 30},
190
+ {:name => "Tango2", :pin_number => 7777, :mailbox_number => 40}
191
+ ].map { |hash| OpenStruct.new(hash) }
192
+
193
+ @groups = [
194
+ {:name => "Brand New Cadillac", :pin_number => 1111, :mailbox_number => 1},
195
+ {:name => "Jimmy Jazz", :pin_number => 2222, :mailbox_number => 2},
196
+ {:name => "Death or Glory", :pin_number => 3333, :mailbox_number => 3},
197
+ {:name => "Rudie Can't Fail", :pin_number => 4444, :mailbox_number => 4},
198
+ {:name => "Spanish Bombs", :pin_number => 5555, :mailbox_number => 5}
199
+ ].map { |hash| OpenStruct.new(hash) }
200
+ end
201
+
202
+ it 'a huge, brittle integration test' do
203
+ vm = Adhearsion::Asterisk::ConfigGenerator::Voicemail.new do |voicemail|
204
+ voicemail.context :default do |context|
205
+ context.mailbox 123 do |mailbox|
206
+ mailbox.name "Administrator"
207
+ mailbox.email "jabberwocky@wonderland.com"
208
+ mailbox.pin_number 9876
209
+ end
210
+ end
211
+
212
+ voicemail.context :employees do |context|
213
+ @employees.each do |employee|
214
+ context.mailbox employee.mailbox_number do |mailbox|
215
+ mailbox.pin_number 1337
216
+ mailbox.name employee.name
217
+ end
218
+ end
219
+ end
220
+
221
+ voicemail.context :groups do |context|
222
+ @groups.each do |group|
223
+ context.mailbox group.mailbox_number do |mailbox|
224
+ mailbox.pin_number 1337
225
+ mailbox.name group.name
226
+ mailbox.email "foo@qaz.org"
227
+ end
228
+ end
229
+ end
230
+
231
+ voicemail.execute_on_pin_change "/path/to/my/changer_script.rb"
232
+ ############################################################################
233
+ ############################################################################
234
+
235
+ signature = "Your Friendly Phone System"
236
+
237
+ # execute_after_email "netcat 192.168.1.2 12345"
238
+ # greeting_maximum 1.minute
239
+ # time_jumped_with_skip_key 3.seconds # milliseconds!
240
+ # logging_in do |config|
241
+ # config.maximum_attempts 3
242
+ # end
243
+
244
+ voicemail.recordings do |config|
245
+ config.format :wav # ONCE YOU PICK A FORMAT, NEVER CHANGE IT UNLESS YOU KNOW THE CONSEQUENCES!
246
+ config.allowed_length 3.seconds..5.minutes
247
+ config.maximum_silence 10.seconds
248
+ # config.silence_threshold 128 # wtf?
249
+ end
250
+
251
+ voicemail.emails do |config|
252
+ config.from :name => signature, :email => "noreply@adhearsion.com"
253
+ config.attach_recordings true
254
+ config.command '/usr/sbin/sendmail -f alice@wonderland.com -t'
255
+ config.subject "New voicemail for #{config[:name]}"
256
+ config.body <<-BODY.strip_heredoc
257
+ Dear #{config[:name]}:
258
+
259
+ The caller #{config[:caller_id]} left you a #{config[:duration]} long voicemail
260
+ (number #{config[:message_number]}) on #{config[:date]} in mailbox #{config[:mailbox]}.
261
+
262
+ #{ "The recording is attached to this email.\n" if config.attach_recordings? }
263
+ - #{signature}
264
+ BODY
265
+ end
266
+ end
267
+ internalized = vm.to_sanitary_hash
268
+ internalized.size.should == 5 # general, zonemessages, default, employees, groups
269
+
270
+ target_config = <<-CONFIG
271
+ [general]
272
+ attach=yes
273
+ emailbody=Dear ${VM_NAME}:\\n\\nThe caller ${VM_CALLERID} left you a ${VM_DUR} long voicemail\\n(number ${VM_MSGNUM}) on ${VM_DATE} in mailbox ${VM_MAILBOX}.\\n\\nThe recording is attached to this email.\\n\\n- Your Friendly Phone System\\n
274
+ emailsubject=New voicemail for ${VM_NAME}
275
+ externpass=/path/to/my/changer_script.rb
276
+ format=wav
277
+ fromstring=Your Friendly Phone System
278
+ mailcmd=/usr/sbin/sendmail -f alice@wonderland.com -t
279
+ serveremail=noreply@adhearsion.com
280
+
281
+ [zonemessages]
282
+ eastern=America/New_York|'vm-received' Q 'digits/at' IMp
283
+ central=America/Chicago|'vm-received' Q 'digits/at' IMp
284
+ central24=America/Chicago|'vm-received' q 'digits/at' H N 'hours'
285
+ military=Zulu|'vm-received' q 'digits/at' H N 'hours' 'phonetic/z_p'
286
+ european=Europe/Copenhagen|'vm-received' a d b 'digits/at' HM
287
+ [default]
288
+ 123 => 9876,Administrator,jabberwocky@wonderland.com
289
+
290
+ [employees]
291
+ 10 => 1337,Tango
292
+ 20 => 1337,Echo
293
+ 30 => 1337,Sierra
294
+ 40 => 1337,Tango2
295
+
296
+ [groups]
297
+ 1 => 1337,Brand New Cadillac,foo@qaz.org
298
+ 2 => 1337,Jimmy Jazz,foo@qaz.org
299
+ 3 => 1337,Death or Glory,foo@qaz.org
300
+ 4 => 1337,Rudie Can't Fail,foo@qaz.org
301
+ 5 => 1337,Spanish Bombs,foo@qaz.org
302
+ CONFIG
303
+ vm.to_s.split("\n").grep(/^$|^[^;]/).join("\n").strip.should == target_config.strip
304
+
305
+ end
306
+ end