Coverbild des Asterisk Buches von Stefan Wintermeyer

Letzte Woche => Endspurt!

Montag den 29.01.07 geht das Buch in die Produktion. Bis dahin laeuft der Beta-Test noch in vollem Umfang. Bitte melden Sie Fehler! Siehe Beta-Test FAQ.

Erscheinungstermin: 03.03.07. Das Buch wird auf dem Asterisk-Tag.org in Chemnitz vorgestellt und kann dort auch erworben werden. 10 Tage spaeter wird es im Buchhandel sein. Wer nicht in Chemnitz sein kann, sollte das Buch vorbestellen: Amazon oder direkt beim Verlag

Asterisk-Schulungen und Consulting vom Autor dieses Buches finden Sie auf http://www.amooma.de. Naechste Asterisk-Schulung: 12.02. - 13.02.07 (noch 2 Plaetze frei) - Ach ja, ... wir suchen auch noch Asterisk Entwickler! => http://www.amooma.de/jobs/


5.2. Der Wählplan (Dialplan)

Im ersten Kapitel haben wir schon einen einfachen Dialplan für zwei Telefone erstellt. Diesmal haben wir jedoch deutlich mehr Teilnehmer und obwohl es im Grunde lediglich Fleißarbeit bedeutet, ist die Pflege einer Konfiguration mit einigen Hundert Teilnehmern zeitaufwändig. Weiterhin fördert eine schlechte Übersichtlichkeit das Einschleichen von Fehlern. Aus diesen Gründen beschäftigen wir uns am Anfang dieses Abschnitts mit ein paar Asterisk-Funktionen, die uns das Leben einfacher und die extensions.conf übersichtlicher machen.

5.2.1. Platzhalter - Pattern Matching

Asterisk bietet die Möglichkeit mit Platzhaltern[31] zu arbeiten. Durch sinnvolles Gruppieren von Nummernblöcken und Zuordnungen können mit Platzhaltern ganze Nummernbereiche mit einzelnen Konfigurationszeilen verwaltet werden. Im Prinzip enthält eine Konfigurationszeile einen variablen Nummernbereich, der mit Hilfe von ''Pattern Matching'' die definierte Regel auf eine Vielzahl von Nummern anwendet. So kann man anstatt der folgenden 10 Zeilen:

exten => 2000,1,Dial(SIP/2000,20)
exten => 2001,1,Dial(SIP/2000,20)
exten => 2002,1,Dial(SIP/2000,20) 
exten => 2003,1,Dial(SIP/2000,20)
exten => 2004,1,Dial(SIP/2000,20)
exten => 2005,1,Dial(SIP/2000,20)
exten => 2006,1,Dial(SIP/2000,20)
exten => 2007,1,Dial(SIP/2000,20)
exten => 2008,1,Dial(SIP/2000,20)
exten => 2009,1,Dial(SIP/2000,20)

auch nur eine Zeile schreiben:

exten => _200X,1,Dial(SIP/2000,20)

Das X steht dann für alle Zahlen von 0 bis 9.[32] Wichtig dabei ist, dass der Suchbegriff (das Pattern) mit einem _ (Underscore) anfängt, sonst würde Asterisk nur auf 200X (also eine 200 und den Buchstaben X) reagieren, da ja Nebenstellen nicht nur aus Ziffern bestehen können/müssen. Das Definieren von Platzhaltern mit Pattern Matching[33] beinhaltet, dass man bestimmte Zeichenketten oder Zahlenfolgen durch entsprechend vordefinierte Platzhalter ersetzt.

In Asterisk kann man folgende Patterns benutzen:

PatternBeschreibung
XAlle Zahlen von 0 bis 9
ZAlle Zahlen von 1 bis 9
NAlle Zahlen von 2 bis 9[a]
[nm]Die Zahlen n und m
[n-m]Alle Zahlen von n bis m
.Eine oder mehrere beliebige Zahlen und Buchstaben

[a] Der Grund für das Pattern N liegt in der Rufnummernplanung von Amerika. Dort beginnt die Vorwahl nicht wie in Deutschland mit einer 0, sondern mit einer 1. Beispiel: 1-555-12345678

Warnung

