FreeSWITCHeR 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/License.txt +20 -0
- data/NEWS +3 -0
- data/README +85 -0
- data/Rakefile +82 -0
- data/bin/cmd_demo.rb +19 -0
- data/bin/ies_demo.rb +19 -0
- data/bin/ies_demo_with_hook.rb +27 -0
- data/bin/oes_demo.rb +22 -0
- data/lib/fsr.rb +86 -0
- data/lib/fsr/app.rb +72 -0
- data/lib/fsr/app/answer.rb +21 -0
- data/lib/fsr/app/bridge.rb +33 -0
- data/lib/fsr/app/conference.rb +29 -0
- data/lib/fsr/app/fifo.rb +38 -0
- data/lib/fsr/app/fs_break.rb +21 -0
- data/lib/fsr/app/fs_sleep.rb +24 -0
- data/lib/fsr/app/hangup.rb +22 -0
- data/lib/fsr/app/log.rb +24 -0
- data/lib/fsr/app/playback.rb +23 -0
- data/lib/fsr/app/set.rb +22 -0
- data/lib/fsr/app/speak.rb +25 -0
- data/lib/fsr/app/transfer.rb +24 -0
- data/lib/fsr/cmd.rb +57 -0
- data/lib/fsr/cmd/fsctl.rb +41 -0
- data/lib/fsr/cmd/originate.rb +46 -0
- data/lib/fsr/cmd/sofia.rb +40 -0
- data/lib/fsr/cmd/sofia/profile.rb +75 -0
- data/lib/fsr/cmd/sofia/status.rb +39 -0
- data/lib/fsr/cmd/sofia_contact.rb +31 -0
- data/lib/fsr/cmd/status.rb +25 -0
- data/lib/fsr/command_socket.rb +29 -0
- data/lib/fsr/database.rb +7 -0
- data/lib/fsr/database/call_limit.rb +21 -0
- data/lib/fsr/database/core.rb +30 -0
- data/lib/fsr/database/sofia_reg_external.rb +0 -0
- data/lib/fsr/database/sofia_reg_internal.rb +0 -0
- data/lib/fsr/database/voicemail_default.rb +0 -0
- data/lib/fsr/event_socket.rb +41 -0
- data/lib/fsr/fake_socket.rb +68 -0
- data/lib/fsr/listener.rb +10 -0
- data/lib/fsr/listener/header_and_content_response.rb +21 -0
- data/lib/fsr/listener/inbound.rb +61 -0
- data/lib/fsr/listener/inbound/event.rb +42 -0
- data/lib/fsr/listener/outbound.rb +62 -0
- data/spec/fsr/app.rb +8 -0
- data/spec/fsr/app/bridge.rb +17 -0
- data/spec/fsr/app/conference.rb +12 -0
- data/spec/fsr/app/fifo.rb +29 -0
- data/spec/fsr/cmd.rb +8 -0
- data/spec/fsr/cmd/originate.rb +12 -0
- data/spec/fsr/cmd/sofia.rb +69 -0
- data/spec/fsr/cmd/sofia/profile.rb +58 -0
- data/spec/fsr/listener.rb +12 -0
- data/spec/fsr/listener/inbound.rb +19 -0
- data/spec/fsr/listener/outbound.rb +19 -0
- data/spec/fsr/loading.rb +27 -0
- data/spec/helper.rb +14 -0
- data/tasks/package.rake +29 -0
- data/tasks/spec.rake +59 -0
- metadata +224 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class Answer < Application
|
6
|
+
def initialize
|
7
|
+
end
|
8
|
+
|
9
|
+
def arguments
|
10
|
+
[]
|
11
|
+
end
|
12
|
+
|
13
|
+
def sendmsg
|
14
|
+
"call-command: execute\nexecute-app-name: %s\n\n" % [app_name]
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
register(:answer, Answer)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class Bridge < Application
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize(target, opts = {})
|
9
|
+
# These are options that will precede the target address
|
10
|
+
@target = target
|
11
|
+
@options = opts || {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def arguments
|
15
|
+
[@target]
|
16
|
+
end
|
17
|
+
|
18
|
+
def modifiers
|
19
|
+
@options.map { |k,v| "%s=%s" % [k, v] }.join(",")
|
20
|
+
end
|
21
|
+
|
22
|
+
def raw
|
23
|
+
"%s({%s}%s)" % [app_name, modifiers, arguments.join(" ")]
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.execute(target, opts = {})
|
27
|
+
self.new(target, opts).raw
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
register(:bridge, Bridge)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class Conference < Application
|
6
|
+
attr_reader :target, :profile
|
7
|
+
|
8
|
+
def initialize(conference_name, conference_profile = nil)
|
9
|
+
# These are options that will precede the target address
|
10
|
+
@target = conference_name
|
11
|
+
@profile = conference_profile || "ultrawideband"
|
12
|
+
end
|
13
|
+
|
14
|
+
def arguments
|
15
|
+
["%s@%s" % [@target, @profile]]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.execute(conference_name, conference_profile = nil)
|
19
|
+
self.new(conference_name, conference_profile).raw
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.[](conference_name)
|
23
|
+
self.execute(conference_name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
register(:conference, Conference)
|
28
|
+
end
|
29
|
+
end
|
data/lib/fsr/app/fifo.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class Fifo < Application
|
6
|
+
attr_accessor :name, :direction
|
7
|
+
attr_reader :options
|
8
|
+
|
9
|
+
def self.<<(name)
|
10
|
+
new(name)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.>>(name)
|
14
|
+
new(name, "out", :wait => true)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(name, direction = nil, options = nil)
|
18
|
+
# These are options that will precede the target address
|
19
|
+
@name = name
|
20
|
+
@direction = direction || "in"
|
21
|
+
raise "Direction must be 'in' or 'out'" unless @direction.match(/^(?:in|out)$/)
|
22
|
+
@options = options || {}
|
23
|
+
raise "options must be a hash" unless @options.kind_of?(Hash)
|
24
|
+
end
|
25
|
+
|
26
|
+
def arguments
|
27
|
+
@args = [@name, @direction]
|
28
|
+
if @direction == "out"
|
29
|
+
@args << (options[:wait] ? "wait" : "nowait")
|
30
|
+
end
|
31
|
+
@args
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
register(:fifo, Fifo)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class FSBreak < Application
|
6
|
+
def initialize
|
7
|
+
end
|
8
|
+
|
9
|
+
def arguments
|
10
|
+
[]
|
11
|
+
end
|
12
|
+
|
13
|
+
def sendmsg
|
14
|
+
"call-command: execute\nexecute-app-name: break\n\n"
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
register(:fs_break, FSBreak)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class FSSleep < Application
|
6
|
+
attr_reader :milliseconds
|
7
|
+
|
8
|
+
def initialize(milliseconds)
|
9
|
+
# milliseconds to sleep
|
10
|
+
@milliseconds = milliseconds
|
11
|
+
end
|
12
|
+
def arguments
|
13
|
+
[@milliseconds]
|
14
|
+
end
|
15
|
+
|
16
|
+
def sendmsg
|
17
|
+
"call-command: execute\nexecute-app-name: sleep\nexecute-app-arg: %s\n\n" % [arguments.join(" ")]
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
register(:fs_sleep, FSSleep)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "fsr/app"
|
2
|
+
module FSR
|
3
|
+
module App
|
4
|
+
# http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_hangup
|
5
|
+
class Hangup < Application
|
6
|
+
def initialize(data = nil)
|
7
|
+
@data = data
|
8
|
+
end
|
9
|
+
|
10
|
+
def arguments
|
11
|
+
@data
|
12
|
+
end
|
13
|
+
|
14
|
+
def sendmsg
|
15
|
+
"call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\n\n" % [app_name, arguments]
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
register(:hangup, Hangup)
|
21
|
+
end
|
22
|
+
end
|
data/lib/fsr/app/log.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "fsr/app"
|
2
|
+
module FSR
|
3
|
+
module App
|
4
|
+
# http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_log
|
5
|
+
class Log < Application
|
6
|
+
attr_reader :level, :text
|
7
|
+
|
8
|
+
def initialize(level = 1, text = "")
|
9
|
+
@level = level
|
10
|
+
@text = text
|
11
|
+
end
|
12
|
+
|
13
|
+
def arguments
|
14
|
+
[@level, @text]
|
15
|
+
end
|
16
|
+
|
17
|
+
def sendmsg
|
18
|
+
"call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\nevent-lock:true\n\n" % [app_name, arguments.join(" ")]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
register(:log, Log)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class Playback < Application
|
6
|
+
attr_reader :wavfile
|
7
|
+
|
8
|
+
def initialize(wavfile)
|
9
|
+
# wav file you wish to play, full path
|
10
|
+
@wavfile = wavfile
|
11
|
+
end
|
12
|
+
def arguments
|
13
|
+
[@wavfile]
|
14
|
+
end
|
15
|
+
|
16
|
+
def sendmsg
|
17
|
+
"call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\nevent-lock:true\n\n" % [app_name, arguments.join(" ")]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
register(:playback, Playback)
|
22
|
+
end
|
23
|
+
end
|
data/lib/fsr/app/set.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require "fsr/app"
|
2
|
+
module FSR
|
3
|
+
module App
|
4
|
+
# http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_set
|
5
|
+
class Set < Application
|
6
|
+
def initialize(key, value)
|
7
|
+
@key = key
|
8
|
+
@value = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def arguments
|
12
|
+
[@key, @value]
|
13
|
+
end
|
14
|
+
|
15
|
+
def sendmsg
|
16
|
+
"call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\nevent-lock:true\n\n" % [app_name, arguments.join("=")]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
register(:set, Set)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class Speak < Application
|
6
|
+
attr_reader :message
|
7
|
+
|
8
|
+
def initialize(message, opts = {})
|
9
|
+
# wav file you wish to play, full path
|
10
|
+
@message = message
|
11
|
+
@voice = opts[:voice] || "slt"
|
12
|
+
end
|
13
|
+
|
14
|
+
def arguments
|
15
|
+
["flite", @voice, @message]
|
16
|
+
end
|
17
|
+
|
18
|
+
def sendmsg
|
19
|
+
"call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\nevent-lock:true\n\n" % [app_name, arguments.join("|")]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
register(:speak, Speak)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "fsr/app"
|
2
|
+
module FSR
|
3
|
+
module App
|
4
|
+
class Transfer < Application
|
5
|
+
attr_reader :destination_number, :dialplan, :context
|
6
|
+
|
7
|
+
def initialize(destination_number, dialplan = nil, context = nil)
|
8
|
+
@destination_number = destination_number
|
9
|
+
@dialplan = dialplan || "XML"
|
10
|
+
@context = context || "default"
|
11
|
+
end
|
12
|
+
|
13
|
+
def arguments
|
14
|
+
[@destination_number, @dialplan, @context]
|
15
|
+
end
|
16
|
+
|
17
|
+
def sendmsg
|
18
|
+
"call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\nevent-lock:true\n\n" % [app_name, arguments.join(" ")]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
register(:transfer, Transfer)
|
23
|
+
end
|
24
|
+
end
|
data/lib/fsr/cmd.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
module FSR
|
2
|
+
module Cmd
|
3
|
+
class Command
|
4
|
+
end
|
5
|
+
|
6
|
+
COMMANDS = {}
|
7
|
+
LOAD_PATH = [File.join(FSR::ROOT, "fsr", "cmd")]
|
8
|
+
|
9
|
+
def self.register(command, obj)
|
10
|
+
COMMANDS[command.to_sym] = obj
|
11
|
+
|
12
|
+
code = "def %s(*args, &block) COMMANDS[%p].new(self, *args, &block) end" % [command, command]
|
13
|
+
Cmd.module_eval(code)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.list
|
17
|
+
COMMANDS.keys
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.load_command(command, force_reload = false)
|
21
|
+
# If we get a path specification and it's an existing file, load it
|
22
|
+
if File.file?(command)
|
23
|
+
if force_reload
|
24
|
+
return load(command)
|
25
|
+
else
|
26
|
+
return require(command)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
Log.debug "Trying load paths"
|
30
|
+
# If we find a file named the same as the command passed in LOAD_PATH, load it
|
31
|
+
if found_command_path = LOAD_PATH.detect { |command_path| File.file?(File.join(command_path, "#{command}.rb")) }
|
32
|
+
command_file = Pathname.new(found_command_path).join(command)
|
33
|
+
Log.debug "Trying to load #{command_file}"
|
34
|
+
if force_reload
|
35
|
+
load command_file.to_s + ".rb"
|
36
|
+
else
|
37
|
+
require command_file
|
38
|
+
end
|
39
|
+
else
|
40
|
+
raise "#{command} not found in #{LOAD_PATH.join(":")}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Load all of the commands we find in Cmd::LOAD_PATH
|
45
|
+
def self.load_all(force_reload = false)
|
46
|
+
LOAD_PATH.each do |load_path|
|
47
|
+
Dir[File.join(load_path, "*.rb")].each { |command_file| load_command(command_file, force_reload) }
|
48
|
+
end
|
49
|
+
list
|
50
|
+
end
|
51
|
+
|
52
|
+
def commands
|
53
|
+
FSR::Cmd.list
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
FSC = FSR::Cmd
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# A lot of methods are missing here. The only one implemented is max_sessions
|
2
|
+
# The max_sessions getter currently returns the raw result but could instead return an Integer
|
3
|
+
|
4
|
+
require "fsr/app"
|
5
|
+
module FSR
|
6
|
+
module Cmd
|
7
|
+
class Fsctl < Command
|
8
|
+
attr_reader :command
|
9
|
+
|
10
|
+
def initialize(fs_socket = nil)
|
11
|
+
@fs_socket = fs_socket # FSR::CommandSocket obj
|
12
|
+
end
|
13
|
+
|
14
|
+
# Get max sessions
|
15
|
+
def max_sessions
|
16
|
+
@command = "max_sessions"
|
17
|
+
run
|
18
|
+
end
|
19
|
+
|
20
|
+
# Set max sessions
|
21
|
+
def max_sessions=(sessions)
|
22
|
+
@command = "max_sessions #{sessions}"
|
23
|
+
run
|
24
|
+
end
|
25
|
+
|
26
|
+
# Send the command to the event socket, using api by default.
|
27
|
+
def run(api_method = :api)
|
28
|
+
orig_command = "%s %s" % [api_method, raw]
|
29
|
+
Log.debug "saying #{orig_command}"
|
30
|
+
@fs_socket.say(orig_command)
|
31
|
+
end
|
32
|
+
|
33
|
+
# This method builds the API command to send to the freeswitch event socket
|
34
|
+
def raw
|
35
|
+
orig_command = "fsctl #{@command}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
register(:fsctl, Fsctl)
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "fsr/app"
|
2
|
+
module FSR
|
3
|
+
module Cmd
|
4
|
+
class Originate < Command
|
5
|
+
attr_accessor :target, :endpoint
|
6
|
+
attr_reader :fs_socket, :target_options
|
7
|
+
|
8
|
+
def initialize(fs_socket = nil, args = {})
|
9
|
+
# These are options that will precede the target address
|
10
|
+
@target_options = args[:target_options] || {:ignore_early_media => true}
|
11
|
+
raise "#{@target_options} must be a hash" unless @target_options.kind_of?(Hash)
|
12
|
+
|
13
|
+
@fs_socket = fs_socket # This socket must support say and <<
|
14
|
+
@target = args[:target] # The target address to call
|
15
|
+
# The origination endpoint (can be an extension (use a string) or application)
|
16
|
+
@endpoint = args[:endpoint] || args[:application]
|
17
|
+
|
18
|
+
@target_options[:origination_caller_id_number] ||= args[:caller_id_number] || FSR::DEFAULT_CALLER_ID_NUMBER
|
19
|
+
@target_options[:origination_caller_id_name] ||= args[:caller_id_name] || FSR::DEFAULT_CALLER_ID_NAME
|
20
|
+
@target_options[:originate_timeout] ||= args[:timeout] || @target_options[:timeout] || 30
|
21
|
+
@target_options[:ignore_early_media] ||= true
|
22
|
+
end
|
23
|
+
|
24
|
+
# Send the command to the event socket, using bgapi by default.
|
25
|
+
def run(api_method = :bgapi)
|
26
|
+
orig_command = "%s %s" % [api_method, raw]
|
27
|
+
Log.debug "saying #{orig_command}"
|
28
|
+
@fs_socket.say(orig_command)
|
29
|
+
end
|
30
|
+
|
31
|
+
# This method builds the API command to send to the freeswitch event socket
|
32
|
+
def raw
|
33
|
+
target_opts = @target_options.keys.sort { |a,b| a.to_s <=> b.to_s }.map { |k| "%s=%s" % [k, @target_options[k]] }.join(",")
|
34
|
+
if @endpoint.kind_of?(String)
|
35
|
+
orig_command = "originate {#{target_opts}}#{@target} #{@endpoint}"
|
36
|
+
elsif @endpoint.kind_of?(FSR::App::Application)
|
37
|
+
orig_command = "originate {#{target_opts}}#{@target} '&#{@endpoint.raw}'"
|
38
|
+
else
|
39
|
+
raise "Invalid endpoint"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
register(:originate, Originate)
|
45
|
+
end
|
46
|
+
end
|