adhearsion 0.8.4 → 0.8.5
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 +12 -0
- data/Rakefile +6 -5
- data/adhearsion.gemspec +9 -5
- data/app_generators/ahn/ahn_generator.rb +5 -0
- data/app_generators/ahn/templates/components/disabled/restful_rpc/restful_rpc.rb +1 -1
- data/app_generators/ahn/templates/components/disabled/sandbox/sandbox.rb +1 -1
- data/app_generators/ahn/templates/components/disabled/xmpp_gateway/README.markdown +3 -0
- data/app_generators/ahn/templates/components/disabled/xmpp_gateway/xmpp_gateway.rb +11 -0
- data/app_generators/ahn/templates/components/disabled/xmpp_gateway/xmpp_gateway.yml +0 -0
- data/app_generators/ahn/templates/config/startup.rb +10 -1
- data/lib/adhearsion/cli.rb +7 -2
- data/lib/adhearsion/foundation/event_socket.rb +1 -1
- data/lib/adhearsion/foundation/future_resource.rb +1 -1
- data/lib/adhearsion/host_definitions.rb +1 -1
- data/lib/adhearsion/initializer.rb +21 -8
- data/lib/adhearsion/initializer/configuration.rb +44 -3
- data/lib/adhearsion/initializer/database.rb +11 -1
- data/lib/adhearsion/initializer/ldap.rb +7 -1
- data/lib/adhearsion/initializer/xmpp.rb +42 -0
- data/lib/adhearsion/version.rb +26 -2
- data/lib/adhearsion/voip/asterisk/agi_server.rb +2 -1
- data/lib/adhearsion/voip/asterisk/commands.rb +186 -85
- data/lib/adhearsion/voip/asterisk/manager_interface.rb +147 -50
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1 -1
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +1 -1
- data/lib/adhearsion/voip/call.rb +15 -8
- data/lib/adhearsion/voip/dial_plan.rb +21 -4
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +1 -1
- data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +2 -2
- data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +2 -2
- data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +2 -2
- data/lib/adhearsion/xmpp/connection.rb +61 -0
- data/lib/theatre/invocation.rb +1 -1
- data/lib/theatre/namespace_manager.rb +1 -1
- metadata +12 -6
- data/lib/adhearsion/foundation/global.rb +0 -1
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'adhearsion/xmpp/connection.rb'
|
2
|
+
|
3
|
+
module Adhearsion
|
4
|
+
class Initializer
|
5
|
+
class XMPPInitializer
|
6
|
+
|
7
|
+
cattr_accessor :config, :jid, :password, :server, :port
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def start
|
11
|
+
require_dependencies
|
12
|
+
XMPP::Connection.extend Blather::DSL
|
13
|
+
ahn_config = Adhearsion::AHN_CONFIG
|
14
|
+
self.config = ahn_config.xmpp
|
15
|
+
self.jid = config.jid
|
16
|
+
self.password = config.password
|
17
|
+
self.server = config.server
|
18
|
+
self.port = config.port
|
19
|
+
|
20
|
+
XMPP::Connection.start(jid, password, server, port)
|
21
|
+
end
|
22
|
+
|
23
|
+
def stop
|
24
|
+
XMPP::Connection.stop
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def require_dependencies
|
30
|
+
begin
|
31
|
+
require 'blather/client/client'
|
32
|
+
require 'blather/client/dsl'
|
33
|
+
rescue LoadError
|
34
|
+
ahn_log.fatal "XMPP support requires the \"blather\" gem."
|
35
|
+
# Silence the abort so we don't get an ugly backtrace
|
36
|
+
abort ""
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/adhearsion/version.rb
CHANGED
@@ -2,8 +2,32 @@ module Adhearsion #:nodoc:
|
|
2
2
|
module VERSION #:nodoc:
|
3
3
|
MAJOR = 0 unless defined? MAJOR
|
4
4
|
MINOR = 8 unless defined? MINOR
|
5
|
-
TINY =
|
5
|
+
TINY = 5 unless defined? TINY
|
6
6
|
|
7
7
|
STRING = [MAJOR, MINOR, TINY].join('.') unless defined? STRING
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
|
+
class PkgVersion
|
11
|
+
include Comparable
|
12
|
+
|
13
|
+
attr_reader :major, :minor, :revision
|
14
|
+
|
15
|
+
def initialize(version="")
|
16
|
+
@major, @minor, @revision = version.split(".").map(&:to_i)
|
17
|
+
end
|
18
|
+
|
19
|
+
def <=>(other)
|
20
|
+
return @major <=> other.major if ((@major <=> other.major) != 0)
|
21
|
+
return @minor <=> other.minor if ((@minor <=> other.minor) != 0)
|
22
|
+
return @revision <=> other.revision if ((@revision <=> other.revision) != 0)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.sort
|
26
|
+
self.sort!{|a,b| a <=> b}
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
@major.to_s + "." + @minor.to_s + "." + @revision.to_s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -12,7 +12,7 @@ module Adhearsion
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def disconnecting(port)
|
15
|
-
@call.deliver_message :cancel
|
15
|
+
@call.deliver_message :cancel if !@call.nil?
|
16
16
|
super(port)
|
17
17
|
end
|
18
18
|
|
@@ -34,6 +34,7 @@ module Adhearsion
|
|
34
34
|
DialPlan::Manager.handle call
|
35
35
|
rescue Hangup
|
36
36
|
ahn_log.agi "HANGUP event for call with uniqueid #{call.variables[:uniqueid].inspect} and channel #{call.variables[:channel].inspect}"
|
37
|
+
Events.trigger_immediately([:asterisk, :after_call], call)
|
37
38
|
call.hangup!
|
38
39
|
rescue DialPlan::Manager::NoContextError => e
|
39
40
|
ahn_log.agi e.message
|
@@ -43,25 +43,32 @@ module Adhearsion
|
|
43
43
|
} unless defined? DYNAMIC_FEATURE_EXTENSIONS
|
44
44
|
|
45
45
|
# Utility method to write to pbx.
|
46
|
+
# @param [String] message raw message
|
46
47
|
def write(message)
|
47
|
-
to_pbx.print(message)
|
48
|
+
to_pbx.print(message + "\n")
|
48
49
|
end
|
49
50
|
|
50
51
|
# Utility method to read from pbx. Hangup if nil.
|
51
52
|
def read
|
52
53
|
returning from_pbx.gets do |message|
|
54
|
+
ahn_log.agi.debug "<<< #{message}"
|
55
|
+
# AGI has many conditions that might indicate a hangup
|
53
56
|
raise Hangup if message.nil?
|
54
57
|
raise Hangup if message.match(/^HANGUP\n?$/i)
|
58
|
+
raise Hangup if message.match(/^HANGUP\s?\d{3}/i)
|
55
59
|
raise Hangup if message.match(/^511 Command Not Permitted on a dead channel/i)
|
56
|
-
ahn_log.agi.debug "<<< #{message}"
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
60
|
-
#
|
61
|
-
#
|
63
|
+
# The underlying method executed by nearly all the command methods in this module.
|
64
|
+
# Used to send the plaintext commands in the proper AGI format over TCP/IP back to an Asterisk server via the
|
62
65
|
# FAGI protocol.
|
66
|
+
#
|
63
67
|
# It is not recommended that you call this method directly unless you plan to write a new command method
|
64
|
-
# in which case use this
|
68
|
+
# in which case use this to communicate directly with an Asterisk server via the FAGI protocol.
|
69
|
+
#
|
70
|
+
# @param [String] message
|
71
|
+
#
|
65
72
|
# @see http://www.voip-info.org/wiki/view/Asterisk+FastAGI More information about FAGI
|
66
73
|
def raw_response(message = nil)
|
67
74
|
raise ArgumentError.new("illegal NUL in message #{message.inspect}") if message =~ /\0/
|
@@ -83,14 +90,13 @@ module Adhearsion
|
|
83
90
|
end
|
84
91
|
end
|
85
92
|
|
86
|
-
#
|
87
|
-
# In typical
|
88
|
-
#
|
89
|
-
# If you do not want your
|
93
|
+
# This must be called first before any other commands can be issued.
|
94
|
+
# In typical Adhearsion applications this is called by default as soon as a call is
|
95
|
+
# transfered to a valid context in dialplan.rb.
|
96
|
+
# If you do not want your Adhearsion application to automatically issue an answer command,
|
90
97
|
# then you must edit your startup.rb file and configure this setting.
|
91
|
-
# Keep in mind that you should not need to issue another answer command after
|
92
|
-
#
|
93
|
-
# by the standard adhearsion configuration.
|
98
|
+
# Keep in mind that you should not need to issue another answer command after one has already
|
99
|
+
# been issued either explicitly by your code or implicitly by the standard adhearsion configuration.
|
94
100
|
def answer
|
95
101
|
response "ANSWER"
|
96
102
|
true
|
@@ -100,10 +106,10 @@ module Adhearsion
|
|
100
106
|
# which are typically run from extensions.conf.
|
101
107
|
#
|
102
108
|
# The most common commands are already made available through the FAGI interface provided
|
103
|
-
# by this code base.
|
109
|
+
# by this code base. For commands that do not fall into this category, then exec is what you
|
104
110
|
# should use.
|
105
111
|
#
|
106
|
-
# For example, if there are specific asterisk modules you have loaded that will not
|
112
|
+
# For example, if there are specific asterisk modules you have loaded that will not be
|
107
113
|
# available through the standard commands provided through FAGI - then you can used EXEC.
|
108
114
|
#
|
109
115
|
# @example Using execute in this way will add a header to an existing SIP call.
|
@@ -118,6 +124,12 @@ module Adhearsion
|
|
118
124
|
end
|
119
125
|
|
120
126
|
# Sends a message to the console via the verbose message system.
|
127
|
+
#
|
128
|
+
# @param [String] message
|
129
|
+
# @param [Integer] level
|
130
|
+
#
|
131
|
+
# @return the result of the command
|
132
|
+
#
|
121
133
|
# @example Use this command to inform someone watching the Asterisk console
|
122
134
|
# of actions happening within Adhearsion.
|
123
135
|
# verbose 'Processing call with Adhearsion' 3
|
@@ -141,7 +153,7 @@ module Adhearsion
|
|
141
153
|
# numbers, Adhearsion assumes you're saying the number, not the digits. For example, play("100")
|
142
154
|
# is pronounced as "one hundred" instead of "one zero zero".
|
143
155
|
#
|
144
|
-
# Note: it
|
156
|
+
# Note: it is not necessary to supply a sound file extension; Asterisk will try to find a sound
|
145
157
|
# file encoded using the current channel's codec, if one exists. If not, it will transcode from
|
146
158
|
# the default codec (GSM). Asterisk stores its sound files in /var/lib/asterisk/sounds.
|
147
159
|
#
|
@@ -176,7 +188,17 @@ module Adhearsion
|
|
176
188
|
#
|
177
189
|
def record(*args)
|
178
190
|
options = args.last.kind_of?(Hash) ? args.pop : {}
|
179
|
-
filename = args.shift || "/tmp/recording_%d
|
191
|
+
filename = args.shift || "/tmp/recording_%d"
|
192
|
+
|
193
|
+
if filename.index("%d")
|
194
|
+
if @call.variables.has_key?(:recording_counter)
|
195
|
+
@call.variables[:recording_counter] += 1
|
196
|
+
else
|
197
|
+
@call.variables[:recording_counter] = 0
|
198
|
+
end
|
199
|
+
filename = filename % @call.variables[:recording_counter]
|
200
|
+
end
|
201
|
+
|
180
202
|
if (!options.has_key?(:format))
|
181
203
|
format = filename.slice!(/\.[^\.]+$/)
|
182
204
|
if (format.nil?)
|
@@ -187,32 +209,36 @@ module Adhearsion
|
|
187
209
|
else
|
188
210
|
format = options.delete(:format)
|
189
211
|
end
|
190
|
-
|
212
|
+
|
213
|
+
# maxduration must be in milliseconds when using RECORD FILE
|
191
214
|
maxduration = options.delete(:maxduration) || -1
|
215
|
+
maxduration = maxduration * 1000 if maxduration > 0
|
216
|
+
|
192
217
|
escapedigits = options.delete(:escapedigits) || "#"
|
218
|
+
silence = options.delete(:silence) || 0
|
193
219
|
|
194
220
|
if (silence > 0)
|
195
|
-
response("RECORD FILE", filename, format, escapedigits, maxduration,0, "BEEP", "s=#{silence}")
|
221
|
+
response("RECORD FILE", filename, format, escapedigits, maxduration, 0, "BEEP", "s=#{silence}")
|
196
222
|
else
|
197
223
|
response("RECORD FILE", filename, format, escapedigits, maxduration, 0, "BEEP")
|
198
224
|
end
|
199
225
|
|
200
226
|
# If the user hangs up before the recording is entered, -1 is returned and RECORDED_FILE
|
201
227
|
# will not contain the name of the file, even though it IS in fact recorded.
|
202
|
-
filename
|
228
|
+
filename + "." + format
|
203
229
|
end
|
204
230
|
|
205
231
|
# Simulates pressing the specified digits over the current channel. Can be used to
|
206
232
|
# traverse a phone menu.
|
207
233
|
def dtmf(digits)
|
208
|
-
|
209
|
-
|
234
|
+
execute "SendDTMF", digits.to_s
|
235
|
+
end
|
210
236
|
|
211
|
-
|
212
|
-
|
213
|
-
|
237
|
+
# The with_next_message method...
|
238
|
+
def with_next_message(&block)
|
239
|
+
raise LocalJumpError, "Must supply a block" unless block_given?
|
214
240
|
block.call(next_message)
|
215
|
-
|
241
|
+
end
|
216
242
|
|
217
243
|
# This command should be used to advance to the next message in the Asterisk Comedian Voicemail application
|
218
244
|
def next_message
|
@@ -224,7 +250,7 @@ module Adhearsion
|
|
224
250
|
not @call.inbox.empty?
|
225
251
|
end
|
226
252
|
|
227
|
-
#
|
253
|
+
# Creates an interactive menu for the caller.
|
228
254
|
#
|
229
255
|
# The following documentation was derived from a post on Jay Phillips' blog (see below).
|
230
256
|
#
|
@@ -389,7 +415,7 @@ module Adhearsion
|
|
389
415
|
end
|
390
416
|
end
|
391
417
|
|
392
|
-
#
|
418
|
+
# Used to receive keypad input from the user. Digits are collected
|
393
419
|
# via DTMF (keypad) input until one of three things happens:
|
394
420
|
#
|
395
421
|
# 1. The number of digits you specify as the first argument is collected
|
@@ -416,8 +442,8 @@ module Adhearsion
|
|
416
442
|
# causes the timer to reset. This is a much more user-friendly approach than an
|
417
443
|
# absolute timeout.
|
418
444
|
#
|
419
|
-
|
420
|
-
|
445
|
+
# Note that when the digit limit is not specified the :accept_key becomes "#".
|
446
|
+
# Otherwise there would be no way to end the collection of digits. You can
|
421
447
|
# obviously override this by passing in a new key with :accept_key.
|
422
448
|
def input(*args)
|
423
449
|
options = args.last.kind_of?(Hash) ? args.pop : {}
|
@@ -469,7 +495,12 @@ module Adhearsion
|
|
469
495
|
# you should assign the important ones to an instance variable first before calling this method.
|
470
496
|
def jump_to(context, overrides={})
|
471
497
|
context = lookup_context_with_name(context) if context.kind_of?(Symbol) || (context.kind_of?(String) && context =~ /^[\w_]+$/)
|
472
|
-
|
498
|
+
|
499
|
+
# JRuby has a bug that prevents us from correctly determining the class name.
|
500
|
+
# See: http://jira.codehaus.org/browse/JRUBY-5026
|
501
|
+
if !(context.kind_of?(Adhearsion::DialPlan::DialplanContextProc) || context.kind_of?(Proc))
|
502
|
+
raise Adhearsion::VoIP::DSL::Dialplan::ContextNotFoundException
|
503
|
+
end
|
473
504
|
|
474
505
|
if overrides.any?
|
475
506
|
overrides = overrides.symbolize_keys
|
@@ -485,9 +516,13 @@ module Adhearsion
|
|
485
516
|
raise Adhearsion::VoIP::DSL::Dialplan::ControlPassingException.new(context)
|
486
517
|
end
|
487
518
|
|
488
|
-
#
|
489
|
-
#
|
519
|
+
# Place a call in a queue to be answered by a registered agent. You must then call join!()
|
520
|
+
#
|
521
|
+
# @param [String] queue_name the queue name to place the caller in
|
522
|
+
# @return [Adhearsion::VoIP::Asterisk::Commands::QueueProxy] a queue proxy object
|
523
|
+
#
|
490
524
|
# @see http://www.voip-info.org/wiki-Asterisk+cmd+Queue Full information on the Asterisk Queue
|
525
|
+
# @see Adhearsion::VoIP::Asterisk::Commands::QueueProxy#join! join!() for further details
|
491
526
|
def queue(queue_name)
|
492
527
|
queue_name = queue_name.to_s
|
493
528
|
|
@@ -503,19 +538,17 @@ module Adhearsion
|
|
503
538
|
end
|
504
539
|
end
|
505
540
|
|
506
|
-
#
|
507
|
-
#
|
508
|
-
# :
|
509
|
-
|
510
|
-
|
511
|
-
# probably doesn't exist. If :channel_unavailable, the callee
|
512
|
-
# phone may not be registered.
|
541
|
+
# Get the status of the last dial(). Possible dial statuses include :answer,
|
542
|
+
# :busy, :no_answer, :cancelled, :congested, and :channel_unavailable.
|
543
|
+
# If :cancel is returned, the caller hung up before the callee picked up.
|
544
|
+
# If :congestion is returned, the dialed extension probably doesn't exist.
|
545
|
+
# If :channel_unavailable, the callee phone may not be registered.
|
513
546
|
def last_dial_status
|
514
547
|
DIAL_STATUSES[get_dial_status]
|
515
548
|
end
|
516
549
|
|
517
|
-
#
|
518
|
-
# by Asterisk.
|
550
|
+
# @return [Boolean] true if your last call to dial() finished with the ANSWER state,
|
551
|
+
# as reported by Asterisk. false otherwise
|
519
552
|
def last_dial_successful?
|
520
553
|
last_dial_status == :answered
|
521
554
|
end
|
@@ -531,7 +564,7 @@ module Adhearsion
|
|
531
564
|
execute SpeechEngines.send(engine, text)
|
532
565
|
end
|
533
566
|
|
534
|
-
#
|
567
|
+
# A high-level way of enabling features you create/uncomment from features.conf.
|
535
568
|
#
|
536
569
|
# Certain Symbol features you enable (as defined in DYNAMIC_FEATURE_EXTENSIONS) have optional
|
537
570
|
# arguments that you can also specify here. The usage examples show how to do this.
|
@@ -560,6 +593,8 @@ module Adhearsion
|
|
560
593
|
|
561
594
|
# Disables a feature name specified in features.conf. If you're disabling it, it was probably
|
562
595
|
# set by enable_feature().
|
596
|
+
#
|
597
|
+
# @param [String] feature_name
|
563
598
|
def disable_feature(feature_name)
|
564
599
|
enabled_features_variable = variable 'DYNAMIC_FEATURES'
|
565
600
|
enabled_features = enabled_features_variable.split('#')
|
@@ -569,17 +604,25 @@ module Adhearsion
|
|
569
604
|
end
|
570
605
|
end
|
571
606
|
|
572
|
-
# Used to join a particular conference with the MeetMe application. To
|
573
|
-
#
|
574
|
-
#
|
607
|
+
# Used to join a particular conference with the MeetMe application. To use MeetMe, be sure you
|
608
|
+
# have a proper timing device configured on your Asterisk box. MeetMe is Asterisk's built-in
|
609
|
+
# conferencing program.
|
610
|
+
#
|
611
|
+
# @param [String] conference_id
|
612
|
+
# @param [Hash] options
|
613
|
+
#
|
575
614
|
# @see http://www.voip-info.org/wiki-Asterisk+cmd+MeetMe Asterisk Meetme Application Information
|
576
615
|
def join(conference_id, options={})
|
577
616
|
conference_id = conference_id.to_s.scan(/\w/).join
|
578
617
|
command_flags = options[:options].to_s # This is a passthrough string straight to Asterisk
|
579
618
|
pin = options[:pin]
|
580
619
|
raise ArgumentError, "A conference PIN number must be numerical!" if pin && pin.to_s !~ /^\d+$/
|
620
|
+
|
621
|
+
# To disable dynamic conference creation set :use_static_conf => true
|
622
|
+
use_static_conf = options.has_key?(:use_static_conf) ? options[:use_static_conf] : false
|
623
|
+
|
581
624
|
# The 'd' option of MeetMe creates conferences dynamically.
|
582
|
-
command_flags += 'd' unless command_flags.include?
|
625
|
+
command_flags += 'd' unless (command_flags.include?('d') or use_static_conf)
|
583
626
|
|
584
627
|
execute "MeetMe", conference_id, command_flags, options[:pin]
|
585
628
|
end
|
@@ -587,7 +630,10 @@ module Adhearsion
|
|
587
630
|
# Issue this command to access a channel variable that exists in the asterisk dialplan (i.e. extensions.conf)
|
588
631
|
# Use get_variable to pass information from other modules or high level configurations from the asterisk dialplan
|
589
632
|
# to the adhearsion dialplan.
|
590
|
-
|
633
|
+
#
|
634
|
+
# @param [String] variable_name
|
635
|
+
#
|
636
|
+
# @see: http://www.voip-info.org/wiki/view/get+variable Asterisk Get Variable
|
591
637
|
def get_variable(variable_name)
|
592
638
|
result = response("GET VARIABLE", variable_name)
|
593
639
|
case result
|
@@ -598,17 +644,22 @@ module Adhearsion
|
|
598
644
|
end
|
599
645
|
end
|
600
646
|
|
601
|
-
#
|
602
|
-
#
|
647
|
+
# Pass information back to the asterisk dial plan.
|
648
|
+
#
|
649
|
+
# Keep in mind that the variables are not global variables. These variables only exist for the channel
|
603
650
|
# related to the call that is being serviced by the particular instance of your adhearsion application.
|
604
651
|
# You will not be able to pass information back to the asterisk dialplan for other instances of your adhearsion
|
605
|
-
# application to share.
|
652
|
+
# application to share. Once the channel is "hungup" then the variables are cleared and their information is gone.
|
653
|
+
#
|
654
|
+
# @param [String] variable_name
|
655
|
+
# @param [String] value
|
656
|
+
#
|
606
657
|
# @see http://www.voip-info.org/wiki/view/set+variable Asterisk Set Variable
|
607
658
|
def set_variable(variable_name, value)
|
608
659
|
response("SET VARIABLE", variable_name, value) == "200 result=1"
|
609
660
|
end
|
610
661
|
|
611
|
-
#
|
662
|
+
# Allows you to either set or get a channel variable from Asterisk.
|
612
663
|
# The method takes a hash key/value pair if you would like to set a variable
|
613
664
|
# Or a single string with the variable to get from Asterisk
|
614
665
|
def variable(*args)
|
@@ -627,10 +678,12 @@ module Adhearsion
|
|
627
678
|
end
|
628
679
|
end
|
629
680
|
|
630
|
-
#
|
631
|
-
#
|
681
|
+
# Send a caller to a voicemail box to leave a message.
|
682
|
+
#
|
632
683
|
# The method takes the mailbox_number of the user to leave a message for and a
|
633
684
|
# greeting_option that will determine which message gets played to the caller.
|
685
|
+
#
|
686
|
+
# @see http://www.voip-info.org/tiki-index.php?page=Asterisk+cmd+VoiceMail Asterisk Voicemail
|
634
687
|
def voicemail(*args)
|
635
688
|
options_hash = args.last.kind_of?(Hash) ? args.pop : {}
|
636
689
|
mailbox_number = args.shift
|
@@ -665,6 +718,9 @@ module Adhearsion
|
|
665
718
|
|
666
719
|
# The voicemail_main method puts a caller into the voicemail system to fetch their voicemail
|
667
720
|
# or set options for their voicemail box.
|
721
|
+
#
|
722
|
+
# @param [Hash] options
|
723
|
+
#
|
668
724
|
# @see http://www.voip-info.org/wiki-Asterisk+cmd+VoiceMailMain Asterisk VoiceMailMain Command
|
669
725
|
def voicemail_main(options={})
|
670
726
|
mailbox, context, folder = options.values_at :mailbox, :context, :folder
|
@@ -702,15 +758,15 @@ module Adhearsion
|
|
702
758
|
voicemail_main
|
703
759
|
end
|
704
760
|
|
705
|
-
#
|
706
|
-
#
|
761
|
+
# Dial an extension or "phone number" in asterisk.
|
762
|
+
# Maps to the Asterisk DIAL command in the asterisk dialplan.
|
707
763
|
#
|
708
|
-
#
|
764
|
+
# @param [String] number represents the extension or "number" that asterisk should dial.
|
709
765
|
# Be careful to not just specify a number like 5001, 9095551001
|
710
766
|
# You must specify a properly formatted string as Asterisk would expect to use in order to understand
|
711
767
|
# whether the call should be dialed using SIP, IAX, or some other means.
|
712
768
|
#
|
713
|
-
#
|
769
|
+
# @param [Hash] options
|
714
770
|
#
|
715
771
|
# +:caller_id+ - the caller id number to be used when the call is placed. It is advised you properly adhere to the
|
716
772
|
# policy of VoIP termination providers with respect to caller id values.
|
@@ -727,7 +783,7 @@ module Adhearsion
|
|
727
783
|
# for a complete list of these options and their usage please check the link below.
|
728
784
|
#
|
729
785
|
# +:confirm+ - ?
|
730
|
-
|
786
|
+
#
|
731
787
|
# @example Make a call to the PSTN using my SIP provider for VoIP termination
|
732
788
|
# dial("SIP/19095551001@my.sip.voip.terminator.us")
|
733
789
|
#
|
@@ -738,7 +794,7 @@ module Adhearsion
|
|
738
794
|
# @example Make a call using the IAX provider to the PSTN
|
739
795
|
# dial("IAX2/my.id@voipjet/19095551234", :name=>"John Doe", :caller_id=>"9095551234")
|
740
796
|
#
|
741
|
-
|
797
|
+
# @see http://www.voip-info.org/wiki-Asterisk+cmd+Dial Asterisk Dial Command
|
742
798
|
def dial(number, options={})
|
743
799
|
*recognized_options = :caller_id, :name, :for, :options, :confirm
|
744
800
|
|
@@ -774,15 +830,19 @@ module Adhearsion
|
|
774
830
|
|
775
831
|
|
776
832
|
# Speaks the digits given as an argument. For example, "123" is spoken as "one two three".
|
833
|
+
#
|
834
|
+
# @param [String] digits
|
777
835
|
def say_digits(digits)
|
778
836
|
execute "saydigits", validate_digits(digits)
|
779
837
|
end
|
780
838
|
|
781
|
-
#
|
839
|
+
# Get the number of seconds the given block takes to execute. This
|
782
840
|
# is particularly useful in dialplans for tracking billable time. Note that
|
783
841
|
# if the call is hung up during the block, you will need to rescue the
|
784
842
|
# exception if you have some mission-critical logic after it with which
|
785
843
|
# you're recording this return-value.
|
844
|
+
#
|
845
|
+
# @return [Float] number of seconds taken for block to execute
|
786
846
|
def duration_of
|
787
847
|
start_time = Time.now
|
788
848
|
yield
|
@@ -790,8 +850,9 @@ module Adhearsion
|
|
790
850
|
end
|
791
851
|
|
792
852
|
#
|
793
|
-
#
|
794
|
-
#
|
853
|
+
# Play a sequence of files, stopping the playback if a digit is pressed.
|
854
|
+
#
|
855
|
+
# @return [String, nil] digit pressed, or nil if none
|
795
856
|
#
|
796
857
|
def interruptible_play(*files)
|
797
858
|
files.flatten.each do |file|
|
@@ -818,14 +879,14 @@ module Adhearsion
|
|
818
879
|
interruptible_play(*files)
|
819
880
|
end
|
820
881
|
|
821
|
-
#
|
882
|
+
# allows setting of the callerid number of the call
|
822
883
|
def set_caller_id_number(caller_id)
|
823
884
|
return unless caller_id
|
824
885
|
raise ArgumentError, "Caller ID must be numerical" if caller_id.to_s !~ /^\d+$/
|
825
886
|
response "SET CALLERID", caller_id
|
826
887
|
end
|
827
888
|
|
828
|
-
#
|
889
|
+
# allows the setting of the callerid name of the call
|
829
890
|
def set_caller_id_name(caller_id_name)
|
830
891
|
return unless caller_id_name
|
831
892
|
variable "CALLERID(name)" => caller_id_name
|
@@ -972,7 +1033,7 @@ module Adhearsion
|
|
972
1033
|
end
|
973
1034
|
|
974
1035
|
def error?(result)
|
975
|
-
result.to_s[/^#{response_prefix}(?:-\d
|
1036
|
+
result.to_s[/^#{response_prefix}(?:-\d+)/]
|
976
1037
|
end
|
977
1038
|
|
978
1039
|
# timeout with pressed digits: 200 result=<digits> (timeout)
|
@@ -1046,8 +1107,9 @@ module Adhearsion
|
|
1046
1107
|
@name, @environment = name, environment
|
1047
1108
|
end
|
1048
1109
|
|
1049
|
-
# Makes the current channel join the queue.
|
1050
|
-
#
|
1110
|
+
# Makes the current channel join the queue.
|
1111
|
+
#
|
1112
|
+
# @param [Hash] options
|
1051
1113
|
#
|
1052
1114
|
# :timeout - The number of seconds to wait for an agent to answer
|
1053
1115
|
# :play - Can be :ringing or :music.
|
@@ -1055,24 +1117,37 @@ module Adhearsion
|
|
1055
1117
|
# :allow_transfer - Can be :caller, :agent, or :everyone. Allow someone to transfer the call.
|
1056
1118
|
# :allow_hangup - Can be :caller, :agent, or :everyone. Allow someone to hangup with the * key.
|
1057
1119
|
#
|
1058
|
-
#
|
1059
|
-
#
|
1060
|
-
#
|
1061
|
-
#
|
1062
|
-
#
|
1063
|
-
#
|
1064
|
-
#
|
1065
|
-
#
|
1066
|
-
#
|
1067
|
-
#
|
1068
|
-
#
|
1069
|
-
#
|
1070
|
-
#
|
1120
|
+
# @example
|
1121
|
+
# queue('sales').join!
|
1122
|
+
# @example
|
1123
|
+
# queue('sales').join! :timeout => 1.minute
|
1124
|
+
# @example
|
1125
|
+
# queue('sales').join! :play => :music
|
1126
|
+
# @example
|
1127
|
+
# queue('sales').join! :play => :ringing
|
1128
|
+
# @example
|
1129
|
+
# queue('sales').join! :announce => "custom/special-queue-announcement"
|
1130
|
+
# @example
|
1131
|
+
# queue('sales').join! :allow_transfer => :caller
|
1132
|
+
# @example
|
1133
|
+
# queue('sales').join! :allow_transfer => :agent
|
1134
|
+
# @example
|
1135
|
+
# queue('sales').join! :allow_hangup => :caller
|
1136
|
+
# @example
|
1137
|
+
# queue('sales').join! :allow_hangup => :agent
|
1138
|
+
# @example
|
1139
|
+
# queue('sales').join! :allow_hangup => :everyone
|
1140
|
+
# @example
|
1141
|
+
# queue('sales').join! :allow_transfer => :agent, :timeout => 30.seconds,
|
1071
1142
|
def join!(options={})
|
1072
1143
|
environment.execute("queue", name, *self.class.format_join_hash_key_arguments(options))
|
1073
1144
|
normalize_queue_status_variable environment.variable("QUEUESTATUS")
|
1074
1145
|
end
|
1075
1146
|
|
1147
|
+
# Get the agents associated with a queue
|
1148
|
+
#
|
1149
|
+
# @param [Hash] options
|
1150
|
+
# @return [QueueAgentsListProxy]
|
1076
1151
|
def agents(options={})
|
1077
1152
|
cached = options.has_key?(:cache) ? options.delete(:cache) : true
|
1078
1153
|
raise ArgumentError, "Unrecognized arguments to agents(): #{options.inspect}" if options.keys.any?
|
@@ -1083,19 +1158,28 @@ module Adhearsion
|
|
1083
1158
|
end
|
1084
1159
|
end
|
1085
1160
|
|
1161
|
+
# Check how many channels are waiting in the queue
|
1162
|
+
# @return [Integer]
|
1163
|
+
# @raise QueueDoesNotExistError
|
1086
1164
|
def waiting_count
|
1087
1165
|
raise QueueDoesNotExistError.new(name) unless exists?
|
1088
1166
|
environment.variable("QUEUE_WAITING_COUNT(#{name})").to_i
|
1089
1167
|
end
|
1090
1168
|
|
1169
|
+
# Check whether the waiting count is zero
|
1170
|
+
# @return [Boolean]
|
1091
1171
|
def empty?
|
1092
1172
|
waiting_count == 0
|
1093
1173
|
end
|
1094
1174
|
|
1175
|
+
# Check whether any calls are waiting in the queue
|
1176
|
+
# @return [Boolean]
|
1095
1177
|
def any?
|
1096
1178
|
waiting_count > 0
|
1097
1179
|
end
|
1098
1180
|
|
1181
|
+
# Check whether a queue exists/is defined in Asterisk
|
1182
|
+
# @return [Boolean]
|
1099
1183
|
def exists?
|
1100
1184
|
environment.execute('RemoveQueueMember', name, 'SIP/AdhearsionQueueExistenceCheck')
|
1101
1185
|
environment.variable("RQMSTATUS") != 'NOSUCHQUEUE'
|
@@ -1103,7 +1187,24 @@ module Adhearsion
|
|
1103
1187
|
|
1104
1188
|
private
|
1105
1189
|
|
1190
|
+
# Ensure the queue exists by interpreting the QUEUESTATUS variable
|
1191
|
+
#
|
1192
|
+
# According to http://www.voip-info.org/wiki/view/Asterisk+cmd+Queue
|
1193
|
+
# possible values are:
|
1194
|
+
# TIMEOUT (:timeout
|
1195
|
+
# FULL (:full)
|
1196
|
+
# JOINEMPTY (:joinempty)
|
1197
|
+
# LEAVEEMPTY (:leaveempty)
|
1198
|
+
# JOINUNAVAIL (:joinunavail)
|
1199
|
+
# LEAVEUNAVAIL (:leaveunavail)
|
1200
|
+
#
|
1201
|
+
# If Adhearsion cannot determine the status then :unknown will be returned.
|
1202
|
+
#
|
1203
|
+
# @param [String] QUEUESTATUS variable from Asterisk
|
1204
|
+
# @return [Symbol] Symbolized version of QUEUESTATUS
|
1205
|
+
# @raise QueueDoesNotExistError
|
1106
1206
|
def normalize_queue_status_variable(variable)
|
1207
|
+
variable = "UNKNOWN" if variable.nil?
|
1107
1208
|
returning variable.downcase.to_sym do |queue_status|
|
1108
1209
|
raise QueueDoesNotExistError.new(name) if queue_status == :unknown
|
1109
1210
|
end
|
@@ -1129,9 +1230,9 @@ module Adhearsion
|
|
1129
1230
|
alias size count
|
1130
1231
|
alias length count
|
1131
1232
|
|
1132
|
-
#
|
1133
|
-
#
|
1134
|
-
# this queue
|
1233
|
+
# @param [Hash] args
|
1234
|
+
# :name value will be viewable in the queue_log
|
1235
|
+
# :penalty is the penalty assigned to this agent for answering calls on this queue
|
1135
1236
|
def new(*args)
|
1136
1237
|
|
1137
1238
|
options = args.last.kind_of?(Hash) ? args.pop : {}
|
@@ -1309,7 +1410,7 @@ module Adhearsion
|
|
1309
1410
|
|
1310
1411
|
end
|
1311
1412
|
|
1312
|
-
class QueueDoesNotExistError <
|
1413
|
+
class QueueDoesNotExistError < StandardError
|
1313
1414
|
def initialize(queue_name)
|
1314
1415
|
super "Queue #{queue_name} does not exist!"
|
1315
1416
|
end
|
@@ -1325,7 +1426,7 @@ module Adhearsion
|
|
1325
1426
|
|
1326
1427
|
module SpeechEngines
|
1327
1428
|
|
1328
|
-
class InvalidSpeechEngine <
|
1429
|
+
class InvalidSpeechEngine < StandardError; end
|
1329
1430
|
|
1330
1431
|
class << self
|
1331
1432
|
def cepstral(text)
|