[Gelöst] Perl Skript in ein AGI Skript (ankommende SMS verarbeiten)

oskars

Neuer User
Mitglied seit
14 Jul 2011
Beiträge
23
Punkte für Reaktionen
0
Punkte
0
Hi,
ich habe gestern angefagen mit perl zu experimentieren. So jetzt hab ich mir nen Perl Skript geschrieben, womit ich den Text einer ankommenden SMS in Asterisk auslesen kann.
Aber ich hab kein Plan wie ich das Skript jetzt verändern muss, damit ich es in Asterisk als AGI Skript ausführen kann. Ich hab mir schon einiges durchgelesen, aber ich blicke da überhaupt nicht durch.

Könnte mir einer erklären, was ich machen muss?

Danke schonmal

hier ist der perl code:
Code:
#!/usr/bin/perl -w

use strict;

#Verzeichnes der ankommenden SMS
my $dir = "/var/spool/asterisk/sms/mtrx/";

#Suche, nach der neusten SMS-Datei
my $LATESTSMS = (
    map{
        $_->[0]
    }
    sort{
        $a->[1] <=> $b->[1]
    }
    map{
        [$_, -M $_]
    }
    grep {
        -f $_ and $_ =~ /Mein-SIPID/
    }
    glob(
         $dir."*"))[0];

#Öffnen der SMS
open(SMS, $LATESTSMS);

#Suche und Ausgabe des SMS Textes
for my $MSG (<SMS>){
        if($MSG =~ /ud=/){
                $MSG =~ s/ud=//;
                print "Der Text der SMS lautet: $MSG";
        }
}
close SMS;
 
Zuletzt bearbeitet:
Da ich Dir so mehr oder weniger dazu geraten habe, sehe ich mich verpflichtet Dir jetzt soweit es geht weiterzuhelfen, obwohl ich mich mit Perl noch so gut wie nie beschäftigt habe. ;-)

Schau mal hier, da steht die Erstellung eines AGI Skripts in Perl Schritt für Schritt.

Was möchtest Du mit dem Skript genau erreichen, soll da nur der Test ausgewertet und zB. als Variable an Asterisk zurückgegeben werden, oder möchtest Du damit noch mehr ausführen?
 
Hi danke ich werds mir nächste woche mal angucken. Ich bin im moment dabei noch perl besser kennen zulernen.
Das gehört alles zu meinem Projekt im Praktikum. Ich soll einen Asteriskserver bauen, der SMS empfangen kann und dann je nach Inhalt der Nachricht und des Absenders eine vorgegebene Telefonlist abtelefoniert. Die angerunfenden müssen dies dann mit einer Taste bestätigen. Deshalb muss ich die SMS datei auslesen und wenn ich das bis jetzt alles richtig verstanden habe kann man mit einem AGI skript viele Sachen einfacher erledigen, als mit einem komplizierten Dialplan.
Naja mal gucken ob ich alles ans laufen bekomme.


-----------------------------
edit(01.08.2011):

habs zum laufen bekommen mit dem beispiel. Es hätte auch vorher funktioniert, aber ich hatte ne neuere perl version installiert und da war der pfad dann /usr/local/bin/perl und nicht mehr /usr/bin/perl. (falls einer nach dem pfad sucht, einfach "which perl" in die console)

Wenn ich mit meinem Ergebnis zufrieden bin, werde ich es posten.

-----------------------------
edit(03.08.2011):

So Hier ist erstmal mein Script zum auslesen, der SMS.
Code:
#!/usr/local/bin/perl -w

use strict;                                                     #hilft bei der Fehlevermeidung
use Asterisk::AGI;

$|=1;
my $MSG, my $ABS;

#-----------------------------------------
#while(<STDIN>) {
#       chomp;
#               last unless length($_);
#               if (/^agi_(\w+)\:\s+(.*)$/) {
#                       $AGI{$1} = $2;
#               }
#}
#print STDERR "AGI Environment Dump:\n";
#foreach my $i (sort keys %AGI) {
#        print STDERR " -- $i = $AGI{$i}\n";
#}
#------------------------------------------------

