sevenscale-adhearsion 0.7.1000

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 (150) hide show
  1. data/CHANGELOG +3 -0
  2. data/LICENSE +456 -0
  3. data/Manifest.txt +149 -0
  4. data/README.txt +6 -0
  5. data/Rakefile +48 -0
  6. data/ahn_generators/component/USAGE +5 -0
  7. data/ahn_generators/component/component_generator.rb +57 -0
  8. data/ahn_generators/component/templates/configuration.rb +0 -0
  9. data/ahn_generators/component/templates/lib/lib.rb.erb +3 -0
  10. data/ahn_generators/component/templates/test/test.rb.erb +12 -0
  11. data/ahn_generators/component/templates/test/test_helper.rb +14 -0
  12. data/app_generators/ahn/USAGE +5 -0
  13. data/app_generators/ahn/ahn_generator.rb +76 -0
  14. data/app_generators/ahn/templates/.ahnrc +12 -0
  15. data/app_generators/ahn/templates/README +8 -0
  16. data/app_generators/ahn/templates/Rakefile +3 -0
  17. data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
  18. data/app_generators/ahn/templates/components/simon_game/lib/simon_game.rb +61 -0
  19. data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +14 -0
  20. data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +31 -0
  21. data/app_generators/ahn/templates/config/startup.rb +53 -0
  22. data/app_generators/ahn/templates/dialplan.rb +4 -0
  23. data/bin/ahn +28 -0
  24. data/bin/ahnctl +68 -0
  25. data/bin/jahn +32 -0
  26. data/lib/adhearsion/blank_slate.rb +5 -0
  27. data/lib/adhearsion/cli.rb +106 -0
  28. data/lib/adhearsion/component_manager.rb +277 -0
  29. data/lib/adhearsion/core_extensions/all.rb +9 -0
  30. data/lib/adhearsion/core_extensions/array.rb +0 -0
  31. data/lib/adhearsion/core_extensions/custom_daemonizer.rb +45 -0
  32. data/lib/adhearsion/core_extensions/global.rb +1 -0
  33. data/lib/adhearsion/core_extensions/guid.rb +5 -0
  34. data/lib/adhearsion/core_extensions/hash.rb +0 -0
  35. data/lib/adhearsion/core_extensions/metaprogramming.rb +17 -0
  36. data/lib/adhearsion/core_extensions/numeric.rb +4 -0
  37. data/lib/adhearsion/core_extensions/proc.rb +0 -0
  38. data/lib/adhearsion/core_extensions/pseudo_uuid.rb +11 -0
  39. data/lib/adhearsion/core_extensions/publishable.rb +73 -0
  40. data/lib/adhearsion/core_extensions/relationship_properties.rb +40 -0
  41. data/lib/adhearsion/core_extensions/string.rb +26 -0
  42. data/lib/adhearsion/core_extensions/thread.rb +13 -0
  43. data/lib/adhearsion/core_extensions/thread_safety.rb +7 -0
  44. data/lib/adhearsion/core_extensions/time.rb +0 -0
  45. data/lib/adhearsion/distributed/gateways/dbus_gateway.rb +0 -0
  46. data/lib/adhearsion/distributed/gateways/osa_gateway.rb +0 -0
  47. data/lib/adhearsion/distributed/gateways/rest_gateway.rb +9 -0
  48. data/lib/adhearsion/distributed/gateways/soap_gateway.rb +9 -0
  49. data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +9 -0
  50. data/lib/adhearsion/distributed/peer_finder.rb +0 -0
  51. data/lib/adhearsion/distributed/remote_cli.rb +0 -0
  52. data/lib/adhearsion/hooks.rb +57 -0
  53. data/lib/adhearsion/host_definitions.rb +63 -0
  54. data/lib/adhearsion/initializer/asterisk.rb +59 -0
  55. data/lib/adhearsion/initializer/configuration.rb +202 -0
  56. data/lib/adhearsion/initializer/database.rb +92 -0
  57. data/lib/adhearsion/initializer/drb.rb +25 -0
  58. data/lib/adhearsion/initializer/freeswitch.rb +22 -0
  59. data/lib/adhearsion/initializer/paths.rb +55 -0
  60. data/lib/adhearsion/initializer/rails.rb +40 -0
  61. data/lib/adhearsion/initializer.rb +217 -0
  62. data/lib/adhearsion/logging.rb +92 -0
  63. data/lib/adhearsion/services/scheduler.rb +5 -0
  64. data/lib/adhearsion/tasks/database.rb +5 -0
  65. data/lib/adhearsion/tasks/generating.rb +20 -0
  66. data/lib/adhearsion/tasks/lint.rb +4 -0
  67. data/lib/adhearsion/tasks/testing.rb +37 -0
  68. data/lib/adhearsion/tasks.rb +15 -0
  69. data/lib/adhearsion/version.rb +9 -0
  70. data/lib/adhearsion/voip/asterisk/agi_server.rb +78 -0
  71. data/lib/adhearsion/voip/asterisk/ami/actions.rb +238 -0
  72. data/lib/adhearsion/voip/asterisk/ami/machine.rb +871 -0
  73. data/lib/adhearsion/voip/asterisk/ami/machine.rl +109 -0
  74. data/lib/adhearsion/voip/asterisk/ami/parser.rb +262 -0
  75. data/lib/adhearsion/voip/asterisk/ami.rb +147 -0
  76. data/lib/adhearsion/voip/asterisk/commands.rb +1186 -0
  77. data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +140 -0
  78. data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +101 -0
  79. data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +250 -0
  80. data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +240 -0
  81. data/lib/adhearsion/voip/asterisk/config_manager.rb +71 -0
  82. data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +80 -0
  83. data/lib/adhearsion/voip/asterisk.rb +4 -0
  84. data/lib/adhearsion/voip/call.rb +402 -0
  85. data/lib/adhearsion/voip/call_routing.rb +64 -0
  86. data/lib/adhearsion/voip/commands.rb +9 -0
  87. data/lib/adhearsion/voip/constants.rb +39 -0
  88. data/lib/adhearsion/voip/conveniences.rb +18 -0
  89. data/lib/adhearsion/voip/dial_plan.rb +205 -0
  90. data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +37 -0
  91. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +151 -0
  92. data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +27 -0
  93. data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +124 -0
  94. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +75 -0
  95. data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +16 -0
  96. data/lib/adhearsion/voip/dsl/numerical_string.rb +117 -0
  97. data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +48 -0
  98. data/lib/adhearsion/voip/freeswitch/event_handler.rb +58 -0
  99. data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +129 -0
  100. data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +38 -0
  101. data/lib/adhearsion/voip/freeswitch/oes_server.rb +195 -0
  102. data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +80 -0
  103. data/lib/adhearsion/voip/menu_state_machine/matchers.rb +123 -0
  104. data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +58 -0
  105. data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +149 -0
  106. data/lib/adhearsion.rb +31 -0
  107. data/script/destroy +14 -0
  108. data/script/generate +14 -0
  109. data/spec/fixtures/dialplan.rb +3 -0
  110. data/spec/initializer/test_configuration.rb +267 -0
  111. data/spec/initializer/test_loading.rb +162 -0
  112. data/spec/initializer/test_paths.rb +43 -0
  113. data/spec/silence.rb +10 -0
  114. data/spec/test_ahn_command.rb +149 -0
  115. data/spec/test_code_quality.rb +87 -0
  116. data/spec/test_component_manager.rb +97 -0
  117. data/spec/test_constants.rb +8 -0
  118. data/spec/test_drb.rb +104 -0
  119. data/spec/test_helper.rb +94 -0
  120. data/spec/test_hooks.rb +37 -0
  121. data/spec/test_host_definitions.rb +79 -0
  122. data/spec/test_initialization.rb +105 -0
  123. data/spec/test_logging.rb +80 -0
  124. data/spec/test_relationship_properties.rb +54 -0
  125. data/spec/voip/asterisk/ami_response_definitions.rb +23 -0
  126. data/spec/voip/asterisk/config_file_generators/test_agents.rb +253 -0
  127. data/spec/voip/asterisk/config_file_generators/test_queues.rb +325 -0
  128. data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +306 -0
  129. data/spec/voip/asterisk/menu_command/test_calculated_match.rb +111 -0
  130. data/spec/voip/asterisk/menu_command/test_matchers.rb +98 -0
  131. data/spec/voip/asterisk/mock_ami_server.rb +176 -0
  132. data/spec/voip/asterisk/test_agi_server.rb +453 -0
  133. data/spec/voip/asterisk/test_ami.rb +227 -0
  134. data/spec/voip/asterisk/test_commands.rb +2006 -0
  135. data/spec/voip/asterisk/test_config_manager.rb +129 -0
  136. data/spec/voip/dsl/dispatcher_spec_helper.rb +45 -0
  137. data/spec/voip/dsl/test_dialing_dsl.rb +268 -0
  138. data/spec/voip/dsl/test_dispatcher.rb +82 -0
  139. data/spec/voip/dsl/test_parser.rb +87 -0
  140. data/spec/voip/freeswitch/test_basic_connection_manager.rb +39 -0
  141. data/spec/voip/freeswitch/test_inbound_connection_manager.rb +39 -0
  142. data/spec/voip/freeswitch/test_oes_server.rb +9 -0
  143. data/spec/voip/test_call_routing.rb +127 -0
  144. data/spec/voip/test_dialplan_manager.rb +372 -0
  145. data/spec/voip/test_numerical_string.rb +48 -0
  146. data/spec/voip/test_phone_number.rb +36 -0
  147. data/test/test_ahn_generator.rb +59 -0
  148. data/test/test_component_generator.rb +52 -0
  149. data/test/test_generator_helper.rb +20 -0
  150. metadata +254 -0
