Test Failed
Push — master ( d4cdd3...569253 )
by Vyacheslav
03:17 queued 01:50
created

command.go (1 issue)

Severity
1
package goagi
2
3
import (
4
	"fmt"
5
	"regexp"
6
)
7
8
// Command sends command as string to the AGI and returns response valus with
9
// text response
10
func (agi *AGI) Command(cmd string) (code int, result int, respStr string, err error) {
11
	resp, err := agi.execute(cmd)
12
	if err != nil {
13
		return -1, -1, "", err
14
	}
15
	return resp.code, int(resp.result), resp.raw, nil
16
}
17
18
// Answer executes AGI command "ANSWER"
19
// Answers channel if not already in answer state.
20
func (agi *AGI) Answer() (bool, error) {
21
	resp, err := agi.execute("ANSWER")
22
	if err != nil {
23
		return false, err
24
	}
25
	return resp.isOk(), nil
26
}
27
28
// AsyncAGIBreak Interrupts Async AGI
29
//	Interrupts expected flow of Async AGI commands and returns control
30
// to previous source (typically, the PBX dialplan).
31
func (agi *AGI) AsyncAGIBreak() (bool, error) {
32
	resp, err := agi.execute("ASYNCAGI BREAK")
33
	if err != nil {
34
		return false, err
35
	}
36
	// Asterisk res_agi always returns 200 result=0
37
	// but for the future try to check response.
38
	return resp.isOk(), nil
39
}
40
41
// ChannelStatus returns status of the connected channel.
42
//
43
// If no channel name is given (empty line) then returns the status of the current channel.
44
//
45
//Return values:
46
//	0 - Channel is down and available.
47
//	1 - Channel is down, but reserved.
48
//	2 - Channel is off hook.
49
//	3 - Digits (or equivalent) have been dialed.
50
//	4 - Line is ringing.
51
//	5 - Remote end is ringing.
52
//	6 - Line is up.
53
//	7 - Line is busy.
54
func (agi *AGI) ChannelStatus(channel string) (int, error) {
55
	resp, err := agi.execute("CHANNEL STATUS " + channel)
56
	if err != nil {
57
		return -1, err
58
	}
59
	if resp.result == -1 {
60
		return -1, errorNew("No channel name matched the argument given.")
61
	}
62
	return int(resp.result), nil
63
}
64
65
// ControlStreamFile sends audio file on channel and allows the listener
66
// to control the stream.
67
//	Send the given file, allowing playback to be controlled by the given digits, if any.
68
// Use double quotes for the digits if you wish none to be permitted. If offsetms
69
// is provided then the audio will seek to offsetms before play starts.
70
//	Returns 0 if playback completes without a digit being pressed, or the ASCII numerical
71
// value of the digit if one was pressed, or -1 on error or if the channel was
72
// disconnected.
73
//	Returns the position where playback was terminated as endpos.
74
//	Example:
75
//	agi.ControlStreamFile("prompt_en", "19", "3000", "#", "0", "#", "1600")
76
//	agi.ControlStreamFile("prompt_en", "")
77
//	agi.ControlStreamFile("prompt_en", "19", "", "", "", "#", "1600")
78
func (agi *AGI) ControlStreamFile(filename, digits string, args ...interface{}) (int32, error) {
79
	cmd := "CONTROL STREAM FILE " + filename
80
	if len(digits) > 0 {
81
		cmd += " " + digits
82
	} else {
83
		cmd += " \"\""
84
	}
85
	resp, err := agi.execute(cmd, args...)
86
	if err != nil {
87
		return 0, err
88
	}
89
	if resp.result == -1 {
90
		return resp.result, errorNew("Error or channel disconnected.")
91
	}
92
93
	return resp.endpos, nil
94
}
95
96
// DatabaseDel deletes an entry in the Asterisk database for a given family and key.
97
//	Returns status and error if fails.
98
func (agi *AGI) DatabaseDel(family, key string) (bool, error) {
99
	resp, err := agi.execute("DATABASE DELETE", family, key)
100
	if err != nil {
101
		return false, err
102
	}
103
	ok := resp.code == 200 && resp.result == 1
104
	return ok, nil
105
}
106
107
// DatabaseDelTree deletes a family or specific keytree within a family in the Asterisk database.
108
func (agi *AGI) DatabaseDelTree(family, keytree string) (bool, error) {
109
	resp, err := agi.execute("DATABASE DELTREE", family, keytree)
110
	if err != nil {
111
		return false, err
112
	}
113
	ok := resp.code == 200 && resp.result == 1
114
	return ok, nil
115
}
116
117
// DatabaseGet Retrieves an entry in the Asterisk database for a given family and key.
118
//	Returns value as string or error if failed or value not set
119
func (agi *AGI) DatabaseGet(family, key string) (string, error) {
120
	resp, err := agi.execute("DATABASE GET", family, key)
121
	if err != nil {
122
		return "", err
123
	}
124
	if resp.result == 0 {
125
		return "", errorNew("Value not set.")
126
	}
127
	return resp.value, nil
128
}
129
130
// DatabasePut adds or updates an entry in the Asterisk database for
131
// a given family, key, and value.
132
func (agi *AGI) DatabasePut(family, key, val string) (bool, error) {
133
	resp, err := agi.execute("DATABASE PUT", family, key, val)
134
	if err != nil {
135
		return false, err
136
	}
137
	ok := resp.code == 200 && resp.result == 1
138
	return ok, nil
139
}
140
141
// Exec executes application with given options.
142
func (agi *AGI) Exec(app, opts string) (int, error) {
143
	opts = `"` + opts + `"`
144
	resp, err := agi.execute("EXEC", app, opts)
145
	if err != nil {
146
		return -1, err
147
	}
148
149
	if resp.result == -2 {
150
		return -2, errorNew("Could not find application " + app)
151
	}
152
	return int(resp.result), nil
153
}
154
155
// GetData Stream the given file, and receive DTMF data.
156
func (agi *AGI) GetData(file string, args ...interface{}) (digit string, timeout bool, err error) {
157
	cmd := "GET DATA " + file
158
	resp, err := agi.execute(cmd, args...)
159
	if err != nil {
160
		return "", false, err
161
	}
162
	re := regexp.MustCompile(`200 result=([\d*]+)`)
163
	result := re.FindStringSubmatch(resp.raw)
164
165
	if len(result) > 1 {
166
		return result[1], false, nil
167
	}
168
169
	if resp.result < 0 {
170
		return "", false, errorNew("Failed get data.")
171
	}
172
	timeout = resp.value == "timeout"
173
	digit = "" //string(resp.result)
174
	return
175
}
176
177
// GetFullVariable evaluates a channel expression
178
func (agi *AGI) GetFullVariable(name string, channel ...string) (string, error) {
179
	cmd := "GET FULL VARIABLE " + name
180
	var resp *agiResp
181
	var err error
182
	if len(channel) > 0 {
183
		resp, err = agi.execute(cmd, channel[0])
184
	} else {
185
		resp, err = agi.execute(cmd)
186
	}
187
	if err != nil {
188
		return "", err
189
	}
190
	if resp.result == 0 {
191
		return "", errorNew("Variable is not set.")
192
	}
193
194
	return resp.value, nil
195
}
196
197
// GetOption Stream file, prompt for DTMF, with timeout.
198
//	Behaves similar to STREAM FILE but used with a timeout option.
199
//	Returns digit pressed, offset and error
200
func (agi *AGI) GetOption(filename, digits string, timeout int32) (int, int32, error) {
201
	cmd := "GET OPTION " + filename
202
	resp, err := agi.execute(cmd, digits, timeout)
203
	if err != nil {
204
		return -1, 0, err
205
	}
206
207
	if resp.result == -1 {
208
		return -1, 0, errorNew("Command failure")
209
	}
210
211
	if resp.result == 0 && resp.endpos == 0 {
212
		return -1, 0, errorNew("Failure on open")
213
	}
214
215
	return int(resp.result), resp.endpos, nil
216
}
217
218
// GetVariable Gets a channel variable.
219
func (agi *AGI) GetVariable(name string) (string, error) {
220
	resp, err := agi.execute("GET VARIABLE", name)
221
	if err != nil {
222
		return "", err
223
	}
224
	if resp.result == 0 {
225
		return "", errorNew("Variable is not set.")
226
	}
227
228
	return resp.value, nil
229
}
230
231
// GetVariable Gets a channel variable.
0 ignored issues
show
comment on exported method AGI.GoSub should be of the form "GoSub ..."
Loading history...
232
func (agi *AGI) GoSub(ctx, ext, prio, args string) (bool, error) {
233
	resp, err := agi.execute("GOSUB", ctx, ext, prio, args)
234
	if err != nil {
235
		return false, err
236
	}
237
	if resp.result == -1 {
238
		return false, errorNew("Failed Gosub")
239
	}
240
	if resp.result == 0 && resp.code == 100 {
241
		chStr, chErr := agi.read()
242
		select {
243
		case str := <-chStr:
244
			resp, err = parseResponse(str)
245
			if err != nil {
246
				return false, err
247
			}
248
			return resp.code == 200, nil
249
		case err := <-chErr:
250
			return false, err
251
		}
252
	}
253
	return true, nil
254
}
255
256
// Hangup a channel.
257
//	Hangs up the specified channel. If no channel name is given, hangs up the current channel
258
func (agi *AGI) Hangup(channel ...string) (bool, error) {
259
	cmd := "HANGUP"
260
	if len(channel) > 0 {
261
		cmd += " " + channel[0]
262
	}
263
	resp, err := agi.execute(cmd)
264
	if err != nil {
265
		return false, err
266
	}
267
	if resp.result == -1 {
268
		return false, errorNew("Failed hangup")
269
	}
270
	return true, nil
271
}
272
273
// Noop Does nothing.
274
func (agi *AGI) Noop() error {
275
	_, err := agi.execute("NOOP")
276
	return err
277
}
278
279
// ReceiveChar Receives one character from channels supporting it.
280
//	Most channels do not support the reception of text. Returns the decimal value of
281
// the character if one is received, or 0 if the channel does not support text reception.
282
//	timeout - The maximum time to wait for input in milliseconds, or 0 for infinite. Most channels
283
//	Returns -1 only on error/hangup.
284
func (agi *AGI) ReceiveChar(timeout int32) (int, error) {
285
	resp, err := agi.execute("RECEIVE CHAR", timeout)
286
	if err != nil {
287
		return -1, err
288
	}
289
	if resp.result == -1 {
290
		return -1, errorNew("Channel error or hangup.")
291
	}
292
	if resp.result == 0 {
293
		return -1, errorNew("Channel does not support text reception.")
294
	}
295
	return int(resp.result), nil
296
}
297
298
// ReceiveText Receives text from channels supporting it.
299
//	timeout - The timeout to be the maximum time to wait for input in milliseconds, or 0 for infinite.
300
func (agi *AGI) ReceiveText(timeout int32) (string, error) {
301
	resp, err := agi.execute("RECEIVE TEXT", timeout)
302
	if err != nil {
303
		return "", err
304
	}
305
	if resp.result == -1 {
306
		return "", errorNew("Failure, hangup or timeout.")
307
	}
308
	return resp.value, nil
309
}
310
311
// RecordFile Record to a file until a given dtmf digit in the sequence is received.
312
// The format will specify what kind of file will be recorded. The timeout is the
313
// maximum record time in milliseconds, or -1 for no timeout.
314
//	offset samples is optional, and, if provided, will seek to the offset without
315
// exceeding the end of the file.
316
//	beep causes Asterisk to play a beep to the channel that is about to be recorded.
317
//	silence is the number of seconds of silence allowed before the function returns
318
// despite the lack of dtmf digits or reaching timeout.
319
//	silence is the number of seconds of silence that are permitted before the
320
// recording is terminated, regardless of the escape_digits or timeout arguments
321
func (agi *AGI) RecordFile(file, format, escDigits string,
322
	timeout, offset int, beep bool, silence int) error {
323
324
	cmd := "RECORD FILE"
325
	cmd = fmt.Sprintf("%s %s %s %s", cmd, file, format, escDigits)
326
	if beep {
327
		cmd = fmt.Sprintf("%s BEEP", cmd)
328
	}
329
	if silence > 0 {
330
		cmd = fmt.Sprintf("%s s=%d", cmd, silence)
331
	}
332
	resp, err := agi.execute(cmd)
333
	if err != nil {
334
		return err
335
	}
336
	if resp.result <= 0 {
337
		return errorNew("Failed record file")
338
	}
339
	return nil
340
}
341
342
func (agi *AGI) say(cmd string, args ...interface{}) error {
343
	resp, err := agi.execute("SAY "+cmd, args...)
344
	if err != nil {
345
		return err
346
	}
347
	if resp.result < 0 {
348
		return errorNew("Failure")
349
	}
350
	return nil
351
}
352
353
// SayAlpha says a given character string, returning early if any of the given
354
// DTMF digits are received on the channel.
355
func (agi *AGI) SayAlpha(number, escDigits string) error {
356
	return agi.say("ALPHA", number, escDigits)
357
}
358
359
// SayDate say a given date, returning early if any of the given DTMF digits
360
// are received on the channel
361
func (agi *AGI) SayDate(date, escDigits string) error {
362
	return agi.say("DATE", date, escDigits)
363
}
364
365
// SayDatetime say a given time, returning early if any of the given DTMF
366
// digits are received on the channel
367
func (agi *AGI) SayDatetime(time, escDigits, format, timezone string) error {
368
	return agi.say("DATETIME", time, escDigits, format, timezone)
369
}
370
371
// SayDigits say a given digit string, returning early if any of the given
372
// DTMF digits are received on the channel
373
func (agi *AGI) SayDigits(number, escDigits string) error {
374
	return agi.say("DIGITS", number, escDigits)
375
}
376
377
// SayNumber say a given digit string, returning early if any of the given
378
// DTMF digits are received on the channel
379
func (agi *AGI) SayNumber(number, escDigits string) error {
380
	return agi.say("NUMBER", number, escDigits)
381
}
382
383
// SayPhonetic say a given character string with phonetics, returning early
384
// if any of the given DTMF digits are received on the channel
385
func (agi *AGI) SayPhonetic(str, escDigits string) error {
386
	return agi.say("PHONETIC", str, escDigits)
387
}
388
389
// SayTime say a given time, returning early if any of the given DTMF digits
390
// are received on the channel
391
func (agi *AGI) SayTime(time, escDigits string) error {
392
	return agi.say("TIME", time, escDigits)
393
}
394
395
// SendImage Sends the given image on a channel. Most channels do not support
396
// the transmission of images.
397
func (agi *AGI) SendImage(image string) error {
398
	resp, err := agi.execute("SEND IMAGE", image)
399
	if err != nil {
400
		return err
401
	}
402
	if resp.result < 0 {
403
		return errorNew("Failure or hangup.")
404
	}
405
	return nil
406
}
407
408
// SendText Sends the given text on a channel. Most channels do not support
409
// the transmission of text.
410
func (agi *AGI) SendText(text string) error {
411
	text = fmt.Sprintf("\"%s\"", text)
412
	resp, err := agi.execute("SEND TEXT", text)
413
	if err != nil {
414
		return err
415
	}
416
	if resp.result < 0 {
417
		return errorNew("Failure or hangup.")
418
	}
419
	return nil
420
}
421
422
// SetAutoHangup Cause the channel to automatically hangup at time seconds in the future.
423
// Setting to 0 will cause the autohangup feature to be disabled on this channel.
424
func (agi *AGI) SetAutoHangup(seconds int) error {
425
	resp, err := agi.execute("SET AUTOHANGUP", seconds)
426
	if err != nil {
427
		return err
428
	}
429
	if resp.result != 0 {
430
		return errorNew("Failure or hangup.")
431
	}
432
	return nil
433
}
434
435
// SetCallerid Changes the callerid of the current channel.
436
func (agi *AGI) SetCallerid(clid string) error {
437
	resp, err := agi.execute("SET CALLERID", clid)
438
	if err != nil {
439
		return err
440
	}
441
	if resp.result != 1 {
442
		return errorNew("Failure or hangup.")
443
	}
444
	return nil
445
}
446
447
// SetContext Sets the context for continuation upon exiting the application.
448
func (agi *AGI) SetContext(ctx string) error {
449
	resp, err := agi.execute("SET CONTEXT", ctx)
450
	if err != nil {
451
		return err
452
	}
453
	if resp.result != 0 {
454
		return errorNew("Failure or hangup.")
455
	}
456
	return nil
457
}
458
459
// SetExtension Changes the extension for continuation upon exiting the application.
460
func (agi *AGI) SetExtension(ext string) error {
461
	resp, err := agi.execute("SET EXTENSION", ext)
462
	if err != nil {
463
		return err
464
	}
465
	if resp.result != 0 {
466
		return errorNew("Failure or hangup.")
467
	}
468
	return nil
469
}
470
471
// SetMusic Enables/Disables the music on hold generator. If class is not specified,
472
// then the default music on hold class will be used.
473
//	Parameters: opt is "on" or "off", and music class as string
474
func (agi *AGI) SetMusic(opt string, class ...string) error {
475
	if opt != "on" && opt != "off" {
476
		return errorNew("Invalid opt: '" + opt + "'. Must be 'on' or 'off'.")
477
	}
478
479
	if class != nil {
480
		opt = fmt.Sprintf("%s %s", opt, class[0])
481
	}
482
483
	resp, err := agi.execute("SET MUSIC", opt)
484
	if err != nil {
485
		return err
486
	}
487
	if resp.result != 0 {
488
		return errorNew("Failure or hangup.")
489
	}
490
	return nil
491
}
492
493
// SetPriority Changes the priority for continuation upon exiting the application.
494
// The priority must be a valid priority or label.
495
func (agi *AGI) SetPriority(priority string) error {
496
	resp, err := agi.execute("SET PRIORITY", priority)
497
	if err != nil {
498
		return err
499
	}
500
	if resp.result != 0 {
501
		return errorNew("Failure or hangup.")
502
	}
503
	return nil
504
}
505
506
// SetVariable Sets a variable to the current channel.
507
func (agi *AGI) SetVariable(name, value string) error {
508
	value = fmt.Sprintf("\"%s\"", value)
509
	resp, err := agi.execute("SET VARIABLE", name, value)
510
	if err != nil {
511
		return err
512
	}
513
	if resp.result != 1 {
514
		return errorNew("Failure or hangup.")
515
	}
516
	return nil
517
}
518
519
// StreamFile Send the given file, allowing playback to be interrupted by the given
520
// digits, if any.
521
func (agi *AGI) StreamFile(file, escDigits string, offset int) (int, error) {
522
	resp, err := agi.execute("STREAM FILE", file, escDigits, offset)
523
	if err != nil {
524
		return -1, err
525
	}
526
	if resp.result == -1 {
527
		return -1, errorNew("Failure or hangup.")
528
	}
529
	return int(resp.result), nil
530
}
531
532
// TDDMode Enable/Disable TDD transmission/reception on a channel.
533
//	Modes: on, off, mate, tdd
534
func (agi *AGI) TDDMode(mode string) error {
535
	resp, err := agi.execute("TDD MODE", mode)
536
	if err != nil {
537
		return err
538
	}
539
	if resp.result != 1 {
540
		return errorNew("Failure or hangup.")
541
	}
542
	return nil
543
}
544
545
// Verbose Sends message to the console via verbose message system.
546
// level is the verbose level (1-4)
547
func (agi *AGI) Verbose(msg string, level ...int) error {
548
	var err error
549
	msg = fmt.Sprintf("\"%s\"", msg)
550
	if level == nil {
551
		_, err = agi.execute("VERBOSE", msg)
552
		return err
553
	}
554
555
	lvl := level[0]
556
	if lvl < 1 && lvl > 4 {
557
		lvl = 1
558
	}
559
	_, err = agi.execute("VERBOSE", msg, lvl)
560
	return err
561
}
562
563
// WaitForDigit Waits up to timeout *milliseconds* for channel to receive a DTMF digit.
564
// Use -1 for the timeout value if you desire the call to block indefinitely.
565
//	Return digit pressed as string or error
566
func (agi *AGI) WaitForDigit(timeout int) (string, error) {
567
	resp, err := agi.execute("WAIT FOR DIGIT", timeout)
568
	if err != nil {
569
		return "", err
570
	}
571
	if resp.result == -1 {
572
		return "", errorNew("Failed run command")
573
	}
574
	if resp.result == 0 {
575
		return "", nil
576
	}
577
	return string(resp.result), nil
578
}
579