Kapitel 4. Programmieren im Dialplan

Die Erstellung von intelligenten Funktionen oder Programmen kann in Asterisk extern über ein AGI-Skript (vergleichbar mit CGI-Skripten bei Webservern) oder intern im Dialplan erfolgen. In diesem Kapitel beschäftigen wir uns mit der internen Variante. AGI-Skripte werden in einem extra Kapitel besprochen.

In der Konfigurationsdatei extensions.conf wird der so genannte Dialplan definiert. Dabei ähnelt der Dialplan häufig einem BASIC-Programm. Der Admin kann in einer einfachen Skriptsprache Programmabläufe und damit auch das Routing von Telefonaten erstellen.

1. Kleines Programmierer Howto

Die Schwierigkeit eines solchen Buches liegt unter anderem im breit gestreuten Grundwissen der Leser. Ein Buch über Asterisk wird von Admins, Programmierern, Telefonanlagentechnikern und vielen anderen technisch interessierten Menschen gelesen. Die praktischen Programmierkenntnisse sind dabei sehr unterschiedlich ausgeprägt. Um die Fähigkeiten von Asterisk auszureizen benötigt man schon einfache Programmierkenntnisse und ein gesundes Basiswissen. In diesem Howto möchte ich die wichtigsten Grundprinzipien und Ideen für Programmierer erläutern. Dabei gehe ich beispielhaft vor und verweise bei Detailfragen auf Anhang B, Applikationen im Dialplan. Einige Themen werden sie hier sicher aus anderen Kapiteln wiedererkennen. Dieses kleine Howto soll ihnen einen sehr schnellen Überblick zu dem Thema bieten.

Programmstruktur

Im Dialplan (also der /etc/asterisk/extensions.conf) gibt es für jede zur Verfügung gestellte Zielrufnummer ein kleines Programm. Dieses Programm heißt bei Asterisk Extension. Eine Extension sieht dabei wie folgt aus:

exten => 1001,1,Answer()
exten => 1001,n,Playback(hello-world)
exten => 1001,n,Hangup()

Häufig sieht man die Prioritäten auch nicht mit n sondern mit Zahlen benannt.

exten => 1001,1,Answer()
exten => 1001,2,Playback(hello-world)
exten => 1001,3,Hangup()

Die Funktionsweise der jeweiligen Extensions ist identisch. Wer mit n programmiert, kann später aber leichter einzelne Zeilen löschen oder hinzufügen.

Variablen

Zum Generieren und Verändern von Variablen wird die Applikation Set() benutzt:

exten => 1002,1,Set(Lieblingstier = "Tiger")
exten => 1002,n,Set(Lieblingszahl = 23)

Zum Lesen und Ausgeben von Variablen wird die Syntax ${VARIABLENNAME} benutzt. Mit der Applikation NoOp() kann man Variablenwerte auf dem CLI ausgeben (ab Verbose-Level 3):

exten => 1003,1,NoOp(${Lieblingstier})
exten => 1003,n,NoOp(${Lieblingszahl})

Es gibt verschiedene Arten von Variablen:

  • Globale Variablen

    Gelten im gesamten Dialplan und werden mit Set(X=23,g) generiert und verändert.

    exten => 1004,1,Set(SOLL-UEBERALL-LESBAR-SEIN = 23,g)
    exten => 1004,n,NoOp(${SOLL-UEBERALL-LESBAR-SEIN})
  • Channel Variablen

    Gelten nur im aktiven Channel (ein Channel kann z.B. ein Gespräch von Peter und Uwe sein). Sie werden mit Set(Y=42) generiert und verändert.

    exten => 1005,1,Set(SOLL-NUR-HIER-LESBAR-SEIN = 42)
    exten => 1005,n,NoOp(${SOLL-NUR-HIER-LESBAR-SEIN})
  • System Variablen

    Diese sind quasi "Gott gegeben" (ok, natürlich eher "Asterisk gegeben" ;-)) und können einfach im Dialplan aufgerufen werden. Eine typische Systemvariable ist ${EXTEN}.

    exten => 1006,1,NoOp(Gewaehlte Nummer: ${EXTEN})

