eric-adhearsion 0.7.999

Sign up to get free protection for your applications and to get access to all the features.
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 +1182 -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 +391 -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 +451 -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,140 @@
1
+ require File.join(File.dirname(__FILE__), 'config_generator')
2
+
3
+ module Adhearsion
4
+ module VoIP
5
+ module Asterisk
6
+ module ConfigFileGenerators
7
+ class Agents < AsteriskConfigGenerator
8
+
9
+ attr_accessor :general_section, :agent_section, :agent_definitions, :agent_section_special
10
+ def initialize
11
+ @general_section = {}
12
+ @agent_section = {}
13
+ @agent_section_special = {} # Uses => separator
14
+ @agent_definitions = []
15
+
16
+ super
17
+ end
18
+
19
+ def to_s
20
+ AsteriskConfigGenerator.warning_message +
21
+ general_section.inject("[general]") { |section,(key,value)| section + "\n#{key}=#{value}" } +
22
+ agent_section.inject("\n[agents]") { |section,(key,value)| section + "\n#{key}=#{value}" } +
23
+ agent_section_special.inject("") { |section,(key,value)| section + "\n#{key} => #{value}" } +
24
+ agent_definitions.inject("\n") do |section,properties|
25
+ section + "\nagent => #{properties[:id]},#{properties[:password]},#{properties[:name]}"
26
+ end
27
+ end
28
+ alias conf to_s # Allows "agents.conf" if agents.kind_of?(Agents)
29
+
30
+ def agent(id, properties)
31
+ agent_definitions << {:id => id}.merge(properties)
32
+ end
33
+
34
+ # Group memberships for agents (may change in mid-file)
35
+ # WHAT DOES GROUPING ACCOMPLISH?
36
+ def groups(*args)
37
+ agent_section[:group] = args.join(",")
38
+ end
39
+
40
+ # Define whether callbacklogins should be stored in astdb for
41
+ # persistence. Persistent logins will be reloaded after
42
+ # Asterisk restarts.
43
+ def persistent_agents(yes_or_no)
44
+ general_section[:persistentagents] = boolean_to_yes_no yes_or_no
45
+ end
46
+
47
+ # enable or disable a single extension from longing in as multiple
48
+ # agents, defaults to enabled
49
+ def allow_multiple_logins_per_extension(yes_or_no)
50
+ general_section[:multiplelogin] = boolean_to_yes_no yes_or_no
51
+ end
52
+
53
+ # Define maxlogintries to allow agent to try max logins before
54
+ # failed. Default to 3
55
+ def max_login_tries(number_of_tries)
56
+ agent_section[:maxlogintries] = number_of_tries
57
+ end
58
+
59
+ # Define autologoff times if appropriate. This is how long
60
+ # the phone has to ring with no answer before the agent is
61
+ # automatically logged off (in seconds)
62
+ def log_off_after_duration(time_in_seconds)
63
+ agent_section[:autologoff] = time_in_seconds
64
+ end
65
+
66
+ # Define autologoffunavail to have agents automatically logged
67
+ # out when the extension that they are at returns a CHANUNAVAIL
68
+ # status when a call is attempted to be sent there.
69
+ # Default is "no".
70
+ def log_off_if_unavailable(yes_or_no)
71
+ agent_section[:autologoffunavail] = boolean_to_yes_no yes_or_no
72
+ end
73
+
74
+ # Define ackcall to require an acknowledgement by '#' when
75
+ # an agent logs in using agentcallbacklogin. Default is "no".
76
+ def require_hash_to_acknowledge(yes_or_no)
77
+ agent_section[:ackcall] = boolean_to_yes_no yes_or_no
78
+ end
79
+
80
+ # Define endcall to allow an agent to hangup a call by '*'.
81
+ # Default is "yes". Set this to "no" to ignore '*'.
82
+ def allow_star_to_hangup(yes_or_no)
83
+ agent_section[:endcall] = boolean_to_yes_no yes_or_no
84
+ end
85
+
86
+ # Define wrapuptime. This is the minimum amount of time when
87
+ # after disconnecting before the caller can receive a new call
88
+ # note this is in milliseconds.
89
+ def time_between_calls(time_in_seconds)
90
+ agent_section[:wrapuptime] = (time_in_seconds * 1000).to_i
91
+ end
92
+
93
+ # Define the default musiconhold for agents
94
+ # musiconhold => music_class
95
+ def hold_music_class(music_class)
96
+ agent_section_special[:musiconhold] = music_class.to_s
97
+ end
98
+
99
+ # TODO: I'm not exactly sure what this even does....
100
+
101
+ # Define the default good bye sound file for agents
102
+ # default to vm-goodbye
103
+ def play_on_agent_goodbye(sound_file_name)
104
+ agent_section_special[:agentgoodbye] = sound_file_name
105
+ end
106
+
107
+ # Define updatecdr. This is whether or not to change the source
108
+ # channel in the CDR record for this call to agent/agent_id so
109
+ # that we know which agent generates the call
110
+ def change_cdr_source(yes_or_no)
111
+ agent_section[:updatecdr] = boolean_to_yes_no yes_or_no
112
+ end
113
+
114
+ # An optional custom beep sound file to play to always-connected agents.
115
+ def play_for_waiting_keep_alive(sound_file)
116
+ agent_section[:custom_beep] = sound_file
117
+ end
118
+
119
+ def record_agent_calls(yes_or_no)
120
+ agent_section[:recordagentcalls] = boolean_to_yes_no yes_or_no
121
+ end
122
+
123
+ def recording_format(symbol)
124
+ raise ArgumentError, "Unrecognized format #{symbol}" unless [:wav, :wav49, :gsm].include? symbol
125
+ agent_section[:recordformat] = symbol
126
+ end
127
+
128
+ def recording_prefix(string)
129
+ agent_section[:urlprefix] = string
130
+ end
131
+
132
+ def save_recordings_in(path_to_directory)
133
+ agent_section[:savecallsin] = path_to_directory
134
+ end
135
+
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,101 @@
1
+ module Adhearsion
2
+ module VoIP
3
+ module Asterisk
4
+ module ConfigFileGenerators
5
+ class AsteriskConfigGenerator
6
+
7
+ SECTION_TITLE = /(\[[\w_-]+\])/
8
+
9
+ class << self
10
+
11
+ # Converts a config file into a Hash of contexts mapping to two dimensional array of pairs
12
+ def create_sanitary_hash_from(config_file_content)
13
+ almost_sanitized = Hash[*config_file_content.
14
+ grep(/^\s*[^;\s]/). # Grep lines that aren't commented out
15
+ join. # Convert them into one String again
16
+ split(SECTION_TITLE). # Separate them into sections
17
+ map(&:strip). # Remove all whitespace
18
+ reject(&:empty?). # Get rid of indices that were only whitespace
19
+ # Lastly, separate the keys/value pairs for the Hash
20
+ map { |token| token =~ /^#{SECTION_TITLE}$/ ? token : token.split(/\n+/).sort }
21
+ ]
22
+ end
23
+
24
+ def warning_message
25
+ %{;; THIS FILE WAS GENERATED BY ADHEARSION ON #{Time.now.ctime}!\n} +
26
+ %{;; ANY CHANGES MADE BELOW WILL BE BLOWN AWAY WHEN THE FILE IS REGENERATED!\n\n}
27
+ end
28
+
29
+ end
30
+
31
+ def initialize
32
+ yield self if block_given?
33
+ end
34
+
35
+ def to_sanitary_hash
36
+ self.class.create_sanitary_hash_from to_s
37
+ end
38
+
39
+ protected
40
+
41
+ def boolean(options)
42
+ cache = options.delete(:with) || properties
43
+ options.each_pair do |key, value|
44
+ cache[key] = boolean_to_yes_no value
45
+ end
46
+ end
47
+
48
+ def string(options)
49
+ cache = options.delete(:with) || properties
50
+ options.each_pair do |key, value|
51
+ cache[key] = value
52
+ end
53
+ end
54
+
55
+ def int(options)
56
+ cache = options.delete(:with) || properties
57
+ options.each_pair do |property,number|
58
+ number = number.to_i if (number.kind_of?(String) && number =~ /^\d+$/) || number.kind_of?(Numeric)
59
+ raise ArgumentError, "#{number.inspect} must be an integer" unless number.kind_of?(Fixnum)
60
+ cache[property] = number.to_i
61
+ end
62
+ end
63
+
64
+ def one_of(criteria, options)
65
+ cache = options.delete(:with) || properties
66
+ options.each_pair do |key, value|
67
+ search = !criteria.find { |criterion| criterion === value }.nil?
68
+ unless search
69
+ msg = "Didn't recognize #{value.inspect}! Must be one of " + criteria.map(&:inspect).to_sentence
70
+ raise ArgumentError, msg
71
+ end
72
+ cache[key] = [true, false].include?(value) ? boolean_to_yes_no(value) : value
73
+ end
74
+ end
75
+
76
+ def one_of_and_translate(criteria, options)
77
+ cache = options.delete(:with) || properties
78
+ options.each_pair do |key, value|
79
+ search = criteria.keys.find { |criterion| criterion === value }
80
+ unless search
81
+ msg = "Didn't recognize #{value.inspect}! Must be one of " + criteria.keys.map(&:inspect).to_sentence
82
+ raise ArgumentError, msg
83
+ end
84
+ cache[key] = criteria[value]
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def boolean_to_yes_no(boolean)
91
+ unless boolean.equal?(boolean) || boolean.equal?(boolean)
92
+ raise "#{boolean.inspect} is not true/false!"
93
+ end
94
+ boolean ? 'yes' : 'no'
95
+ end
96
+
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,250 @@
1
+ require File.join(File.dirname(__FILE__), 'config_generator')
2
+
3
+ module Adhearsion
4
+ module VoIP
5
+ module Asterisk
6
+ module ConfigFileGenerators
7
+
8
+ # This will generate a queues.conf file. If there is no documentation on what a method
9
+ # actually does, take a look at the documentation for its original key/value pair in
10
+ # an unedited queues.conf file. WARNING! Don't get too embedded with these method names.
11
+ # I'm still not satisfied. These settings will be greatly abstracted eventually.
12
+ class Queues < AsteriskConfigGenerator
13
+
14
+ DEFAULT_GENERAL_SECTION = {
15
+ :autofill => "yes"
16
+ }
17
+
18
+ attr_reader :general_section, :queue_definitions, :properties
19
+ def initialize
20
+ @general_section = DEFAULT_GENERAL_SECTION.clone
21
+ @properties = {}
22
+ @queue_definitions = []
23
+ super
24
+ end
25
+
26
+ def queue(name)
27
+ new_queue = QueueDefinition.new name
28
+ yield new_queue if block_given?
29
+ queue_definitions << new_queue
30
+ new_queue
31
+ end
32
+
33
+ def to_s
34
+ AsteriskConfigGenerator.warning_message +
35
+ general_section.inject("[general]") { |section,(key,value)| section + "\n#{key}=#{value}" } + "\n\n" +
36
+ queue_definitions.map(&:to_s).join("\n\n")
37
+ end
38
+ alias conf to_s
39
+
40
+ def persistent_members(yes_no)
41
+ boolean :persistentmembers => yes_no, :with => general_section
42
+ end
43
+
44
+ def monitor_type(symbol)
45
+ criteria = {:monitor => "Monitor", :mix_monitor => "MixMonitor"}
46
+ one_of_and_translate criteria, 'monitor-type' => symbol, :with => general_section
47
+ end
48
+
49
+
50
+ class QueueDefinition < AsteriskConfigGenerator
51
+
52
+ DEFAULT_QUEUE_PROPERTIES = {
53
+ :autofill => 'yes',
54
+ :eventwhencalled => 'vars',
55
+ :eventmemberstatus => 'yes',
56
+ :setinterfacevar => 'yes'
57
+ }
58
+
59
+ SUPPORTED_RING_STRATEGIES = [:ringall, :roundrobin, :leastrecent, :fewestcalls, :random, :rrmemory]
60
+
61
+ DEFAULT_SOUND_FILES = {
62
+ 'queue-youarenext' => 'queue-youarenext',
63
+ 'queue-thereare' => 'queue-thereare',
64
+ 'queue-callswaiting' => 'queue-callswaiting',
65
+ 'queue-holdtime' => 'queue-holdtime',
66
+ 'queue-minutes' => 'queue-minutes',
67
+ 'queue-seconds' => 'queue-seconds',
68
+ 'queue-thankyou' => 'queue-thankyou',
69
+ 'queue-lessthan' => 'queue-less-than',
70
+ 'queue-reporthold' => 'queue-reporthold',
71
+ 'periodic-announce' => 'queue-periodic-announce'
72
+ }
73
+
74
+ SOUND_FILE_SYMBOL_INTERPRETATIONS = {
75
+ :you_are_next => 'queue-youarenext',
76
+ :there_are => 'queue-thereare',
77
+ :calls_waiting => 'queue-callswaiting',
78
+ :hold_time => 'queue-holdtime',
79
+ :minutes => 'queue-minutes',
80
+ :seconds => 'queue-seconds',
81
+ :thank_you => 'queue-thankyou',
82
+ :less_than => 'queue-lessthan',
83
+ :report_hold => 'queue-reporthold',
84
+ :periodic_announcement => 'periodic-announce'
85
+ }
86
+
87
+ attr_reader :members, :name, :properties
88
+ def initialize(name)
89
+ @name = name
90
+ @members = []
91
+ @properties = DEFAULT_QUEUE_PROPERTIES.clone
92
+ @sound_files = DEFAULT_SOUND_FILES.clone
93
+ end
94
+
95
+ def to_s
96
+ "[#{name}]\n" +
97
+ properties.merge(@sound_files).map { |key, value| "#{key}=#{value}" }.sort.join("\n") + "\n\n" +
98
+ members.map { |member| "member => #{member}" }.join("\n")
99
+ end
100
+
101
+ def music_class(moh_identifier)
102
+ string :musicclass => moh_identifier
103
+ end
104
+
105
+ def play_on_connect(sound_file)
106
+ string :announce => sound_file
107
+ end
108
+
109
+ def strategy(symbol)
110
+ one_of SUPPORTED_RING_STRATEGIES, :strategy => symbol
111
+ end
112
+
113
+ def service_level(seconds)
114
+ int :servicelevel => seconds
115
+ end
116
+
117
+ # A context may be specified, in which if the user types a SINGLE
118
+ # digit extension while they are in the queue, they will be taken out
119
+ # of the queue and sent to that extension in this context. This context
120
+ # should obviously be a different context other than the one that
121
+ # normally forwards to Adhearsion (though the context that handles
122
+ # these digits should probably go out to Adhearsion too).
123
+ def exit_to_context_on_digit_press(context_name)
124
+ string :context => context_name
125
+ end
126
+
127
+ # Ex: ring_timeout 15.seconds
128
+ def ring_timeout(seconds)
129
+ int :timeout => seconds
130
+ end
131
+
132
+ # Ex: retry_after_waiting 5.seconds
133
+ def retry_after_waiting(seconds)
134
+ int :retry => seconds
135
+ end
136
+
137
+ # THIS IS UNSUPPORTED
138
+ def weight(number)
139
+ int :weight => number
140
+ end
141
+
142
+ # Ex: wrapup_time 1.minute
143
+ def wrapup_time(seconds)
144
+ int :wrapuptime => seconds
145
+ end
146
+
147
+
148
+ def autopause(yes_no)
149
+ boolean :autopause => yes_no
150
+ end
151
+
152
+ def maximum_length(number)
153
+ int :maxlen => number
154
+ end
155
+
156
+ def queue_status_announce_frequency(seconds)
157
+ int "announce-frequency" => seconds
158
+ end
159
+
160
+ def periodically_announce(sound_file, options={})
161
+ frequency = options.delete(:every) || 1.minute
162
+
163
+ string 'periodic-announce' => sound_file
164
+ int 'periodic-announce-frequency' => frequency
165
+ end
166
+
167
+ def announce_hold_time(seconds)
168
+ one_of [true, false, :once], "announce-holdtime" => seconds
169
+ end
170
+
171
+ def announce_round_seconds(yes_no_or_once)
172
+ int "announce-round-seconds" => yes_no_or_once
173
+ end
174
+
175
+ def monitor_format(symbol)
176
+ one_of [:wav, :gsm, :wav49], 'monitor-format' => symbol
177
+ end
178
+
179
+ def monitor_type(symbol)
180
+ criteria = {:monitor => "Monitor", :mix_monitor => "MixMonitor"}
181
+ one_of_and_translate criteria, 'monitor-type' => symbol
182
+ end
183
+
184
+ # Ex: join_empty true
185
+ # Ex: join_empty :strict
186
+ def join_empty(yes_no_or_strict)
187
+ one_of [true, false, :strict], :joinempty => yes_no_or_strict
188
+ end
189
+
190
+ def leave_when_empty(yes_no)
191
+ boolean :leavewhenempty => yes_no
192
+ end
193
+
194
+ def report_hold_time(yes_no)
195
+ boolean :reportholdtime => yes_no
196
+ end
197
+
198
+ def ring_in_use(yes_no)
199
+ boolean :ringinuse => yes_no
200
+ end
201
+
202
+ # Number of seconds to wait when an agent is to be bridged with
203
+ # a caller. Normally you'd want this to be zero.
204
+ def delay_connection_by(seconds)
205
+ int :memberdelay => seconds
206
+ end
207
+
208
+ def timeout_restart(yes_no)
209
+ boolean :timeoutrestart => yes_no
210
+ end
211
+
212
+ # Give a Hash argument here to override the default sound files for this queue.
213
+ #
214
+ # Usage:
215
+ #
216
+ # queue.sound_files :you_are_next => 'queue-youarenext',
217
+ # :there_are => 'queue-thereare',
218
+ # :calls_waiting => 'queue-callswaiting',
219
+ # :hold_time => 'queue-holdtime',
220
+ # :minutes => 'queue-minutes',
221
+ # :seconds => 'queue-seconds',
222
+ # :thank_you => 'queue-thankyou',
223
+ # :less_than => 'queue-less-than',
224
+ # :report_hold => 'queue-reporthold',
225
+ # :periodic_announcement => 'queue-periodic-announce'
226
+ #
227
+ # Note: the Hash values are the defaults. You only need to specify the ones you
228
+ # wish to override.
229
+ def sound_files(hash_of_files)
230
+ hash_of_files.each_pair do |key, value|
231
+ unless SOUND_FILE_SYMBOL_INTERPRETATIONS.has_key? key
232
+ message = "Unrecogized sound file identifier #{key.inspect}. " +
233
+ "Supported: " + SOUND_FILE_SYMBOL_INTERPRETATIONS.keys.map(&:inspect).to_sentence
234
+ raise ArgumentError, message
235
+ end
236
+ @sound_files[SOUND_FILE_SYMBOL_INTERPRETATIONS[key]] = value
237
+ end
238
+ end
239
+
240
+ def member(driver)
241
+ members << (driver.kind_of?(String) && driver =~ %r'/' ? driver : "Agent/#{driver}")
242
+ end
243
+
244
+ end
245
+
246
+ end
247
+ end
248
+ end
249
+ end
250
+ end