Ein Pattern muss immer mit einem _ (Underscore) anfangen!

Für Asterisk ist sowohl ein 2XXX als auch ein _2XXX als Wert sinnvoll, wird jedoch vollkommen unterschiedlich ausgewertet.

5.2.1.1. Beispiele für Patterns

Die folgenden Varianten dienen als Beispiele für die Möglichkeiten:

PatternBeschreibung
_XXXAlle 3-stelligen Zahlen. Wobei auch 007 eine 3-stellige Zahl ist.
_XXX[13579]Alle 4-stelligen Zahlen, die ungerade sind.
_[1-5]XAlle 2-stelligen Zahlen von 10 bis 59.
_0.Eine beliebige Zeichenkette, die mit einer 0 anfängt.
_.Alles! (sollte mit entsprechender Vorsicht benutzt werden)

Detailierte Informationen zum Thema Pattern Matching finden Sie in Abschnitt 2.3, „Regular Expressions“.

5.2.2. Die Variable ${EXTEN}

Obwohl wir eigentlich erst später über Variablen sprechen, möchte ich eine sehr einfache und intuitiv zu benutzende Variable schon hier vorstellen. Es handelt sich um ${EXTEN}. In dieser Variable ist die gewählte Nummer gespeichert. Ich kann also in der extensions.conf anstatt:

exten => 2000,1,Dial(SIP/2000)

auch einfach

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

schreiben. Bei einer Zeile ist das natürlich noch wenig sinnvoll, aber wenn man diese Funktionalität mit Pattern Matching kombiniert, dann kann man sehr viel Zeit und Aufwand sparen und bekommt zusätzlich auch noch eine viel übersichtlichere Konfiguration.

Um somit alle SIP-Telefone mit den Durchwahlen 2000 bis 2999 in der extensions.conf anwählbar zu machen, reicht folgende Zeile:

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

5.2.3. Include

Innerhalb der extensions.conf können Bereiche mit einem include => Contextname eingefügt werden. So kann man eine einmal erstellte Definition in mehreren Contexten wiederverwenden. Beispiel:

[telefone-im-ersten-stock]
include => 2000er
include => anrufbeantworter

[telefone-im-zweiten-stock]
include => 2000er
include => anrufbeantworter

[telefone-im-dritten-stock]
include => 2000er

[2000er]
exten => _2XXX,1,Dial(SIP/${EXTEN})

[anrufbeantworter]
exten => 3000,1,VoicemailMain(${CALLERID(num)})

Der Vorteil dieses Weges ist, dass wenn man z.B. die Rufnummer des Anrufbeantworters ändern will, es reicht, dieses genau in einem Bereich zu machen.

Tipp

Die Funktion ${CALLERID(num)} übergibt die Nummer des Anrufenden. So kann die Applikation VoiceMailMain() mit dieser Variable aufgerufen werden und fragt dann nicht mehr nach der Mailbox, sondern nur noch nach dem Passwort der entsprechenden Mailbox.

Warnung

Wer intensiv mit Includes arbeitet, sollte Abschnitt 4, „Includes im Dialplan“ lesen.

5.2.4. Die extensions.conf für die Apfelmus GmbH

Der von uns entwickelte Rufnummernplan[34] lässt sich nun wie folgt in eine übersichtliche extensions.conf übertragen:

[sonstige]

[hausmeister]
include => interne-gespraeche
include => voicemailsystem-komfort

[it]
include => interne-gespraeche
include => voicemailsystem-komfort
;
; Aus Debugging Gruenden ist es fuer
; die IT Abteilung teilweise nuetzlich
; auf alle Voicemailboxen zugreifen 
; zu koennen.
;
include => voicemailsystem-normal

[geschaeftsfuehrer]
include => interne-gespraeche
include => voicemailsystem-komfort

[sekretariat]
include => interne-gespraeche
include => voicemailsystem-komfort

[verkauf-national]
include => interne-gespraeche
include => voicemailsystem-komfort

[verkauf-ausland]
include => interne-gespraeche
include => voicemailsystem-komfort

[versand]
include => interne-gespraeche
include => voicemailsystem-komfort

[produktion]
include => interne-gespraeche
include => voicemailsystem-komfort

