sip-lab 1.12.0 → 1.12.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sip-lab",
3
- "version": "1.12.0",
3
+ "version": "1.12.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "engines": {
@@ -28,7 +28,11 @@ async function test() {
28
28
  domain,
29
29
  server,
30
30
  username: 'user1',
31
- password: 'pass1'
31
+ password: 'pass1',
32
+ headers: {
33
+ 'X-MyHeader1': 'aaa',
34
+ 'X-MyHeader2': 'bbb',
35
+ },
32
36
  })
33
37
 
34
38
  sip.account.register(a1, {auto_register: true})
@@ -42,6 +46,8 @@ async function test() {
42
46
  $fd: domain,
43
47
  $tU: 'user1',
44
48
  $td: domain,
49
+ '$hdr(X-MyHeader1)': 'aaa',
50
+ '$hdr(X-MyHeader2)': 'bbb',
45
51
  }),
46
52
  },
47
53
  ], 1000)
@@ -0,0 +1,333 @@
1
+ var sip = require ('../index.js')
2
+ var Zester = require('zester')
3
+ var z = new Zester()
4
+ var m = require('data-matching')
5
+ var sip_msg = require('sip-matching')
6
+
7
+ async function test() {
8
+ //sip.set_log_level(6)
9
+ sip.dtmf_aggregation_on(500)
10
+
11
+ z.trap_events(sip.event_source, 'event', (evt) => {
12
+ var e = evt.args[0]
13
+ return e
14
+ })
15
+
16
+ console.log(sip.start((data) => { console.log(data)} ))
17
+
18
+ t1 = sip.transport.create({address: "127.0.0.1", port: 5090, type: 'tcp'})
19
+ t2 = sip.transport.create({address: "127.0.0.1", port: 5092, type: 'tcp'})
20
+
21
+ console.log("t1", t1)
22
+ console.log("t2", t2)
23
+
24
+ oc = sip.call.create(t1.id, {
25
+ from_uri: '"abc"<sip:alice@test.com>',
26
+ to_uri: `sip:bob@${t2.address}:${t2.port}`,
27
+ headers: {
28
+ 'X-MyHeader1': 'abc',
29
+ 'X-MyHeader2': 'def',
30
+ },
31
+ })
32
+
33
+ await z.wait([
34
+ {
35
+ event: "incoming_call",
36
+ call_id: m.collect("call_id"),
37
+ msg: sip_msg({
38
+ $rm: 'INVITE',
39
+ $fU: 'alice',
40
+ $fd: 'test.com',
41
+ $tU: 'bob',
42
+ '$hdr(X-MyHeader1)': 'abc',
43
+ '$hdr(X-MyHeader2)': 'def',
44
+ }),
45
+ },
46
+ {
47
+ event: 'response',
48
+ call_id: oc.id,
49
+ method: 'INVITE',
50
+ msg: sip_msg({
51
+ $rs: '100',
52
+ $rr: 'Trying',
53
+ '$(hdrcnt(via))': 1,
54
+ '$hdr(call-id)': m.collect('sip_call_id'),
55
+ $fU: 'alice',
56
+ $fd: 'test.com',
57
+ $tU: 'bob',
58
+ '$hdr(l)': '0',
59
+ }),
60
+ },
61
+ ], 1000)
62
+
63
+ ic = {
64
+ id: z.store.call_id,
65
+ sip_call_id: z.store.sip_call_id,
66
+ }
67
+
68
+ sip.call.respond(ic.id, {
69
+ code: 200,
70
+ reason:'OK',
71
+ headers: {
72
+ 'X-MyHeader3': 'ghi',
73
+ 'X-MyHeader4': 'jkl',
74
+ },
75
+ })
76
+
77
+ await z.wait([
78
+ {
79
+ event: 'media_status',
80
+ call_id: oc.id,
81
+ status: 'setup_ok',
82
+ local_mode: 'sendrecv',
83
+ remote_mode: 'sendrecv',
84
+ },
85
+ {
86
+ event: 'media_status',
87
+ call_id: ic.id,
88
+ status: 'setup_ok',
89
+ local_mode: 'sendrecv',
90
+ remote_mode: 'sendrecv',
91
+ },
92
+ {
93
+ event: 'response',
94
+ call_id: oc.id,
95
+ method: 'INVITE',
96
+ msg: sip_msg({
97
+ $rs: '200',
98
+ $rr: 'OK',
99
+ '$(hdrcnt(VIA))': 1,
100
+ $fU: 'alice',
101
+ $fd: 'test.com',
102
+ $tU: 'bob',
103
+ '$hdr(content-type)': 'application/sdp',
104
+ $rb: '!{_}a=sendrecv',
105
+ '$hdr(X-MyHeader3)': 'ghi',
106
+ '$hdr(X-MyHeader4)': 'jkl',
107
+ }),
108
+ },
109
+ ], 1000)
110
+
111
+ sip.call.start_recording(oc.id, {file: './oc.wav'})
112
+ sip.call.start_recording(ic.id, {file: './ic.wav'})
113
+
114
+ sip.call.send_dtmf(oc.id, {digits: '1234', mode: 0})
115
+ sip.call.send_dtmf(ic.id, {digits: '4321', mode: 1})
116
+
117
+ await z.wait([
118
+ {
119
+ event: 'dtmf',
120
+ call_id: ic.id,
121
+ digits: '1234',
122
+ mode: 0,
123
+ },
124
+ {
125
+ event: 'dtmf',
126
+ call_id: oc.id,
127
+ digits: '4321',
128
+ mode: 1,
129
+ },
130
+ ], 2000)
131
+
132
+
133
+ sip.call.reinvite(oc.id, { hold: true })
134
+
135
+ await z.wait([
136
+ {
137
+ event: 'response',
138
+ call_id: oc.id,
139
+ method: 'INVITE',
140
+ msg: sip_msg({
141
+ $rs: '200',
142
+ $rr: 'OK',
143
+ $rb: '!{_}a=recvonly',
144
+ }),
145
+ },
146
+ {
147
+ event: 'media_status',
148
+ call_id: oc.id,
149
+ status: 'setup_ok',
150
+ local_mode: 'sendonly',
151
+ remote_mode: 'recvonly',
152
+ },
153
+ {
154
+ event: 'media_status',
155
+ call_id: ic.id,
156
+ status: 'setup_ok',
157
+ local_mode: 'recvonly',
158
+ remote_mode: 'sendonly',
159
+ },
160
+ ], 500)
161
+
162
+ sip.call.send_dtmf(oc.id, {digits: '1234', mode: 0})
163
+ sip.call.send_dtmf(ic.id, {digits: '4321', mode: 0}) // this will not generate event 'dtmf' as the call is on hold
164
+
165
+ await z.wait([
166
+ {
167
+ event: 'dtmf',
168
+ call_id: ic.id,
169
+ digits: '1234',
170
+ mode: 0,
171
+ },
172
+ ], 2000)
173
+
174
+ sip.call.reinvite(ic.id)
175
+
176
+ await z.wait([
177
+ {
178
+ event: 'response',
179
+ call_id: ic.id,
180
+ method: 'INVITE',
181
+ msg: sip_msg({
182
+ $rs: '200',
183
+ $rr: 'OK',
184
+ $rb: '!{_}a=sendonly',
185
+ }),
186
+ },
187
+ {
188
+ event: 'media_status',
189
+ call_id: oc.id,
190
+ status: 'setup_ok',
191
+ local_mode: 'sendonly',
192
+ remote_mode: 'recvonly',
193
+ },
194
+ {
195
+ event: 'media_status',
196
+ call_id: ic.id,
197
+ status: 'setup_ok',
198
+ local_mode: 'recvonly',
199
+ remote_mode: 'sendonly',
200
+ },
201
+ ], 500)
202
+
203
+ sip.call.send_dtmf(oc.id, {digits: '1234', mode: 0})
204
+ sip.call.send_dtmf(ic.id, {digits: '4321', mode: 1}) // this will not generate event 'dtmf' as the call is on hold
205
+
206
+ await z.wait([
207
+ {
208
+ event: 'dtmf',
209
+ call_id: ic.id,
210
+ digits: '1234',
211
+ mode: 0,
212
+ },
213
+ ], 2000)
214
+
215
+ sip.call.send_request(oc.id, {method: 'INFO'})
216
+
217
+ await z.wait([
218
+ {
219
+ event: 'request',
220
+ call_id: ic.id,
221
+ msg: sip_msg({
222
+ $rm: 'INFO',
223
+ }),
224
+ },
225
+ {
226
+ event: 'response',
227
+ call_id: oc.id,
228
+ method: 'INFO',
229
+ msg: sip_msg({
230
+ $rs: '200',
231
+ $rr: 'OK',
232
+ }),
233
+ },
234
+ ], 500)
235
+
236
+ sip.call.reinvite(oc.id)
237
+
238
+ await z.wait([
239
+ {
240
+ event: 'response',
241
+ call_id: oc.id,
242
+ method: 'INVITE',
243
+ msg: sip_msg({
244
+ $rs: '200',
245
+ $rr: 'OK',
246
+ $rb: '!{_}a=sendrecv',
247
+ }),
248
+ },
249
+ {
250
+ event: 'media_status',
251
+ call_id: oc.id,
252
+ status: 'setup_ok',
253
+ local_mode: 'sendrecv',
254
+ remote_mode: 'sendrecv',
255
+ },
256
+ {
257
+ event: 'media_status',
258
+ call_id: ic.id,
259
+ status: 'setup_ok',
260
+ local_mode: 'sendrecv',
261
+ remote_mode: 'sendrecv',
262
+ },
263
+ ], 500)
264
+
265
+ sip.call.send_dtmf(oc.id, {digits: '1234', mode: 0})
266
+ sip.call.send_dtmf(ic.id, {digits: '4321', mode: 1})
267
+
268
+ await z.wait([
269
+ {
270
+ event: 'dtmf',
271
+ call_id: ic.id,
272
+ digits: '1234',
273
+ mode: 0,
274
+ },
275
+ {
276
+ event: 'dtmf',
277
+ call_id: oc.id,
278
+ digits: '4321',
279
+ mode: 1,
280
+ },
281
+ ], 2000)
282
+
283
+ sip.call.start_playing(oc.id, {file: '/home/takeshi/work/src/svn/brastel/SIP-Tools/trunk/sip-tester/yosemitesam.wav'})
284
+ sip.call.start_playing(ic.id, {file: '/home/takeshi/work/src/svn/brastel/SIP-Tools/trunk/sip-tester/yosemitesam.wav'})
285
+
286
+ await z.sleep(2000)
287
+
288
+ stat1 = sip.call.get_stream_stat(oc.id)
289
+ stat2 = sip.call.get_stream_stat(ic.id)
290
+
291
+ console.log("stat1", stat1)
292
+ console.log("stat2", stat2)
293
+
294
+ sip.call.stop_recording(oc.id)
295
+ sip.call.stop_recording(ic.id)
296
+
297
+
298
+ sip.call.terminate(oc.id)
299
+
300
+ await z.wait([
301
+ {
302
+ event: 'call_ended',
303
+ call_id: oc.id,
304
+ },
305
+ {
306
+ event: 'call_ended',
307
+ call_id: ic.id,
308
+ },
309
+ {
310
+ event: 'response',
311
+ call_id: oc.id,
312
+ method: 'BYE',
313
+ msg: sip_msg({
314
+ $rs: '200',
315
+ $rr: 'OK',
316
+ }),
317
+ },
318
+ ], 1000)
319
+
320
+ await z.sleep(1000)
321
+
322
+ console.log("Success")
323
+
324
+ sip.stop()
325
+ }
326
+
327
+
328
+ test()
329
+ .catch(e => {
330
+ console.error(e)
331
+ process.exit(1)
332
+ })
333
+
package/src/sip.cpp CHANGED
@@ -426,9 +426,10 @@ static void server_on_evsub_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata, i
426
426
 
