extensions.conf
aussieht. Das kann man
am besten an Beispielen veranschaulichen. Es wird vorausgesetzt, dass Sie
bereits mit der Dialplan-Programmierung vertraut sind.;
“
(Semikolon) abgeschlossen werden, da theoretisch auch mehrere Befehle in
einer Zeile stehen könnten (was jedoch unüblich ist).{ ...
}
“) verwendet. Die Angabe von Prioritäten
(1
, n
) ist nicht mehr
erforderlich. In der extensions.ael
hat man also
endlich nicht mehr den zweifelhaften Charme früher BASIC-Programme, in
denen man noch die Zeilennummern angeben musste, und man erspart sich
auch das überflüssige mehrfache Tippen der gleichen Extension für
mehrere Zeilen bzw. Befehle. Diese Stärke kommt vor allem bei längeren
Dialplänen zum Tragen, weshalb die kurzen Beispiele hier manchmal etwas
unfair gegen AEL sind.extensions.conf | extensions.ael |
---|---|
[interne-benutzer] exten => 21,1,Dial(SIP/anna) exten => 21,n,VoiceMail(anna) exten => 22,1,Dial(SIP/lisa) exten => 22,n,VoiceMail(lisa) exten => _3X,1,Dial(SIP/${EXTEN}) | context interne-benutzer { 21 => { Dial(SIP/anna); VoiceMail(anna); } 22 => { Dial(SIP/lisa); VoiceMail(lisa); } _3X => { Dial(SIP/${EXTEN}); } } |
context default { 23 => Playback(hello-world); } |
context default { 23 => { Playback(hello-world); } } |
jump
, siehe „Labels, goto und jump“) kann die kurze Schreibweise sinnvoll
sein.{
“
eines Blocks muss immer auf der gleichen Zeile stehen, nicht auf einer
eigenen!//
“
(zwei Schrägstriche) eingeleitet./* ...
*/
). Für mehrzeilige Kommentare leiten Sie bitte
jede Zeile separat mit „//
“ ein.extensions.conf | extensions.ael |
---|---|
; ein Kommentar exten => 10,1,Dial(SIP/anna) ; Dial | // ein Kommentar 10 => { Dial(SIP/anna); // Dial } |
extensions.conf | extensions.ael |
---|---|
[verkauf] exten => 2001,1,Dial(SIP/anna) exten => 2002,1,Dial(SIP/hans) [lager] exten => 3001,1,Dial(SIP/lisa) [tag] include => verkauf include => lager [nacht] exten => _.,1,VoiceMail(${EXTEN},u) [von-extern] include => tag|09:00-17:00|mon-fri|*|* include => tag|09:00-14:00|sat|*|* include => nacht | context verkauf { 2001 => { Dial(SIP/anna); } 2002 => { Dial(SIP/hans); } } context lager { 3001 => { Dial(SIP/lisa); } } context tag { includes { verkauf; lager; } } context nacht { _. => { VoiceMail(${EXTEN},u); } } context von-extern { includes { tag|09:00-17:00|mon-fri|*|*; tag|09:00-14:00|sat|*|*; nacht; } } |
s
“ am
Ende von „includes
“.globals
gesetzt werden.extensions.conf | extensions.ael |
---|---|
[globals]
KUCHEN=Marmorkuchen
KLINGELZEIT=60
| globals { KUCHEN=Marmorkuchen; KLINGELZEIT=60; } |
if()
, while()
, der (mittleren)
Abbruchbedingung in for()
sowie der rechten Seite von
Zuweisungen (assignments) so behandelt, als stünden
sie in einem $[...
]
-Ausdruck
(siehe Expression).context test {
123 => {
ergebnis=10/2;
NoOp(ergebnis ist ${ergebnis});
}
} |
Set()
(siehe Abschnitt C.149, „Set()
“) zu
verwenden:context test {
123 => {
Set(ergebnis=$[ 10 / 2 ]);
NoOp(ergebnis ist ${ergebnis});
}
} |
if()
, while()
usw. ist dieses Verhalten allerdings gut, da es die unübersichtlichen
Klammern $[ ...
]
einspart:extensions.conf | extensions.ael |
---|---|
exten => 50,1,Set(a=test)
exten => 50,n,ExecIf($["${a}" = "101"],SayDigits,123)
| 50 => {
Set(a=test);
if ("${a}" = "test") {
SayDigits(123);
}
} |
extensions.conf
-Programmierer ist man (zwangsweise)
daran gewöhnt, mit Goto()
, GotoIf()
,
Gosub()
und GosubIf()
zu
„Prioritäten“ oder Labels (Markern) zu springen.
(Eigentlich ist das aber nur eine Behelfslösung, weil es in der
extensions.conf
keine sauberen Kontrollstrukturen
für den Programmablauf gibt.):
“) am Zeilenende:extensions.conf | extensions.ael |
---|---|
[beispiel] ; zu einem Label in der ; gleichen Extension gehen: ; exten => 10,1(anfang),NoOp() exten => 10,n,Wait(1) exten => 10,n,SayNumber(1) exten => 10,n,NoOp(Endlosschleife) exten => 10,n,Goto(anfang) ; zu einem Label in einer ; anderen Extension im ; gleichen Kontext gehen: ; exten => 20,1,SayNumber(20) exten => 20,n,Goto(10,anfang) ; zu einem Label in einem ; anderen Kontext gehen: ; exten => 30,1,SayNumber(30) exten => 30,n,Goto(cntxt2,40,vierzig) [cntxt2] exten => 40,1(vierzig),NoOp() exten => 40,n,SayNumber(40) exten => 50,1,Goto(40,1) exten => 60,1,Goto(beispiel,10,1) | context beispiel { // zu einem Label in der // gleichen Extension gehen: // 10 => { anfang: Wait(1); SayNumber(10); NoOp(Endlosschleife); goto anfang; } // zu einem Label in einer // anderen Extension im // gleichen Kontext gehen: // 20 => { SayNumber(20); goto 10|anfang; } // zu einem Label in einem // anderen Kontext gehen: // 30 => { SayNumber(30); goto cntxt2|40|vierzig; } } context cntxt2 { 40 => { vierzig: SayNumber(40); } 50 => jump 40; 60 => jump 10@beispiel; } |
extensions.conf
auf die
Applikation Goto()
(siehe Abschnitt C.65, „Goto()
“) angewiesen ist, sollte man diese in AEL
nicht mehr verwenden (man kann es aber problemlos tun). Dafür gibt es
jetzt das neue Sprachkonstrukt goto
.Goto()
und
goto
zeigt, dass es hier keinen großen Erklärungsbedarf
gibt:.conf |
|
.ael |
|
goto
auch noch die Anweisung
jump
..conf |
|
.ael (schlecht!) |
|
.ael (gut) |
|
goto
-Sprünge zu
definieren, da es echte Kontrollstrukturen gibt.if
- als auch switch
-Blöcke. Das ist ein riesiger
Vorteil, denn es erleichtert die Lesbarkeit ganz entscheidend, und je
umfangreicher die Programmlogik wird, desto mehr kommt dieser Vorteil
zum Tragen. Vergleichen Sie selbst:if
extensions.conf | extensions.ael |
---|---|
exten => 90,1,Dial(SIP/anna) exten => 90,n,GotoIf($["${DIALSTATUS}" = "BUSY"]?b:n) exten => 90,10(b),Answer() exten => 90,11,Playback(hello-world) exten => 90,12,Voicemail(anna,b) exten => 90,13,Goto(ende) exten => 90,20(n),Dial(SIP/lisa) exten => 90,21,Playback(beeperr) exten => 90,22,Goto(ende) exten => 90,30(ende),NoOp(Fertig) | 90 => { Dial(SIP/anna); if ("${DIALSTATUS}" = "BUSY") { Answer(); Playback(hello-world) Voicemail(anna,b); } else { Dial(SIP/lisa); Playback(beeperr); } NoOp(Fertig); } |
GotoIf()
zu Recht als umständlich, mal
ganz zu schweigen davon, dass man bei einem Befehl wie
GotoIf($["${DIALSTATUS}" = "BUSY"]?b:n)
nicht auf den
ersten Blick sieht, ob all die Klammern richtig sind.{
“ eines Blocks auf der gleichen Zeile
stehen muss, nicht auf einer eigenen!switch
extensions.conf | extensions.ael |
---|---|
exten => 70,1,Dial(SIP/anna) exten => 70,n,Goto(70-${DIALSTATUS},10) exten => 70,n(ende),NoOp(Fertig) exten => 70-BUSY,10,NoOp(besetzt) exten => 70-BUSY,11,Goto(ende) exten => 70-NOANSWER,10,NoOp(hebt nicht ab) exten => 70-NOANSWER,11,Goto(ende) exten => _70-.,10,NoOp(was anderes) exten => _70-.,11,Goto(ende) | 70 => { Dial(SIP/anna); switch ("${DIALSTATUS}") { case "BUSY": NoOp(besetzt); break; case "NOANSWER": NoOp(hebt nicht ab); break; default: NoOp(was anderes); } NoOp(Fertig); } |
case
-Sprungpunkten im
switch
-Block in AEL immer an die
break
-Anweisungen! Ohne diese Begrenzung läuft die
Programmausführung einfach nach unten weiter, also zum nächsten
case
oder default
– eben zur nächsten
Zeile.switch
-Anweisung
in der traditionellen extensions.conf
eine mittlere
Katastrophe ist, braucht wohl nicht groß erwähnt zu werden.
Verschachtelte if
- oder switch
-Blöcke wären
vollkommen unübersichtlich und unwartbar.switch
-Blöcken nicht nur
case
-Vergleiche, sondern auch pattern
:extensions.conf | extensions.ael |
---|---|
exten => _70,1,NoOp(Gewaehlt: ${EXTEN}) exten => _70,n,Goto(70-${EXTEN},10) exten => 70-703,10,NoOp(703) exten => 70-703,11,Goto(ende) exten => 70-704,10,NoOp(704) exten => 70-704,11,Goto(ende) exten => _70-70[5-8],10,NoOp(70[5-8]); exten => _70-70[5-8],11,Goto(ende) exten => _70-.,10,NoOp(was anderes) exten => _70-.,11,Goto(ende) exten => 70,n(ende),NoOp(Fertig) | _70. => { NoOp(Gewaehlt: ${EXTEN}); switch (${EXTEN}) { case 703: NoOp(703); break; case 704: NoOp(704); break; pattern 70[5-8]: NoOp(70[5-8]); break; default: NoOp(was anderes); } NoOp(Fertig); } |
ifTime
GotoIfTime()
(siehe Abschnitt C.67, „GotoIfTime()
“) gibt, nämlich das Sprachkonstrukt
ifTime
.20 => { ifTime (08:00-18:00|mon-fri|*|*) { Dial(SIP/20); } else { Playback(ansage-geschlossen); Voicemail(20,s); } } |
GotoIfTime()
. ifTime
ist eigentlich
überflüssig, denn mit einem normalen if
und der Funktion
IFTIME()
(Abschnitt D.51, „IFTIME()
“) kann man das
Gleiche erreichen. Der Programmcode ist nur etwas länger:20 => { if (${IFTIME(08:00-18:00|mon-fri|*|*?1:0)}) { Dial(SIP/20); } else { Playback(ansage-geschlossen); Voicemail(20,s); } } |
random
random(){...}
ist ein Sprachkonstrukt, bei dem man in
Klammern einen ganzzahligen Prozentwert von 1 bis 99 angibt, der
bestimmt, mit welcher Wahrscheinlichkeit der Code-Block ausgeführt
wird.20 => { random (42) { NoOp(42 % Chance); } else { NoOp(58 % Chance); } } |
random
ist eigentlich
überflüssig, denn mit einem normalen if
und der Funktion
RAND()
(Abschnitt D.80, „RAND()
“) kann man das
Gleiche erreichen. Der Code ist nur etwas länger:20 => { if (${RAND(0,100)} < 42) { NoOp(42 % Chance); } else { NoOp(58 % Chance); } } |
for
-
und while
-Schleifen, wie
sie aus anderen Programmiersprachen bekannt sind.while
while
-Block in AEL entspricht in etwa der
Verwendung von While()
(Abschnitt C.195, „While()
“) und EndWhile()
(Abschnitt C.47, „EndWhile()
“).break
und continue
lassen sich in Schleifen nutzen.
break
springt zum Ende des Schleifenblocks,
continue
zum Anfang. Das ist also die Entsprechung zu
ExitWhile()
(Abschnitt C.53, „ExitWhile()
“)
bzw. ContinueWhile()
(Abschnitt C.24, „ContinueWhile()
“).extensions.conf | extensions.ael |
---|---|
exten => 30,1,Set(x=0) exten => 30,n,While($[${x} <= 9]) exten => 30,n,NoOp(x ist ${x}) exten => 30,n,ExecIf($[${x} > 5],ExitWhile) exten => 30,n,Playback(beep) exten => 30,n,Set(x=$[${x} + 1]) exten => 30,n,EndWhile() exten => 30,n,NoOp(Fertig) | 30 => { x=0; while (${x} <= 9) { NoOp(x ist ${x}); if (${x} > 5) { break; } Playback(beep); x=${x} + 1; } NoOp(Fertig); } |
if
-Block vor dem
break
noch einen zweiten Befehl wie NoOp()
auszuführen. Dann nämlich reicht im .conf
-Format
nicht mehr ein ExecIf()
, sondern man braucht ein
kompliziertes mehrzeiliges Konstrukt mit GotoIf()
.for
while
gibt es in AEL auch
for
-Schleifen. Diese habe keine Entsprechung im
.conf
-Format. (Allerdings lässt sich jede
for
-Schleife als while
-Schleife
schreiben.)extensions.conf | extensions.ael |
---|---|
exten => 40,1,Set(x=0) exten => 40,n,While($[${x} <= 5]) exten => 40,n,NoOp(x ist ${x}) exten => 40,n,Playback(beep) exten => 40,n,Set(x=$[${x} + 1]) exten => 40,n,EndWhile() exten => 40,n,NoOp(Fertig) | 40 => { for (x=0; ${x}<=5; x=${x}+1) { NoOp(x ist ${x}); Playback(beep); } NoOp(Fertig); } |
Macro()
(Abschnitt C.81, „Macro()
“) oder Gosub()
(Abschnitt C.63, „Gosub()
“) verwenden soll, denn Makros gibt es in
AEL als Sprachkonstrukt macro
.extensions.conf | extensions.ael |
---|---|
[macro-countdown] exten => s,1,Set(c=${ARG1}) exten => s,n,While($[ ${c} > 0]) exten => s,n,SayNumber(${c}) exten => s,n,Set(c=$[ ${c} - 1 ]) exten => s,n,EndWhile() [default] exten => 123,1,Macro(countdown,3) exten => 124,1,Macro(countdown,5) | macro countdown( count ) { for (c=${count}; ${c}>0; c=${c}-1) { SayNumber(${c}); } } context default { 123 => { &countdown(3); } 124 => &countdown(5); } |
macro
automatisch
eine Gosub()
-Subroutine, was uns aber glücklicherweise
nicht interessieren muss.extensions.conf | extensions.ael |
---|---|
[interne-benutzer] exten => 21,hint,SIP/anna exten => 21,1,Dial(SIP/anna) exten => 22,hint,SIP/lisa exten => 22,1,Dial(SIP/lisa) | context interne-benutzer { hint(SIP/anna) 21 => { Dial(SIP/anna); } hint(SIP/lisa) 22 => { Dial(SIP/lisa); } } |
extensions.conf | extensions.ael |
---|---|
[interne-benutzer] exten => 21,hint,SIP/21 exten => 22,hint,SIP/22 exten => _2X,1,Dial(SIP/${EXTEN}) | context interne-benutzer { hint(SIP/21) 21 => {} hint(SIP/22) 22 => {} _2X => { Dial(SIP/${EXTEN}); } } |
extensions.conf | extensions.ael |
---|---|
exten => 10/55555,1,NoOp(Ex-Freundin) exten => 10/55555,n,Busy() exten => 10,1,Dial(SIP/karl) exten => 10,n,Voicemail(karl) | 10/55555 => {
NoOp(Ex-Freundin);
Busy();
}
10 => {
Dial(SIP/karl);
Voicemail(karl);
} |
55555
anruft, würde sie auf Busy()
geleitet, alle anderen Anrufer jedoch nicht./_0123.
könnte man also direkt einen ganzen Vorwahl-Bereich matchen.