my $dir = "/var/spool/asterisk/sms/mtrx/";                      #Pfad zum SMS Ordner
my $lastsms_pfad = (reverse(sort(glob "$dir/Meine-SIPID*")))[0];    #letzte SMS Datei mit Pfad

&lastsms;                                                       #ruft die Sub-Funktion auf

open(SMS, $lastsms_pfad);                                       #öffent die Datei, um damit zuarbeiten
foreach my $line (<SMS>){                                       #kontrolliert jede Zeile in der SMS, die aktuelle Zeile wird in der Variable $line gespeichert
        if($line =~ /ud=/){                                     #sucht nach der Nachricht, bei einer SMS von Asterisk beginnt diese Zeile mit "ud=".
                $MSG = $line;                                   #setzt die Variabel $MSG gleich der aktuellen Zeile
                $MSG =~ s/ud=//;                                #entfernt das voran stehende "ud="
                print "Der Text lautet: $MSG";                 #gibt die Nachricht aus
                print "SET VARIABLE SMST \"$MSG/";        #gibt die Variable weiter an Asterisk
        }
        if($line =~ /oa=/){                                     #sucht nach der Absendernummer (s.o). --> Später soll der Absender in einer Datenbank geucht werden.
                $ABS = $line;
                $ABS =~ s/oa=//;
                print "Die Absendernr. ist: $ABS";
        }
}
close SMS;                                                      #schließt die Datei


#----------------------
#****SUB-FUNKTIONEN****
#----------------------

#Entfernen des Dateipfades zur neusten SMS
sub lastsms {                                                   #Erstellen der Sub-Funktion
        my $lastsms_name = $lastsms_pfad;                       #überträgt den Namen
        $lastsms_name =~ s/$dir\///;                            #entfernt den Pfad
        print "$lastsms_name\n";                                #gibt den Dateinamen aus
}

So zum Code:
Ich hab den AGI Kram immer noch nicht so ganz gescheckt, bzw welche Angaben wirklich benötigt werden und welche nicht. Deshalb habe ich den Teil am Anfang auskommentiert, da ich ja nix einlesen will, sondern nur das Script ausführen und was zurück geben will.
Die Suche nach der neusten Datei ist noch nicht perfekt, da hier nach dem Namen sortiert wird. Allerdings funktioniert es trotzdem, weil im Namen das Datum mit Uhrzeit enthalten ist und sonst alles andere gleich ist. Ich versuche es aber später noch zuverbessern. Im moment bin ich dabei anhand der Absendernummer, die entprechenden Daten aus einer Datenbank (MySQL) zulesen.
 
Zuletzt bearbeitet:
Hi, ich bin schon etwas weiter (werde mein aktuellen Stand morgen posten). Habe aber eine Frage ist es möglich meine in der Datenbank eingetragenen Telefonliste abzutelefonieren via Perl skript oder gibt es da eine besondere Funktion für den Dialplan? Meine Lösung wäre jetzt jede einzelne Nummer mit einem Perlskript aus der Datenbank auszulesen und dann an den Dialplan zusenden, den Anrufen auszuführen und dann mit dem Perlskript die nächste Nummer aus lesen. Aber das ist recht umständlich. Habe hier im Forum gesucht, aber wahrscheinlich habe ich nur nach den Falschenbegriffen gesucht.
 
Hi oskars!
oskars; schrieb:
Habe hier im Forum gesucht, aber wahrscheinlich habe ich nur nach den Falschenbegriffen gesucht.
Wo solll denn Falschenbegriffen vorkommen? In Asterisk, PHP Perl oder AGI?
 
Danach hab ich schon gesucht, hab mir auch die meinsten beiträge mal angeguckt Ich habe jetzt auch den Beitrag "Telefonterror" gefunden, aber ich bin daraus nicht schlau geworden..
Meine Idee für die Lösung wäre jetzt, dass ich mit meinem perl skript immer eine Nummer aus der Datenbank auslese und dann an asterisk sende und dort anrufe, und danach die nächste nummer, wie oben beschrieben. Aber das kommt mir irgendwie sehr kompliziert vor, nicht das programmieren, sondern der Ablauf, der dann immer wieder ausgeführt wird. Naja ich arbeite im moment erstmal an nen Bestätigungsmenu beim Anruf, vll kennt ja einer von euch ne Lösung eine Telefonliste abzutelefonieren. Es soll kein Spam oder ähnliches sein.