427
427
  bool dlg_create(pjsip_dialog **dlg, Transport *transport, const char *from_uri, const char *to_uri, const char *request_uri, const char *realm, const char *username, const char *password, const char *local_contact);
428
428
 
429
- static int call_create(Transport *t, unsigned flags, pjsip_dialog *dlg, const char *proxy_uri, const char *additional_headers);
429
+ static int call_create(Transport *t, unsigned flags, pjsip_dialog *dlg, const char *proxy_uri, Document &document);
430
430
 
431
- bool subscription_subscribe(Subscription *s, int expires, const char *additional_headers);
431
+ bool subscription_subscribe_no_headers(Subscription *s, int expires);
432
+ bool subscription_subscribe(Subscription *s, int expires, Document &document);
432
433
 
433
434
  static pjmedia_transport *create_media_transport(const pj_str_t *addr);
434
435
  void close_media_transport(pjmedia_transport *med_transport);
@@ -446,11 +447,12 @@ bool set_proxy(pjsip_dialog *dlg, const char *proxy_uri);
446
447
  void build_local_contact(char *dest, pjsip_transport *transport, const char *contact_username);
447
448
  void build_local_contact_from_tpfactory(char *dest, pjsip_tpfactory *tpfactory, const char *contact_username, pjsip_transport_type_e type);
