opensips-mi 0.0.1
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.
- checksums.yaml +15 -0
- data/.gitignore +28 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +275 -0
- data/Rakefile +20 -0
- data/lib/opensips.rb +4 -0
- data/lib/opensips/mi.rb +23 -0
- data/lib/opensips/mi/command.rb +167 -0
- data/lib/opensips/mi/response.rb +122 -0
- data/lib/opensips/mi/transport.rb +10 -0
- data/lib/opensips/mi/transport/datagram.rb +40 -0
- data/lib/opensips/mi/transport/fifo.rb +90 -0
- data/lib/opensips/mi/transport/xmlrpc.rb +43 -0
- data/lib/opensips/mi/version.rb +5 -0
- data/opensips-mi.gemspec +24 -0
- data/test/fixtures/dlg_list +20 -0
- data/test/fixtures/ul_dump +168 -0
- data/test/helper.rb +53 -0
- data/test/test_command.rb +110 -0
- data/test/test_response.rb +101 -0
- data/test/test_transport.rb +187 -0
- metadata +127 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MjczNzYxY2E2ZWRkNjEwOWFiYThmNmQ2YTU1YTA2MzBlMjZlZDYzNg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MjIwNDQwZTk0NTY4NDVmNmJjODM0ZjBiYTRiNDVmNzExODVhNGY1MQ==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YThmNzdmNzRkNmZiOTdlMWE2NDJkZWZhMTU4MTEzNGU1MDMzNjlmNGVkMmY3
|
10
|
+
ZGEyZTJjYWQyOTg0OTA4YTIyYTg1OTczNTI4MzExNTNlYWM5NzRiMTkwOTQz
|
11
|
+
Mzg1ZjM1ODYyZTdiZDcwMmM0NmUxMzgxNWI2OTAyNDMxOWY1Y2Y=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YzMwZTc1OWNjM2FkYTZmY2ZhOTk0YmQzNDJlN2JjNzI0OGU0YTcyMjE5ZTBj
|
14
|
+
ZmFiYmU1ZmRhMTRkODg5NjhmM2MzNTMyNmJiMDk1MTJhNjM5OWI5MjMwZDdh
|
15
|
+
NmJhYWNiODBkZTZlYzdmNzYyYTBhNzI3ZWI0YTE5YmY4YTRmNjQ=
|
data/.gitignore
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Ignore temporary files
|
2
|
+
.*swp
|
3
|
+
*~
|
4
|
+
|
5
|
+
*.gem
|
6
|
+
*.rbc
|
7
|
+
Gemfile*.lock
|
8
|
+
.bundle
|
9
|
+
.config
|
10
|
+
coverage
|
11
|
+
InstalledFiles
|
12
|
+
lib/bundler/man
|
13
|
+
pkg
|
14
|
+
rdoc
|
15
|
+
spec/reports
|
16
|
+
test/tmp
|
17
|
+
test/version_tmp
|
18
|
+
tmp
|
19
|
+
|
20
|
+
# YARD artifacts
|
21
|
+
.yardoc
|
22
|
+
_yardoc
|
23
|
+
doc/
|
24
|
+
|
25
|
+
.DS_Store
|
26
|
+
results.html
|
27
|
+
html
|
28
|
+
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Stas Kobzar
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,275 @@
|
|
1
|
+
# Opensips::Mi
|
2
|
+
|
3
|
+
OpenSIPs management interface API.
|
4
|
+
This library support following management interface OpenSIPs modules:
|
5
|
+
|
6
|
+
* mi_fifo
|
7
|
+
* mi_datagram
|
8
|
+
* mi_xmlrpc
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'opensips-mi'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install opensips-mi
|
23
|
+
|
24
|
+
## Connecting management interfaces
|
25
|
+
|
26
|
+
### Generic connection interface
|
27
|
+
|
28
|
+
Using generic function to connect management interface:
|
29
|
+
```ruby
|
30
|
+
require 'opensips-mi'
|
31
|
+
Opensips::MI.connect INTERFACE, PARAMS
|
32
|
+
```
|
33
|
+
Parameters:
|
34
|
+
|
35
|
+
*INTRFACE* - interface key. One of the following:
|
36
|
+
|
37
|
+
* :fifo
|
38
|
+
* :datagram
|
39
|
+
* :xmlrpc
|
40
|
+
|
41
|
+
*PARAMS* - connection parameters. Depends on interface. See below.
|
42
|
+
|
43
|
+
This function will raise exceptions if there are parameters or environment errors.
|
44
|
+
Function returns instance of one of the following classes:
|
45
|
+
|
46
|
+
* Opensips::MI::Transport::Fifo
|
47
|
+
* Opensips::MI::Transport::Datagram
|
48
|
+
* Opensips::MI::Transport::Xmlrpc
|
49
|
+
|
50
|
+
### FIFO
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
require 'opensips-mi'
|
54
|
+
opensips = Opensips::MI.connect :fifo,
|
55
|
+
:fifo_name => '/tmp/opensips_fifo',
|
56
|
+
:reply_fifo => 'opensips_reply' . $$,
|
57
|
+
:reply_dir => '/tmp'
|
58
|
+
|
59
|
+
```
|
60
|
+
|
61
|
+
**Parameters hash:**
|
62
|
+
|
63
|
+
* fifo_name: OpenSIPs fifo file. See mi_fifo module parameter: `modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")`.
|
64
|
+
* reply_fifo: (OPTIONAL) Name of the reply fifo file. If not used will generate random file in *reply_dir* and delete after use.
|
65
|
+
* reply_dir: (OPTIONAL) Path to directory of reply fifo file.
|
66
|
+
|
67
|
+
### Datagram
|
68
|
+
```ruby
|
69
|
+
require 'opensips-mi'
|
70
|
+
opensips = Opensips::MI.connect :datagram,
|
71
|
+
:host => "sipproxy.com",
|
72
|
+
:port => 8809
|
73
|
+
```
|
74
|
+
**Parameters hash:**
|
75
|
+
|
76
|
+
* host: Hostname or IP address of OpenSIPs server
|
77
|
+
* port: Datagram port. See mi_datagram module configuration parameter: `modparam("mi_datagram", "socket_name", "udp:192.168.2.133:8809")`
|
78
|
+
|
79
|
+
### XMLRPC
|
80
|
+
```ruby
|
81
|
+
require 'opensips-mi'
|
82
|
+
opensips = Opensips::MI.connect :xmlrpc,
|
83
|
+
:host => "192.168.122.128",
|
84
|
+
:port => 8080
|
85
|
+
```
|
86
|
+
**Parameters hash:**
|
87
|
+
|
88
|
+
* host: Hostname or IP address of OpenSIPs server
|
89
|
+
* port: Datagram port. See mi_xmlrpc module configuration parameter: `modparam("mi_xmlrpc", "port", 8080)`
|
90
|
+
|
91
|
+
### Command function
|
92
|
+
|
93
|
+
Function "*command*" expects fifo command as first argument following by command parameters.
|
94
|
+
For example:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
require 'opensips-mi'
|
98
|
+
opensips = Opensips::MI.connect :fifo,
|
99
|
+
:fifo_name => '/tmp/opensips_fifo'
|
100
|
+
|
101
|
+
opensips.command('which')
|
102
|
+
opensips.command('get_statistics', 'dialog','tm')
|
103
|
+
```
|
104
|
+
|
105
|
+
### Command method interface
|
106
|
+
|
107
|
+
It is also possible to use command names as a method interface:
|
108
|
+
```ruby
|
109
|
+
require 'opensips-mi'
|
110
|
+
opensips = Opensips::MI.connect :datagram,
|
111
|
+
:host => "192.168.122.128",
|
112
|
+
:port => 8809
|
113
|
+
|
114
|
+
opensips.which
|
115
|
+
opensips.get_statistics('dialog','tm')
|
116
|
+
opensips.uptime
|
117
|
+
opensips.ul_show_contact('location', 'alice')
|
118
|
+
```
|
119
|
+
|
120
|
+
Such methods first check if fifo function exists against `which` fifo command.
|
121
|
+
|
122
|
+
### Response
|
123
|
+
|
124
|
+
Command function returns `Opensips::MI::Response` class. This class containe following class members which can be used to process responses:
|
125
|
+
|
126
|
+
* code: *Integer* Response code: 200, 404 etc
|
127
|
+
* message: *String* Response messages: "OK", "Bad headers"
|
128
|
+
* rawdata: *Array* Raw response data as array
|
129
|
+
* result: *Mixed* Struct/Hash/Array/Nil. This is member used by helper response methods for pretty formated result. See below.
|
130
|
+
|
131
|
+
### Response helpers methods
|
132
|
+
|
133
|
+
There are several helper methods which return conveniently formatted data:
|
134
|
+
* ul_dump
|
135
|
+
* uptime
|
136
|
+
* cache_fetch
|
137
|
+
* ul_show_contact
|
138
|
+
* dlg_list
|
139
|
+
|
140
|
+
See example files for details.
|
141
|
+
|
142
|
+
## Dialog methods
|
143
|
+
|
144
|
+
Dialog methods are interface to `t_uac_dlg` function of OpenSIPs' *tm* (transactions) module.
|
145
|
+
Module generates and sends a local SIP request.
|
146
|
+
|
147
|
+
### Interface to t_uac_dlg function of transaction (tm) module
|
148
|
+
Very cool method from OpenSIPs. Can generate and send SIP request method to destination.
|
149
|
+
Example of usage:
|
150
|
+
* Send NOTIFY with special Event header to force restart SIP phone (equivalent of ASterisk's "sip notify peer")
|
151
|
+
* Send PUBLISH to trigger device state change notification
|
152
|
+
* Send REFER to transfer call
|
153
|
+
* etc., etc., etc.
|
154
|
+
|
155
|
+
**Headers***
|
156
|
+
Headers parameter "hf" is a hash of headers of format:
|
157
|
+
```
|
158
|
+
header-name => header-value
|
159
|
+
```
|
160
|
+
Example:
|
161
|
+
```
|
162
|
+
hf["From"] => "Alice Liddell <sip:alice@wanderland.com>;tag=843887163"
|
163
|
+
```
|
164
|
+
|
165
|
+
Special "nl" header with any value is used to input additional "\r\n". This is
|
166
|
+
useful, for example, for message-summary event to separate application body. This is
|
167
|
+
because t_uac_dlg expect body parameter as xml only.
|
168
|
+
|
169
|
+
Thus, using multiple headers with same header-name is not possible with header hash.
|
170
|
+
However, it is possible to use multiple header-values comma separated (rfc3261, section 7.3.1):
|
171
|
+
```
|
172
|
+
hf["Route"] => "<sip:alice@atlanta.com>, <sip:bob@biloxi.com>"
|
173
|
+
```
|
174
|
+
Is equivalent to:
|
175
|
+
```
|
176
|
+
Route: <sip:alice@atlanta.com>
|
177
|
+
Route: <sip:bob@biloxi.com>
|
178
|
+
```
|
179
|
+
If there is headers To and From not found, then exception ArgumentError is raised. Also if
|
180
|
+
body part present, Content-Type and Content-length are also mandatory and exception is raised.
|
181
|
+
|
182
|
+
**Parameters**
|
183
|
+
* method: SIP request method (NOTIFY, PUBLISH etc)
|
184
|
+
* ruri: Request URI, ex.: sip:555@10.0.0.55:5060
|
185
|
+
* hf: Headers array. Additional headers will be added to request. At least "From" and "To" headers must be specify.
|
186
|
+
* nhop: Next hop SIP URI (OBP); use "." if no value.
|
187
|
+
* socket: Local socket to be used for sending the request; use "." if no value. Ex.: udp:10.130.8.21:5060
|
188
|
+
* body: (optional, may not be present) request body (if present, requires the "Content-Type" and "Content-length" headers)
|
189
|
+
|
190
|
+
**Example of usage**
|
191
|
+
```ruby
|
192
|
+
opensips.uac_dlg "NOTIFY", "sip:alice@127.0.0.1:5066",
|
193
|
+
{
|
194
|
+
"From" => "<sip:alice@wanderland.com>;tag=8755a8d01a12f7e903a6f4ccaf393f04",
|
195
|
+
"To" => "<sip:alice@wanderland.com>",
|
196
|
+
"Event" => "check-sync"
|
197
|
+
}
|
198
|
+
```
|
199
|
+
|
200
|
+
### NOTIFY check-sync like event
|
201
|
+
NOTIFY Events to restart phone, force configuration reload or
|
202
|
+
report for some SIP IP phone models.
|
203
|
+
The events list was taken from Asterisk configuration file (sip_notify.conf)
|
204
|
+
Note that SIP IP phones usually should be configured to accept special notify
|
205
|
+
event to reboot. For example, Polycom configuration option to enable special
|
206
|
+
event would be:
|
207
|
+
```
|
208
|
+
voIpProt.SIP.specialEvent.checkSync.alwaysReboot="1"
|
209
|
+
```
|
210
|
+
This function will generate To/From/Event headers. Will use random tag for
|
211
|
+
From header.
|
212
|
+
*NOTE*: This function will not generate To header tag. This is not complying with
|
213
|
+
SIP protocol specification (rfc3265). NOTIFY must be part of a subscription
|
214
|
+
dialog. However, it works for the most of the SIP IP phone models.
|
215
|
+
**Parameters**
|
216
|
+
* uri: Valid client contact URI (sip:alice@10.0.0.100:5060). To get client URI use *ul_show_contact => contact* function
|
217
|
+
* event: One of the events from EVENTNOTIFY constant hash
|
218
|
+
* hf: Header fields. Add To/From header fields here if you do not want them to be auto-generated. Header field example: `hf['To'] => '<sip:alice@wanderland.com>'`
|
219
|
+
|
220
|
+
**Example of usage**
|
221
|
+
Will reboot Polycom phone:
|
222
|
+
```ruby
|
223
|
+
opensips.event_notify 'sip:alice@127.0.0.1:5060', :polycom_check_cfg
|
224
|
+
```
|
225
|
+
|
226
|
+
**List of available events' keys:**
|
227
|
+
|
228
|
+
* :astra_check_cfg
|
229
|
+
* :aastra_xml
|
230
|
+
* :digium_check_cfg
|
231
|
+
* :linksys_cold_restart
|
232
|
+
* :linksys_warm_restart
|
233
|
+
* :polycom_check_cfg
|
234
|
+
* :sipura_check_cfg
|
235
|
+
* :sipura_get_report
|
236
|
+
* :snom_check_cfg
|
237
|
+
* :snom_reboot
|
238
|
+
* :cisco_check_cfg
|
239
|
+
* :avaya_check_cfg
|
240
|
+
|
241
|
+
### Presence MWI
|
242
|
+
|
243
|
+
Send message-summary NOTIFY Event to update phone voicemail status.
|
244
|
+
|
245
|
+
**Parameters**
|
246
|
+
|
247
|
+
* uri: Request URI (sip:alice@wanderland.com:5060). To get client URI use *ul_show_contact => contact* function
|
248
|
+
* vmaccount:Message Account value. Ex.: sip:*97@asterisk.com
|
249
|
+
* new: Number of new messages. If more than 0 then Messages-Waiting header will be "yes". Set to 0 to clear phone MWI
|
250
|
+
* old: (optional) Old messages
|
251
|
+
* urg_new: (optional) New urgent messages
|
252
|
+
* urg_old: (optional) Old urgent messages
|
253
|
+
|
254
|
+
**Example of usage**
|
255
|
+
```ruby
|
256
|
+
opensips.mwi_update 'sip:alice@wanderland.com:5060', 'sip:*97@voicemail.pbx.com', 5
|
257
|
+
```
|
258
|
+
|
259
|
+
## Examples
|
260
|
+
|
261
|
+
There are some sample files in *examples* directory.
|
262
|
+
|
263
|
+
## TODO:
|
264
|
+
|
265
|
+
Support for mi_xmlrpc_ng
|
266
|
+
|
267
|
+
----
|
268
|
+
## Contributing
|
269
|
+
|
270
|
+
1. Fork it
|
271
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
272
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
273
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
274
|
+
5. Create new Pull Request
|
275
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/clean"
|
3
|
+
require 'opensips/mi/version'
|
4
|
+
|
5
|
+
require "rdoc/task"
|
6
|
+
Rake::RDocTask.new do |rd|
|
7
|
+
rd.rdoc_dir = 'rdoc'
|
8
|
+
rd.main = "README.md"
|
9
|
+
rd.rdoc_files.include("README.md","lib/**/*.rb")
|
10
|
+
rd.title = "OpenSIPs management interface " << Opensips::MI::VERSION
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'rake/testtask'
|
14
|
+
Rake::TestTask.new(:test) do |test|
|
15
|
+
test.libs << 'lib' << 'test'
|
16
|
+
test.pattern = 'test/**/test_*.rb'
|
17
|
+
#test.verbose = true
|
18
|
+
end
|
19
|
+
|
20
|
+
task :default => :test
|
data/lib/opensips.rb
ADDED
data/lib/opensips/mi.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'fcntl'
|
3
|
+
require 'securerandom'
|
4
|
+
require 'socket'
|
5
|
+
require 'xmlrpc/client'
|
6
|
+
|
7
|
+
require "opensips/mi/version"
|
8
|
+
require "opensips/mi/response"
|
9
|
+
require "opensips/mi/command"
|
10
|
+
require "opensips/mi/transport"
|
11
|
+
|
12
|
+
module Opensips
|
13
|
+
module MI
|
14
|
+
def self.connect(transport, params)
|
15
|
+
class_name = transport.to_s.capitalize
|
16
|
+
# send to transport class
|
17
|
+
Transport.const_get(class_name).init params
|
18
|
+
rescue NameError => e
|
19
|
+
raise NameError, "Unknown transport method: " << transport.to_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module Opensips
|
2
|
+
module MI
|
3
|
+
class Command
|
4
|
+
EVENTNOTIFY = {
|
5
|
+
# Aastra
|
6
|
+
aastra_check_cfg: 'check-sync',
|
7
|
+
aastra_xml: 'aastra-xml',
|
8
|
+
# Digium
|
9
|
+
digium_check_cfg: 'check-sync',
|
10
|
+
# Linksys
|
11
|
+
linksys_cold_restart: 'reboot_now',
|
12
|
+
linksys_warm_restart: 'restart_now',
|
13
|
+
# Polycom
|
14
|
+
polycom_check_cfg: 'check-sync',
|
15
|
+
# Sipura
|
16
|
+
sipura_check_cfg: 'resync',
|
17
|
+
sipura_get_report: 'report',
|
18
|
+
# Snom
|
19
|
+
snom_check_cfg: 'check-sync;reboot=false',
|
20
|
+
snom_reboot: 'check-sync;reboot=true',
|
21
|
+
# Cisco
|
22
|
+
cisco_check_cfg: 'check-sync',
|
23
|
+
# Avaya
|
24
|
+
avaya_check_cfg: 'check-sync',
|
25
|
+
}
|
26
|
+
|
27
|
+
# Interface to mi methods direct call
|
28
|
+
def method_missing(md, *params, &block)
|
29
|
+
response = command 'which'
|
30
|
+
raise NoMethodError,
|
31
|
+
"Method #{md} does not exists" unless response.rawdata.include?(md.to_s)
|
32
|
+
response = command md.to_s, params
|
33
|
+
# return special helper output if exists
|
34
|
+
return response unless response.success
|
35
|
+
if response.respond_to?(md)
|
36
|
+
response.send md
|
37
|
+
else
|
38
|
+
response
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# = Interface to t_uac_dlg function of transaction (tm) module
|
43
|
+
# Very cool method from OpenSIPs. Can generate and send SIP request method to destination.
|
44
|
+
# Example of usage:
|
45
|
+
# - Send NOTIFY with special Event header to force restart SIP phone (equivalent of ASterisk's "sip notify peer")
|
46
|
+
# - Send PUBLISH to trigger device state change notification
|
47
|
+
# - Send REFER to transfer call
|
48
|
+
# - etc., etc., etc.
|
49
|
+
#
|
50
|
+
# == Headers
|
51
|
+
# Headers parameter "hf" is a hash of headers of format:
|
52
|
+
# header-name => header-value
|
53
|
+
# Example:
|
54
|
+
# hf["From"] => "Alice Liddell <sip:alice@wanderland.com>;tag=843887163"
|
55
|
+
#
|
56
|
+
# Special "nl" header with any value is used to input additional "\r\n". This is
|
57
|
+
# useful, for example, for message-summary event to separate application body. This is
|
58
|
+
# because t_uac_dlg expect body parameter as xml only.
|
59
|
+
#
|
60
|
+
# Thus, using multiple headers with same header-name is not possible with header hash.
|
61
|
+
# However, it is possible to use multiple header-values comma separated (rfc3261, section 7.3.1):
|
62
|
+
# hf["Route"] => "<sip:alice@atlanta.com>, <sip:bob@biloxi.com>"
|
63
|
+
# Is equivalent to:
|
64
|
+
# Route: <sip:alice@atlanta.com>
|
65
|
+
# Route: <sip:bob@biloxi.com>
|
66
|
+
#
|
67
|
+
# If there is headers To and From not found, then exception ArgumentError is raised. Also if
|
68
|
+
# body part present, Content-Type and Content-length are also mandatory and exception is raised.
|
69
|
+
#
|
70
|
+
# == Parameters
|
71
|
+
# method: SIP request method (NOTIFY, PUBLISH etc)
|
72
|
+
# ruri: Request URI, ex.: sip:555@10.0.0.55:5060
|
73
|
+
# hf: Headers array. Additional headers will be added to request.
|
74
|
+
# At least "From" and "To" headers must be specify
|
75
|
+
# nhop: Next hop SIP URI (OBP); use "." if no value.
|
76
|
+
# socket: Local socket to be used for sending the request; use "." if no value. Ex.: udp:10.130.8.21:5060
|
77
|
+
# body: (optional, may not be present) request body (if present, requires the "Content-Type" and "Content-length" headers)
|
78
|
+
#
|
79
|
+
def uac_dlg method, ruri, hf, next_hop = ?., socket = ?., body = nil
|
80
|
+
mandatory_hf = Array['To', 'From']
|
81
|
+
mandatory_hf += ['Content-Type', 'Content-Length'] unless body.nil?
|
82
|
+
mandatory_hf.map{|h|h.downcase}.each do |n|
|
83
|
+
raise ArgumentError,
|
84
|
+
"Missing mandatory header #{n.capitalize}" unless hf.keys.map{|h| h.downcase}.include?(n)
|
85
|
+
end
|
86
|
+
# compile headers to string
|
87
|
+
headers = hf.map{|name,val| name.eql?("nl") ? "" : "#{name}: #{val}"}.join "\r\n"
|
88
|
+
headers << "\r\n"
|
89
|
+
|
90
|
+
# hack for xmlrpc which fails if headers are quoted
|
91
|
+
headers = set_header(headers)
|
92
|
+
#params = [method, ruri, next_hop, socket, "\"#{headers}\""]
|
93
|
+
params = [method, ruri, next_hop, socket, headers]
|
94
|
+
params << body unless body.nil?
|
95
|
+
# send it and return Response
|
96
|
+
command 't_uac_dlg', params
|
97
|
+
end
|
98
|
+
|
99
|
+
# = NOTIFY check-sync like event
|
100
|
+
# NOTIFY Events to restart phone, force configuration reload or
|
101
|
+
# report for some SIP IP phone models.
|
102
|
+
# The events list was taken from Asterisk configuration file (sip_notify.conf)
|
103
|
+
# Note that SIP IP phones usually should be configured to accept special notify
|
104
|
+
# event to reboot. For example, Polycom configuration option to enable special
|
105
|
+
# event would be:
|
106
|
+
# voIpProt.SIP.specialEvent.checkSync.alwaysReboot="1"
|
107
|
+
#
|
108
|
+
# This function will generate To/From/Event headers. Will use random tag for
|
109
|
+
# From header.
|
110
|
+
# *NOTE*: This function will not generate To header tag. This is not complying with
|
111
|
+
# SIP protocol specification (rfc3265). NOTIFY must be part of a subscription
|
112
|
+
# dialog. However, it works for the most of the SIP IP phone models.
|
113
|
+
# == Parameters
|
114
|
+
# - uri: Valid client contact URI (sip:alice@10.0.0.100:5060).
|
115
|
+
# To get client URI use *ul_show_contact => contact* function
|
116
|
+
# - event: One of the events from EVENTNOTIFY constant hash
|
117
|
+
# - hf: Header fields. Add To/From header fields here if you do not want them
|
118
|
+
# to be auto-generated. Header field example:
|
119
|
+
# hf['To'] => '<sip:alice@wanderland.com>'
|
120
|
+
#
|
121
|
+
def event_notify uri, event, hf = {}
|
122
|
+
raise ArgumentError,
|
123
|
+
"Invalid notify event: #{event.to_s}" unless EVENTNOTIFY.keys.include?(event)
|
124
|
+
hf['To'] = "<#{uri}>" unless hf.keys.map{|k|k.downcase}.include?('to')
|
125
|
+
hf['From'] = "<#{uri}>;tag=#{SecureRandom.hex}" unless hf.keys.map{|k|k.downcase}.include?('from')
|
126
|
+
hf['Event'] = EVENTNOTIFY[event]
|
127
|
+
|
128
|
+
uac_dlg "NOTIFY", uri, hf
|
129
|
+
end
|
130
|
+
|
131
|
+
# = Presence MWI
|
132
|
+
# Send message-summary NOTIFY Event to update phone voicemail status.
|
133
|
+
#
|
134
|
+
# == Parameters
|
135
|
+
# - uri: Request URI (sip:alice@wanderland.com:5060)
|
136
|
+
# To get client URI use *ul_show_contact => contact* function
|
137
|
+
# - vmaccount:Message Account value. Ex.: sip:*97@asterisk.com
|
138
|
+
# - new: Number of new messages. If more than 0 then Messages-Waiting header
|
139
|
+
# will be "yes". Set to 0 to clear phone MWI
|
140
|
+
# - old: (optional) Old messages
|
141
|
+
# - urg_new: (optional) New urgent messages
|
142
|
+
# - urg_old: (optional) Old urgent messages
|
143
|
+
#
|
144
|
+
def mwi_update uri, vmaccount, new, old = 0, urg_new = 0, urg_old = 0
|
145
|
+
mbody = Hash[
|
146
|
+
'Messages-Waiting' => (new > 0 ? "yes" : "no"),
|
147
|
+
'Message-Account' => vmaccount,
|
148
|
+
'Voice-Message' => "#{new}/#{old} (#{urg_new}/#{urg_old})",
|
149
|
+
]
|
150
|
+
hf = Hash[
|
151
|
+
'To' => "<#{uri}>",
|
152
|
+
'From' => "<#{uri}>;tag=#{SecureRandom.hex}",
|
153
|
+
'Event' => "message-summary",
|
154
|
+
'Subscription-State'=> "active",
|
155
|
+
'Content-Type' => "application/simple-message-summary",
|
156
|
+
'Content-Length' => mbody.map{|k,v| "#{k}: #{v}"}.join("\r\n").length,
|
157
|
+
'nl' => "",
|
158
|
+
]
|
159
|
+
|
160
|
+
uac_dlg "NOTIFY", uri, hf.merge(mbody)
|
161
|
+
end
|
162
|
+
|
163
|
+
def set_header(header);"\"#{header}\"";end
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|