jicksta-adhearsion 0.7.999

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 (107) hide show
  1. data/CHANGELOG +6 -0
  2. data/EVENTS +11 -0
  3. data/LICENSE +456 -0
  4. data/README.txt +5 -0
  5. data/Rakefile +120 -0
  6. data/adhearsion.gemspec +146 -0
  7. data/app_generators/ahn/USAGE +5 -0
  8. data/app_generators/ahn/ahn_generator.rb +87 -0
  9. data/app_generators/ahn/templates/.ahnrc +34 -0
  10. data/app_generators/ahn/templates/README +8 -0
  11. data/app_generators/ahn/templates/Rakefile +23 -0
  12. data/app_generators/ahn/templates/components/ami_remote/ami_remote.rb +15 -0
  13. data/app_generators/ahn/templates/components/disabled/HOW_TO_ENABLE +7 -0
  14. data/app_generators/ahn/templates/components/disabled/stomp_gateway/README.markdown +47 -0
  15. data/app_generators/ahn/templates/components/disabled/stomp_gateway/config.yml +12 -0
  16. data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.rb +34 -0
  17. data/app_generators/ahn/templates/components/restful_rpc/README.markdown +11 -0
  18. data/app_generators/ahn/templates/components/restful_rpc/config.yml +34 -0
  19. data/app_generators/ahn/templates/components/restful_rpc/example-client.rb +48 -0
  20. data/app_generators/ahn/templates/components/restful_rpc/restful_rpc.rb +87 -0
  21. data/app_generators/ahn/templates/components/simon_game/simon_game.rb +56 -0
  22. data/app_generators/ahn/templates/config/startup.rb +53 -0
  23. data/app_generators/ahn/templates/dialplan.rb +3 -0
  24. data/app_generators/ahn/templates/events.rb +32 -0
  25. data/bin/ahn +28 -0
  26. data/bin/ahnctl +68 -0
  27. data/bin/jahn +42 -0
  28. data/examples/asterisk_manager_interface/standalone.rb +51 -0
  29. data/lib/adhearsion/cli.rb +223 -0
  30. data/lib/adhearsion/component_manager/spec_framework.rb +24 -0
  31. data/lib/adhearsion/component_manager.rb +208 -0
  32. data/lib/adhearsion/events_support.rb +84 -0
  33. data/lib/adhearsion/foundation/all.rb +9 -0
  34. data/lib/adhearsion/foundation/blank_slate.rb +5 -0
  35. data/lib/adhearsion/foundation/custom_daemonizer.rb +45 -0
  36. data/lib/adhearsion/foundation/event_socket.rb +203 -0
  37. data/lib/adhearsion/foundation/future_resource.rb +36 -0
  38. data/lib/adhearsion/foundation/global.rb +1 -0
  39. data/lib/adhearsion/foundation/metaprogramming.rb +17 -0
  40. data/lib/adhearsion/foundation/numeric.rb +13 -0
  41. data/lib/adhearsion/foundation/pseudo_guid.rb +10 -0
  42. data/lib/adhearsion/foundation/relationship_properties.rb +42 -0
  43. data/lib/adhearsion/foundation/string.rb +26 -0
  44. data/lib/adhearsion/foundation/synchronized_hash.rb +96 -0
  45. data/lib/adhearsion/foundation/thread_safety.rb +7 -0
  46. data/lib/adhearsion/host_definitions.rb +67 -0
  47. data/lib/adhearsion/initializer/asterisk.rb +81 -0
  48. data/lib/adhearsion/initializer/configuration.rb +254 -0
  49. data/lib/adhearsion/initializer/database.rb +49 -0
  50. data/lib/adhearsion/initializer/drb.rb +31 -0
  51. data/lib/adhearsion/initializer/freeswitch.rb +22 -0
  52. data/lib/adhearsion/initializer/rails.rb +40 -0
  53. data/lib/adhearsion/initializer.rb +373 -0
  54. data/lib/adhearsion/logging.rb +92 -0
  55. data/lib/adhearsion/tasks/database.rb +5 -0
  56. data/lib/adhearsion/tasks/deprecations.rb +59 -0
  57. data/lib/adhearsion/tasks/generating.rb +20 -0
  58. data/lib/adhearsion/tasks/lint.rb +4 -0
  59. data/lib/adhearsion/tasks/testing.rb +37 -0
  60. data/lib/adhearsion/tasks.rb +16 -0
  61. data/lib/adhearsion/version.rb +9 -0
  62. data/lib/adhearsion/voip/asterisk/agi_server.rb +81 -0
  63. data/lib/adhearsion/voip/asterisk/commands.rb +1284 -0
  64. data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +140 -0
  65. data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +101 -0
  66. data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +250 -0
  67. data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +240 -0
  68. data/lib/adhearsion/voip/asterisk/config_manager.rb +71 -0
  69. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1754 -0
  70. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +286 -0
  71. data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +78 -0
  72. data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +87 -0
  73. data/lib/adhearsion/voip/asterisk/manager_interface.rb +562 -0
  74. data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +80 -0
  75. data/lib/adhearsion/voip/asterisk/super_manager.rb +19 -0
  76. data/lib/adhearsion/voip/asterisk.rb +4 -0
  77. data/lib/adhearsion/voip/call.rb +440 -0
  78. data/lib/adhearsion/voip/call_routing.rb +64 -0
  79. data/lib/adhearsion/voip/commands.rb +9 -0
  80. data/lib/adhearsion/voip/constants.rb +39 -0
  81. data/lib/adhearsion/voip/conveniences.rb +18 -0
  82. data/lib/adhearsion/voip/dial_plan.rb +218 -0
  83. data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +37 -0
  84. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +151 -0
  85. data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +27 -0
  86. data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +124 -0
  87. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +71 -0
  88. data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +16 -0
  89. data/lib/adhearsion/voip/dsl/numerical_string.rb +117 -0
  90. data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +48 -0
  91. data/lib/adhearsion/voip/freeswitch/event_handler.rb +58 -0
  92. data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +129 -0
  93. data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +38 -0
  94. data/lib/adhearsion/voip/freeswitch/oes_server.rb +195 -0
  95. data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +80 -0
  96. data/lib/adhearsion/voip/menu_state_machine/matchers.rb +123 -0
  97. data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +58 -0
  98. data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +149 -0
  99. data/lib/adhearsion.rb +37 -0
  100. data/lib/theatre/README.markdown +64 -0
  101. data/lib/theatre/callback_definition_loader.rb +84 -0
  102. data/lib/theatre/guid.rb +23 -0
  103. data/lib/theatre/invocation.rb +121 -0
  104. data/lib/theatre/namespace_manager.rb +153 -0
  105. data/lib/theatre/version.rb +2 -0
  106. data/lib/theatre.rb +151 -0
  107. metadata +177 -0
