AsteriskRuby 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,139 @@
1
+ =begin rdoc
2
+ Copyright (c) 2007, Vonage Holdings
3
+
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+ * Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+ * Neither the name of Vonage Holdings nor the names of its
15
+ contributors may be used to endorse or promote products derived from this
16
+ software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ Author: Michael Komitee <mkomitee@gmail.com>
31
+ AGIExceptions declares various exception classes for the AGI Framework.
32
+ =end
33
+
34
+ #There are several possible Exceptions that can occur with AGI communication. This file provides custom exception classes that mirror them.
35
+ #= Exceptions:
36
+ #* AGIError
37
+ #* AGIHangupError
38
+ #* AGITimeoutError
39
+ #* AGIChannelError
40
+ #* AGICommandError
41
+ #* AGIInitializeError
42
+
43
+ #AGIError is the base Exception Class from which all other AGI Exceptions inherit.
44
+ #= Children:
45
+ #* AGIHangupError
46
+ #* AGITimeoutError
47
+ #* AGIChannelError
48
+ #* AGICommandError
49
+ #* AGIInitializeError
50
+ class AGIError < Exception
51
+ # This is the raw string returned from Asterisk to the AGI if one was available
52
+ attr_accessor :raw_data
53
+ def initialize(raw_data, *rest)
54
+ @raw_data = raw_data
55
+ super(rest)
56
+ end
57
+ def to_s
58
+ @raw_data
59
+ end
60
+ def to_str
61
+ self.to_s
62
+ end
63
+ end
64
+
65
+ #AGIHangupError signifies that the Asterisk Channel associated with the AGI has been hung up, unexpectedly. It inherits from AGIError.
66
+ class AGIHangupError < AGIError
67
+ end
68
+
69
+ #AGITimeoutError signifies that a Asterisk notified the AGI that a requested command timed out. It inherits from AGIError.
70
+ class AGITimeoutError < AGIError
71
+ end
72
+
73
+ #AGIChannelError signifies that Asterisk notified the AGI of a channel error. It inherits from AGIError.
74
+ class AGIChannelError < AGIError
75
+ end
76
+
77
+ #AGICommandError signifies that Asterisk has notified us that there was an error with the requested Command, usually the syntax. It inherits from AGIError.
78
+ class AGICommandError < AGIError
79
+ end
80
+
81
+ #AGIInitializeError significes that the AGI has been instructed to initialize a channel which had previously been reinitialized. If this is actually intended, it can be accomplished by first calling reinit, which will reset channel parameters beforehand.
82
+ class AGIInitializeError < AGIError
83
+ end
84
+
85
+ #AGIMenuFailure signifies that there was a failure in constructing or playing an AGIMenu
86
+ class AGIMenuFailure < Exception
87
+ def initialize(str)
88
+ @message = str
89
+ end
90
+ def to_s
91
+ @message
92
+ end
93
+ def to_str
94
+ self.to_s
95
+ end
96
+ end
97
+
98
+ class AGIStateFailure < Exception
99
+ def initialize(str)
100
+ @message = str
101
+ end
102
+ def to_s
103
+ @message
104
+ end
105
+ def to_str
106
+ self.to_s
107
+ end
108
+ end
109
+
110
+ =begin
111
+ Copyright (c) 2007, Vonage Holdings
112
+
113
+ All rights reserved.
114
+
115
+ Redistribution and use in source and binary forms, with or without
116
+ modification, are permitted provided that the following conditions are met:
117
+
118
+ * Redistributions of source code must retain the above copyright
119
+ notice, this list of conditions and the following disclaimer.
120
+ * Redistributions in binary form must reproduce the above copyright
121
+ notice, this list of conditions and the following disclaimer in the
122
+ documentation and/or other materials provided with the distribution.
123
+ * Neither the name of Vonage Holdings nor the names of its
124
+ contributors may be used to endorse or promote products derived from this
125
+ software without specific prior written permission.
126
+
127
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
128
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
129
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
130
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
131
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
132
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
133
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
134
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
135
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
136
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
137
+ POSSIBILITY OF SUCH DAMAGE.
138
+
139
+ =end
@@ -0,0 +1,69 @@
1
+ =begin rdoc
2
+ Copyright (c) 2007, Vonage Holdings
3
+
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+ * Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+ * Neither the name of Vonage Holdings nor the names of its
15
+ contributors may be used to endorse or promote products derived from this
16
+ software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ Author: Michael Komitee <mkomitee@gmail.com>
31
+
32
+ This is a meta package for the framework at large.
33
+ =end
34
+
35
+ require 'AGI'
36
+ require 'AGIMenu'
37
+ require 'AGIServer'
38
+ require 'AGIState'
39
+ require 'AGISelection'
40
+
41
+ =begin
42
+ Copyright (c) 2007, Vonage Holdings
43
+
44
+ All rights reserved.
45
+
46
+ Redistribution and use in source and binary forms, with or without
47
+ modification, are permitted provided that the following conditions are met:
48
+
49
+ * Redistributions of source code must retain the above copyright
50
+ notice, this list of conditions and the following disclaimer.
51
+ * Redistributions in binary form must reproduce the above copyright
52
+ notice, this list of conditions and the following disclaimer in the
53
+ documentation and/or other materials provided with the distribution.
54
+ * Neither the name of Vonage Holdings nor the names of its
55
+ contributors may be used to endorse or promote products derived from this
56
+ software without specific prior written permission.
57
+
58
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
59
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
62
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
63
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
64
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
65
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
66
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
67
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
68
+ POSSIBILITY OF SUCH DAMAGE.
69
+ =end
@@ -0,0 +1,244 @@
1
+ =begin rdoc
2
+ Copyright (c) 2007, Vonage Holdings
3
+
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+ * Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+ * Neither the name of Vonage Holdings nor the names of its
15
+ contributors may be used to endorse or promote products derived from this
16
+ software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ Author: Michael Komitee <mkomitee@gmail.com>
31
+
32
+ Sometimes when dealing with Asterisk AGI, a generic AGIMenu object can come in handy. Thats where the aptly named AGIMenu object comes into play. With AGIMenu, you can configure a menu of options based on a yaml configuration or a hash. For example:
33
+
34
+ AGIMenu.sounds_dir = 'agimenu-test/sounds/'
35
+ hash = {:introduction=>["welcome", "instructions"],
36
+ :conclusion=>"what-is-your-choice",
37
+ :timeout=>17,
38
+ :choices=>
39
+ [{:dtmf=>"*", :audio=>["to-go-back", "press", "digits/star"]},
40
+ {:dtmf=>1, :audio=>["press", "digits/1", "for-option-1"]},
41
+ {:dtmf=>2, :audio=>["press", "digits/2", "for-option-2"]},
42
+ {:dtmf=>"#", :audio=>["or", "press", "digits/pound", "to-repeat"]}]}
43
+
44
+ menu = AGIMenu.new(hash)
45
+ menu.play(:agi => AGI.new())
46
+
47
+ This results in Asterisk using sounds in it's agimenu-test/sounds directory to play a menu which accepts the DTMF *, 1, 2, or #. It will first play the introduction sound files 'welcome' and 'instructions', then play the menu sound files 'to-go-back' 'press' 'digits/star' 'press' 'digits/1' 'for-option-1' 'press 'digits/2' 'for-option-2' 'or' 'press' 'digits/pound' 'to-repeat', and then play the conslusion sound file 'what-is-your-choice' and then wait 17 seconds.
48
+
49
+ You could hand AGIMenu.new() a filename, a file, a yaml oject, a hash, or nothing at all. You can then modify the menu with the classes various methods.
50
+ =end
51
+
52
+ require 'yaml'
53
+ require 'AGI'
54
+
55
+ class AGIMenu
56
+ @@sounds_dir = ''
57
+ attr_accessor :title
58
+ attr_reader :params
59
+ def initialize(input=nil)
60
+ @title = 'AGIMenu:' + self.object_id.to_s
61
+ @sounds = Hash.new
62
+ @order = []
63
+ @introduction = []
64
+ @conclusion = []
65
+ @default_timeout = 600
66
+ @params=input
67
+ configure(input)
68
+ end
69
+ def add(digit, sound)
70
+ if @order.include?(digit.to_s) then
71
+ raise AGIMenuFailure.new("Duplicate Digit entry (#{digit.to_s}) in AGIMenu: '#{@title}'")
72
+ elsif digit.to_s =~ /[0-9#*]/
73
+ @sounds[digit.to_s] = [ sound ].flatten
74
+ @order.push(digit.to_s)
75
+ else
76
+ raise AGIMenuFailure.new("Invalid Digit entry (#{digit.to_s}) in AGIMenu: '#{@title}'")
77
+ end
78
+ end
79
+ def digits
80
+ @order
81
+ end
82
+ alias :dtmf :digits
83
+ alias :order :digits
84
+ def timeout=(timeout)
85
+ @default_timeout = timeout.to_i
86
+ end
87
+ def timeout
88
+ @default_timeout
89
+ end
90
+ def introduction=(introduction)
91
+ @introduction = [ introduction ].flatten
92
+ end
93
+ def introduction
94
+ @introduction
95
+ end
96
+ def conclusion=(conclusion)
97
+ @conclusion = [ conclusion ].flatten
98
+ end
99
+ def conclusion
100
+ @conclusion
101
+ end
102
+ def reorder(new_order, force=false)
103
+ new_order.collect!{ |dtmf| dtmf.to_s }
104
+ if @order.sort != new_order.sort
105
+ raise AGIMenuFailure.new("New and old order are incompatible in AGIMenu: '#{@title}'") unless force
106
+ end
107
+ @order = new_order
108
+ end
109
+
110
+ def play(conf={})
111
+ defaults = {:introduction => true, :conclusion => true, :timeout => @default_timeout}
112
+ conf = defaults.merge(conf)
113
+ unless conf[:agi].respond_to?(:background) and conf[:agi].respond_to?(:wait_for_digit)
114
+ raise ArgumentError, ":agi required, must be an AsteriskAGI for AGIMenu.play in AGIMenu: '#{@title}'"
115
+ end
116
+ digits = @order.join()
117
+ audio = []
118
+ case
119
+ when conf[:introduction].class == TrueClass
120
+ audio << add_introduction
121
+ when conf[:introduction]
122
+ audio << add_introduction(conf[:introduction])
123
+ end
124
+ audio << add_body
125
+ audio << add_conclusion if conf[:conclusion]
126
+ result = conf[:agi].background(audio.flatten, "'#{digits}'")
127
+ return result unless result.nil?
128
+ return result if conf[:timeout].nil?
129
+ return handle_timeout(conf[:agi], conf[:timeout].to_i)
130
+ end
131
+ alias :background :play
132
+ alias :execute :play
133
+
134
+ def AGIMenu.sounds_dir=(dir)
135
+ @@sounds_dir = dir
136
+ end
137
+ def AGIMenu.sounds_dir
138
+ @@sounds_dir
139
+ end
140
+
141
+ private
142
+ def handle_timeout(agi, timeout)
143
+ begin
144
+ start = Time.now.to_i
145
+ result = agi.wait_for_digit(timeout*1000)
146
+ if self.dtmf.include?(result.data.to_s)
147
+ return result
148
+ else
149
+ raise AGIMenuFailure.new("Invalid DTMF Supplied #{result.data.to_s} in AGIMenu: '#{@title}'")
150
+ end
151
+ rescue AGITimeoutError
152
+ return nil
153
+ rescue AGIMenuFailure => err
154
+ retry if timeout == -1
155
+ elapsed = Time.now.to_i - start.to_i
156
+ timeout = timeout - elapsed
157
+ return nil if timeout <= 0
158
+ retry
159
+ end
160
+ end
161
+
162
+ def add_introduction(introduction=[])
163
+ audio = []
164
+ introduction = @introduction if introduction.empty?
165
+ [introduction].flatten.each { |i| audio << "#{@@sounds_dir}#{i}" }
166
+ return audio
167
+ end
168
+
169
+ def add_body
170
+ audio = []
171
+ @order.each do
172
+ |i|
173
+ begin
174
+ @sounds[i].each { |sound| audio << "#{@@sounds_dir}#{sound}" }
175
+ rescue NoMethodError => err
176
+ raise AGIMenuFailure.new("Invalid Order forced, #{i} an invalid choice in AGIMenu: '#{@title}'")
177
+ puts "Caught #{err.class}: #{err} - #{err.message}"
178
+ end
179
+ end
180
+ return audio
181
+ end
182
+ def add_conclusion
183
+ audio = []
184
+ @conclusion.flatten.each { |i| audio << "#{@@sounds_dir}#{i}" }
185
+ return audio
186
+ end
187
+ def configure(input)
188
+ if input.respond_to?(:read)
189
+ config = YAML::load( input )
190
+ elsif input.respond_to?(:to_hash)
191
+ config = input
192
+ elsif input.respond_to?(:to_s) and File.exists?(input.to_s) and File.readable?(input.to_s)
193
+ config = File.open( input.to_s ) { |f| YAML::load( f ) }
194
+ end
195
+ if config.respond_to?(:to_hash)
196
+ @params = config
197
+ if config.has_key?(:introduction)
198
+ @introduction = [config[:introduction]].flatten
199
+ end
200
+ if config.has_key?(:conclusion)
201
+ @conclusion = [config[:conclusion]].flatten
202
+ end
203
+ if config.has_key?(:timeout)
204
+ @default_timeout = config[:timeout]
205
+ end
206
+ if config.has_key?(:choices)
207
+ config[:choices].each { |choice| add(choice[:dtmf], choice[:audio]) }
208
+ end
209
+ if config.has_key?(:title)
210
+ @title = config[:title]
211
+ end
212
+ end
213
+ end
214
+ end
215
+
216
+ =begin
217
+ Copyright (c) 2007, Vonage Holdings
218
+
219
+ All rights reserved.
220
+
221
+ Redistribution and use in source and binary forms, with or without
222
+ modification, are permitted provided that the following conditions are met:
223
+
224
+ * Redistributions of source code must retain the above copyright
225
+ notice, this list of conditions and the following disclaimer.
226
+ * Redistributions in binary form must reproduce the above copyright
227
+ notice, this list of conditions and the following disclaimer in the
228
+ documentation and/or other materials provided with the distribution.
229
+ * Neither the name of Vonage Holdings nor the names of its
230
+ contributors may be used to endorse or promote products derived from this
231
+ software without specific prior written permission.
232
+
233
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
234
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
235
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
237
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
238
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
239
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
240
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
241
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
242
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
243
+ POSSIBILITY OF SUCH DAMAGE.
244
+ =end