opensips-mi 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|