AGI-Skripte für Asterisk unter Windows editieren – Was ist zu beachten?

9. März 2023

Windows ist weit verbreitet. Deshalb schreiben nicht wenige ihre AGI-Skripte auf Windows, um sie dann in ihren Raspberry Pi zu kopieren. Wer einige Dinge nicht beachtet, wird die Skripte nicht zum Laufen bekommen. Hier sind die Fallstricke beschrieben, die mich viel Zeit gekostet haben. Die Beispiele beziehen sich auf Python. Sie haben für andere Programmiersprachen die entsprechende Gültigkeit.

Der Programmier-Code ist fehlerfrei. Trotzdem läuft das AGI-Skript nicht. Warum verflixt noch einmal? Die Gründe sind nachfolgend beschrieben und oft banal.

Vorab das Hauptproblem mit dem Carriage Return (CR) und dem Line Feed (LF): Line Feed (LF) und Carriage Return (CR) sind Steuerzeichen, die aus der Fernschreibtechnik stammen. Ursprünglich wurden diese Steuerzeichen verwendet, um den physischen Mechanismus der Fernschreiber zu steuern.

Carriage Return (CR) bedeutet „Wagenrücklauf“ und bezieht sich auf den Mechanismus der Fernschreiber, bei dem der Wagen, der die Papierrolle trägt, am Ende einer Zeile zurückgeschoben wird, um eine neue Zeile zu beginnen. Line Feed (LF) bedeutet „Zeilenfütterung“ und bezieht sich auf den Mechanismus, bei dem das Papier auf der Rolle um eine Zeile weitergeführt wird, um eine neue Zeile zu beginnen.

Diese Steuerzeichen wurden später in Computer-Systemen übernommen, um den Zeilenumbruch in Textdateien zu markieren. Dabei wird das CR-Zeichen verwendet, um den Cursor an den Anfang der Zeile zurückzusetzen, und das LF-Zeichen, um den Cursor um eine Zeile nach unten zu setzen. In modernen Textverarbeitungs- und Betriebssystemen wird häufig nur das LF-Zeichen verwendet, um den Zeilenumbruch zu markieren, während das CR-Zeichen in der Regel implizit durch das LF-Zeichen dargestellt wird.

LF und CR in der Linux- und Windows-Welt: Line Feed (LF) und Carriage Return (CR) sind demnach Steuerzeichen, die auch in Textdateien verwendet werden, um den Zeilenumbruch zu markieren.

In Linux-Systemen wird nur das LF-Zeichen verwendet, um den Zeilenumbruch zu markieren. Dies bedeutet, dass jede Zeile in einer Textdatei mit einem LF-Zeichen abgeschlossen wird.

In Windows-Systemen wird hingegen das CR-Zeichen gefolgt von einem LF-Zeichen verwendet, um den Zeilenumbruch zu markieren. Dies bedeutet, dass jede Zeile in einer Textdatei mit einem CR und einem LF-Zeichen abgeschlossen wird.

Diese Unterschiede können dazu führen, dass Textdateien, die von einem System auf ein anderes übertragen werden, inkorrekt angezeigt werden. Wenn beispielsweise eine Textdatei von einem Windows-System auf ein Linux-System übertragen wird, können die CR-Zeichen als unerwünschte Zeichen angezeigt werden. Wenn eine Textdatei von einem Linux-System auf ein Windows-System übertragen wird, können die Zeilenumbrüche fehlen und die Textdatei wird als eine lange Zeile angezeigt.

Es gibt Tools, die es ermöglichen, Textdateien zwischen verschiedenen Betriebssystemen zu konvertieren, um diese Probleme zu vermeiden. Das bekannteste Tool ist „dos2unix“, das CR-Zeichen aus einer Textdatei entfernt, um sie in ein Unix-System zu übertragen, und „unix2dos“, das ein LF-Zeichen in CR-LF-Zeichen konvertiert, um eine Textdatei für Windows-Systeme zu formatieren.

Skripte unter Windows editieren: Die Skripte lassen sich sehr gut mit Notepad++ unter Windows editieren. Notepad++ ist kostenlos und hier erhältlich. Es sind zwei Einstellungen von Notepad++ zu beachten, damit die Dateien fit für Linux sind:

Die Kodierung ist auf UTF-8 zu stellen:

UTF-8 auswählen

Das Format des Zeilenendes ist auf UNIX (LF) zu stellen:

UNIX (LF) wählen

Ich schreibe meine AGI-Skripte auf Python, weil Python auf Linux und Raspbian schon vorinstalliert ist. Bei  Raspbian Buster ist Python 2.7 vorinstalliert. Man kann Python 3 nachinstallieren. Die meisten Skripte laufen auf beiden Versionen. Selbstverständlich gehen auch viele andere Programmiersprachen für AGI-Skripte. Eventuell sind die Interpreter zu installieren. Meine Skripte für Python fangen wie folgt an:

So fangen meine Python AGI-Skripte an
#!/usr/bin/env python
# -*- coding: utf-8 -*-

Die erste Zeile „#!/usr/bin/env python“ gibt das sogenannte „Shebang“ an, welches dem Betriebssystem sagt, welches Programm zum Ausführen des Skripts verwendet werden soll. In diesem Fall wird „env“ verwendet, um die Umgebung zu suchen, die das Programm „python“ ausführt. Dies bedeutet, dass das Skript auf jedem System ausgeführt werden kann, auf dem Python installiert ist, ohne dass der Pfad zur Python-Installation explizit angegeben werden muss.

Die zweite Zeile „# –– coding: utf-8 –-“ gibt die Zeichenkodierung des Skripts an. In diesem Fall ist es „utf-8“, was bedeutet, dass das Skript Unicode-Zeichen unterstützt. Es ist wichtig, die richtige Kodierung anzugeben, um sicherzustellen, dass das Skript korrekt interpretiert wird und Probleme mit Zeichenkodierung vermieden werden.

Wohin das Skript kopieren? Jetzt müssen wir noch wissen, in welchen Pfad wir das kleine AGI-Skript zu kopieren haben. Dies erfahren wir in der asterisk.conf. Sie befindet sich in dem Pfad, in dem sich die anderen Asterisk-Konfigurationsdateien befinden. Nachfolgend ein Ausschnitt aus der asterisk.conf:

[directories](!)
astcachedir => /var/cache/asterisk
astetcdir => /etc/asterisk
astmoddir => /usr/lib/asterisk/modules
astvarlibdir => /var/lib/asterisk
astdbdir => /var/lib/asterisk
astkeydir => /var/lib/asterisk
astdatadir => /var/lib/asterisk
astagidir => /var/lib/asterisk/agi-bin ; Hier steht der Pfad für die AGI-Skripte
astspooldir => /var/spool/asterisk
astrundir => /var/run/asterisk
astlogdir => /var/log/asterisk
astsbindir => /usr/sbin

[options]

Unter astagidir ist der Pfad eingetragen, in dem Asterisk die Skripte findet. Im obigen Beispiel also /var/lib/asterisk/agi-bin. Bei meiner Version Asterisk 16.2.1 sind die AGI-Skripte unter /usr/share/asterisk/agi-bin untergebracht. Also aufpassen, was in älterer Literatur eventuell steht.

Und wie kopiere ich die Dateien von Windows auf meinen Raspberry? Das ist nachfolgend beschrieben:

Mit dem FTP-Client FileZilla gelingt von Windows aus der Zugriff auf Raspberry-Dateien. Der Raspberry kann das von Haus aus.
Von Windows auf den Raspberry Pi zugreifen – 5.12.2021: Auf meinem Raspberry Pi betreibe ich einen kleinen SIP-Server mit Asterisk. Von Windows 10 aus möchte ich direkten Zugriff auf die Asterisk-Konsole und auf die Kommandozeilenebene (CLI) des Raspbian haben. Außerdem möchte ich zur Datensicherung und zu Konfigurationszwecken die Konfigurationsdateien von Windows aus sichern und verändern können. Dies erspart einen zweiten Bildschirm. – weiter