--------------------------------------
edit(10.08.2011):
So hier ist mein jetziger Stand.
-> habs gelöscht da unten das gleiche nochmal ist.
 
Zuletzt bearbeitet:
Hi,

das hier hab ich bis jetzt. Es wird die ankommende SMS ausgelesen und überprüft, ob die Absendernr. in der Datenbank vorhanden ist. Wenn dies der Fall ist wird der Text nach einem Schlüsselwort überprüft. Wird dieser gefunden wird der Name der abzuspieleden Sounddatei ausgegeben, falls nicht wird Text to Speech verwendet.
Nun werden die Nummern der Mitarbeiter aus der Datenbank ausgelesen und in Arrays gespeichert. Diese werden dann nach einander angerufen.

Hier habe ich noch das Probleme, wenn ein Mitarbeiter nicht direkt nach abspielen des Soundfiles auflegt, wird er mit dem nächsten verbunden, was aber nicht passieren soll. Aber das werde ich heute noch verbessern.

Sonst bin ich recht zufrieden. Es ist bestimmt nicht die beste Lösung, aber es funktioniert erstmal alles, auch wenn es teilweise recht umständlich ist (hab erst vor ca. 2 1/2 Wochen angefangen mit Perl zuarbeiten und muss auch erst Asterisk richitg verstehen). Ein paar kleine Sachen muss ich noch verbessern, sowie ein Bestätigungsmenü einbauen.

So hier ist das Script, vll hilft es ja irgendeinen.

1.SMS auslesen und überprüfen.
Code:
#!/usr/local/bin/perl -w

#****Funktionen/Module****
use strict;                                                     #hilft bei der Fehlevermeidung
use Asterisk::AGI;
use DBI;
use DBD::mysql;

$|=1;

#****Variablen****
my $MSG; #Textnachricht
my $ABS; #Absendernummer
my $DATI; #DAte und TIme
my $DATE; #Eingangsdatum
my $TIME; #Eingagnszeitpunkt

#----------------------------------------------------------------------
#****************************Datei auslesen****************************
#----------------------------------------------------------------------
my $dir = "/var/spool/asterisk/sms/mtrx/";                      #Pfad zum SMS Ordner
my $lastsms_pfad = (reverse(sort(glob "$dir/SIPGATEID*")))[0];    #letzte SMS Datei mit Pfad (kurze Version)

open(SMS, $lastsms_pfad);                                       #öffent die Datei, um damit zuarbeiten
foreach my $line (<SMS>){                                       #kontrolliert jede Zeile in der SMS, die aktuelle Zeile wird in der Variable $line gespeichert
        if($line =~ /oa=/){                                     #sucht nach der Absendernummer, bei einer SMS von Asterisk beginnt diese Zeile mit "oa=".
                $ABS = $line;                                   #setzt die Variabel $ABS gleich der aktuellen Zeile
                $ABS =~ s/oa=//;                                #entfernt das voran stehende "oa="
                #print "Nummer: $ABS";                                  #gibt die Nummer aus
                print "SET VARIABLE ABS \"$ABS";
                chomp $ABS;
        }elsif($line =~ /ud=/){                                 #sucht nach dem Text  und gibt diesen aus.
                $MSG = $line;
                $MSG =~ s/ud=//;
                #print "Text: $MSG";
                print "SET VARIABLE MSG \"$MSG";
                chomp $MSG;
        }elsif($line =~ /scts=/){                               #sucht nach dem Eingagnsdatum mit Zeit und splitet es in Datum und Zeit auf.
                $DATI = $line;
                $DATI =~ s/scts=//;
                my @DATI = split /T/, $DATI;
                $DATE = $DATI[0];
                #print "Datum: $DATE\n";
                print "SET VARIABLE DATE \"$DATE\n";
                $TIME = $DATI[1];
                #print "Zeit: $TIME\n";
                print "SET VARIABLE TIME \"$TIME\n";

        }
}
close SMS;                                                      #schließt die Datei

#---------------------------------------------------------------------
#********************Verbindung mit der Datenbank*********************
#---------------------------------------------------------------------