Siehe auch:  Abschnitt 2, „Variablen“

Labels und Goto()

Mit Goto() kann man innerhalb des Dialplanes Sprünge zu einem mit (Labelname) definierten Label vollziehen:[24]

  • Innerhalb einer Extension:

    exten => 1007,1,Answer()
    exten => 1007,n(Anfang),Wait(1)
    exten => 1007,n,Playback(hello-world)
    exten => 1007,n,Goto(Anfang)
  • Von Extension zu Extension:

    exten => 1008,1,Answer()
    exten => 1008,n,Goto(1009,Ping)
    
    exten => 1009,1(Ping),Playback(hello-world)
    exten => 1009,n,Wait(2)
    exten => 1009,n,Goto(1010,Pong)
    
    exten => 1010,1(Pong),Playback(weasels-eaten-phonesys)
    exten => 1010,n,Wait(2)
    exten => 1010,n,Goto(1009,Ping)
  • Von Context zu Context:

    [zentrale]
    exten => 1011,1,Answer()
    exten => 1011,n,Playback(hello-world)
    exten => 1011,n,Goto(verkauf,1012,1)
    
    [verkauf]
    exten => 1012,1,Playback(hello-world)
    exten => 1012,n,Hangup()

Siehe auch:  Abschnitt 49, „Goto()

While() Schleifen

Mit While() lassen sich Schleifen im Dialplan erzeugen:

exten => 1013,1,Answer()
exten => 1013,n,Set(i=1)
exten => 1013,n,While($[${i} < 10])
exten => 1013,n,SayNumber(${i})
exten => 1013,n,Wait(1)
exten => 1013,n,Set(i=$[${i} + 1])
exten => 1013,n,EndWhile()
exten => 1013,n,Hangup()

Siehe auch:  Abschnitt 139, „While()

GotoIf() Bedingung

Mit GotoIf() lassen sich Sprünge zu anderen Teilen im Dialplan mit einer Bedingung verbinden:

exten => 1014,1,Answer()
exten => 1014,n,Set(Lieblingsnebenstelle = 0815)
exten => 1014,n,NoOp(Ueberpruefe, ob Anruf von ${Lieblingsnebenstelle} kommt.)
exten => 1014,n,GotoIf($[${CALLERID(num) = ${Lieblingsnebenstelle}]?ja,nein)

exten => 1014,n(ja),Playback(hello-world)
exten => 1014,n,Hangup()

exten => 1014,n(nein),Playback(tt-monkeys)
exten => 1014,n,Hangup()

Siehe auch:  Abschnitt 50, „GotoIf()

Gosub() Unterprogramme

Mit Gosub() kann man in ein Unterprogramm springen und aus diesem mit Return() wieder zurück:

exten => 1015,1,Gosub(cid-setzen)
exten => 1015,n,Dial(SIP/${EXTEN})

exten => 1015,n(cid-setzen),Set(CALLERID(all)=Apfelmus GmbH <012345678>)
exten => 1015,n,Return()

Siehe auch: Abschnitt 47, „Gosub(), Abschnitt 48, „GosubIf(), Abschnitt 99, „Return(), Abschnitt 58, „Macro()

2. Variablen

Variablen sind Platzhalter für konkrete Werte. Diese konkreten Werte sind abhängig von der Definition der Variablen, also dem Typ, und können bei Asterisk Zahlen, Buchstaben und Buchstabenfolgen sein. Variablen dienen dazu, das kompilierte Programm flexibler zu gestalten und für unterschiedliche oder wechselnde Einsatzzwecke anzupassen. Die Verwendung von Variablen ermöglicht erst den individuellen Einsatz eines Programms, ohne die erneute Übersetzung des Programmcodes in ein ausführbares Programm.

[Tipp]Tipp

Wer noch nie programmiert hat oder mit Variablen in Berührung gekommen ist, sollte sich an dieser Stelle kurz bei http://de.wikipedia.org/wiki/Variable_%28Programmierung%29 in die Materie einlesen.

Variablen haben bei Asterisk unterschiedliche Reichweiten. Es gibt lokale (im Asterisk-Jargon Channel-Variablen genannt) Variablen, die Werte nur für den jeweiligen und aktiven Channel (also das aktuelle Gespräch) setzen, und globale Variablen, die Werte für alle Channels setzen. Die bereits von Asterisk vorgesehenen Variablen haben wir ja in Form der Parameter in den Konfigurationsdateien schon ausführlich kennen gelernt. Neben diesen gibt es auch die Möglichkeit, eigene Variablen zu definieren und diese in den Konfigurationsdateien zu verwenden.

Variablen in einer Extension auslesen

Der Wert einer Variable kann immer in der Syntax ${VARIABLENNAME} ausgelesen werden. Es gibt Variablen, die vom Asterisk-System automatisch gesetzt werden. So wird z.B. die angerufene Nummer immer in der Variable EXTEN abgespeichert. Durch Regular Expressions und den Einsatz von Variablen kann man somit einen langen Dialplan häufig stark komprimieren.

Beispiel vorher:

exten => 100,1,Dial(SIP/100)
exten => 101,1,Dial(SIP/101)
exten => 102,1,Dial(SIP/102)
exten => 103,1,Dial(SIP/103)
exten => 104,1,Dial(SIP/104)
exten => 105,1,Dial(SIP/105)
exten => 106,1,Dial(SIP/106)
exten => 107,1,Dial(SIP/107)
exten => 108,1,Dial(SIP/108)
exten => 109,1,Dial(SIP/109)

Beispiel nachher:

exten => _10X,1,Dial(SIP/${EXTEN})

Allgemeines

Variablennamen müssen nicht wie in unseren Beispielen großgeschrieben werden und sind auch nicht an Groß- und Kleinschreibung gebunden. Die Großschreibung von Variablen führt aber meistens zu besser lesbarem Code, da Sie bereits an der Schreibweise erkennen können, dass es sich um eine Variable handelt. Umgekehrt bedeutet das aber auch, dass Groß- und Kleinschreibung nicht für die Unterscheidung von Variablen verwendet werden kann.

[Wichtig]Wichtig

Die von Asterisk selbst generierten Variablen wie ${EXTEN} müssen immer in Großbuchstaben geschrieben werden.

Strings

Strings (als Variablen, die keine Zahlen, sondern Text enthalten) sollten immer in Anführungszeichen gesetzt werden. Asterisk akzeptiert sie aber auch ohne diese Markierung. So sind die folgenden zwei Zeilen im Ergebnis gleich:

exten => 1234,1,Set(OBST=Apfel)
exten => 1234,2,Set(OBST="Apfel")

Sollte der String ein Komma oder ein Leerzeichen enthalten, dann müssen Sie Anführungszeichen verwenden, da diese sonst als Kommandos und nicht als Strings interpretiert werden:

exten => 1234,1,Set(OBSTSORTEN="Apfel, Birne, usw.")

Quoting

Bei einer Variablen, die Zeichen oder Zeichenfolgen (Wörter, Text) als Werte enthält, kann es vorkommen, dass man bestimmte Zeichen verwenden möchte, die bereits für andere Funktionen reserviert sind. Wollen Sie zum Beispiel ein Underscore-Zeichen als Bestandteil des Variablenwertes verwenden, müssen Sie es besonders kennzeichnen, bzw. maskieren. Diese Kennzeichnung nennt man beim Programmieren escapen. Folgende Zeichen müssen auf jeden Fall maskiert („escaped“) werden:

[ ] $ " \

Das Quoting in der extensions.conf erfolgt mit einem vorangestellten \ (Backslash).

Beispiel:

exten => 1234,1,Set(BETRAG="10,00 US \$")

Integer

Bestehen Variablen aus einer Ganzzahl (Integer), so kann diese maximal 18 Stellen betragen. Bei Zahlen, die größer sind, tritt ein Fehler auf, der im Logfile protokolliert wird.

[Tipp]Tipp

Wer mit größeren oder Kommazahlen (Real) arbeiten will, kann dies mit einem AGI-Skript realisieren (siehe Abschnitt 1, „TBD“).

Globale Variablen in der extensions.conf definieren

Eine globale Variable kann am Anfang der extensions.conf gesetzt werden. Dies muss im besonderen Context [globals] erfolgen (er folgt dem Context [general]).

Beispiel:

[general]

[globals]
KLINGELZEIT=90

[from-intern]
exten => _XXX,1,Dial(SIP/${EXTEN},${KLINGELZEIT})
exten => _XXX,n,VoiceMail(${EXTEN})

Variablen mit Set() definieren

Die Applikation Set() wird benutzt, um eine Variable in einer Extension zu setzen.[25]

Syntax

Set(Variablenname=Wert[,Variablenname2=Wert2][,Option])

Als Option kann ein g angegeben werden. Mit diesem g kann mit Set() eine globale Variable gesetzt werden. Ohne diese Option geht Asterisk immer von lokalen Channel-Variablen aus.

Beispiel:

; Eine globale Variable setzen:
exten => 10,1,Set(KLINGELZEIT=90,g)

; Eine Channel-Variable setzen:
exten => 10,2,Set(LIEBLINGSOBSTSORTE="Apfel")

; Zwei Channel-Variablen auf einmal setzen:
exten => 10,3,Set(VAR1=10,VAR2=23)

; Die Variablen auf dem CLI ausgeben
exten => 10,4,NoOp(KLINGELZEIT = ${KLINGELZEIT})
exten => 10,5,NoOp(LIEBLINGSOBSTSORTE = ${LIEBLINGSOBSTSORTE})
exten => 10,6,NoOp(VAR1 = ${VAR1})
exten => 10,7,NoOp(VAR2 = ${VAR2})

Vererbung von Channel-Variablen

Wird im Lauf eines Gespräches ein weiterer Channel aufgebaut, so hat dieser natürlich wieder eigene Channel-Variablen.

Einstufige Vererbung

Will man eine Channel-Variable übergeben, aber keine globale Variable dafür benutzen, so kann man der Channel-Variable ein _ (Underscore) voransetzen. Diese Channel-Variable wird dann an den nächsten Channel vererbt. Dabei wird der Underscore entfernt. Die Vererbung kann also nur einmal erfolgen.

Beispiel:

exten => 1234,1,Set(_KUCHENSORTE="Marmorkuchen")

Mehrstufige Vererbung

Will man eine Channel-Variable beliebig oft vererben, so muss man zwei __ (Underscore)-Zeichen vor die Variable setzen. Die zwei Underscore-Zeichen werden dann immer mitvererbt.

[Warnung]Warnung

Asterisk unterscheidet die Namen von Variablen, die mit einem Underscore anfangen, nicht von Variablen, die keinen Underscore haben. So wird im folgenden Beispiel aus der vererbbaren Channel-Variable KUCHENSORTE eine normale (nicht vererbbare) Channel-Variable:

exten => 1234,1,Set(__KUCHENSORTE="Marmorkuchen")
exten => 1234,n,Set(KUCHENSORTE="Marmorkuchen")

Beispiel:

exten => 1234,1,Set(__KUCHENSORTE="Nusskuchen")

Bei einem Abruf einer vererbten Channel-Variable ist es egal, ob man die Unterstriche voranstellt oder nicht. Die beiden folgenden Zeilen geben zweimal den gleichen Wert im CLI aus:

exten => 1234,1,NoOp(${__KUCHENSORTE})
exten => 1234,n,NoOp(${KUCHENSORTE})

Feste Channel-Variablen

Die folgende Liste enthält die wichtigsten fest einprogrammierten Channel-Variablen, die nicht in der extensions.conf überschrieben, aber ausgelesen werden können.

[Warnung]Warnung

Eine komplette Liste aller vordefinierten Variablen finden Sie in der Datei doc/README.variables (Asterisk 1.2) und doc/channelvariables.txt (Asterisk 1.4). In dieser Liste werden nur nicht DEPRECATED Variablen aufgelistet. So finden Sie z.B. ein ${CALLERIDNUM} nicht in dieser Liste, weil dies deprecated ist (man soll anstatt die Funktion ${CALLERID(num)} benutzen).

Die für das jeweilige Thema relevanten Variablen werden aber im Buch immer in jedem Kapitel extra aufgeführt.[26]

[Anmerkung]Anmerkung

Bei einigen der hier aufgeführten Variablen handelt es sich gar nicht um Variablen, sondern um eingebaute Funktionen. Da dies in der Praxis aber oft verschwimmt, werden sie hier trotzdem aufgelistet.

${ANSWEREDTIME}

Die Gesamtzeit (in Sekunden) seitdem das Gespräch zustande gekommen ist.

${BLINDTRANSFER}

Der Name des Channels auf der anderen Seite eines Blind-Transfers.

${CHANNEL}

Name des aktuellen Channels

${CONTEXT}

Name des aktuellen Contextes

${EPOCH}

Aktueller Unix Style Epoch.

${EXTEN}

Aktuell gewählte Extension

${ENV(VARIABLENNAME)}

Umgebungsvariable VARIABLENNAME

${HANGUPCAUSE}

Grund für das Beenden (hangup) eines Gespräches

${INVALID_EXTEN}

Wird in der i-Extension benutzt und enthält die gewählte Extension.

${PRIORITY}

Aktuelle Priorität innerhalb der Extension

${TRANSFER_CONTEXT}

Context eines weiterverbundenen Gespräches

${UNIQUEID}

Im System einzigartige (unique) ID für das aktuelle Gespräch

${SYSTEMNAME}

In der /etc/asterisk/asterisk.conf Datei eingetragener systemname Parameter.

Variablenmanipulation

Variablen an sich eröffnen ihren Nutzen erst dann, wenn man sie zur Laufzeit verändern kann. Mit Hilfe dieser Variabilität lassen sich komplexe Verhaltensweisen steuern und vorsehen.

Substring

In der Regel bezeichnen Strings eine Aneinanderreihung einzelner Zeichen (character). Die Größe eines Strings bestimmt sich durch die Anzahl der identifizierbaren einzelnen Zeichen. Zum Beispiel besteht der String „Apfelbaum“ aus 9 Zeichen. Ein String kann grundsätzlich in so genannte Teilstrings zerlegt werden, also Strings, die, wenn man sie wieder aneinanderreiht, den ursprünglichen String ergeben. Im genannten Beispiel könnten wir den String „Apfelbaum“ in die Teilstrings „Apfel“ und „baum“ zerlegen, aber auch „Apf“ und „elbaum“ sind echte Teilstrings. Ein String hat theoretisch keine begrenzte Größe, er kann beliebig viele Zeichen enthalten, der gesamte Text dieses Buches könnte so als ein String aufgefasst werden. Natürlich wäre das dann nicht mehr sehr handlich, dennoch ist der Vorgang des Zerlegens eines Strings in Teilstrings eine Standardprozedur beim Programmieren von Anwendungen. In vielen Programmiersprachen heißt die hier beschriebene Funktionalität Substring. Mit einer Substring-Funktion kann man Teile eines Strings ausschneiden und das Ergebnis in einer anderen Variablen abspeichern. In Asterisk gibt es keine eigenständige Routine für diese Substring-Funktion, sondern hierfür wird ein : (Doppelpunkt) nach dem Variablennamen eingesetzt. Vom Inhalt der Variablen, also dem String, wird dann eine vorgegebene Anzahl von Zeichen (Länge) als Teilstring abgetrennt.

Syntax

${VARIABLENNAME[:Anfang[:Laenge]]}

Beispiele

Bei einer Telefonanlage wird traditionell eine führende 0 (Null) gewählt, um eine Amtsleitung zu bekommen. Die zu wählende Telefonnummer darf diese 0 aber nicht enthalten. Wird die Nummer 0030 227 32320 gewählt, so kann man mit folgender Zeile die eigentliche Rufnummer in die Variable ${RUFNUMMER} abspeichern.[27]

exten => _0X.,1,Set(RUFNUMMER=${EXTEN:1})

Wenn die Angabe der Länge fehlt, wird automatisch der Rest des Strings genommen.

Wenn wir die letzten 5 Ziffern der gewählten Nummer benötigen, dann erreichen wir das mit einer negativen Zahl. Bei der oben gewählten Nummer würde die folgende Zeile den Wert 32320 in der Variablen ${DURCHWAHL} abspeichern.

exten => _0X.,1,Set(DURCHWAHL=${EXTEN:-5})

Möchten wir die Vorwahl in einer separaten Variable abspeichern, so erreichen wir dies durch:

exten => _0X.,1,Set(VORWAHL=${EXTEN:1:3})

Diese Zeile geht davon aus, dass die Vorwahl 3-stellig ist und speichert sie in der Variable ${VORWAHL}.[28]

Nehmen wir an, wir möchten bei Telefonaten zur Nummer 00012024562121 nach Amerika die einzelnen Bestandteile herausfiltern:[29]

exten => _0001X.,1,Set(INTERNATIONALEVORWAHL=${EXTEN:3:1})
exten => _0001X.,n,Set(ORTSVORWAHL=${EXTEN:4:3})
exten => _0001X.,n,Set(RUFNUMMER=${EXTEN:7})
exten => _0001X.,n,Set(DURCHWAHL=${EXTEN:-4}

3. Besondere Extensions

Da sämtliche Programmierlogik über Extensions programmiert werden muss, benötigen wir noch eine Reihe von besonderen und vom System vorbelegte Extensions.

Die h-Extension

Das h steht bei dieser Standard-Extension für Hangup (Auflegen). Sie wird aufgerufen, sobald ein Gespräch beendet wurde. Dabei muss berücksichtig werden, dass dann logischerweise der Wert der Variable ${EXTEN} nicht mehr die ursprüngliche Extension, sondern den Wert h enthält.

Beispiel

Sollen in der globalen Variable GESPRAECHE immer die Anzahl der aktuell geführten Gespräche gespeichert werden, so muss diese beim Aufbau eines Gesprächs um 1 erhöht und beim Abbau eines Gesprächs (also beim Auflegen) wieder um 1 vermindert werden. Der folgende Dialplan zeigt die Grundidee:

[global]
GESPRAECHE=0

[from-intern]
exten => _X.,1,Set(GESPRAECHE=$[${GESPRAECHE} + 1]|g)
exten => _X.,2,Dial(SIP/${EXTEN})

exten => h,1,Set(GESPRAECHE=$[${GESPRAECHE} - 1]|g)

Die i-Extension

Um einen Context "wasserdicht" zu machen, wird die i-Extension benutzt. Das i steht dabei für invalid (ungültig) und behandelt alle im entsprechenden Context nicht definierten Zielrufnummern. Auch hier wird in der Variable EXTEN natürlich nicht mehr die angewählte Nummer abgebildet, diese ist mit der Variable INVALID_EXTEN abrufbar.

Beispiel

In der Apfelmus GmbH können aus der Abteilung B nur die Rufnummern 100 bis 199 angerufen werden. Alle anderen Gespräche führen zur Ansage des Bausteines that-is-not-rec-phn-num.[30]

[abteilung-b]
exten => _1XX,1,Dial(${EXTEN})

exten => i,1,NoOp(Undefinierte Nummer ${INVALID_EXTEN} wurde gewaehlt.)
exten => i,2,Answer()
exten => i,3,Playback(that-is-not-rec-phn-num)
exten => i,4,Hangup()

Die o- und a-Extension

Wurde in der Konfigurationsdatei voicemail.conf der Eintrag operator=yes gesetzt, so kann innerhalb der Voicemailbox durch Drücken der 0 (Null) die o-Extension aufgerufen werden (o für Operator).

Durch Drücken der Stern-Taste (*) kommt man hingegen in die a-Extension (abort, Abbruch).

Die t- und T-Extension

Bei den t- und T-Extensions handelt es sich jeweils um Timeout-Extensions, also Zeitüberschreitungen.

t-Extension

Erfolgt nach einer bestimmten Zeit in einem IVR-Menü keine Eingabe, so wird die t-Extension aufgerufen.

Beispiel:

[hauptmenue]
exten => 10,1,Answer()
exten => 10,n,Background(marryme)             ; "Heiraten? 1 für ja, 2 für nein"

exten => 1,1,Playback(thank-you-cooperation)  ; 1 => "Danke"
exten => 1,n,Hangup()

exten => 2,1,Playback(hangup-try-again)       ; 2 => "Nochmal probieren"
exten => 2,n,Hangup()

exten => t,1,Hangup()                         ; keine Eingabe => auflegen

T-Extension

Die T-Extension wird nach einem Absolute Timeout aufgerufen. Dieser kann mit Set(TIMEOUT(absolute)=<Sekunden>) gesetzt werden.

[Warnung]Warnung

Bitte achten Sie darauf, das vor und nach dem "=" Zeichen kein Leerzeichen stehen darf.

Der Timeout wird immer dann gestartet, wenn der Zähler neu gesetzt wird (es wird also nicht automatisch vom Anfang des Gespräches gezählt). Mit Set(TIMEOUT(absolute)=0) wird dieser Timeout wieder deaktiviert.

Beispiel:

exten => 20,1,Answer()
exten => 20,2,Set(TIMEOUT(absolute)=120)
exten => 20,3,Playback(hello-world)
exten => 20,4,Wait(1)
exten => 20,5,Goto(3)

exten => T,1,Wait(1)
exten => T,2,Playback(thank-you-for-calling)
exten => T,3,Wait(1)
exten => T,4,Hangup()

Die s-Extension

Der erste Parameter einer Regel (Extension) ist immer der Name bzw. die Nummer. Was passiert aber, falls der Anruf auf einer klassischen analogen Leitung eintrifft und Asterisk gar nicht wissen kann, an wen der Anruf gerichtet ist? Dies ist dann der Fall, wenn Sie Asterisk mittels eines analogen Anschlusses an das Festnetz anschließen und die Rufnummerweitergabe aus dem Festnetz an den analogen Teilnehmeranschluss nicht erfolgt. Für dieses und alle anderern Szenarien, in denen der eingehende Anruf ohne eine Zielrufnummer ankommt, gibt es die s-Extension.

[Warnung]Warnung

Wenn Sie ein ATA-Device, also einen Analog to VoIP-Adapter benutzen, so benötigen Sie dafür keine s-Extension. Die Zielrufnummer müssen Sie hierbei im Adapter (meist über ein Webinterface) konfigurieren.

Beispiel:

exten => s,1,Answer()
exten => s,2,Wait(1)
exten => s,3,Play(carried-away-by-monkeys)
exten => s,4,Wait(1)
exten => s,5,Hangup()

4. Macro

Ein Macro ist eine Art Unterprogramm. Es kann komplexe Workflows enthalten und dann im restlichen Dialplan immer mit einer einzigen Zeile aufgerufen werden. Ein einfaches Beispiel kann so aussehen:

[macro-anruf]
exten => s,1,Dial(SIP/${MACRO_EXTEN},10)
exten => s,n,VoiceMail(${MACRO_EXTEN})

Ein solches Macro würde im rest des Dialplanes dann wie folgt aufgerufen werden:

[verkauf]
exten => _2XXX,1,Macro(anruf)

[hausmeister]
exten => _2XXX,1,Macro(anruf)

Bei einem zweizeiligen Macro ist der Effekt natürlich nicht so groß wie bei einem langen Macro, aber es ist klar, worum es geht.

Die Benutzung oder nicht Benutzung von Macros spaltet die Asterisk Entwicklergemeinde in zwei Lager. Für die eine Hälfte machen sie den Dialplan übersichtlicher und für die andere Hälfte machen sie ihn total unübersichtlich. Entscheiden Sie selber, zu welcher Gruppierung Sie gehören!

Macro Basics

Bei der Definition eines Macros sind folgende Punkte zu beachten:

  • Bei der Definition eines Macros gibt es nur eine Extension (die s-Extension).

  • Auf die ursprünglichen Variablen ${EXTEN} und ${CONTEXT} kann innerhalb des Macros nicht direkt zugegriffen werden. Das geschieht über die Variablen ${MACRO_EXTEN} und ${MACRO_CONTEXT}.

  • Beim Aufruf eines Macros können zusätzliche Argumente übergeben werden (mit Komma oder Pipe abgetrennt). Diese können im Macro mit ${ARGn} (n ist dabei eine natürliche Zahl) abgerufen werden.

  • Ein Macro wird durch [macro-macroname] definiert und mit der Applikation Macro() im Dialplan aufgerufen.

Weitere Informationen zu Macros finden Sie unter Abschnitt 58, „Macro().

[Tipp]Tipp

Mit der Applikation MacroExclusive() kann man sicherstellen, das das konkrete Macro immer nur einmal zu einem gegebenen Zeitpunkt aufgerufen wird (siehe Abschnitt 59, „MacroExclusive()).

5. Priority Jumping ist deprecated

Lange Zeit wurde in Asterisk Dialplänen hauptsächlich mit Priority Jumping gearbeitet. Dazu wurde von bestimmten Applikationen (z.B. Dial()) die Priorität bei bestimmten Ereignissen um 101 hochgesetzt. Diese Funktionalität ist aber mittlerweile offiziell deprecated (also im Sinne von "überholt")) und wird zwar teilweise noch unterstützt, sollte jedoch nicht mehr benutzt werden. Die Klassifizierung "deprecated" bezeichnet zumeist Funktionen und Funktionsaufrufe, für die mittlerweile entsprechende Nachfolger oder Folgekonstrukte existieren und künftig durch diese neuen ersetzt werden sollen. Beim Suchen nach Lösungen und Anregungen im Internet oder auch in anderen Asteriskbüchern werden Sie ebenfalls immer wieder auf Lösungsvorschläge stoßen, die dieses überholte Konstrukt mit den Prioritäten verwenden. Auch wenn die Unterstützung für derart erstellte Dialpläne sicher nicht morgen eingestellt wird, so werden sie doch mittelfristig schlechter unterstützt werden und man kann dann nicht sicher sein, dass es eine Lösung in der alten Notation geben wird. Es hat auch Vorteile sich aktiv mit einer Umstellung frühzeitig zu beschäftigen, da sie bei künftigen Updates der Asterisk-Software deutlich weniger Gefahr laufen werden, dass ihr Dialplan nicht mehr so funktioniert, wie sie das gewohnt sind.



[24] Man kann natürlich mit Goto() auch zu einer bestimmten Priorität springen. Aber dann ist der ganze Vorteil der n-Priorität wieder weg.

[26] Ein klassisches Henne-Ei-Problem

[27] Für alle neugierigen Leser: Das ist die Telefonnummer des Parlamentsarchives des Deutschen Bundestages in Berlin.

[28] Leider macht diese Variante in Deutschland wenig Sinn, da es unterschiedlich lange Vorwahlen gibt. Mehr Informationen zur deutschen Vorwahl finden Sie unter http://de.wikipedia.org/wiki/Telefonvorwahl_%28Deutschland%29.

[29] Um Ihnen das Gespräch nach Amerika zu sparen: Dies ist die Nummer der Besucherzentrale des Weißen Hauses in Washington DC. ;-)

[30] Der Sprachbaustein in der Datei that-is-not-rec-phn-num.gsm enthält den folgenden Text: "That is not a recognized phone number".


$Revision:473 $

Beta-Version!

2.0 Entwickler-Version des Asterisk Buches. Die 1.0 stabile Version ist natürlich noch online. Die 2.0er Version enthält viele Neuerungen, ist aber noch nicht 100% fehlerfrei. Im Zweifelsfall bitte auf die 1.0er Version gehen.

Bitte melden Sie Fehler und Feedback zur neuen 2.0er Version per E-Mail an den Autor.

Asterisk-Tag.org 2008

Auf der Asterisk-Tag.org Webseite finden Sie die Folien und Videos der Vorträge.

Werbung