@@ -0,0 +1,402 @@
1
+ require 'uri'
2
+ #TODO Some of this is asterisk-specific
3
+ module Adhearsion
4
+ class << self
5
+ def active_calls
6
+ @calls ||= Calls.new
7
+ end
8
+
9
+ def receive_call_from(io, &block)
10
+ active_calls << (call = Call.receive_from(io, &block))
11
+ call
12
+ end
13
+
14
+ def remove_inactive_call(call)
15
+ active_calls.remove_inactive_call(call)
16
+ end
17
+ end
18
+
19
+ ##
20
+ # This manages the list of calls the Adhearsion service receives
21
+ class Calls
22
+ def initialize
23
+ @semaphore = Monitor.new
24
+ @calls = {}
25
+ end
26
+
27
+ def <<(call)
28
+ atomically do
29
+ calls[call.unique_identifier] = call
30
+ end
31
+ end
32
+
33
+ def any?
34
+ atomically do
35
+ !calls.empty?
36
+ end
37
+ end
38
+
39
+ def size
40
+ atomically do
41
+ calls.size
42
+ end
43
+ end
44
+
45
+ def remove_inactive_call(call)
46
+ atomically do
47
+ calls.delete call.unique_identifier
48
+ end
49
+ end
50
+
51
+ # Searches all active calls by their unique_identifier. See Call#unique_identifier.
52
+ def find(id)
53
+ atomically do
54
+ return calls[id]
55
+ end
56
+ end
57
+
58
+ def clear!
59
+ atomically do
60
+ calls.clear
61
+ end
62
+ end
63
+
64
+ private
65
+ attr_reader :semaphore, :calls
66
+
67
+ def atomically(&block)
68
+ semaphore.synchronize(&block)
69
+ end
70
+
71
+ end
72
+
73
+ class UselessCallException < Exception; end
74
+
75
+ class MetaAgiCallException < Exception
76
+ attr_reader :call
77
+ def initialize(call)
78
+ super()
79
+ @call = call
80
+ end
81
+ end
82
+
83
+
84
+ class FailedExtensionCallException < MetaAgiCallException; end
85
+
86
+ class HungupExtensionCallException < MetaAgiCallException; end
87
+
88
+ ##
89
+ # Encapsulates call-related data and behavior.
90
+ # For example, variables passed in on call initiation are
91
+ # accessible here as attributes
92
+ class Call
93
+
94
+ # This is basically a translation of ast_channel_reason2str() from main/channel.c and
95
+ # ast_control_frame_type in include/asterisk/frame.h in the Asterisk source code. When
96
+ # Asterisk jumps to the 'failed' extension, it sets a REASON channel variable to a number.
97
+ # The indexes of these symbols represent the possible numbers REASON could be.
98
+ ASTERISK_FRAME_STATES = [
99
+ :failure, # "Call Failure (not BUSY, and not NO_ANSWER, maybe Circuit busy or down?)"
100
+ :hangup, # Other end has hungup
101
+ :ring, # Local ring
102
+ :ringing, # Remote end is ringing
103
+ :answer, # Remote end has answered
104
+ :busy, # Remote end is busy
105
+ :takeoffhook, # Make it go off hook
106
+ :offhook, # Line is off hook
107
+ :congestion, # Congestion (circuits busy)
108
+ :flash, # Flash hook
109
+ :wink, # Wink
110
+ :option, # Set a low-level option
111
+ :radio_key, # Key Radio
112
+ :radio_unkey, # Un-Key Radio
113
+ :progress, # Indicate PROGRESS
114
+ :proceeding, # Indicate CALL PROCEEDING
115
+ :hold, # Indicate call is placed on hold
116
+ :unhold, # Indicate call is left from hold
117
+ :vidupdate # Indicate video frame update
118
+ ]
119
+
120
+
121
+ class << self
122
+ ##
123
+ # The primary public interface for creating a Call instance.
124
+ # Given an IO (probably a socket accepted from an Asterisk service),
125
+ # creates a Call instance which encapsulates everything we know about that call.
126
+ def receive_from(io, &block)
127
+ returning new(io, variable_parser_for(io).variables) do |call|
128
+ block.call(call) if block
129
+ end
130
+ end
131
+
132
+ private
133
+ def variable_parser_for(io)
134
+ Variables::Parser.parse(io)
135
+ end
136
+
137
+ end
138
+
139
+ attr_accessor :io, :type, :variables, :originating_voip_platform, :inbox
140
+ def initialize(io, variables)
141
+ @io, @variables = io, variables.symbolize_keys
142
+ check_if_valid_call
143
+ define_variable_accessors
144
+ set_originating_voip_platform!
145
+ end
146
+
147
+ def deliver_message(message)
148
+ inbox << message
149
+ end
150
+ alias << deliver_message
151
+
152
+ def inbox
153
+ @inbox ||= Queue.new
154
+ end
155
+
156
+ def hangup!
157
+ io.close
158
+ Adhearsion.remove_inactive_call self
159
+ end
160
+
161
+ def closed?
162
+ io.closed?
163
+ end
164
+
165
+ # Asterisk sometimes uses the "failed" extension to indicate a failed dial attempt.
166
+ # Since it may be important to handle these, this flag helps the dialplan Manager
167
+ # figure that out.
168
+ def failed_call?
169
+ @failed_call
170
+ end
171
+
172
+ def hungup_call?
173
+ @hungup_call
174
+ end
175
+
176
+ # Adhearsion indexes calls by this identifier so they may later be found and manipulated. For calls from Asterisk, this
177
+ # method uses the following properties for uniqueness, falling back to the next if one is for some reason unavailable:
178
+ #
179
+ # Asterisk channel ID -> unique ID -> Call#object_id
180
+ # (e.g. SIP/mytrunk-jb12c88a) -> (e.g. 1215039989.47033) -> (e.g. 2792080)
181
+ #
182
+ # Note: channel is used over unique ID because channel may be used to bridge two channels together.
183
+ def unique_identifier
184
+ case originating_voip_platform
185
+ when :asterisk
186
+ variables[:channel] || variables[:uniqueid] || object_id
187
+ else
188
+ raise NotImplementedError
189
+ end
190
+ end
191
+
192
+ def define_variable_accessors(recipient=self)
193
+ variables.each do |key, value|
194
+ define_singleton_accessor_with_pair(key, value, recipient)
195
+ end
196
+ end
197
+
198
+ def extract_failed_reason_from(environment)
199
+ if originating_voip_platform == :asterisk
200
+ failed_reason = environment.variable 'REASON'
201
+ failed_reason &&= ASTERISK_FRAME_STATES[failed_reason.to_i]
202
+ define_singleton_accessor_with_pair(:failed_reason, failed_reason, environment)
203
+ end
204
+ end
205
+
206
+ private
207
+
208
+ def define_singleton_accessor_with_pair(key, value, recipient=self)
209
+ recipient.metaclass.send :attr_accessor, key unless recipient.class.respond_to?("#{key}=")
210
+ recipient.send "#{key}=", value
211
+ end
212
+
213
+ def check_if_valid_call
214
+ extension = variables[:extension]
215
+ @failed_call = true if extension == 'failed'
216
+ @hungup_call = true if extension == 'h'
217
+ raise UselessCallException if extension == 't' # TODO: Move this whole method to Manager
218
+ end
219
+
220
+ def set_originating_voip_platform!
221
+ # TODO: we can make this determination programatically at some point,
222
+ # but it will probably involve a bit more engineering than just a case statement (like
223
+ # subclasses of Call for the various platforms), so we'll be totally cheap for now.
224
+ self.originating_voip_platform = :asterisk
225
+ end
226
+
227
+ module Variables
228
+
229
+ module Coercions
230
+
231
+ COERCION_ORDER = %w{
232
+ remove_agi_prefixes_from_keys_and_strip_whitespace
233
+ coerce_keys_into_symbols
234
+ coerce_extension_into_phone_number_object
235
+ coerce_numerical_values_to_numerics
236
+ replace_unknown_values_with_nil
237
+ replace_yes_no_answers_with_booleans
238
+ coerce_request_into_uri_object
239
+ decompose_uri_query_into_hash
240
+ override_variables_with_query_params
241
+ remove_dashes_from_context_name
242
+ coerce_type_of_number_into_symbol
243
+ }
244
+
245
+ class << self
246
+
247
+ def remove_agi_prefixes_from_keys_and_strip_whitespace(variables)
248
+ variables.inject({}) do |new_variables,(key,value)|
249
+ returning new_variables do
250
+ stripped_name = key.kind_of?(String) ? key[/^(agi_)?(.+)$/,2] : key
251
+ new_variables[stripped_name] = value.kind_of?(String) ? value.strip : value
252
+ end
253
+ end
254
+ end
255
+
256
+ def coerce_keys_into_symbols(variables)
257
+ variables.inject({}) do |new_variables,(key,value)|
258
+ returning new_variables do
259
+ new_variables[key.to_sym] = value
260
+ end
261
+ end
262
+ end
263
+
264
+ def coerce_extension_into_phone_number_object(variables)
265
+ returning variables do
266
+ variables[:extension] = Adhearsion::VoIP::DSL::PhoneNumber.new(variables[:extension])
267
+ end
268
+ end
269
+
270
+ def coerce_numerical_values_to_numerics(variables)
271
+ variables.inject({}) do |vars,(key,value)|
272
+ returning vars do
273
+ is_numeric = value =~ /^-?\d+(?:(\.)\d+)?$/
274
+ is_float = $1
275
+ vars[key] = if is_numeric
276
+ if Adhearsion::VoIP::DSL::NumericalString.starts_with_leading_zero?(value)
277
+ Adhearsion::VoIP::DSL::NumericalString.new(value)
278
+ else
279
+ is_float ? value.to_f : value.to_i
280
+ end
281
+ else
282
+ value
283
+ end
284
+ end
285
+ end
286
+ end
287
+
288
+ def replace_unknown_values_with_nil(variables)
289
+ variables.each do |key,value|
290
+ variables[key] = nil if value == 'unknown'
291
+ end
292
+ end
293
+
294
+ def replace_yes_no_answers_with_booleans(variables)
295
+ variables.each do |key,value|
296
+ case value
297
+ when 'yes' : variables[key] = true
298
+ when 'no' : variables[key] = false
299
+ end
300
+ end
301
+ end
302
+
303
+ def coerce_request_into_uri_object(variables)
304
+ returning variables do
305
+ variables[:request] = URI.parse(variables[:request]) unless variables[:request].kind_of? URI
306
+ end
307
+ end
308
+
309
+ def coerce_type_of_number_into_symbol(variables)
310
+ returning variables do
311
+ variables[:type_of_calling_number] = Adhearsion::VoIP::Constants::Q931_TYPE_OF_NUMBER[variables.delete(:callington).to_i]
312
+ end
313
+ end
314
+
315
+ def decompose_uri_query_into_hash(variables)
316
+ returning variables do
317
+ if variables[:request].query
318
+ variables[:query] = variables[:request].query.split('&').inject({}) do |query_string_parameters, key_value_pair|
319
+ parameter_name, parameter_value = *key_value_pair.match(/(.+)=(.+)/).captures
320
+ query_string_parameters[parameter_name] = parameter_value
321
+ query_string_parameters
322
+ end
323
+ else
324
+ variables[:query] = {}
325
+ end
326
+ end
327
+ end
328
+
329
+ def override_variables_with_query_params(variables)
330
+ returning variables do
331
+ if variables[:query]
332
+ variables[:query].each do |key, value|
333
+ variables[key.to_sym] = value
334
+ end
335
+ end
336
+ end
337
+ end
338
+
339
+ def remove_dashes_from_context_name(variables)
340
+ returning variables do
341
+ variables[:context].gsub!('-', '_')
342
+ end
343
+ end
344
+
345
+ end
346
+ end
347
+
348
+ class Parser
349
+
350
+ class << self
351
+ def parse(*args, &block)
352
+ returning new(*args, &block) do |parser|
353
+ parser.parse
354
+ end
355
+ end
356
+
357
+ def coerce_variables(variables)
358
+ Coercions::COERCION_ORDER.inject(variables) do |tmp_variables, coercing_method_name|
359
+ Coercions.send(coercing_method_name, tmp_variables)
360
+ end
361
+ end
362
+
363
+ def separate_line_into_key_value_pair(line)
364
+ line.match(/^([^:]+):\s?(.+)/).captures
365
+ end
366
+ end
367
+
368
+ attr_reader :io, :variables, :lines
369
+ def initialize(io)
370
+ @io = io
371
+ @lines = []
372
+ end
373
+
374
+ def parse
375
+ extract_variable_lines_from_io
376
+ initialize_variables_as_hash_from_lines
377
+ @variables = self.class.coerce_variables(variables)
378
+ end
379
+
380
+ private
381
+
382
+ def initialize_variables_as_hash_from_lines
383
+ @variables = lines.inject({}) do |new_variables,line|
384
+ returning new_variables do
385
+ key, value = self.class.separate_line_into_key_value_pair line
386
+ new_variables[key] = value
387
+ end
388
+ end
389
+ end
390
+
391
+ def extract_variable_lines_from_io
392
+ while line = io.readline.chomp
393
+ break if line.empty?
394
+ @lines << line
395
+ end
396
+ end
397
+
398
+ end
399
+
400
+ end
401
+ end
402
+ end
@@ -0,0 +1,64 @@
1
+ module Adhearsion
2
+ module VoIP
3
+ module CallRouting
4
+ class Rule
5
+ attr_reader :patterns, :providers, :options
6
+
7
+ def initialize(*args, &block)
8
+ @options = args.pop
9
+ @patterns = Array(args)
10
+ @providers = Array(options[:to])
11
+ end
12
+ end
13
+
14
+ class RuleSet < Array
15
+ def [](index)
16
+ case index
17
+ when String
18
+ detect do |rule|
19
+ rule.patterns.any? do |pattern|
20
+ index =~ pattern
21
+ end
22
+ end
23
+ else
24
+ super
25
+ end
26
+ end
27
+ end
28
+
29
+ class Router
30
+ class << self
31
+ attr_accessor :rules
32
+
33
+ def define(&block)
34
+ returning new do |router|
35
+ router.define(&block)
36
+ rules.concat router.rules
37
+ end
38
+ end
39
+
40
+ def calculate_route_for(end_point)
41
+ if rule = rules[end_point.to_s]
42
+ rule.providers
43
+ end
44
+ end
45
+ end
46
+
47
+ self.rules ||= RuleSet.new
48
+
49
+ attr_reader :rules
50
+ def initialize
51
+ @rules = []
52
+ end
53
+
54
+ def define(&block)
55
+ instance_eval(&block)
56
+ end
57
+
58
+ def route(*args, &block)
59
+ rules << Rule.new(*args, &block)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,9 @@
1
+ module Adhearsion
2
+ module VoIP
3
+ module Commands
4
+ def self.for(platform_name)
5
+ Adhearsion::VoIP.const_get(platform_name.to_s.classify).const_get("Commands")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ # Adhearsion, open source collaboration framework
2
+ # Copyright (C) 2006,2007,2008 Jay Phillips
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ module Adhearsion
19
+ module VoIP
20
+
21
+ # Please help adjust these if they may be inaccurate!
22
+ module Constants
23
+ US_LOCAL_NUMBER = /^[1-9]\d{6}$/
24
+ US_NATIONAL_NUMBER = /^1?[1-9]\d{2}[1-9]\d{6}$/
25
+ ISN = /^\d+\*\d+$/ # See http://freenum.org
26
+ SIP_URI = /^sip:[\w\._%+-]+@[\w\.-]+\.[a-zA-Z]{2,4}$/
27
+
28
+ # Type of Number definitions given over PRI. Taken from the Q.931-ITU spec, page 68.
29
+ Q931_TYPE_OF_NUMBER = Hash.new(:unknown).merge 0b001 => :international,
30
+ 0b010 => :national,
31
+ 0b011 => :network_specific,
32
+ 0b100 => :subscriber,
33
+ 0b110 => :abbreviated_number
34
+ end
35
+
36
+ include Constants
37
+
38
+ end
39
+ end
@@ -0,0 +1,18 @@
1
+ module Adhearsion
2
+ module VoIP
3
+ module Conveniences
4
+
5
+ # Compiles the provided Asterisk dialplan pattern into a Ruby regular
6
+ # expression. For more usage of Asterisk's pattern syntax, see
7
+ # http://www.voip-info.org/wiki/view/Asterisk+Dialplan+Patterns
8
+ def _(pattern)
9
+ # Uncomment the following code fragment for complete compatibility.
10
+ # The fragment handles the seldom-used hyphen number spacer with no
11
+ # meaning.
12
+ Regexp.new '^' << pattern.# gsub(/(?!\[[\w+-]+)-(?![\w-]+\])/,'').
13
+ gsub('X', '[0-9]').gsub('Z', '[1-9]').gsub('N','[2-9]').
14
+ gsub('.','.+').gsub('!','.*') << '$'
15
+ end
16
+ end
17
+ end
18
+ end