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.
Files changed (36) hide show
  1. data/CHANGELOG +12 -0
  2. data/Rakefile +6 -5
  3. data/adhearsion.gemspec +9 -5
  4. data/app_generators/ahn/ahn_generator.rb +5 -0
  5. data/app_generators/ahn/templates/components/disabled/restful_rpc/restful_rpc.rb +1 -1
  6. data/app_generators/ahn/templates/components/disabled/sandbox/sandbox.rb +1 -1
  7. data/app_generators/ahn/templates/components/disabled/xmpp_gateway/README.markdown +3 -0
  8. data/app_generators/ahn/templates/components/disabled/xmpp_gateway/xmpp_gateway.rb +11 -0
  9. data/app_generators/ahn/templates/components/disabled/xmpp_gateway/xmpp_gateway.yml +0 -0
  10. data/app_generators/ahn/templates/config/startup.rb +10 -1
  11. data/lib/adhearsion/cli.rb +7 -2
  12. data/lib/adhearsion/foundation/event_socket.rb +1 -1
  13. data/lib/adhearsion/foundation/future_resource.rb +1 -1
  14. data/lib/adhearsion/host_definitions.rb +1 -1
  15. data/lib/adhearsion/initializer.rb +21 -8
  16. data/lib/adhearsion/initializer/configuration.rb +44 -3
  17. data/lib/adhearsion/initializer/database.rb +11 -1
  18. data/lib/adhearsion/initializer/ldap.rb +7 -1
  19. data/lib/adhearsion/initializer/xmpp.rb +42 -0
  20. data/lib/adhearsion/version.rb +26 -2
  21. data/lib/adhearsion/voip/asterisk/agi_server.rb +2 -1
  22. data/lib/adhearsion/voip/asterisk/commands.rb +186 -85
  23. data/lib/adhearsion/voip/asterisk/manager_interface.rb +147 -50
  24. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1 -1
  25. data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +1 -1
  26. data/lib/adhearsion/voip/call.rb +15 -8
  27. data/lib/adhearsion/voip/dial_plan.rb +21 -4
  28. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +1 -1
  29. data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +2 -2
  30. data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +2 -2
  31. data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +2 -2
  32. data/lib/adhearsion/xmpp/connection.rb +61 -0
  33. data/lib/theatre/invocation.rb +1 -1
  34. data/lib/theatre/namespace_manager.rb +1 -1
  35. metadata +12 -6
  36. 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
@@ -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 = 4 unless defined? TINY
5
+ TINY = 5 unless defined? TINY
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.') unless defined? STRING
8
8
  end
9
- end
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
- # This method is the underlying method executed by nearly all the command methods in this module.
61
- # It is used to send the plaintext commands in the proper AGI format over TCP/IP back to an Asterisk server via the
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 method you to communicate directly with an Asterisk server via the FAGI protocol.
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
- # The answer command must be called first before any other commands can be issued.
87
- # In typical adhearsion applications the answer command is called by default as soon
88
- # as a call is transfered to a valid context in dialplan.rb.
89
- # If you do not want your adhearsion application to automatically issue an answer command,
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
- # an answer command has already been issued either explicitly by your code or implicitly
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. For commands that do not fall into this category, then exec is what you
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's not necessary to supply a sound file extension; Asterisk will try to find a sound
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.gsm"
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
- silence = options.delete(:silence) || 0
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.index("%d") ? get_variable('RECORDED_FILE') : filename + "." + format
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
- execute "SendDTMF", digits.to_s
209
- end
234
+ execute "SendDTMF", digits.to_s
235
+ end
210
236
 