[interne-gespraeche]
exten => _[1-5]XX,1,Dial(SIP/${EXTEN},60)
exten => _[1-5]XX,2,VoiceMail(${EXTEN})

[voicemailsystem-komfort]
;
; Der User muss nicht die Nummer der 
; Voicemailbox eingeben.
;
exten => 800,1,VoicemailMain(${CALLERID(num)})

[voicemailsystem-normal]
exten => 801,1,VoicemailMain()

Der Context [interne-gespraeche] definiert, dass alle Anrufe an die Nummern 100 bis 599 mit dem Programm Dial() auch mit dieser Nebenstelle verbunden werden. Wer die 800 anruft, bekommt die Voicemailbox für sein eigenes Telefon. Nur die IT-Abteilung kann die 801 anrufen und wird dann vom System erst nach der gewünschten Nebenstelle (Extension) gefragt. Da die IT-Abteilung auch den internen Support der Telefonanlage zur Verfügung stellt, benötigt sie diese Funktion zur Störungsermittlung (Debugging).

5.2.4.1. Schwarze Löcher im Rufnummernplan

Genau genommen müsste dieser Dialplan noch etwas komplexer sein, da es ja laut Rufnummernplan Bereiche gibt (z.B. 270 bis 299), die gar nicht mit Telefonen belegt sind. Da wir dies nicht beachten, kann es zu Missverständnissen kommen. Ein Anrufer kann eine nicht vergebene Rufnummer anrufen und dort auf dem Anrufbeantworter eine Nachricht hinterlassen. Diese Nachricht würde aber nie abgehört werden. Um dies zu vermeiden, müsste man korrekterweise den Context [interne-gespraeche] wie folgt gestalten:

[interne-gespraeche]
exten => _1[5-6]X,1,Dial(SIP/${EXTEN},60)
exten => _1[5-6]X,2,VoiceMail(${EXTEN})

exten => _2[0-6]X,1,Dial(SIP/${EXTEN},60)
exten => _2[0-6]X,2,VoiceMail(${EXTEN})

exten => _[358]XX,1,Dial(SIP/${EXTEN},60)
exten => _[358]XX,2,VoiceMail(${EXTEN})

exten => _4[0-4]XX,1,Dial(SIP/${EXTEN},60)
exten => _4[0-4]XX,2,VoiceMail(${EXTEN})

Wir verzichten bei der Apfelmus GmbH der Einfachheit halber auf diese ausführlichere Variante und benutzen nur den folgenden Context:

[interne-gespraeche]
exten => _[1-5]XX,1,Dial(SIP/${EXTEN},60)
exten => _[1-5]XX,2,VoiceMail(${EXTEN})

5.2.5. voicemail.conf

Die voicemail.conf bleibt wie im ersten Kapitel beschrieben. Es werden einfach nur ein paar mehr Einträge eingefügt:

[general]
format = gsm
serveremail = voicemail@apfelmus-gmbh.de
maxmessage = 600

[local]
150 => 999999,Hans Hausmeister,hausmeister@apfelmus-gmbh.de
200 => 999999,Ernst Wichtig,ernst.wichtig@apfelmus-gmbh.de
201 => 999999,Hans Toll,hans.toll@apfelmus-gmbh.de

; Ich verzichte hier darauf, die restlichen Eintraege aufzulisten, sie sind analog zu den aufgefuehrten Zeilen


[31] Unix- und Linux-Fans werden das Konzept des ''Pattern Matching'' von den ''regulären Ausdrücken'' in Programmen wie grep und sed kennen.

[32] Das Beispiel macht natürlich wenig Sinn. Warum sollte der Anrufer die 2009 wählen, um zur 2000 verbunden zu werden? Zur Lösung dieses Problems kommen wir gleich.

[33] Es gibt keinen wirklich passenden deutschen Begriff zum Fachbegriff ''Pattern Matching''. Eine mögliche Übersetzung könnte ''Musterabgleich'' oder ''Mustervergleich'' lauten.

[34] Mit Ausnahme der Notrufnummern, die wir später behandeln, da wir jetzt noch keine Verbindung zur Außenwelt eingerichtet haben.