#Verbindung mit der Datenbank
my $host = 'localhost';                                         #host
my $database = 'asterisk';                                      #Tabellenname
my $user = 'user';                                              #benutzer
my $pw = 'password';                                           #passwort
my $dsn = "dbi:mysql:$database:localhost:3306";                 #adresse
my $dbh = DBI->connect($dsn, $user, $pw) or die DBI::errstr;    #Verbindung herstellen

#--->1.Suche nach dem Absender
#Datensatz auslesen
my $title = $dbh->prepare("SELECT * FROM Anrufer WHERE Handy = $ABS");#Normaler SQL Befehl
my $control = $title->execute();

#Überprüfen, ob die NUmmer in der Datenbank eingetragen ist, wenn nicht wird das Skript abgebrochen
if($control == undef){
        print "SET VARIABLE vorhanden no\n";
        die DBI::errstr;
}else{
        print "SET VARIABLE vorhanden yes\n";
}

while (my $anrufer = $title->fetchrow_hashref){
        #print $anrufer->{Name};
};

#
#--->2.Suche nach der Nachricht
#Datensatz auslesen (Text für Text to Speech oder Soundfile)
my $problem = $dbh->prepare("SELECT * FROM Probleme WHERE Schluessel = '$MSG'");
$control = $problem->execute();

#Überprüfen, ob der Text in der Datenbank vorhanden ist, wenn ja wird der Name der Sounddatei ausgegeben sonst wird Text to Speech verwendet.
if ($control ne undef){
        #Datensatz in einem Hash speichern
        while (my $probleme = $problem->fetchrow_hashref) {
                my $sound2 = $probleme->{Soundname};
                print "SET VARIABLE sound \"$sound2\n";
                print "SET VARIABLE tts no\n";
                }
}else{
        print "SET VARIABLE tts yes\n";
}

$dbh->disconnect();#trennt die Verbindung zur Datenbank

2.Nummern auslesen und in Arrays speichern
Code:
#!/usr/local/bin/perl

#use strict;
use DBI;
use DBD::mysql;


#---------------------------------------------------------------
#******************Auslesen aus der Datenbank*******************
#---------------------------------------------------------------
my $host = 'localhost';                                         #host
my $database = 'asterisk';                                      #Tabellenname
my $user = 'root';                                              #benutzer
my $pw = '18usc795+';                                           #passwort
my $dsn = "dbi:mysql:$database:localhost:3306";                 #adresse
my $dbh = DBI->connect($dsn, $user, $pw) or die DBI::errstr;    #Verbindung herstellen

my $mitarbeiter = $dbh->prepare("SELECT * FROM Mitarbeiter");
$mitarbeiter->execute;

my $anzahl = $mitarbeiter->execute;

while (my $anrufer = $mitarbeiter->fetchrow_hashref){
};

my $telnum = $dbh->prepare("SELECT m.MID, m.Name, t.Nummer FROM Mitarbeiter AS m INNER JOIN Telefonnummer AS t ON m.MID = t.MID");
$telnum->execute();

my %hash;
my @nummern;
my $l1 = 1;
my $l2 = 1;

while ($l1 <= $anzahl){
        print "Mitarbeiter Nr.$l1\n";
        $telnum->execute();
        while (my $row = $telnum->fetchrow_arrayref){
                if($row->[0] eq "$l1"){
                        foreach my $nummer ($row->[2]){
                                #my @nummern =($row->[2]);
                                #print "$nummern[$zah2]\n";
                                print "$l2. Nummer => $nummer\n";
                                push @{"mitnummer_$l1"}, $nummer;
                        }
                }
        }
        $l1 += 1;#Hochzählen der Mitarbeiternummer
        $l2 += 1;#Hochzähler der Nummer für die Telefonummern
}
$dbh->disconnect();#trennt die Verbindung zur Datenbank

#---------------------------------------------------------------
#*****************Übertragung an Asterisk***********************
#---------------------------------------------------------------

my $mid = $ARGV[0];#gibt die Mitarbeiternummer an
my $numid = $ARGV[1];
my $control;

#Anzahl der Nummern je Mitarbeiter
my $numanzahl = (@{"mitnummer_$mid"}-1);
print "$numanzahl \n";

