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