448
449
 
449
- pj_bool_t add_additional_headers(pj_pool_t *pool, pjsip_tx_data *tdata, const char *additional_headers);
450
+ //pj_bool_t add_additional_headers(pj_pool_t *pool, pjsip_tx_data *tdata, const char *additional_headers);
451
+ pj_bool_t add_headers(pj_pool_t *pool, pjsip_tx_data *tdata, Document &document);
450
452
 
451
- pj_bool_t add_additional_headers_for_account(pjsip_regc* regc, const char *additional_headers);
453
+ pj_bool_t add_headers_for_account(pjsip_regc* regc, Document &document);
452
454
 
453
- pj_bool_t get_content_type_and_subtype_from_additional_headers(const char *additional_headers, char *type, char *subtype);
455
+ pj_bool_t get_content_type_and_subtype_from_headers(Document &document, char *type, char *subtype);
454
456
 
455
457
  bool build_subscribe_info(ostringstream *oss, pjsip_rx_data *rdata, Subscriber *s);
456
458
  //bool build_notify_info(pjsip_rx_data *rdata, Subscription *s);
@@ -1256,7 +1258,6 @@ int pjw_account_create(int t_id, const char *json, int *out_acc_id)
1256
1258
  char *password;
1257
1259
  char *c_to_uri = NULL;