@@ -0,0 +1,440 @@
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
+ def with_tag(tag)
65
+ atomically do
66
+ calls.inject(Array.new) do |calls_with_tag,(key,call)|
67
+ call.tagged_with?(tag) ? calls_with_tag << call : calls_with_tag
68
+ end
69
+ end
70
+ end
71
+
72
+ def to_a
73
+ calls.values
74
+ end
75
+
76
+ private
77
+ attr_reader :semaphore, :calls
78
+
79
+ def atomically(&block)
80
+ semaphore.synchronize(&block)
81
+ end
82
+
83
+ end
84
+
85
+ class UselessCallException < Exception; end
86
+
87
+ class MetaAgiCallException < Exception
88
+ attr_reader :call
89
+ def initialize(call)
90
+ super()
91
+ @call = call
92
+ end
93
+ end
94
+
95
+ class FailedExtensionCallException < MetaAgiCallException; end
96
+
97
+ class HungupExtensionCallException < MetaAgiCallException; end
98
+
99
+ ##
100
+ # Encapsulates call-related data and behavior.
101
+ # For example, variables passed in on call initiation are
102
+ # accessible here as attributes
103
+ class Call
104
+
105
+ # This is basically a translation of ast_channel_reason2str() from main/channel.c and
106
+ # ast_control_frame_type in include/asterisk/frame.h in the Asterisk source code. When
107
+ # Asterisk jumps to the 'failed' extension, it sets a REASON channel variable to a number.
108
+ # The indexes of these symbols represent the possible numbers REASON could be.
109
+ ASTERISK_FRAME_STATES = [
110
+ :failure, # "Call Failure (not BUSY, and not NO_ANSWER, maybe Circuit busy or down?)"
111
+ :hangup, # Other end has hungup
112
+ :ring, # Local ring
113
+ :ringing, # Remote end is ringing
114
+ :answer, # Remote end has answered
115
+ :busy, # Remote end is busy
116
+ :takeoffhook, # Make it go off hook
117
+ :offhook, # Line is off hook
118
+ :congestion, # Congestion (circuits busy)
119
+ :flash, # Flash hook
120
+ :wink, # Wink
121
+ :option, # Set a low-level option
122
+ :radio_key, # Key Radio
123
+ :radio_unkey, # Un-Key Radio
124
+ :progress, # Indicate PROGRESS
125
+ :proceeding, # Indicate CALL PROCEEDING
126
+ :hold, # Indicate call is placed on hold
127
+ :unhold, # Indicate call is left from hold
128
+ :vidupdate # Indicate video frame update
129
+ ]
130
+
131
+
132
+ class << self
133
+ ##
134
+ # The primary public interface for creating a Call instance.
135
+ # Given an IO (probably a socket accepted from an Asterisk service),
136
+ # creates a Call instance which encapsulates everything we know about that call.
137
+ def receive_from(io, &block)
138
+ returning new(io, variable_parser_for(io).variables) do |call|
139
+ block.call(call) if block
140
+ end
141
+ end
142
+
143
+ private
144
+ def variable_parser_for(io)
145
+ Variables::Parser.parse(io)
146
+ end
147
+
148
+ end
149
+
150
+ attr_accessor :io, :type, :variables, :originating_voip_platform, :inbox
151
+ def initialize(io, variables)
152
+ @io, @variables = io, variables.symbolize_keys
153
+ check_if_valid_call
154
+ define_variable_accessors
155
+ set_originating_voip_platform!
156
+ @tag_mutex = Mutex.new
157
+ @tags = []
158
+ end
159
+
160
+ def tags
161
+ @tag_mutex.synchronize do
162
+ return @tags.clone
163
+ end
164
+ end
165
+
166
+ def tag(symbol)
167
+ raise ArgumentError, "tag must be a Symbol" unless symbol.is_a? Symbol
168
+ @tag_mutex.synchronize do
169
+ @tags << symbol
170
+ end
171
+ end
172
+
173
+ def remove_tag(symbol)
174
+ @tag_mutex.synchronize do
175
+ @tags.reject! { |tag| tag == symbol }
176
+ end
177
+ end
178
+
179
+ def tagged_with?(symbol)
180
+ @tag_mutex.synchronize do
181
+ @tags.include? symbol
182
+ end
183
+ end
184
+
185
+ def deliver_message(message)
186
+ inbox << message
187
+ end
188
+ alias << deliver_message
189
+
190
+ def inbox
191
+ @inbox ||= Queue.new
192
+ end
193
+
194
+ def hangup!
195
+ io.close
196
+ Adhearsion.remove_inactive_call self
197
+ end
198
+
199
+ def closed?
200
+ io.closed?
201
+ end
202
+
203
+ # Asterisk sometimes uses the "failed" extension to indicate a failed dial attempt.
204
+ # Since it may be important to handle these, this flag helps the dialplan Manager
205
+ # figure that out.
206
+ def failed_call?
207
+ @failed_call
208
+ end
209
+
210
+ def hungup_call?
211
+ @hungup_call
212
+ end
213
+
214
+ # Adhearsion indexes calls by this identifier so they may later be found and manipulated. For calls from Asterisk, this
215
+ # method uses the following properties for uniqueness, falling back to the next if one is for some reason unavailable:
216
+ #
217
+ # Asterisk channel ID -> unique ID -> Call#object_id
218
+ # (e.g. SIP/mytrunk-jb12c88a) -> (e.g. 1215039989.47033) -> (e.g. 2792080)
219
+ #
220
+ # Note: channel is used over unique ID because channel may be used to bridge two channels together.
221
+ def unique_identifier
222
+ case originating_voip_platform
223
+ when :asterisk
224
+ variables[:channel] || variables[:uniqueid] || object_id
225
+ else
226
+ raise NotImplementedError
227
+ end
228
+ end
229
+
230
+ def define_variable_accessors(recipient=self)
231
+ variables.each do |key, value|
232
+ define_singleton_accessor_with_pair(key, value, recipient)
233
+ end
234
+ end
235
+
236
+ def extract_failed_reason_from(environment)
237
+ if originating_voip_platform == :asterisk
238
+ failed_reason = environment.variable 'REASON'
239
+ failed_reason &&= ASTERISK_FRAME_STATES[failed_reason.to_i]
240
+ define_singleton_accessor_with_pair(:failed_reason, failed_reason, environment)
241
+ end
242
+ end
243
+
244
+ private
245
+
246
+ def define_singleton_accessor_with_pair(key, value, recipient=self)
247
+ recipient.metaclass.send :attr_accessor, key unless recipient.class.respond_to?("#{key}=")
248
+ recipient.send "#{key}=", value
249
+ end
250
+
251
+ def check_if_valid_call
252
+ extension = variables[:extension]
253
+ @failed_call = true if extension == 'failed'
254
+ @hungup_call = true if extension == 'h'
255
+ raise UselessCallException if extension == 't' # TODO: Move this whole method to Manager
256
+ end
257
+
258
+ def set_originating_voip_platform!
259
+ # TODO: we can make this determination programatically at some point,
260
+ # but it will probably involve a bit more engineering than just a case statement (like
261
+ # subclasses of Call for the various platforms), so we'll be totally cheap for now.
262
+ self.originating_voip_platform = :asterisk
263
+ end
264
+
265
+ module Variables
266
+
267
+ module Coercions
268
+
269
+ COERCION_ORDER = %w{
270
+ remove_agi_prefixes_from_keys_and_strip_whitespace
271
+ coerce_keys_into_symbols
272
+ coerce_extension_into_phone_number_object
273
+ coerce_numerical_values_to_numerics
274
+ replace_unknown_values_with_nil
275
+ replace_yes_no_answers_with_booleans
276
+ coerce_request_into_uri_object
277
+ decompose_uri_query_into_hash
278
+ override_variables_with_query_params
279
+ remove_dashes_from_context_name
280
+ coerce_type_of_number_into_symbol
281
+ }
282
+
283
+ class << self
284
+
285
+ def remove_agi_prefixes_from_keys_and_strip_whitespace(variables)
286
+ variables.inject({}) do |new_variables,(key,value)|
287
+ returning new_variables do
288
+ stripped_name = key.kind_of?(String) ? key[/^(agi_)?(.+)$/,2] : key
289
+ new_variables[stripped_name] = value.kind_of?(String) ? value.strip : value
290
+ end
291
+ end
292
+ end
293
+
294
+ def coerce_keys_into_symbols(variables)
295
+ variables.inject({}) do |new_variables,(key,value)|
296
+ returning new_variables do
297
+ new_variables[key.to_sym] = value
298
+ end
299
+ end
300
+ end
301
+
302
+ def coerce_extension_into_phone_number_object(variables)
303
+ returning variables do
304
+ variables[:extension] = Adhearsion::VoIP::DSL::PhoneNumber.new(variables[:extension])
305
+ end
306
+ end
307
+
308
+ def coerce_numerical_values_to_numerics(variables)
309
+ variables.inject({}) do |vars,(key,value)|
310
+ returning vars do
311
+ is_numeric = value =~ /^-?\d+(?:(\.)\d+)?$/
312
+ is_float = $1
313
+ vars[key] = if is_numeric
314
+ if Adhearsion::VoIP::DSL::NumericalString.starts_with_leading_zero?(value)
315
+ Adhearsion::VoIP::DSL::NumericalString.new(value)
316
+ else
317
+ is_float ? value.to_f : value.to_i
318
+ end
319
+ else
320
+ value
321
+ end
322
+ end
323
+ end
324
+ end
325
+
326
+ def replace_unknown_values_with_nil(variables)
327
+ variables.each do |key,value|
328
+ variables[key] = nil if value == 'unknown'
329
+ end
330
+ end
331
+
332
+ def replace_yes_no_answers_with_booleans(variables)
333
+ variables.each do |key,value|
334
+ case value
335
+ when 'yes' : variables[key] = true
336
+ when 'no' : variables[key] = false
337
+ end
338
+ end
339
+ end
340
+
341
+ def coerce_request_into_uri_object(variables)
342
+ returning variables do
343
+ variables[:request] = URI.parse(variables[:request]) unless variables[:request].kind_of? URI
344
+ end
345
+ end
346
+
347
+ def coerce_type_of_number_into_symbol(variables)
348
+ returning variables do
349
+ variables[:type_of_calling_number] = Adhearsion::VoIP::Constants::Q931_TYPE_OF_NUMBER[variables.delete(:callington).to_i]
350
+ end
351
+ end
352
+
353
+ def decompose_uri_query_into_hash(variables)
354
+ returning variables do
355
+ if variables[:request].query
356
+ variables[:query] = variables[:request].query.split('&').inject({}) do |query_string_parameters, key_value_pair|
357
+ parameter_name, parameter_value = *key_value_pair.match(/(.+)=(.*)/).captures
358
+ query_string_parameters[parameter_name] = parameter_value
359
+ query_string_parameters
360
+ end
361
+ else
362
+ variables[:query] = {}
363
+ end
364
+ end
365
+ end
366
+
367
+ def override_variables_with_query_params(variables)
368
+ returning variables do
369
+ if variables[:query]
370
+ variables[:query].each do |key, value|
371
+ variables[key.to_sym] = value
372
+ end
373
+ end
374
+ end
375
+ end
376
+
377
+ def remove_dashes_from_context_name(variables)
378
+ returning variables do
379
+ variables[:context].gsub!('-', '_')
380
+ end
381
+ end
382
+
383
+ end
384
+ end
385
+
386
+ class Parser
387
+
388
+ class << self
389
+ def parse(*args, &block)
390
+ returning new(*args, &block) do |parser|
391
+ parser.parse
392
+ end
393
+ end
394
+
395
+ def coerce_variables(variables)
396
+ Coercions::COERCION_ORDER.inject(variables) do |tmp_variables, coercing_method_name|
397
+ Coercions.send(coercing_method_name, tmp_variables)
398
+ end
399
+ end
400
+
401
+ def separate_line_into_key_value_pair(line)
402
+ line.match(/^([^:]+):\s?(.+)/).captures
403
+ end
404
+ end
405
+
406
+ attr_reader :io, :variables, :lines
407
+ def initialize(io)
408
+ @io = io
409
+ @lines = []
410
+ end
411
+
412
+ def parse
413
+ extract_variable_lines_from_io
414
+ initialize_variables_as_hash_from_lines
415
+ @variables = self.class.coerce_variables(variables)
416
+ end
417
+
418
+ private
419
+
420
+ def initialize_variables_as_hash_from_lines
421
+ @variables = lines.inject({}) do |new_variables,line|
422
+ returning new_variables do
423
+ key, value = self.class.separate_line_into_key_value_pair line
424
+ new_variables[key] = value
425
+ end
426
+ end
427
+ end
428
+
429
+ def extract_variable_lines_from_io
430
+ while line = io.readline.chomp
431
+ break if line.empty?
432
+ @lines << line
433
+ end
434
+ end
435
+
436
+ end
437
+
438
+ end
439
+ end
440
+ 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