if($mid <= $anzahl){
        $control = "no";
        print "SET VARIABLE CONTROL \"$control\n";
}else{
        $control = "done";
}       print "SET VARIABLE CONTROL \"$control\n";

if($control ne "done"){
        my $NUM = ${"mitnummer_$mid"}[$numid];
        print "SET VARIABLE NUM \"$NUM\n";
        print "SET VARIABLE NUMANZAHL \"$numanzahl\n";
        print "SET VARIABLE CONTROL \"$control\n";
        $mid += 1;
        $numid += 1;
}else{
        print "SET VARIABLE end ende\n";
};

3.Hier meine extensions.ael
Code:
context eingang {
        1000 => {
                Answer();
                AGI(SMS-Eingang);
                SET(GLOBAL(sound)=${sound});
                SET(GLOBAL(TextToSpeech)=${MSG});
                SET(GLOBAL(tts)=${tts});
                SET(GLOBAL(vorhanden)=${vorhanden});
                NoOp(${vorhanden});
                if(${vorhanden} = yes){
                        jump 2003@spass;
                }else{
                        NoOp("Der Absender ist nicht in der Datenbank vorhanden!");
                }
        }
}


context spass   {
        2003 => {
                SET(GLOBAL(MID)=1);
                SET(GLOBAL(NUMID)=0);
                SET(GLOBAL(CONTROL)="no");
                SET(GLOBAL(NUMANZAHL)=0);
                jump 2002;
        }
        2002 => {
                AGI(Liste,${MID},${NUMID});
                SET(GLOBAL(NUM)=${NUM});
                SET(GLOBAL(NUMANZAHL)=${NUMANZAHL});
                NoOp(${NUMANZAHL});
                SET(GLOBAL(CONTROL)=${CONTROL});
                if(${CONTROL} =done){
                        jump 2007;
                }
                NoOp(${NUM});
                NoOp(${NUMID});
                jump 2004;
        }
        2006 => {
                if(${NUMID}<${NUMANZAHL}){
                        SET(GLOBAL(NUMID)=${MATH(${NUMID}+1,int)});
                        jump 2002;
                }else{
                        SET(GLOBAL(MID)=${MATH(${MID}+1,int)});
                        SET(GLOBAL(NUMID)=0);
                        NoOp(${MID});
                        jump 2002;
                }
        }

        2004 => {
                DIAL(SIP/${NUM},5,G(spass^2005^1));
                if(${DIALSTATUS}=NOANSWER OR CONGESTION OR BUSY){
                        jump 2006;
                }
        }

        2005 => {
                Wait(3);
                if(${tts}=yes){
                        System(rm -rf /tmp/test.wav);
                        System(/opt/swift/bin/swift -o /tmp/test.wav -p audio/sampling-rate=8000,audio/channels=1 "${TextToSpeech}");
                        Playback(/tmp/test);
                }else{
                        Playback(${sound});
                }
                Wait(5);
                Hangup();
                jump 2006;
        }

        2007 => {
                NoOp("FERTIG !!!!!!!!!!!!");
        }
}

So werde nächste Woche oder so noch ne verbesserte Version posten.

ps: teilweise sind überflüssige Codezeilen im Script. Diese haben meistens als Test gedient oder ich weiß nicht dass diese überflüssig sind. :)
 
Zuletzt bearbeitet:
So, hab jetzt fast alles vollständig. Muss nur noch die einzelnen Skripte usw. zusammenfügen und noch nen paar kleinere Verbesserungen machen und Funktionen einfügen. Und dann nochmal alles testen. Falls Interesse besteht werde ich es dann komplett posten.
 
Holen Sie sich 3CX - völlig kostenlos!
Verbinden Sie Ihr Team und Ihre Kunden Telefonie Livechat Videokonferenzen

Gehostet oder selbst-verwaltet. Für bis zu 10 Nutzer dauerhaft kostenlos. Keine Kreditkartendetails erforderlich. Ohne Risiko testen.

3CX
Für diese E-Mail-Adresse besteht bereits ein 3CX-Konto. Sie werden zum Kundenportal weitergeleitet, wo Sie sich anmelden oder Ihr Passwort zurücksetzen können, falls Sie dieses vergessen haben.