Basic Expressions
Asterisk 에서 모든 표현식(수식)은 $ [ ] 로 표시된다.
$[expression]
그리고 다음과 같이 사용할 수 있다.
$[${COUNT} + 1]$[${COUNT} / 2]
Asterisk Dialplan 내에서 표현식이 있다면 해당 구문은 먼저 모든 표현식이 계산된 이후에 진행된다.
다음의 예제를 생각해보자.
exten => 204,1,Noop() same => n,Answer() same => n,Set(COUNT=3) same => n,Set(NEWCOUNT=$[${COUNT} + 1]) same => n,SayNumber(${NEWCOUNT})
2번째 priority 에서 COUNT 변수에 3을 입력했다.
그리고 3번째 priority 에서 하나의 Set appilication 만이 사용됐는데, 사실은 3가지 일이 벌어졌다.
1. ${COUNT} 를 3으로 대치한다. 즉, 표현식은 다음과 같이 변경된다.
same => n,Set(NEWCOUNT=$[3 + 1])2. 표현식을 계산한다. 즉, 3과 1을 더한다. 결과값 4가 나온다.
same => n,Set(NEWCOUNT=4)3. Set() Application이 NEWCOUNT 에 4를 입력한다.
Operators
Boolean operators
expr1 | expr2
or 연산자. expr1 혹은 expr2 둘 중 하나라도 참이라면 참.
expr1 & expr2
and 연산자. expr1 혹은 expr2 둘 중 하나라도 거짓이면 거짓.
expr1 {=, >, >=, <, <=, !=} expr2비교 연산자. expr1, expr2 각 숫자라면 숫자 비교를 하고, 아니라면 문자열 비교를 한다.
Mathematical operators
expr1 {+, -} expr2
더하기, 빼기.
expr1 {*, /, %} expr2
곱하기, 나누기, 나머지.
Regular expression operators
expr1 : expr2
정규 표현식 내용 참조.
expr1 =~ expr2
정규 표현식 내용 참조.
String
exten => 234,1,Set(NEWTEST=blah${TEST})
Dialplan Functions
Dialplan Function 들은 많은 기능들을 가지고 있다. 문자열 길이 계산, 시간 및 날짜 계산, MD5 체크섬 오류 확인 등등의 기능을 제공한다.
Syntax
Dialplan Function 은 다음과 같은 기본 Syntax 구조를 가진다.
FUNCTION_NAME(argument)
그리고 다음과 같이 Function 자체가 다른 Function 의 Argument 로 사용되는 것도 가능하다.
${FUNCTION_NAME(${FUNCTION_NAME(argument)})}
Conditional Branching
Asterisk 에서 제공하는 함수들을 이용하면 여러가지 조건에 따라 분기를 생성할 수 있다. 이를 Conditional Branching 이라고 한다.
The GotoIf() Application
Conditional Branching 의 핵심은 GotoIf() Application 이다. GotoIf() Application 은 입력된 조건 식의 참/거짓 여부에 따라 해당 콜을 다른 곳으로 분배시키는 역할을 한다.
GotoIf(expression?destination1:destination2)
만약 expression 이 참이면 destination1로, 거짓이면 destination2 로 해당 콜을 넘겨준다. 그렇다면 무엇이 참이고 거짓일까? 표현식의 결과값이 공백 String 이거나 0이면 거짓이고 그 외의 것들은 모두 참으로 판별한다.
destination 은 다음중 한가지로 지정할 수 있다.
– weasels 와 같이 동일한 extension 내의 priority label- 123,wesels 와 같이 동일한 context 내의 다른 extension 과 priority label
– incoming,123,weasels 와 같이 다른 context, 다른 extension, 다른 priority label
입력되는 destination 중 하나는 생략이 가능하다. 즉, 하나의 destination 만 입력을 해도 괜찮다는 뜻이다. 하지만 이는 역으로 반드시 하나는 입력해야 된다는 뜻이다. 입력되지 않은 destination 의 경우, 그냥 다음 priority 구문을 진행한다.
exten => 207,1,NoOp() same => n,Set(TEST=1) same => n,GotoIf($[${TEST} = 1]?weasels:iguanas) same => n(weasels),Playback(weasels-eaten-phonesys) same => n,Hangup() same => n(iguanas),Playback(office-iguanas) same => n,Hangup()
기능은 정상적으로 작동하지만 뭔가 알아보기 힘들다. 다음과 같이 작성해보자.
exten => 208,1,NoOp() same => n,Answer() same => n,Set(TEST=1) same => n,GotoIf($[${TEST} = 1]?weasels,1:iguanas,1) ; now we're going to extension,priority exten => weasels,1,NoOp() same => n,Playback(weasels-eaten-phonesys) ; this is NOT a label. It is different extension same => n,Hangup() exten => iguanas,1,NoOp() same => n,Playback(office-iguanas) same => n,Hangup()
다음은 10부터 0까지 카운트 다운을 하는 Dialplan 이다.
exten => 209,1,NoOp() same => n,Answer() same => n,Set(COUNT=10) same => n(start),GotoIf($[${COUNT} > 0]?:goodbye) same => n,SayNumber(${COUNT}) same => n,Set(COUNT=$[${COUNT} - 1]) same => n,Goto(start) same => n(goodbye),Hangup()
Time-Based Conditional Branching with GotoIfTime()
GotoIf() Application 이 표현식에 따른 분기였다면, GotoIfTime() Application 은 system time 에 따른 분기라고 말할 수 있다.
GotoIfTime(times,days_of_week,days_of_month,months?label)
짧게 말해서, GotoIfTime() 은 지정된 시간에 콜을 지정된 label 로 보내는 Application 이라고 할 수 있다.
times:
시간대 범위. 하나 혹은 여러개를 지정할 수 있다. 24-hour 형식을 사용함. 예를 들어 09:00 AM 부터 05:00 PM 까지의 시간대를 지정한다면 09:00-17:00 으로 표시할 수 있다. 하루를 통째로 입력한다면 00:00-23:59 로 표시한다.days_of_week:
요일 범위. 하나 혹은 여러개를 지정할 수 있다. mon,tue,wed,thu,fri,sat,sun 으로만 표시가 가능하다. 월요일부터 금요일까지를 표시하고자 한다면 mon-fri 로 표시한다. 화요일과 목요일만 표시하고자 한다면 tue&thu 로 표시한다.days_of_month:
일 범위. 하나 혹은 여러개를 지정할 수 있다. 1 부터 31 까지 지정하고자 하는 날짜를 입력하면 된다. 7일부터 12일까지라면 7-12, 15일과 30일 이틀만 지정하고자 한다면 15&30 으로 표시한다.month:
달 범위. 하나 혹은 여러개를 지정할 수 있다. jan-apr 과 같이 지정 가능하며 jan&mar&jun 과 같은 지정도 가능하다. 물론 jan-apr&jun&oct-dec 와 같은 지정도 가능하다.모든 범위:
만약 모든 날짜(1년 내내와 같이..)를 지정하고자 한다면 해당 입력 부분에 * 표시를 입력하면 된다.label:
같은 extension 부분에 있는 priority. ex) time_has_passed
같은 context 에 있는 다른 extension, priority. ex) 123,time_has_passed
다른 context, extension, priority. ex) incoming,123,time_has_passed
예제를 보자. 매주 월요일부터 금요일까지 오전 9:00 부터 오후 05:59 사이에 오는 콜을 처리하는 Dialplan 이다.
exten => s,1,NoOp() same => n,GotoIfTime(09:00-17:59,mon-fri,*,*?open,s,1)
만약 발신자가 해당 시간에 전화를 하게 되면 open context 내의 s extension 의 첫번째 priority 구문을 실행한다.
아래 예제는 참고로 보길 바란다.
exten => 212,1,NoOp() same => n,GotoIfTime(09:00-17:59,mon-fri,*,*?open,s,1) ; If it's any hour of the day, on any day of the week, ; during the fourth day of the month, in the month of July, ; we're closed same => n,GotoIfTime(*,*,4,jul?closed,s,1) ; During business hours, send calls to the open context same => n,GotoIfTime(09:00-17:59,mon-fri,*,*?open,s,1) same => n,GotoIfTime(09:00-11:59,sat,*,*?open,s,1)
Macro
만약 여러개의 Dialplan 을 편집해야 한다면? 그 수가 굉장히 많다면? Macro 가 그 해답일 수 있다.
모든 Macro 는 macro- 구문으로 시작한다. 만약 voicemail 을 위한 Macro 를 생성한다면 다음처럼 생성하면 된다.
[macro-voicemail]
다음은 예제로 작성된 voicemail macro 이다.
[macro-voicemail] exten => s,1,NoOp() same => n,Dial(${JOHN},10) same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy:unavail) same => n(unavail),VoiceMail(101@default,u) same => n,Hangup() same => n(busy),VoiceMail(101@default,b) same => n,Hangup()
Calling Macros from the Dialplan
Dialplan 에서 Macro 를 사용하기 위해서는 Macro() application 이 필요하다. Macro() application 은 Macro 를 호출하고 인자값들을 넘겨주는 역할을 한다.
예를 들어 방금 생성한 voicemail macro 를 호출하기 위해서는 다음과 같이 작성하면 된다.
exten => 213,1,Macro(voicemail)
Macro() application 은 특수 변수들을 가지고 있다.
${MACRO_CONTEXT}
Macro 를 호출한 extension 의 context${MACRO_EXTEN}Macro 를 호출한 Extension
${MACRO_PRIORITY}
Macro 를 호출한 Priority${ARG n}
Macro 를 호출하면서 넘겨진 인자 값들. 첫번째 인자값은 ${ARG1}, 두번째 인자값은 ${ARG2} 와 같다.
자, 이제 조금전 생성한 voicemail macro 를 수정해보자. 조금전 생성한 voicemail macro 는 오직 101 extension 에 대해서만 voicemail 을 수행했었다.
이를 호출되는 extension 의 voicemail 로 수정해보자.
[macro-voicemail] exten => s,1,NoOp() same => n,Dial(${ARG1},20) same => n,Goto(s-${DIALSTATUS},1) exten => s-NOANSWER,1,VoiceMail(${MACRO_EXTEN}@default,u) same => n,Goto(incoming,s,1) exten => s-BUSY,1,VoiceMail(${MACRO_EXTEN}@default,b) same => n,Goto(incoming,s,1) exten => _s-.,1,NoOp() same => n,Goto(s-NOANSWER,1)
GoSub
GoSub() application 은 Macro() application 과 비슷하다. 하지만 Macro() 와는 달리 별도의 Naming rule 이 필요하지 않다. 하지만 GoSub 루틴임을 알리기 위해 prefix 를 붙이는 것이 관례적이다.
다음은 Subroutine 예제이다.
[subVoicemail] exten => start,1,NoOp() same => n,Dial(${ARG1},10) same => n,VoiceMail(${ARG2}@default,${IF($[DIALSTATUS} = BUSY]?b:u)}) same => n,Hangup() [LocalSets] exten => 217,1,GoSub(subVoicemail,start,1(${JOHN},${EXTEN})) exten => 218,1,GoSub(subVoicemail,start,1(${JANE},${EXTEN})) exten => 219,1,GoSub(subVoicemail,start,1(${JACK},${EXTEN}))