Wenn die auszuführende Datei auf dem Raspberry ist, dann muss sie ausführbar gemacht werden und sollte zur Sicherheit nochmals für Linux angepasst werden: Nachfolgend wird alles als Beispiel mit der callerid.py erklärt, einem Python-Skript. Wer seine Skripte auf Windows bearbeitet oder erhält und dann auf den Raspberry  kopiert, wird die Programme nicht zum Laufen bekommen. Der Grund sind die unterschiedlichen Steuerzeichen für den Wagenrücklauf (CR) und den Papiervorschub (LF). Die Bezeichnungen stammen noch aus der Zeit, als mit UNIX-Rechnern auf Fernschreibern ausgedruckt wurde. Zum Glück gibt es eine Lösung, die auf https://phoenixnap.com/kb/convert-dos-to-unix beschrieben ist. Demnach müssen wir auf unserem Linux bzw. Raspbian mit dem Befehl

sudo apt-get update
sudo apt install dos2unix

ein kleines Programm installieren, mit dem wir mit dem Befehl dos2unix die Windows- oder DOS-Dateien konvertieren können. Wie das genau geht, steht auf der vorhergehend genannten Seite. Zum Beispiel geht das für unser Beispiel wie folgt:

sudo dos2unix /usr/share/asterisk/agi-bin/callerid.py

Dem Skript-Dateien Zugriffsrechte vergeben: Damit die Skripte auch laufen, müssen sie noch einige Zugriffsrechte erhalten und die Rechte für die Ausführbarkeit erhalten. Dies können wir radikal mit dem Befehl

sudo chmod 777 /usr/share/asterisk/agi-bin/callerid.py

erreichen. Wenn wir eine AGI-Skript Datei von Windows zum Pi herüberziehen und eine alte Datei ersetzen, brauchen wir diese Befehle nicht mehr verwenden.

Debugging: Ob unser AGI-Skript läuft, können wir sogleich wie folgt testen:

sudo python /usr/share/asterisk/agi-bin/callerid.py

Wir erfahren, dann gegebenenfalls, in welcher Zeile das Programm fehlerhaft ist.

Ich habe mir angewöhnt alle drei Befehle in die Zwischenablage von Windows zu packen:

sudo dos2unix /usr/share/asterisk/agi-bin/call.py
sudo chmod 777 /usr/share/asterisk/agi-bin/call.py
sudo python /usr/share/asterisk/agi-bin/call.py

Die Linux-Konsole läuft unter Windows über Putty. Mit der rechten Maustaste lassen sich die drei Befehle auf einen Schlag in die Linux-Konsole kopieren und ausführen. Viel Arbeit gespart.

Wie wechsele ich zwischen dem Asterisk-CLI und und der Linux-Kommandozeileneingabe? So geht es:

pi@raspberrypi:~ $ sudo su
root@raspberrypi:/home/pi# asterisk -rvvvvvvvvv
Asterisk 16.2.1~dfsg-1+deb10u2, Copyright (C) 1999 - 2018, Digium, Inc. and others.
Created by Mark Spencer <markster@digium.com>
Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.
This is free software, with components licensed under the GNU General Public
License version 2 and other licenses; you are welcome to redistribute it under
certain conditions. Type 'core show license' for details.
=========================================================================
Connected to Asterisk 16.2.1~dfsg-1+deb10u2 currently running on raspberrypi (pid = 456)
raspberrypi*CLI> exit
Asterisk cleanly ending (0).
Executing last minute cleanups
root@raspberrypi:/home/pi#

Mit „asterisk -rvvvvv“ rufe ich die Asterisk-Konsole auf und mit „exit“ verlasse ich sie wieder. Asterisk läuft selbstverständlich im Hintergrund weiter. Mehr muss man nicht wissen.

Vielleicht noch eines. In der Asterisk-Software stehen die v-Optionen für die Anzahl der Verbose-Level, die im Systemprotokoll angezeigt werden sollen. Jedes v erhöht das Niveau der detaillierten Ausgabe in der Konsole. Wenn Sie also „asterisk -rvvvvv“ eingeben, geben Sie an, dass Sie 5 Verbose-Level anzeigen möchten. Das bedeutet, dass Asterisk bei der Ausführung des Befehls eine sehr ausführliche Ausgabe generiert, die möglicherweise hilfreich ist, um spezifische Details und Fehler bei der Ausführung von Skripten und Anwendungen zu erkennen.

AGI-Skript ausführen: Jetzt können wir unser AGI-Skript ausprobieren, wenn es beim  Debugging keine Fehler gezeigt hatte. In der extensions.conf haben wir bereits einen entsprechenden Aufruf geschrieben, der durch die Anwahl einer Nummer das AGI-Skript ausführt. Damit wir im Asterisk-CLI sehen, wie das AGI-Skript mit Asterisk interagiert ist im Asterisk-CLI folgendes einzustellen:

agi set debug on

In meiner extensions.conf steht zum Beispiel folgendes, um durch das Anwählen der 344 das AGI-Skript callerid.py aufzurufen:

exten => 344,1,Noop(Anruf erfolgt von: "${CALLERID(name)}" <${CALLERID(num)}>) 
  same => n,Answer()
  same => n,Set(callerid=${CALLERID(num)})
  same => n,AGI(callerid.py,${callerid})
  same => n,Hangup()

Wenn alles klappt, erhalte ich folgende Meldungen in der Asterisk-Konsole:

 == Using SIP RTP TOS bits 184
  == Using SIP RTP CoS mark 5
       > 0x73f65f18 -- Strict RTP learning after remote address set to: 192.168.1.44:10000
    -- Executing [344@janson:1] NoOp("SIP/1088-0000002f", "Anruf erfolgt von: "Volker Lange-Janson" <1088>") in new stack
    -- Executing [344@janson:2] Answer("SIP/1088-0000002f", "") in new stack
       > 0x73f65f18 -- Strict RTP switching to RTP target address 192.168.1.44:10000 as source
    -- Executing [344@janson:3] Set("SIP/1088-0000002f", "callerid=1088") in new stack
    -- Executing [344@janson:4] AGI("SIP/1088-0000002f", "callerid.py,1088") in new stack
    -- Launched AGI Script /usr/share/asterisk/agi-bin/callerid.py