1258
1260
  int expires = 60;
1259
- char *additional_headers = NULL;
1260
1261
 
1261
1262
  pj_str_t server_uri;
1262
1263
  pj_str_t from_uri;
@@ -1322,11 +1323,8 @@ int pjw_account_create(int t_id, const char *json, int *out_acc_id)
1322
1323
  goto out;
1323
1324
  }
1324
1325
 
1325
- if(additional_headers) {
1326
- if(!add_additional_headers_for_account(regc, additional_headers)) {
1327
- set_error("add_additional_headers_for_account failed");
1328
- goto out;
1329
- }
1326
+ if(!add_headers_for_account(regc, document)) {
1327
+ goto out;
1330
1328
  }
1331
1329
 
1332
1330
  if(!g_account_ids.add((long)regc, acc_id)){
@@ -1542,8 +1540,6 @@ int pjw_call_respond(long call_id, const char *json)
1542
1540
 
1543
1541
  Call *call;
1544
1542
 
1545
- char *additional_headers = NULL;
1546
-
1547
1543
  char buffer[MAX_JSON_INPUT];
1548
1544
 
1549
1545
  Document document;
@@ -1602,7 +1598,7 @@ int pjw_call_respond(long call_id, const char *json)
1602
1598
  goto out;
1603
1599
  }
1604
1600
 
1605
- if(!add_additional_headers(call->inv->dlg->pool, tdata, additional_headers)) {
1601
+ if(!add_headers(call->inv->dlg->pool, tdata, document)) {
1606
1602
  goto out;
1607
1603
  }
1608
1604
  }
@@ -1634,8 +1630,6 @@ int pjw_call_terminate(long call_id, const char *json)
1634
1630
  char *reason = (char*)"";
1635
1631
  pj_str_t r;// = pj_str((char*)reason);
1636
1632
 
1637
- const char *additional_headers;
1638
-
1639
1633
  Call *call;
1640
1634
 
1641
1635
  char buffer[MAX_JSON_INPUT];
@@ -1677,8 +1671,7 @@ int pjw_call_terminate(long call_id, const char *json)
1677
1671
  goto out;
1678
1672
  }
1679
1673
 