211
- # The with_next_message method...
212
- def with_next_message(&block)
213
- raise LocalJumpError, "Must supply a block" unless block_given?
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
- end
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
- # Menu creates an interactive menu for the caller.
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
- # This method is used to receive keypad input from the user. Digits are collected
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
- # Note that when you don't specify a digit limit, the :accept_key becomes "#"
420
- # because there'd be no other way to end the collection of digits. You can
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
- raise Adhearsion::VoIP::DSL::Dialplan::ContextNotFoundException unless context.kind_of?(Adhearsion::DialPlan::DialplanContextProc)
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
- # The queue method puts a call into a call queue to be answered by an agent registered with that queue.
489
- # The queue method takes a queue_name as an argument to place the caller in the appropriate queue.
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
- # Returns the status of the last dial(). Possible dial
507
- # statuses include :answer, :busy, :no_answer, :cancelled,
508
- # :congested, and :channel_unavailable. If :cancel is
509
- # returned, the caller hung up before the callee picked
510
- # up. If :congestion is returned, the dialed extension
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
- # Returns true if your last call to dial() finished with the ANSWER state, as reported
518
- # by Asterisk. Returns false otherwise
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
- # This method is a high-level way of enabling features you create/uncomment from features.conf.
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
- # use MeetMe, be sure you have a proper timing device configured on your
574
- # Asterisk box. MeetMe is Asterisk's built-in conferencing program.
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? 'd'
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
- # @see: http://www.voip-info.org/wiki/view/get+variable Asterisk Get Variable
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
- # Use set_variable to pass information back to the asterisk dial plan.
602
- # Keep in mind that the variables are not global variables. These variables only exist for the channel
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. Once the channel is "hungup" then the variables are cleared and their information is gone.
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
- # The variable method allows you to either set or get a channel variable from Asterisk
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
- # Use the voicemail method to send a caller to a voicemail box to leave a message.
631
- # @see http://www.voip-info.org/tiki-index.php?page=Asterisk+cmd+VoiceMail Asterisk Voicemail
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
- # Use this command to dial an extension or "phone number" in asterisk.
706
- # This command maps to the Asterisk DIAL command in the asterisk dialplan.
761
+ # Dial an extension or "phone number" in asterisk.
762
+ # Maps to the Asterisk DIAL command in the asterisk dialplan.
707
763
  #
708
- # The first parameter, number, must be a string that represents the extension or "number" that asterisk should dial.
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
- # Options Parameter:
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
- # @see http://www.voip-info.org/wiki-Asterisk+cmd+Dial Asterisk Dial Command
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
- # Returns the number of seconds the given block takes to execute as a Float. This
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
- # This will play a sequence of files, stopping the playback if a digit is pressed. If a digit is pressed, it will be
794
- # returned as a String. If the files played with no keypad input, nil will be returned.
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
- # set_callier_id_number method allows setting of the callerid number of the call
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
- # set_caller_id_name method allows the setting of the callerid name of the call
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+|0)/]
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. Below are explanations of the recognized Hash-key
1050
- # arguments supported by this method.
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
- # Usage examples:
1059
- #
1060
- # - queue('sales').join!
1061
- # - queue('sales').join! :timeout => 1.minute
1062
- # - queue('sales').join! :play => :music
1063
- # - queue('sales').join! :play => :ringing
1064
- # - queue('sales').join! :announce => "custom/special-queue-announcement"
1065
- # - queue('sales').join! :allow_transfer => :caller
1066
- # - queue('sales').join! :allow_transfer => :agent
1067
- # - queue('sales').join! :allow_hangup => :caller
1068
- # - queue('sales').join! :allow_hangup => :agent
1069
- # - queue('sales').join! :allow_hangup => :everyone
1070
- # - queue('sales').join! :allow_transfer => :agent, :timeout => 30.seconds,
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
- # Supported Hash-key arguments are :penalty and :name. The :name value will be viewable in
1133
- # the queue_log. The :penalty is the penalty assigned to this agent for answering calls on
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 < Exception
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 < Exception; end
1429
+ class InvalidSpeechEngine < StandardError; end
1329
1430
 
1330
1431
  class << self
1331
1432
  def cepstral(text)