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.
- data/CHANGELOG +6 -0
- data/EVENTS +11 -0
- data/LICENSE +456 -0
- data/README.txt +5 -0
- data/Rakefile +120 -0
- data/adhearsion.gemspec +146 -0
- data/app_generators/ahn/USAGE +5 -0
- data/app_generators/ahn/ahn_generator.rb +87 -0
- data/app_generators/ahn/templates/.ahnrc +34 -0
- data/app_generators/ahn/templates/README +8 -0
- data/app_generators/ahn/templates/Rakefile +23 -0
- data/app_generators/ahn/templates/components/ami_remote/ami_remote.rb +15 -0
- data/app_generators/ahn/templates/components/disabled/HOW_TO_ENABLE +7 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/README.markdown +47 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/config.yml +12 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.rb +34 -0
- data/app_generators/ahn/templates/components/restful_rpc/README.markdown +11 -0
- data/app_generators/ahn/templates/components/restful_rpc/config.yml +34 -0
- data/app_generators/ahn/templates/components/restful_rpc/example-client.rb +48 -0
- data/app_generators/ahn/templates/components/restful_rpc/restful_rpc.rb +87 -0
- data/app_generators/ahn/templates/components/simon_game/simon_game.rb +56 -0
- data/app_generators/ahn/templates/config/startup.rb +53 -0
- data/app_generators/ahn/templates/dialplan.rb +3 -0
- data/app_generators/ahn/templates/events.rb +32 -0
- data/bin/ahn +28 -0
- data/bin/ahnctl +68 -0
- data/bin/jahn +42 -0
- data/examples/asterisk_manager_interface/standalone.rb +51 -0
- data/lib/adhearsion/cli.rb +223 -0
- data/lib/adhearsion/component_manager/spec_framework.rb +24 -0
- data/lib/adhearsion/component_manager.rb +208 -0
- data/lib/adhearsion/events_support.rb +84 -0
- data/lib/adhearsion/foundation/all.rb +9 -0
- data/lib/adhearsion/foundation/blank_slate.rb +5 -0
- data/lib/adhearsion/foundation/custom_daemonizer.rb +45 -0
- data/lib/adhearsion/foundation/event_socket.rb +203 -0
- data/lib/adhearsion/foundation/future_resource.rb +36 -0
- data/lib/adhearsion/foundation/global.rb +1 -0
- data/lib/adhearsion/foundation/metaprogramming.rb +17 -0
- data/lib/adhearsion/foundation/numeric.rb +13 -0
- data/lib/adhearsion/foundation/pseudo_guid.rb +10 -0
- data/lib/adhearsion/foundation/relationship_properties.rb +42 -0
- data/lib/adhearsion/foundation/string.rb +26 -0
- data/lib/adhearsion/foundation/synchronized_hash.rb +96 -0
- data/lib/adhearsion/foundation/thread_safety.rb +7 -0
- data/lib/adhearsion/host_definitions.rb +67 -0
- data/lib/adhearsion/initializer/asterisk.rb +81 -0
- data/lib/adhearsion/initializer/configuration.rb +254 -0
- data/lib/adhearsion/initializer/database.rb +49 -0
- data/lib/adhearsion/initializer/drb.rb +31 -0
- data/lib/adhearsion/initializer/freeswitch.rb +22 -0
- data/lib/adhearsion/initializer/rails.rb +40 -0
- data/lib/adhearsion/initializer.rb +373 -0
- data/lib/adhearsion/logging.rb +92 -0
- data/lib/adhearsion/tasks/database.rb +5 -0
- data/lib/adhearsion/tasks/deprecations.rb +59 -0
- data/lib/adhearsion/tasks/generating.rb +20 -0
- data/lib/adhearsion/tasks/lint.rb +4 -0
- data/lib/adhearsion/tasks/testing.rb +37 -0
- data/lib/adhearsion/tasks.rb +16 -0
- data/lib/adhearsion/version.rb +9 -0
- data/lib/adhearsion/voip/asterisk/agi_server.rb +81 -0
- data/lib/adhearsion/voip/asterisk/commands.rb +1284 -0
- data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +140 -0
- data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +101 -0
- data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +250 -0
- data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +240 -0
- data/lib/adhearsion/voip/asterisk/config_manager.rb +71 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1754 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +286 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +78 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +87 -0
- data/lib/adhearsion/voip/asterisk/manager_interface.rb +562 -0
- data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +80 -0
- data/lib/adhearsion/voip/asterisk/super_manager.rb +19 -0
- data/lib/adhearsion/voip/asterisk.rb +4 -0
- data/lib/adhearsion/voip/call.rb +440 -0
- data/lib/adhearsion/voip/call_routing.rb +64 -0
- data/lib/adhearsion/voip/commands.rb +9 -0
- data/lib/adhearsion/voip/constants.rb +39 -0
- data/lib/adhearsion/voip/conveniences.rb +18 -0
- data/lib/adhearsion/voip/dial_plan.rb +218 -0
- data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +37 -0
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +151 -0
- data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +27 -0
- data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +124 -0
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +71 -0
- data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +16 -0
- data/lib/adhearsion/voip/dsl/numerical_string.rb +117 -0
- data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +48 -0
- data/lib/adhearsion/voip/freeswitch/event_handler.rb +58 -0
- data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +129 -0
- data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +38 -0
- data/lib/adhearsion/voip/freeswitch/oes_server.rb +195 -0
- data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +80 -0
- data/lib/adhearsion/voip/menu_state_machine/matchers.rb +123 -0
- data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +58 -0
- data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +149 -0
- data/lib/adhearsion.rb +37 -0
- data/lib/theatre/README.markdown +64 -0
- data/lib/theatre/callback_definition_loader.rb +84 -0
- data/lib/theatre/guid.rb +23 -0
- data/lib/theatre/invocation.rb +121 -0
- data/lib/theatre/namespace_manager.rb +153 -0
- data/lib/theatre/version.rb +2 -0
- data/lib/theatre.rb +151 -0
- metadata +177 -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
|