<SIP/1088-0000002f>AGI Tx >> agi_request: callerid.py
<SIP/1088-0000002f>AGI Tx >> agi_channel: SIP/1088-0000002f
<SIP/1088-0000002f>AGI Tx >> agi_language: en
<SIP/1088-0000002f>AGI Tx >> agi_type: SIP
<SIP/1088-0000002f>AGI Tx >> agi_uniqueid: 1678367052.103
<SIP/1088-0000002f>AGI Tx >> agi_version: 16.2.1~dfsg-1+deb10u2
<SIP/1088-0000002f>AGI Tx >> agi_callerid: 1088
<SIP/1088-0000002f>AGI Tx >> agi_calleridname: Volker Lange-Janson
<SIP/1088-0000002f>AGI Tx >> agi_callingpres: 0
<SIP/1088-0000002f>AGI Tx >> agi_callingani2: 0
<SIP/1088-0000002f>AGI Tx >> agi_callington: 0
<SIP/1088-0000002f>AGI Tx >> agi_callingtns: 0
<SIP/1088-0000002f>AGI Tx >> agi_dnid: 344
<SIP/1088-0000002f>AGI Tx >> agi_rdnis: unknown
<SIP/1088-0000002f>AGI Tx >> agi_context: janson
<SIP/1088-0000002f>AGI Tx >> agi_extension: 344
<SIP/1088-0000002f>AGI Tx >> agi_priority: 4
<SIP/1088-0000002f>AGI Tx >> agi_enhanced: 0.0
<SIP/1088-0000002f>AGI Tx >> agi_accountcode:
<SIP/1088-0000002f>AGI Tx >> agi_threadid: 1861940128
<SIP/1088-0000002f>AGI Tx >> agi_arg_1: 1088
<SIP/1088-0000002f>AGI Tx >>
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/hello ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/hello.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=6400
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/your ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/your.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=5120
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/telephone-number ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/telephone-number.gsm' (escape_digits=) (sample_offset 0) (language 'en')
       > 0x73f65f18 -- Strict RTP learning complete - Locking on source address 192.168.1.44:10000
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=11200
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/is ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/is.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=4960
<SIP/1088-0000002f>AGI Rx << SAY NUMBER 1088 ""
    -- <SIP/1088-0000002f> Playing 'digits/1.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/thousand.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/80.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/8.gsm' (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0
<SIP/1088-0000002f>AGI Rx << SAY NUMBER 1088 ""
    -- <SIP/1088-0000002f> Playing 'digits/1.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/thousand.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/80.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/8.gsm' (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0
<SIP/1088-0000002f>AGI Rx << SAY NUMBER 1088 ""
    -- <SIP/1088-0000002f> Playing 'digits/1.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/thousand.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/80.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/8.gsm' (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0
<SIP/1088-0000002f>AGI Rx << SAY NUMBER 1088 ""
    -- <SIP/1088-0000002f> Playing 'digits/1.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/thousand.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/80.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/8.gsm' (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/beep ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/beep.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=3520
<SIP/1088-0000002f>AGI Rx << SAY DIGITS 1088 ""
    -- <SIP/1088-0000002f> Playing 'digits/1.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/0.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/8.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/8.gsm' (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/beep ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/beep.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=3520
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/beep ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/beep.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=3520
<SIP/1088-0000002f>AGI Rx << SAY DIGITS 1088 ""
    -- <SIP/1088-0000002f> Playing 'digits/1.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/0.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/8.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/8.gsm' (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/beep ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/beep.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=3520
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/beep ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/beep.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=3520
<SIP/1088-0000002f>AGI Rx << SAY DIGITS 1088 ""
    -- <SIP/1088-0000002f> Playing 'digits/1.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/0.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/8.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/8.gsm' (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/beep ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/beep.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=3520
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/beep ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/beep.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=3520
<SIP/1088-0000002f>AGI Rx << SAY DIGITS 1088 ""
    -- <SIP/1088-0000002f> Playing 'digits/1.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/0.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/8.gsm' (language 'en')
    -- <SIP/1088-0000002f> Playing 'digits/8.gsm' (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/beep ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/beep.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=3520
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/beep ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/beep.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=3520
<SIP/1088-0000002f>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/en_US_f_Allison/goodbye ""
    -- <SIP/1088-0000002f> Playing '/usr/share/asterisk/sounds/en_US_f_Allison/goodbye.gsm' (escape_digits=) (sample_offset 0) (language 'en')
<SIP/1088-0000002f>AGI Tx >> 200 result=0 endpos=7520
    -- <SIP/1088-0000002f>AGI Script callerid.py completed, returning 0
    -- Executing [344@janson:5] Hangup("SIP/1088-0000002f", "") in new stack
  == Spawn extension (janson, 344, 5) exited non-zero on 'SIP/1088-0000002f'
raspberrypi*CLI>

Eigentlich ist nur der Anfang interessant. Die Ausgabe ist wegen der vielen Soundfiles, die zu hören sind so lang geworden.

Nachfolgend ist die callerid.py beschrieben:

Dieses AGI-Skript reagiert auf die Caller-ID des Anrufers und dient als Muster für ähnliche Skripte
Ein AGI-Skript in Python für Asterisk erkennt die Caller-ID und trifft danach Entscheidungen – 9. März 2023: Dieses AGI-Skript in Python gibt die Caller-ID und damit in der Regel die Telefonnummer des Anrufers zurück und verarbeitet sie weiter. Fängt die Nummer nicht mit Null an, wird die Caller-ID als Nummer angesagt. Fängt die Caller-ID mit einer Null an, wird die Nummer als Folge von einzelnen Ziffern aufgesagt. Damit erklärt diese Programm die Prinzipien, wie Caller-IDs eingelesen werden können und anschließend weiterverarbeitet werden. – weiter

Zur Übersicht über Asterisk und zu weiteren AGI-Skripten:

Auf einem Raspberry Pi lässt sich ein kompletter Telefonserver betreiben, der seinen Teilnehmern über Landesgrenzen hinweg kostenloses Telefonieren von unterwegs oder daheim ermöglicht.
Asterisk-Telefonserver auf einem Raspberry Pi – Installation, Konfiguration, Programmierung, SIP, IAX2, AGI-Skripte, Sicherheit und Tipps zum praktischen Betrieb – 2.11.2022: Diese Seite richtet sich an jene, welche einen Asterisk-Telefon-Server auf einem Raspberry Pi betreiben möchten und später ein kleines Netzwerk aus Asterisk-Servern planen, um ein eigenständiges Telefonnetz aufzubauen. Los geht es mit der Installation von Raspbian und Asterisk auf einem Raspberry Pi und dann nach Lust und Laune immer tiefer in die Programmierung von Asterisk. Die Themen werden laufend erweitert.

Selbstverständlich muss es nicht unbedingt ein Raspberry Pi sein. Andere Linux-Rechner gehen auch. – weiter