@gibme/asterisk-gateway-interface 1.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.
@@ -0,0 +1,1033 @@
1
+ "use strict";
2
+ // Copyright (c) 2016-2022 Brandon Lehmann
3
+ //
4
+ // Please see the included LICENSE file for more information.
5
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
6
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
7
+ return new (P || (P = Promise))(function (resolve, reject) {
8
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
9
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
10
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
11
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
12
+ });
13
+ };
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ const events_1 = require("events");
19
+ const util_1 = require("util");
20
+ const types_1 = require("./types");
21
+ const response_arguments_1 = __importDefault(require("./response_arguments"));
22
+ /**
23
+ * Represents an AGI Channel
24
+ */
25
+ class Channel extends events_1.EventEmitter {
26
+ /**
27
+ * Creates a new instance of a channel object
28
+ * @param connection the AGI socket connection
29
+ */
30
+ constructor(connection) {
31
+ super();
32
+ this.m_message = '';
33
+ this.m_network = '';
34
+ this.m_network_script = '';
35
+ this.m_request = '';
36
+ this.m_channel = '';
37
+ this.m_language = '';
38
+ this.m_type = '';
39
+ this.m_uniqueid = '';
40
+ this.m_version = '';
41
+ this.m_callerid = '';
42
+ this.m_calleridname = '';
43
+ this.m_callingpres = '';
44
+ this.m_callingani2 = '';
45
+ this.m_callington = '';
46
+ this.m_callingtns = '';
47
+ this.m_dnid = '';
48
+ this.m_rdnis = '';
49
+ this.m_context = '';
50
+ this.m_extension = '';
51
+ this.m_priority = '';
52
+ this.m_enhanced = '';
53
+ this.m_accountcode = '';
54
+ this.m_threadid = '';
55
+ this.setMaxListeners(10);
56
+ this.m_connection = connection;
57
+ this.m_state = types_1.ContextState.INIT;
58
+ this.m_connection.on('data', (data) => this.read(data));
59
+ this.m_connection.on('close', () => this.emit('close'));
60
+ this.m_connection.on('error', (error) => this.emit('error', error));
61
+ this.m_connection.on('timeout', () => this.emit('timeout'));
62
+ this.on('hangup', () => this.close());
63
+ }
64
+ on(event, listener) {
65
+ return super.on(event, listener);
66
+ }
67
+ /**
68
+ * Whether this AGI request is over the network
69
+ */
70
+ get network() {
71
+ return (this.m_network.toLowerCase() === 'yes');
72
+ }
73
+ /**
74
+ * The network path included in the AGI request
75
+ * ie. agi://127.0.0.1:3000/test
76
+ * This value would return 'test'
77
+ */
78
+ get network_script() {
79
+ return this.m_network_script;
80
+ }
81
+ /**
82
+ * The version of Asterisk
83
+ */
84
+ get version() {
85
+ return this.m_version;
86
+ }
87
+ /**
88
+ * The filename of your script
89
+ * ie. agi
90
+ */
91
+ get request() {
92
+ return this.m_request;
93
+ }
94
+ /**
95
+ * The originating channel (your phone)
96
+ */
97
+ get channel() {
98
+ return this.m_channel;
99
+ }
100
+ /**
101
+ * The language code (e.g. “en”)
102
+ */
103
+ get language() {
104
+ return this.m_language;
105
+ }
106
+ /**
107
+ * The originating channel type (e.g. “SIP” or “ZAP”)
108
+ */
109
+ get type() {
110
+ return this.m_type;
111
+ }
112
+ /**
113
+ * A unique ID for the call
114
+ */
115
+ get uniqueid() {
116
+ return this.m_uniqueid;
117
+ }
118
+ /**
119
+ * The caller ID number (or “unknown”)
120
+ */
121
+ get callerid() {
122
+ return this.m_callerid;
123
+ }
124
+ /**
125
+ * The caller ID name (or “unknown”)
126
+ */
127
+ get calleridname() {
128
+ return this.m_calleridname;
129
+ }
130
+ /**
131
+ * The presentation for the callerid in a ZAP channel
132
+ */
133
+ get callingpres() {
134
+ return this.m_callingpres;
135
+ }
136
+ /**
137
+ * The number which is defined in ANI2 see Asterisk Detailed Variable List (only for PRI Channels)
138
+ */
139
+ get callingani2() {
140
+ return this.m_callingani2;
141
+ }
142
+ /**
143
+ * The type of number used in PRI Channels see Asterisk Detailed Variable List
144
+ */
145
+ get callington() {
146
+ return this.m_callington;
147
+ }
148
+ /**
149
+ * An optional 4 digit number (Transit Network Selector) used in PRI Channels see Asterisk Detailed Variable List
150
+ */
151
+ get callingtns() {
152
+ return this.m_callingtns;
153
+ }
154
+ /**
155
+ * The dialed number id (or “unknown”)
156
+ */
157
+ get dnid() {
158
+ return this.m_dnid;
159
+ }
160
+ /**
161
+ * The referring DNIS number (or “unknown”)
162
+ */
163
+ get rdnis() {
164
+ return this.m_rdnis;
165
+ }
166
+ /**
167
+ * Origin context in extensions.conf
168
+ */
169
+ get context() {
170
+ return this.m_context;
171
+ }
172
+ /**
173
+ * The called number
174
+ */
175
+ get extension() {
176
+ return this.m_extension;
177
+ }
178
+ /**
179
+ * The priority it was executed as in the dial plan
180
+ */
181
+ get priority() {
182
+ return this.m_priority;
183
+ }
184
+ /**
185
+ * The flag value is 1.0 if started as an EAGI script, 0.0 otherwise
186
+ */
187
+ get enhanced() {
188
+ return this.m_enhanced;
189
+ }
190
+ /**
191
+ * Account code of the origin channel
192
+ */
193
+ get accountcode() {
194
+ return this.m_accountcode;
195
+ }
196
+ /**
197
+ * Thread ID of the AGI script
198
+ */
199
+ get threadid() {
200
+ return this.m_threadid;
201
+ }
202
+ /**
203
+ * Answers channel if not already in answer state.
204
+ */
205
+ answer() {
206
+ return __awaiter(this, void 0, void 0, function* () {
207
+ const response = yield this.sendCommand('ANSWER');
208
+ if (response.code !== 200 || response.result !== 0) {
209
+ throw new Error('Could not answer call');
210
+ }
211
+ });
212
+ }
213
+ /**
214
+ * Interrupts expected flow of Async AGI commands and returns control to
215
+ * previous source (typically, the PBX dialplan).
216
+ */
217
+ break() {
218
+ return __awaiter(this, void 0, void 0, function* () {
219
+ const response = yield this.sendCommand('ASYNCAGI BREAK');
220
+ if (response.code !== 200 || response.result !== 0) {
221
+ throw new Error('Could not interrupt processing');
222
+ }
223
+ return this.close();
224
+ });
225
+ }
226
+ /**
227
+ * Returns status of the connected channel.
228
+ * @param channel
229
+ */
230
+ channelStatus(channel) {
231
+ return __awaiter(this, void 0, void 0, function* () {
232
+ const response = yield this.sendCommand((0, util_1.format)('CHANNEL STATUS %s', channel || ''));
233
+ if (response.code !== 200 || response.result === -1) {
234
+ throw new Error('Could not get channel status');
235
+ }
236
+ return response.result;
237
+ });
238
+ }
239
+ /**
240
+ * Sends audio file on channel and allows the listener to control the stream.
241
+ * @param filename
242
+ * @param escapeDigits
243
+ * @param skipms
244
+ * @param fastForwardCharacter
245
+ * @param rewindCharacter
246
+ * @param pauseCharacter
247
+ */
248
+ controlStreamFile(filename, escapeDigits = '', skipms, fastForwardCharacter, rewindCharacter, pauseCharacter) {
249
+ return __awaiter(this, void 0, void 0, function* () {
250
+ const response = yield this.sendCommand((0, util_1.format)('CONTROL STREAM FILE %s "%s" %s %s %s %s', filename, escapeDigits, skipms || '', fastForwardCharacter || '', rewindCharacter || '', pauseCharacter || ''));
251
+ if (response.code !== 200 || response.result === -1) {
252
+ throw new Error('Could not control stream file');
253
+ }
254
+ const playbackStatus = yield this.getVariable('CPLAYBACKSTATUS ');
255
+ const playbackOffset = yield this.getVariable('CPLAYBACKOFFSET ');
256
+ let status = types_1.PlaybackStatus.ERROR;
257
+ switch (playbackStatus.toUpperCase()) {
258
+ case 'SUCCESS':
259
+ status = types_1.PlaybackStatus.SUCCESS;
260
+ break;
261
+ case 'USERSTOPPED':
262
+ status = types_1.PlaybackStatus.USER_STOPPED;
263
+ break;
264
+ case 'REMOTESTOPPED':
265
+ status = types_1.PlaybackStatus.REMOTE_STOPPED;
266
+ break;
267
+ }
268
+ return {
269
+ digit: response.arguments.char('result'),
270
+ playbackStatus: status,
271
+ playbackOffset: parseInt(playbackOffset, 10)
272
+ };
273
+ });
274
+ }
275
+ /**
276
+ * Attempts to establish a new outgoing connection on a channel, and then link it to the calling input channel.
277
+ * @param target
278
+ * @param timeout
279
+ * @param params
280
+ */
281
+ dial(target, timeout = 30, params) {
282
+ return __awaiter(this, void 0, void 0, function* () {
283
+ yield this.exec('Dial', (0, util_1.format)('%s,%s,%s', target, timeout, params || ''));
284
+ const dialstatus = yield this.getVariable('DIALSTATUS');
285
+ switch (dialstatus.toUpperCase()) {
286
+ case 'ANSWER':
287
+ return types_1.DialStatus.ANSWER;
288
+ case 'BUSY':
289
+ return types_1.DialStatus.BUSY;
290
+ case 'NOANSWER':
291
+ return types_1.DialStatus.NOANSWER;
292
+ case 'CANCEL':
293
+ return types_1.DialStatus.CANCEL;
294
+ case 'CONGESTION':
295
+ return types_1.DialStatus.CONGESTION;
296
+ case 'CHANUNAVAIL':
297
+ return types_1.DialStatus.CHANUNAVAIL;
298
+ case 'DONTCALL':
299
+ return types_1.DialStatus.DONTCALL;
300
+ case 'TORTURE':
301
+ return types_1.DialStatus.TORTURE;
302
+ case 'INVALIDARGS':
303
+ return types_1.DialStatus.INVALIDARGS;
304
+ default:
305
+ throw new Error('Unknown dial status');
306
+ }
307
+ });
308
+ }
309
+ /**
310
+ * Deletes an entry in the Asterisk database for a given family and key.
311
+ * @param family
312
+ * @param key
313
+ */
314
+ databaseDel(family, key) {
315
+ return __awaiter(this, void 0, void 0, function* () {
316
+ const response = yield this.sendCommand((0, util_1.format)('DATABASE DEL %s %s', family, key));
317
+ if (response.code !== 200 || response.result === 0) {
318
+ throw new Error('Could not delete from the database');
319
+ }
320
+ });
321
+ }
322
+ /**
323
+ * Deletes a family or specific keytree within a family in the Asterisk database.
324
+ * @param family
325
+ * @param keyTree
326
+ */
327
+ databaseDelTree(family, keyTree) {
328
+ return __awaiter(this, void 0, void 0, function* () {
329
+ const response = yield this.sendCommand((0, util_1.format)('DATABASE DELTREE %s %s', family, keyTree || ''));
330
+ if (response.code !== 200) {
331
+ throw new Error('Could not delete tree from database');
332
+ }
333
+ return (response.result === 0);
334
+ });
335
+ }
336
+ /**
337
+ * Retrieves an entry in the Asterisk database for a given family and key.
338
+ * @param family
339
+ * @param key
340
+ */
341
+ databaseGet(family, key) {
342
+ return __awaiter(this, void 0, void 0, function* () {
343
+ const response = yield this.sendCommand((0, util_1.format)('DATABASE GET %s %s', family, key));
344
+ if (response.code !== 200 || response.result === 0) {
345
+ throw new Error('Database key not set');
346
+ }
347
+ return response.arguments.nokey();
348
+ });
349
+ }
350
+ /**
351
+ * Adds or updates an entry in the Asterisk database for a given family, key, and value.
352
+ * @param family
353
+ * @param key
354
+ * @param value
355
+ */
356
+ databasePut(family, key, value) {
357
+ return __awaiter(this, void 0, void 0, function* () {
358
+ const response = yield this.sendCommand((0, util_1.format)('DATABASE PUT %s %s %s', family, key, value));
359
+ if (response.code !== 200 || response.result === 0) {
360
+ throw new Error('Database key not set');
361
+ }
362
+ return response.arguments.string('value');
363
+ });
364
+ }
365
+ /**
366
+ * Executes application with given options
367
+ * @param application.
368
+ * @param args
369
+ */
370
+ exec(application, ...args) {
371
+ return __awaiter(this, void 0, void 0, function* () {
372
+ const response = yield this.sendCommand((0, util_1.format)('EXEC %s %s', application, args.join(' ')));
373
+ if (response.code !== 200 || response.result === -2) {
374
+ throw new Error('Could not execute application');
375
+ }
376
+ return response.result;
377
+ });
378
+ }
379
+ /**
380
+ * Stream the given file, and receive DTMF data.
381
+ * @param soundFile
382
+ * @param timeout
383
+ * @param maxDigits
384
+ */
385
+ getData(soundFile, timeout = 5, maxDigits) {
386
+ return __awaiter(this, void 0, void 0, function* () {
387
+ const response = yield this.sendCommand((0, util_1.format)('GET DATA %s %s %s', soundFile, timeout * 1000, maxDigits || ''));
388
+ if (response.code !== 200 || response.result === -1) {
389
+ throw new Error('Could not get data from channel');
390
+ }
391
+ return {
392
+ digits: response.arguments.string('result'),
393
+ timeout: (response.arguments.string('value') === '(timeout)')
394
+ };
395
+ });
396
+ }
397
+ /**
398
+ * Evaluates a channel expression
399
+ * Understands complex variable names and builtin variables, unlike GET VARIABLE.
400
+ * @param key
401
+ * @param channel
402
+ */
403
+ getFullVariable(key, channel) {
404
+ return __awaiter(this, void 0, void 0, function* () {
405
+ const response = yield this.sendCommand((0, util_1.format)('GET FULL VARIABLE %s %s', key.toUpperCase(), channel || ''));
406
+ if (response.code !== 200 || response.result === 0) {
407
+ throw new Error('Variable not set');
408
+ }
409
+ return response.arguments.nokey();
410
+ });
411
+ }
412
+ /**
413
+ * Stream file, prompt for DTMF, with timeout.
414
+ * Behaves similar to STREAM FILE but used with a timeout option.
415
+ * @param soundFile
416
+ * @param escapeDigits
417
+ * @param timeout
418
+ */
419
+ getOption(soundFile, escapeDigits = '#', timeout = 5) {
420
+ return __awaiter(this, void 0, void 0, function* () {
421
+ const response = yield this.sendCommand((0, util_1.format)('GET OPTION %s "%s" %s', soundFile, escapeDigits, timeout * 1000));
422
+ if (response.code !== 200 || response.result === -1) {
423
+ throw new Error('Could not get option');
424
+ }
425
+ if (response.arguments.number('endpos') === 0) {
426
+ throw new Error('Could Not play file');
427
+ }
428
+ return {
429
+ digit: response.arguments.char('result'),
430
+ endpos: response.arguments.number('endpos')
431
+ };
432
+ });
433
+ }
434
+ /**
435
+ * Gets a channel variable.
436
+ * @param key
437
+ */
438
+ getVariable(key) {
439
+ return __awaiter(this, void 0, void 0, function* () {
440
+ const response = yield this.sendCommand((0, util_1.format)('GET VARIABLE %s', key.toUpperCase()));
441
+ if (response.code !== 200 || response.result === 0) {
442
+ throw new Error('Variable not set');
443
+ }
444
+ return response.arguments.nokey();
445
+ });
446
+ }
447
+ /**
448
+ * Cause the channel to execute the specified dialplan subroutine.
449
+ * @param context
450
+ * @param extension
451
+ * @param priority
452
+ * @param argument
453
+ */
454
+ goSub(context, extension, priority, argument) {
455
+ return __awaiter(this, void 0, void 0, function* () {
456
+ const response = yield this.sendCommand((0, util_1.format)('GOSUB %s %s %s %s', context, extension, priority, argument || ''));
457
+ if (response.code !== 200 || response.result !== 0) {
458
+ throw new Error('Could not execute gosub');
459
+ }
460
+ });
461
+ }
462
+ /**
463
+ * Hangs up the specified channel. If no channel name is given, hangs up the current channel
464
+ * @param channel
465
+ */
466
+ hangup(channel) {
467
+ return __awaiter(this, void 0, void 0, function* () {
468
+ const response = yield this.sendCommand((0, util_1.format)('HANGUP %s', channel || ''));
469
+ if (response.code !== 200 || response.result !== 1) {
470
+ throw new Error('Could not hang up call');
471
+ }
472
+ });
473
+ }
474
+ /**
475
+ * Does nothing
476
+ */
477
+ noop() {
478
+ return __awaiter(this, void 0, void 0, function* () {
479
+ const response = yield this.sendCommand('NOOP');
480
+ if (response.code !== 200 || response.result !== 0) {
481
+ throw new Error('Could not NOOP');
482
+ }
483
+ });
484
+ }
485
+ /**
486
+ * Receives one character from channels supporting it.
487
+ * @param timeout
488
+ */
489
+ receiveChar(timeout = 5) {
490
+ return __awaiter(this, void 0, void 0, function* () {
491
+ const response = yield this.sendCommand((0, util_1.format)('RECEIVE CHAR %s', timeout * 1000));
492
+ if (response.code !== 200 || response.result === -1) {
493
+ throw new Error('Could not get data from channel');
494
+ }
495
+ return {
496
+ char: response.arguments.char('result'),
497
+ timeout: response.arguments.boolean('timeout')
498
+ };
499
+ });
500
+ }
501
+ /**
502
+ * Receives text from channels supporting it.
503
+ * @param timeout
504
+ */
505
+ receiveText(timeout = 5) {
506
+ return __awaiter(this, void 0, void 0, function* () {
507
+ const response = yield this.sendCommand((0, util_1.format)('RECEIVE TEXT %s', timeout * 1000));
508
+ if (response.code !== 200 || response.result === -1) {
509
+ throw new Error('Could not get data from channel');
510
+ }
511
+ return response.arguments.string('result');
512
+ });
513
+ }
514
+ /**
515
+ * Records to a given file.
516
+ * @param filename
517
+ * @param fileFormat
518
+ * @param escapeDigits
519
+ * @param timeout
520
+ * @param beep
521
+ * @param silence
522
+ * @param offsetSamples
523
+ */
524
+ recordFile(filename, fileFormat = 'gsm', escapeDigits = '#', timeout = 10, beep, silence, offsetSamples) {
525
+ return __awaiter(this, void 0, void 0, function* () {
526
+ const response = yield this.sendCommand((0, util_1.format)('RECORD FILE %s %s "%s" %s %s %s %s', filename, fileFormat, escapeDigits, timeout * 1000, offsetSamples || '', (beep) ? 'BEEP' : '', (silence) ? (0, util_1.format)('s=%s', silence) : ''));
527
+ if (response.code !== 200 || response.result === -1) {
528
+ throw new Error('Could not record file');
529
+ }
530
+ return {
531
+ digit: response.arguments.char('result'),
532
+ endpos: response.arguments.number('endpos'),
533
+ timeout: response.arguments.boolean('timeout')
534
+ };
535
+ });
536
+ }
537
+ /**
538
+ * Says a given character string.
539
+ * @param value
540
+ * @param escapeDigits
541
+ */
542
+ sayAlpha(value, escapeDigits = '#') {
543
+ return __awaiter(this, void 0, void 0, function* () {
544
+ const response = yield this.sendCommand((0, util_1.format)('SAY ALPHA %s "%s"', value, escapeDigits));
545
+ if (response.code !== 200 || response.result === -1) {
546
+ throw new Error('Could not say alpha');
547
+ }
548
+ return response.arguments.char('result');
549
+ });
550
+ }
551
+ /**
552
+ * Says a given date.
553
+ * @param value
554
+ * @param escapeDigits
555
+ */
556
+ sayDate(value, escapeDigits = '#') {
557
+ return __awaiter(this, void 0, void 0, function* () {
558
+ const response = yield this.sendCommand((0, util_1.format)('SAY DATE %s "%s"', (typeof value === 'number') ? value : Math.floor(value.getTime() / 1000), escapeDigits));
559
+ if (response.code !== 200 || response.result === -1) {
560
+ throw new Error('Could not say date');
561
+ }
562
+ return response.arguments.char('result');
563
+ });
564
+ }
565
+ /**
566
+ * Says a given time as specified by the format given.
567
+ * @param value
568
+ * @param escapeDigits
569
+ * @param dateFormat
570
+ * @param timezone
571
+ */
572
+ sayDateTime(value, escapeDigits = '#', dateFormat, timezone) {
573
+ return __awaiter(this, void 0, void 0, function* () {
574
+ const response = yield this.sendCommand((0, util_1.format)('SAY DATETIME %s "%s" %s %s', (typeof value === 'number') ? value : Math.floor(value.getTime() / 1000), escapeDigits, dateFormat || '', timezone || ''));
575
+ if (response.code !== 200 || response.result === -1) {
576
+ throw new Error('Could not say date time');
577
+ }
578
+ return response.arguments.char('result');
579
+ });
580
+ }
581
+ /**
582
+ * Says a given digit string.
583
+ * @param value
584
+ * @param escapeDigits
585
+ */
586
+ sayDigits(value, escapeDigits = '#') {
587
+ return __awaiter(this, void 0, void 0, function* () {
588
+ const response = yield this.sendCommand((0, util_1.format)('SAY DIGITS %s "%s"', value, escapeDigits));
589
+ if (response.code !== 200 || response.result === -1) {
590
+ throw new Error('Could not say digits');
591
+ }
592
+ return response.arguments.char('result');
593
+ });
594
+ }
595
+ /**
596
+ * Says a given number.
597
+ * @param value
598
+ * @param escapeDigits
599
+ */
600
+ sayNumber(value, escapeDigits = '#') {
601
+ return __awaiter(this, void 0, void 0, function* () {
602
+ const response = yield this.sendCommand((0, util_1.format)('SAY NUMBER %s "%s"', value, escapeDigits));
603
+ if (response.code !== 200 || response.result === -1) {
604
+ throw new Error('Could not say number');
605
+ }
606
+ return response.arguments.char('result');
607
+ });
608
+ }
609
+ /**
610
+ * Says a given character string with phonetics.
611
+ * @param value
612
+ * @param escapeDigits
613
+ */
614
+ sayPhonetic(value, escapeDigits = '#') {
615
+ return __awaiter(this, void 0, void 0, function* () {
616
+ const response = yield this.sendCommand((0, util_1.format)('SAY PHONETIC %s "%s"', value, escapeDigits));
617
+ if (response.code !== 200 || response.result === -1) {
618
+ throw new Error('Could not say phonetic');
619
+ }
620
+ return response.arguments.char('result');
621
+ });
622
+ }
623
+ /**
624
+ * Says a given time.
625
+ * @param value
626
+ * @param escapeDigits
627
+ */
628
+ sayTime(value, escapeDigits = '#') {
629
+ return __awaiter(this, void 0, void 0, function* () {
630
+ const response = yield this.sendCommand((0, util_1.format)('SAY TIME %s "%s"', (typeof value === 'number') ? value : Math.floor(value.getTime() / 1000), escapeDigits));
631
+ if (response.code !== 200 || response.result === -1) {
632
+ throw new Error('Could not say time');
633
+ }
634
+ return response.arguments.char('result');
635
+ });
636
+ }
637
+ /**
638
+ * Sends images to channels supporting it.
639
+ * @param image
640
+ */
641
+ sendImage(image) {
642
+ return __awaiter(this, void 0, void 0, function* () {
643
+ const response = yield this.sendCommand((0, util_1.format)('SEND IMAGE %s', image));
644
+ if (response.code !== 200 || response.result !== 0) {
645
+ throw new Error('Could not send image');
646
+ }
647
+ });
648
+ }
649
+ /**
650
+ * Sends text to channels supporting it.
651
+ * @param text
652
+ */
653
+ sendText(text) {
654
+ return __awaiter(this, void 0, void 0, function* () {
655
+ const response = yield this.sendCommand((0, util_1.format)('SEND TEXT "%s"', text));
656
+ if (response.code !== 200 || response.result !== 0) {
657
+ throw new Error('Could not send text');
658
+ }
659
+ });
660
+ }
661
+ /**
662
+ * Autohangup channel in some time.
663
+ * @param timeout
664
+ */
665
+ setAutoHangup(timeout = 60) {
666
+ return __awaiter(this, void 0, void 0, function* () {
667
+ const response = yield this.sendCommand((0, util_1.format)('SET AUTOHANGUP %s', timeout));
668
+ if (response.code !== 200 || response.result !== 0) {
669
+ throw new Error('Could not set auto hangup');
670
+ }
671
+ });
672
+ }
673
+ /**
674
+ * Sets callerid for the current channel.
675
+ * @param callerNumber
676
+ * @param callerName
677
+ */
678
+ setCallerID(callerNumber, callerName) {
679
+ return __awaiter(this, void 0, void 0, function* () {
680
+ const callerid = (callerName)
681
+ ? (0, util_1.format)('"%s"<%s>', callerName, callerNumber)
682
+ : callerNumber;
683
+ const response = yield this.sendCommand((0, util_1.format)('SET CALLERID %s', callerid));
684
+ if (response.code !== 200 || response.result !== 1) {
685
+ throw new Error('Could not set caller id');
686
+ }
687
+ });
688
+ }
689
+ /**
690
+ * Sets channel context.
691
+ * @param context
692
+ */
693
+ setContext(context) {
694
+ return __awaiter(this, void 0, void 0, function* () {
695
+ const response = yield this.sendCommand((0, util_1.format)('SET CONTEXT %s', context));
696
+ if (response.code !== 200 || response.result !== 0) {
697
+ throw new Error('Could not set context');
698
+ }
699
+ });
700
+ }
701
+ /**
702
+ * Changes channel extension.
703
+ * @param extension
704
+ */
705
+ setExtension(extension) {
706
+ return __awaiter(this, void 0, void 0, function* () {
707
+ const response = yield this.sendCommand((0, util_1.format)('SET EXTENSION %s', extension));
708
+ if (response.code !== 200 || response.result !== 0) {
709
+ throw new Error('Could not set extension');
710
+ }
711
+ });
712
+ }
713
+ /**
714
+ * Enable/Disable Music on hold generator
715
+ * @param status
716
+ * @param musicClass
717
+ */
718
+ setMusic(status = true, musicClass) {
719
+ return __awaiter(this, void 0, void 0, function* () {
720
+ const response = yield this.sendCommand((0, util_1.format)('SET MUSIC %s %s', (status) ? 'ON' : 'OFF', musicClass || ''));
721
+ if (response.code !== 200 || response.result !== 0) {
722
+ throw new Error('Could not set priority');
723
+ }
724
+ });
725
+ }
726
+ /**
727
+ * Set channel dialplan priority.
728
+ * @param priority
729
+ */
730
+ setPriority(priority) {
731
+ return __awaiter(this, void 0, void 0, function* () {
732
+ const response = yield this.sendCommand((0, util_1.format)('SET PRIORITY %s', priority));
733
+ if (response.code !== 200 || response.result !== 0) {
734
+ throw new Error('Could not set priority');
735
+ }
736
+ });
737
+ }
738
+ /**
739
+ * Set channel dialplan priority.
740
+ * @param key
741
+ * @param value
742
+ */
743
+ setVariable(key, value) {
744
+ return __awaiter(this, void 0, void 0, function* () {
745
+ const response = yield this.sendCommand((0, util_1.format)('SET VARIABLE %s "%s"', key.toUpperCase(), value));
746
+ if (response.code !== 200 || response.result !== 1) {
747
+ throw new Error('Could not set variable');
748
+ }
749
+ });
750
+ }
751
+ speechActivateGrammar(grammar) {
752
+ return __awaiter(this, void 0, void 0, function* () {
753
+ // TODO: Handle the response
754
+ return this.sendCommand((0, util_1.format)('SPEECH ACTIVATE GRAMMAR %s', grammar));
755
+ });
756
+ }
757
+ speechCreate(engine) {
758
+ return __awaiter(this, void 0, void 0, function* () {
759
+ // TODO: Handle the response
760
+ return this.sendCommand((0, util_1.format)('SPEECH CREATE ENGINE %s', engine));
761
+ });
762
+ }
763
+ speechDeactivateGrammar(grammar) {
764
+ return __awaiter(this, void 0, void 0, function* () {
765
+ // TODO: Handle the response
766
+ return this.sendCommand((0, util_1.format)('SPEECH DEACTIVATE GRAMMAR %s', grammar));
767
+ });
768
+ }
769
+ speechDestroy() {
770
+ return __awaiter(this, void 0, void 0, function* () {
771
+ // TODO: Handle the response
772
+ return this.sendCommand('SPEECH DESTROY');
773
+ });
774
+ }
775
+ speechLoadGrammar(grammar, path) {
776
+ return __awaiter(this, void 0, void 0, function* () {
777
+ // TODO: Handle the response
778
+ return this.sendCommand((0, util_1.format)('SPEECH LOAD GRAMMAR %s %s', grammar, path));
779
+ });
780
+ }
781
+ speechRecognize(soundFile, timeout = 5, offset) {
782
+ return __awaiter(this, void 0, void 0, function* () {
783
+ // TODO: Handle the response
784
+ return this.sendCommand((0, util_1.format)('SPEECH RECOGNIZE %s %s %s', soundFile, timeout * 1000, offset));
785
+ });
786
+ }
787
+ speechSet(key, value) {
788
+ return __awaiter(this, void 0, void 0, function* () {
789
+ // TODO: Handle the response
790
+ return this.sendCommand((0, util_1.format)('SPEECH SET %s %s', key, value));
791
+ });
792
+ }
793
+ speedUnloadGrammar(grammar) {
794
+ return __awaiter(this, void 0, void 0, function* () {
795
+ // TODO: Handle the response
796
+ return this.sendCommand((0, util_1.format)('SPEECH UNLOAD GRAMMAR %s', grammar));
797
+ });
798
+ }
799
+ /**
800
+ * Sends audio file on channel.
801
+ * @param filename
802
+ * @param escapeDigits
803
+ * @param offset
804
+ */
805
+ streamFile(filename, escapeDigits = '#', offset) {
806
+ return __awaiter(this, void 0, void 0, function* () {
807
+ const response = yield this.sendCommand((0, util_1.format)('STREAM FILE %s "%s" %s', filename, escapeDigits, offset || ''));
808
+ if (response.code !== 200 || response.result === -1) {
809
+ throw new Error('Could not stream file');
810
+ }
811
+ const status = yield this.getVariable('PLAYBACKSTATUS ');
812
+ if (status.toUpperCase() !== 'SUCCESS') {
813
+ throw new Error('Could not stream file');
814
+ }
815
+ return {
816
+ digit: response.arguments.char('result'),
817
+ endpos: response.arguments.number('endpos')
818
+ };
819
+ });
820
+ }
821
+ /**
822
+ * Toggles TDD mode (for the deaf).
823
+ * @param status
824
+ */
825
+ tddMode(status) {
826
+ return __awaiter(this, void 0, void 0, function* () {
827
+ const response = yield this.sendCommand((0, util_1.format)('TDD MODE %s', (status) ? 'ON' : 'OFF'));
828
+ if (response.code !== 200 || response.result !== 1) {
829
+ throw new Error('Could not set TDD mode');
830
+ }
831
+ });
832
+ }
833
+ /**
834
+ * Logs a message to the asterisk verbose log.
835
+ * @param message
836
+ * @param level
837
+ */
838
+ verbose(message, level) {
839
+ return __awaiter(this, void 0, void 0, function* () {
840
+ const response = yield this.sendCommand((0, util_1.format)('VERBOSE "%s" %s', message, level || ''));
841
+ if (response.code !== 200 || response.result !== 1) {
842
+ throw new Error('Could not send logging message');
843
+ }
844
+ });
845
+ }
846
+ /**
847
+ * Waits for a digit to be pressed.
848
+ * @param timeout
849
+ */
850
+ waitForDigit(timeout = 5) {
851
+ return __awaiter(this, void 0, void 0, function* () {
852
+ const response = yield this.sendCommand((0, util_1.format)('WAIT FOR DIGIT %s', timeout * 1000));
853
+ if (response.code !== 200 || response.result === -1) {
854
+ throw new Error('Could not wait for digit');
855
+ }
856
+ return response.arguments.char('result');
857
+ });
858
+ }
859
+ /* Internal Methods */
860
+ close() {
861
+ this.m_connection.destroy();
862
+ }
863
+ read(data) {
864
+ if (data.length === 0) {
865
+ return;
866
+ }
867
+ this.m_message += data.toString();
868
+ if (this.m_state === types_1.ContextState.INIT) {
869
+ if (this.m_message.indexOf('\n\n') === -1) {
870
+ return;
871
+ }
872
+ this.readVariables(this.m_message);
873
+ }
874
+ else if (this.m_state === types_1.ContextState.WAITING) {
875
+ if (this.m_message.indexOf('\n') === -1) {
876
+ return;
877
+ }
878
+ this.readResponse(this.m_message);
879
+ }
880
+ this.m_message = '';
881
+ }
882
+ handleVariable(id, value) {
883
+ switch (id) {
884
+ case 'network':
885
+ this.m_network = value;
886
+ break;
887
+ case 'network_script':
888
+ this.m_network_script = value;
889
+ break;
890
+ case 'request':
891
+ this.m_request = value;
892
+ break;
893
+ case 'channel':
894
+ this.m_channel = value;
895
+ break;
896
+ case 'language':
897
+ this.m_language = value;
898
+ break;
899
+ case 'type':
900
+ this.m_type = value;
901
+ break;
902
+ case 'uniqueid':
903
+ this.m_uniqueid = value;
904
+ break;
905
+ case 'version':
906
+ this.m_version = value;
907
+ break;
908
+ case 'callerid':
909
+ this.m_callerid = value;
910
+ break;
911
+ case 'calleridname':
912
+ this.m_calleridname = value;
913
+ break;
914
+ case 'callingpres':
915
+ this.m_callingpres = value;
916
+ break;
917
+ case 'callingani2':
918
+ this.m_callingani2 = value;
919
+ break;
920
+ case 'callington':
921
+ this.m_callington = value;
922
+ break;
923
+ case 'callingtns':
924
+ this.m_callingtns = value;
925
+ break;
926
+ case 'dnid':
927
+ this.m_dnid = value;
928
+ break;
929
+ case 'rdnis':
930
+ this.m_rdnis = value;
931
+ break;
932
+ case 'context':
933
+ this.m_context = value;
934
+ break;
935
+ case 'extension':
936
+ this.m_extension = value;
937
+ break;
938
+ case 'priority':
939
+ this.m_priority = value;
940
+ break;
941
+ case 'enhanced':
942
+ this.m_enhanced = value;
943
+ break;
944
+ case 'accountcode':
945
+ this.m_accountcode = value;
946
+ break;
947
+ case 'threadid':
948
+ this.m_threadid = value;
949
+ break;
950
+ default:
951
+ }
952
+ }
953
+ readVariables(message) {
954
+ message.split('\n')
955
+ .forEach(line => {
956
+ const split = line.split(':');
957
+ const name = (split[0] || '').trim();
958
+ const value = (split[1] || '').trim();
959
+ const id = name.substring(4);
960
+ this.handleVariable(id, value);
961
+ });
962
+ this.m_state = types_1.ContextState.WAITING;
963
+ this.emit('ready');
964
+ }
965
+ readResponse(message) {
966
+ const lines = message.split('\n');
967
+ lines.map((line) => this.readResponseLine(line));
968
+ }
969
+ readResponseLine(line) {
970
+ if (!line) {
971
+ return;
972
+ }
973
+ this.emit('recv', line);
974
+ const parsed = line.split(' ');
975
+ if (!parsed || parsed[0] === 'HANGUP') {
976
+ return this.emit('hangup');
977
+ }
978
+ const code = parseInt(parsed[0], 10);
979
+ parsed.shift();
980
+ const args = new response_arguments_1.default();
981
+ for (const value of parsed) {
982
+ if (value.indexOf('=') !== -1) {
983
+ const parts = value.split('=', 2);
984
+ const key = parts[0].trim();
985
+ const val = parts[1].trim();
986
+ args.addArgument(key, val);
987
+ }
988
+ else if (value.indexOf('(') !== -1) {
989
+ const name = value.substring(1, value.length - 1);
990
+ args.addArgument(name, true);
991
+ }
992
+ else {
993
+ args.addArgument('value', value);
994
+ }
995
+ }
996
+ const response = {
997
+ code,
998
+ result: args.number('result'),
999
+ arguments: args
1000
+ };
1001
+ this.emit('response', response);
1002
+ }
1003
+ send(message) {
1004
+ return __awaiter(this, void 0, void 0, function* () {
1005
+ return new Promise((resolve, reject) => {
1006
+ this.emit('send', message);
1007
+ this.m_connection.write(message, (error) => {
1008
+ if (error) {
1009
+ return reject(error);
1010
+ }
1011
+ return resolve();
1012
+ });
1013
+ });
1014
+ });
1015
+ }
1016
+ sendCommand(command) {
1017
+ return __awaiter(this, void 0, void 0, function* () {
1018
+ return new Promise((resolve, reject) => {
1019
+ const handleResponse = (response) => {
1020
+ this.removeListener('response', handleResponse);
1021
+ return resolve(response);
1022
+ };
1023
+ this.once('response', handleResponse);
1024
+ this.send((0, util_1.format)('%s\n', command.trim()))
1025
+ .catch(error => {
1026
+ this.removeListener('response', handleResponse);
1027
+ return reject(error);
1028
+ });
1029
+ });
1030
+ });
1031
+ }
1032
+ }
1033
+ exports.default = Channel;