1680
- if(!add_additional_headers(call->inv->dlg->pool, tdata, additional_headers)) {
1681
- set_error("add_additional_headers failed");
1674
+ if(!add_headers(call->inv->dlg->pool, tdata, document)) {
1682
1675
  goto out;
1683
1676
  }
1684
1677
 
@@ -1720,8 +1713,6 @@ int pjw_call_create(long t_id, const char *json, long *out_call_id, char *out_si
1720
1713
  char *request_uri = NULL;
1721
1714
  char *proxy_uri = NULL;
1722
1715
 
1723
- char *headers = NULL;
1724
-
1725
1716
  char *realm = NULL;
1726
1717
  char *username = NULL;
1727
1718
  char *password = NULL;
@@ -1761,16 +1752,6 @@ int pjw_call_create(long t_id, const char *json, long *out_call_id, char *out_si
1761
1752
  goto out;
1762
1753
  }
1763
1754
 
1764
- /*
1765
- const Value& headers = document["headers"];
1766
- if(document.HasMember("headers") {
1767
- if(!headers.IsArray()) {
1768
- set_error("headers must be an array");
1769
- goto out;
1770
- }
1771
- }
1772
- */
1773
-
1774
1755
  if(document.HasMember("auth")) {
1775
1756
  if(!document["auth"].IsObject()) {
1776
1757
  set_error("Parameter auth must be an object");
@@ -1828,7 +1809,7 @@ int pjw_call_create(long t_id, const char *json, long *out_call_id, char *out_si
1828
1809
  goto out;
1829
1810
  }
1830
1811
 
1831
- call_id = call_create(t, flags, dlg, proxy_uri, headers);
1812
+ call_id = call_create(t, flags, dlg, proxy_uri, document);
1832
1813
  if(call_id < 0) {
1833
1814
  goto out;
1834
1815
  }
@@ -2007,7 +1988,7 @@ bool dlg_create(pjsip_dialog **dlg, Transport *transport, const char *from_uri,
2007
1988
  }
2008
1989
 
2009
1990
 
2010
- int call_create(Transport *t, unsigned flags, pjsip_dialog *dlg, const char *proxy_uri, const char *additional_headers)
1991
+ int call_create(Transport *t, unsigned flags, pjsip_dialog *dlg, const char *proxy_uri, Document &document)
2011
1992
  {
2012
1993
  pjsip_inv_session *inv;
2013
1994
  //in_addr addr;
@@ -2092,7 +2073,7 @@ int call_create(Transport *t, unsigned flags, pjsip_dialog *dlg, const char *pro
2092
2073
 
2093
2074
 
2094
2075
 
2095
- if(!add_additional_headers(dlg->pool, tdata, additional_headers)) {
2076
+ if(!add_headers(dlg->pool, tdata, document)) {
2096
2077
  g_call_ids.remove(call_id, (long &)call);
2097
2078
  close_media_transport(med_transport); //Todo:
2098
2079
  status = pjsip_dlg_terminate(dlg); //ToDo:
@@ -2382,7 +2363,6 @@ int pjw_call_send_request(long call_id, const char *json)
2382
2363
  clear_error();
2383
2364
 
2384
2365
  char *method = NULL;
2385
- char *additional_headers = NULL;
2386
2366
  char *body = NULL;
2387
2367
  char *ct_type = NULL;
2388
2368
  char *ct_subtype = NULL;
@@ -2454,7 +2434,7 @@ int pjw_call_send_request(long call_id, const char *json)
2454
2434
  goto out;
2455
2435
  }
2456
2436
 
2457
- if(!add_additional_headers(call->inv->dlg->pool, tdata, additional_headers)) {
2437
+ if(!add_headers(call->inv->dlg->pool, tdata, document)) {
2458
2438
  goto out;
2459
2439
  }
2460
2440
 
@@ -3704,17 +3684,13 @@ static void on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer
3704
3684
  // Keep call on-hold by setting 'sendonly' attribute.
3705
3685
  // (See RFC 3264 Section 8.4 and RFC 4317 Section 3.1)
3706
3686
  if(call->remote_hold) {
3707
- printf("p1\n");
3708
3687
  attr = pjmedia_sdp_attr_create(inv->pool, "inactive", NULL);
3709
3688
  } else {
3710
- printf("p2\n");
3711
3689
  attr = pjmedia_sdp_attr_create(inv->pool, "sendonly", NULL);
3712
3690
  }
3713
3691
  } else if(call->remote_hold) {
3714
- printf("p3\n");
3715
3692
  attr = pjmedia_sdp_attr_create(inv->pool, "recvonly", NULL);
3716
3693
  } else {
3717
- printf("p4\n");
3718
3694
  attr = pjmedia_sdp_attr_create(inv->pool, "sendrecv", NULL);
3719
3695
  }
3720
3696
  pjmedia_sdp_media_add_attr(answer->media[0], attr);
@@ -4433,7 +4409,7 @@ static void on_client_refresh( pjsip_evsub *sub ) {
4433
4409
  goto out;
4434
4410
  }
4435
4411
 
4436
- if(!subscription_subscribe(subscription, -1, "")) {
4412
+ if(!subscription_subscribe_no_headers(subscription, -1)) {
4437
4413
  goto out;
4438
4414
  }
4439
4415
 
@@ -4852,7 +4828,6 @@ int pjw_call_refer(long call_id, const char *json, long *out_subscription_id)
4852
4828
  clear_error();
4853
4829
 
4854
4830
  char *dest_uri;
4855
- char *additional_headers;
4856
4831
 
4857
4832
  long val;
4858
4833
  Call *call;
@@ -4895,7 +4870,7 @@ int pjw_call_refer(long call_id, const char *json, long *out_subscription_id)
4895
4870
  s_dest_uri = pj_str((char*)dest_uri);
4896
4871
  status = pjsip_xfer_initiate(sub, &s_dest_uri, &tdata);
4897
4872
 
4898
- if(!add_additional_headers(call->inv->dlg->pool, tdata, additional_headers)) {
4873
+ if(!add_headers(call->inv->dlg->pool, tdata, document)) {
4899
4874
  goto out;
4900
4875
  }
4901
4876
 
@@ -4960,7 +4935,7 @@ int pjw_call_get_info(long call_id, const char *required_info, char *out_info)
4960
4935
  return 0;
4961
4936
  }
4962
4937
 
4963
- bool notify(pjsip_evsub *evsub, const char *content_type, const char *body, int subscription_state, const char *reason, const char *additional_headers) {
4938
+ bool notify(pjsip_evsub *evsub, const char *content_type, const char *body, int subscription_state, const char *reason, Document &document) {
4964
4939
  //pj_str_t s_content_type;
4965
4940
  //pj_str_t s_body;
4966
4941
  pj_str_t s_reason;
@@ -5014,7 +4989,9 @@ bool notify(pjsip_evsub *evsub, const char *content_type, const char *body, int
5014
4989
  }
5015
4990
  s_content_type_subtype = pj_str(tok);
5016
4991
 
5017
- add_additional_headers(tdata->pool, tdata, additional_headers);
4992
+ if(!add_headers(tdata->pool, tdata, document)) {
4993
+ return false;
4994
+ }
5018
4995
 
5019
4996
  msg_body->content_type.type = s_content_type_type;
5020
4997
  msg_body->content_type.subtype = s_content_type_subtype;
@@ -5045,7 +5022,6 @@ int pjw_notify(long subscriber_id, const char *json)
5045
5022
  char *body = NULL;
5046
5023
  int subscription_state;
5047
5024
  char *reason = NULL;
5048
- char *additional_headers = NULL;
5049
5025
 
5050
5026
  long val;
5051
5027
 
@@ -5086,7 +5062,7 @@ int pjw_notify(long subscriber_id, const char *json)
5086
5062
  goto out;
5087
5063
  }
5088
5064
 
5089
- if(!notify(subscriber->evsub, content_type, body, subscription_state, reason, additional_headers)){
5065
+ if(!notify(subscriber->evsub, content_type, body, subscription_state, reason, document)){
5090
5066
  goto out;
5091
5067
  }
5092
5068
 
@@ -5174,6 +5150,7 @@ out:
5174
5150
  return 0;
5175
5151
  }
5176
5152
 
5153
+ /*
5177
5154
  pj_bool_t add_additional_headers(pj_pool_t *pool, pjsip_tx_data *tdata, const char *additional_headers) {
5178
5155
 
5179
5156
  if(additional_headers && additional_headers[0]){
@@ -5210,94 +5187,133 @@ pj_bool_t add_additional_headers(pj_pool_t *pool, pjsip_tx_data *tdata, const ch
5210
5187
  }
5211
5188
  return PJ_TRUE;
5212
5189
  }
5190
+ */
5213
5191
 
5214
- pj_bool_t add_additional_headers_for_account(pjsip_regc *regc, const char *additional_headers) {
5215
5192
 
5216
- if(additional_headers && additional_headers[0]){
5217
- pjsip_hdr hdr_list;
5218
- pj_list_init(&hdr_list);
5193
+ pj_bool_t add_headers(pj_pool_t *pool, pjsip_tx_data *tdata, Document &document) {
5194
+ if(!document.HasMember("headers")) {
5195
+ return PJ_TRUE;
5196
+ }
5219
5197
 
5220
- char pool_buf[4096];
5221
- pj_pool_t *pool;
5222
- pool = pj_pool_create_on_buf(NULL, pool_buf, sizeof(pool_buf));
5198
+ if(!document["headers"].IsObject()) {
5199
+ set_error("Parameter headers must be an object");
5200
+ return PJ_FALSE;
5201
+ }
5223
5202
 
5224
- char buf[2048];
5225
- strcpy(buf,additional_headers);
5226
- char *saved;
5227
- char *token = strtok_r(buf, "\n", &saved);
5228
- while(token){
5229
- char *name = strtok(token, ":");
5230
- char *value = strtok(NULL, "\n");
5231
- //addon_log(LOG_LEVEL_DEBUG, "Adding %s:%s\n", name, value);
5203
+ Value headers = document["headers"].GetObject();
5232
5204
 
5233
- if(!name || !value) {
5234
- set_error("Invalid additional_header");
5235
- return PJ_FALSE;
5236
- }
5205
+ for (Value::ConstMemberIterator itr = headers.MemberBegin(); itr != headers.MemberEnd(); ++itr) {
5206
+ printf("%s => '%s'\n", itr->name.GetString(), itr->value.GetString());
5237
5207
 
5238
- pj_str_t hname = pj_str(name);
5239
- pjsip_hdr *hdr = (pjsip_hdr*)pjsip_parse_hdr(pool,
5240
- &hname,
5241
- value,
5242
- strlen(value),
5243
- NULL);
5208
+ const char *name = itr->name.GetString();
5209
+ if(!itr->value.IsString()) {
5210
+ set_error("Parameter headers key '%s' found with non-string value", name);
5211
+ return PJ_FALSE;
5212
+ }
5244
5213
 
5245
- if(!hdr) {
5246
- set_error("Failed to parse additional header to INVITE");
5247
- return PJ_FALSE;
5248
- }
5249
-
5250
- pj_list_push_back(&hdr_list, hdr);
5251
- token = strtok_r(NULL, "\n", &saved);
5252
- }
5253
- pjsip_regc_add_headers(regc, &hdr_list);
5254
- }
5214
+ const char *value = itr->value.GetString();
5215
+
5216
+ pj_str_t hname = pj_str((char*)name);
5217
+ pjsip_hdr *hdr = (pjsip_hdr*)pjsip_parse_hdr(pool,
5218
+ &hname,
5219
+ (char*)value,
5220
+ strlen(value),
5221
+ NULL);
5222
+
5223
+ if(!hdr) {
5224
+ set_error("Failed to parse header '%s' => '%s'", name, value);
5225
+ return PJ_FALSE;
5226
+ }
5227
+ pjsip_hdr *clone_hdr = (pjsip_hdr*) pjsip_hdr_clone(pool, hdr);
5228
+ pjsip_msg_add_hdr(tdata->msg, clone_hdr);
5229
+ }
5255
5230
  return PJ_TRUE;
5256
5231
  }
5257
5232
 
5258
- pj_bool_t get_content_type_and_subtype_from_additional_headers(const char *additional_headers, char *type, char *subtype) {
5233
+ pj_bool_t add_headers_for_account(pjsip_regc *regc, Document &document) {
5234
+ pjsip_hdr hdr_list;
5235
+ pj_list_init(&hdr_list);
5259
5236
 
5260
- if(!additional_headers || !additional_headers[0]){
5261
- set_error("Header Content-Type not supplied");
5262
- return PJ_FALSE;
5263
- }
5237
+ char pool_buf[4096];
5238
+ pj_pool_t *pool;
5239
+ pool = pj_pool_create_on_buf(NULL, pool_buf, sizeof(pool_buf));
5264
5240
 
5265
- char buf[1000];
5266
- strcpy(buf,additional_headers);
5267
- char *saved;
5268
- char *token = strtok_r(buf, "\n", &saved);
5269
- while(token){
5270
- char *name = strtok(token, ":");
5271
- char *value = strtok(NULL, " ");
5272
- addon_log(LOG_LEVEL_DEBUG, "Checking %s: %s\n", name, value);
5273
-
5274
- if(!name || !value) {
5275
- set_error("Invalid additional_header");
5276
- return PJ_FALSE;
5277
- }
5241
+ if(!document.HasMember("headers")) {
5242
+ return PJ_TRUE;
5243
+ }
5278
5244
 
5279
- if(strcmp(name, "Content-Type")==0) {
5280
- char *token_type = strtok(value, "/");
5281
- if(!token_type) {
5282
- set_error("No type specified in header Content-Type");
5283
- return PJ_FALSE;
5284
- }
5285
-
5286
- char *token_subtype = strtok(NULL, "\n");
5287
- if(!token_subtype) {
5288
- set_error("No subtype specified in header Content-Type");
5289
- return PJ_FALSE;
5290
- }
5245
+ if(!document["headers"].IsObject()) {
5246
+ set_error("Parameter headers must be an object");
5247
+ return PJ_FALSE;
5248
+ }
5291
5249
 
5292
- strcpy(type, token_type);
5293
- strcpy(subtype, token_subtype);
5294
- addon_log(LOG_LEVEL_DEBUG, "Checking parsing of Content-Type. type=%s: subtype=%s\n", type, subtype);
5295
- return PJ_TRUE;
5296
- }
5297
- token = strtok_r(NULL, "\n", &saved);
5250
+ Value headers = document["headers"].GetObject();
5251
+
5252
+ for (Value::ConstMemberIterator itr = headers.MemberBegin(); itr != headers.MemberEnd(); ++itr) {
5253
+ printf("%s => '%s'\n", itr->name.GetString(), itr->value.GetString());
5254
+
5255
+ const char *name = itr->name.GetString();
5256
+ if(!itr->value.IsString()) {
5257
+ set_error("Parameter headers key '%s' found with non-string value", name);
5258
+ return PJ_FALSE;
5259
+ }
5260
+
5261
+ const char *value = itr->value.GetString();
5262
+
5263
+ pj_str_t hname = pj_str((char*)name);
5264
+ pjsip_hdr *hdr = (pjsip_hdr*)pjsip_parse_hdr(pool,
5265
+ &hname,
5266
+ (char*)value,
5267
+ strlen(value),
5268
+ NULL);
5269
+
5270
+ if(!hdr) {
5271
+ set_error("Failed to parse header %s", name);
5272
+ return PJ_FALSE;
5273
+ }
5274
+
5275
+ pj_list_push_back(&hdr_list, hdr);
5298
5276
  }
5299
- set_error("Header Content-Type not supplied");
5300
- return PJ_FALSE;
5277
+
5278
+ pjsip_regc_add_headers(regc, &hdr_list);
5279
+ return PJ_TRUE;
5280
+ }
5281
+
5282
+ pj_bool_t get_content_type_and_subtype_from_headers(Document &document, char *type, char *subtype) {
5283
+ if(!document.HasMember("headers")) {
5284
+ set_error("Parameter headers absent");
5285
+ return PJ_FALSE;
5286
+ }
5287
+
5288
+ if(!document["headers"].IsObject()) {
5289
+ set_error("Parameter headers must be an object");
5290
+ return PJ_FALSE;
5291
+ }
5292
+
5293
+ Value headers = document["headers"].GetObject();
5294
+
5295
+ if(!headers.HasMember("Content-Type")) {
5296
+ set_error("Parameter headers doesn't contain key Content-Type");
5297
+ return PJ_FALSE;
5298
+ }
5299
+
5300
+ const char *content_type = headers["Content-Type"].GetString();
5301
+
5302
+ const char *slash;
5303
+ int index;
5304
+
5305
+ slash = strchr(content_type, '/');
5306
+ if(!slash) {
5307
+ set_error("Invalid header Content-Type");
5308
+ return PJ_FALSE;
5309
+ }
5310
+
5311
+ index = (int)(slash - content_type);
5312
+
5313
+ strncpy(type, content_type, index-1);
5314
+ strcpy(subtype, content_type+index);
5315
+ addon_log(LOG_LEVEL_DEBUG, "Checking parsing of Content-Type. type=%s: subtype=%s\n", type, subtype);
5316
+ return PJ_TRUE;
5301
5317
  }
5302
5318
 
5303
5319
 
@@ -5505,7 +5521,37 @@ out:
5505
5521
  return 0;
5506
5522
  }
5507
5523
 
5508
- bool subscription_subscribe(Subscription *s, int expires, const char *additional_headers) {
5524
+ bool subscription_subscribe_no_headers(Subscription *s, int expires) {
5525
+ pj_status_t status;
5526
+ pjsip_tx_data *tdata;
5527
+
5528
+ status = pjsip_evsub_initiate(s->evsub,
5529
+ NULL,
5530
+ expires,
5531
+ &tdata);
5532
+ if(status != PJ_SUCCESS) {
5533
+ set_error("pjsip_evsub_initiate failed");
5534
+ return false;
5535
+ }
5536
+
5537
+ status = pjsip_evsub_send_request(s->evsub, tdata);
5538
+ if(status != PJ_SUCCESS) {
5539
+ set_error("pjsip_inv_send_msg failed");
5540
+ return false;
5541
+ }
5542
+
5543
+ //Without this, on_rx_response will not be called
5544
+ status = pjsip_dlg_add_usage(s->dlg, &mod_tester, s);
5545
+ if(status != PJ_SUCCESS) {
5546
+ set_error("pjsip_dlg_add_usage failed");
5547
+ return false;
5548
+ }
5549
+
5550
+ return true;
5551
+ }
5552
+
5553
+
5554
+ bool subscription_subscribe(Subscription *s, int expires, Document &document) {
5509
5555
  pj_status_t status;
5510
5556
  pjsip_tx_data *tdata;
5511
5557
 
@@ -5518,7 +5564,7 @@ bool subscription_subscribe(Subscription *s, int expires, const char *additional
5518
5564
  return false;
5519
5565
  }
5520
5566
 
5521
- if(!add_additional_headers(s->dlg->pool, tdata, additional_headers)) {
5567
+ if(!add_headers(s->dlg->pool, tdata, document)) {
5522
5568
  return false;
5523
5569
  }
5524
5570
 
@@ -5544,7 +5590,6 @@ int pjw_subscription_subscribe(long subscription_id, const char *json) {
5544
5590
  clear_error();
5545
5591
 
5546
5592
  int expires;
5547
- char *additional_headers = NULL;
5548
5593
 
5549
5594
  Subscription *subscription;
5550
5595
 
@@ -5568,7 +5613,7 @@ int pjw_subscription_subscribe(long subscription_id, const char *json) {
5568
5613
  goto out;
5569
5614
  }
5570
5615
 
5571
- if(!subscription_subscribe(subscription, expires, additional_headers)) {
5616
+ if(!subscription_subscribe(subscription, expires, document)) {
5572
5617
  goto out;
5573
5618
  }
5574
5619