Asterisk und Jajah!: Unterschied zwischen den Versionen

Aus NOBAQ
Zur Navigation springenZur Suche springen
(Die Seite wurde neu angelegt: left Wirklich schade, dass es peterzahlt.de nicht für Österreich gibt! So eine Einbindung in Asterisk wär ja wirklich spannend zu machen. Aber da...)
 
 
(3 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
 +
<section begin="head"/>
 
[[Bild:jajaah.gif|left]]
 
[[Bild:jajaah.gif|left]]
 
Wirklich schade, dass es peterzahlt.de nicht für Österreich gibt! So eine Einbindung in Asterisk wär ja wirklich spannend zu machen. Aber dafür hab ich etwas von Jajah gehört (ursprünglich offenbar ein Konkurrenzprodukt zu Skype). Auf der Homepage gibt man seine eigene Nummer an, die Zielnummer und man wird zurück gerufen. Wär einfach interessant, das in Asterisk zu implementieren. Und so hab ich zu hacken begonnen. Ein AGI-Script loggt sich über LWP::UserAgent in Jajah ein, und fordert den Rückruf an.
 
Wirklich schade, dass es peterzahlt.de nicht für Österreich gibt! So eine Einbindung in Asterisk wär ja wirklich spannend zu machen. Aber dafür hab ich etwas von Jajah gehört (ursprünglich offenbar ein Konkurrenzprodukt zu Skype). Auf der Homepage gibt man seine eigene Nummer an, die Zielnummer und man wird zurück gerufen. Wär einfach interessant, das in Asterisk zu implementieren. Und so hab ich zu hacken begonnen. Ein AGI-Script loggt sich über LWP::UserAgent in Jajah ein, und fordert den Rückruf an.
  
Und genau da kommt das große Problem: Der Rückruf kommt sehr schnell! Im Regelfall geht sich nicht einmal ein Hangup() aus. So ist für den eingehenden “Callback”-Anruf die Nebenstelle blockiert und er landet im Anrufbeantworter. Nicht schön. Gesucht wäre also eine Möglichkeit, einen eingehenden Anruf mit einem geantworteten Channel zu verbinden. Dazu hab ich aber leider nichts gefunden :-(. Aber über einen kleinen Hack gehts trotzdem…
+
Und genau da kommt das große Problem: Der Rückruf kommt sehr schnell! Im Regelfall geht sich nicht einmal ein Hangup() aus. So ist für den eingehenden “Callback”-Anruf die Nebenstelle blockiert und er landet im Anrufbeantworter. Nicht schön. Gesucht wäre also eine Möglichkeit, einen eingehenden Anruf mit einem geantworteten Channel zu verbinden. Dazu hab ich aber leider nichts gefunden :-(. Aber über einen kleinen Hack gehts trotzdem...
 +
<section end="head"/>
  
 
Um ehrlich zu sein, hab ich dieses Problem am Anfang gar nicht bedacht und einfach einmal angefangen, das Parser-Script zu hacken. Erst beim Testen kam ich drauf, dass ich da was vergessen hatte.
 
Um ehrlich zu sein, hab ich dieses Problem am Anfang gar nicht bedacht und einfach einmal angefangen, das Parser-Script zu hacken. Erst beim Testen kam ich drauf, dass ich da was vergessen hatte.
Zeile 71: Zeile 73:
 
Der Hauptcode des AGI-Scripts sieht so aus:
 
Der Hauptcode des AGI-Scripts sieht so aus:
  
 +
<source lang="perl">
 
#!/usr/bin/perl
 
#!/usr/bin/perl
  
Zeile 76: Zeile 79:
 
# copyright 2006 nikolaus hammler
 
# copyright 2006 nikolaus hammler
 
# licensed under GNU GPL
 
# licensed under GNU GPL
 +
  
 
use strict;
 
use strict;
Zeile 91: Zeile 95:
 
if($ARGV[0] eq "in")
 
if($ARGV[0] eq "in")
 
{
 
{
print STDERR "Dialin mode\n";
+
  print STDERR "Dialin mode\n";
 
 
my $exten = $input{'callerid'};
 
 
 
my $id = $AGI->get_variable("DB(jajah/$exten)");
 
if($id)
 
{
 
print STDERR "Yes, our callback. exten=$exten, id=$id\n";
 
  
$AGI->exec('DBDel', "jajah/$exten");
+
  my $exten = $input{'callerid'};
 
+
 
if(time() - $id < 120)
+
  my $id = $AGI->get_variable("DB(jajah/$exten)");
{
+
  if($id)
$AGI->exec(’Answer’);
+
  {
$AGI->exec(’MeetMe’, $id|Aqd”);
+
    print STDERR "Yes, our callback. exten=$exten, id=$id\n";
$AGI->exec(’Hangup’);
+
   
}
+
    $AGI->exec('DBDel', "jajah/$exten");
else
+
   
{
+
    if(time() - $id < 120)
print STDERR “Warning: time’s up!\n”;
+
    {
exit 0;
+
      $AGI->exec('Answer');
}
+
      $AGI->exec('MeetMe', "$id|Aqd");
}
+
      $AGI->exec('Hangup');
else
+
    }
{
+
    else
print STDERR “Maybe not our callback, ignoring\n”;
+
    {
exit 0;
+
      print STDERR "Warning: time's up!\n";
}
+
      exit 0;
 +
    }
 +
  }
 +
  else
 +
  {
 +
    print STDERR "Maybe not our callback, ignoring\n";
 +
    exit 0;
 +
  }
 
}
 
}
elsif($ARGV[0] ne “out”)
+
elsif($ARGV[0] ne "out")
 
{
 
{
print STDERR “First argument (mode) must either be ‘in’ or ‘out’\n”;
+
  print STDERR "First argument (mode) must either be 'in' or 'out'\n";
$AGI->exec(’Set’, ‘JAJAH_STATUS=8′);
+
  $AGI->exec('Set', 'JAJAH_STATUS=8');
exit 0;
+
  exit 0;
 
}
 
}
  
print STDERR “Dialout mode\n”;
+
print STDERR "Dialout mode\n";
  
my $UserAgent = ‘Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rev:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1′;
+
my $UserAgent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rev:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1';
  
 
my $ua = LWP::UserAgent->new();
 
my $ua = LWP::UserAgent->new();
Zeile 137: Zeile 141:
 
$ua->cookie_jar(HTTP::Cookies->new);
 
$ua->cookie_jar(HTTP::Cookies->new);
  
my $username = $AGI->get_variable(’JAJAH_USER’);
+
my $username = $AGI->get_variable('JAJAH_USER');
my $password = $AGI->get_variable(’JAJAH_PASS’);
+
my $password = $AGI->get_variable('JAJAH_PASS');
my $jajahnum = $AGI->get_variable(’JAJAH_NUMBER’);
+
my $jajahnum = $AGI->get_variable('JAJAH_NUMBER');
  
print STDERR “Jajah Username: $username\n”;
+
print STDERR "Jajah Username: $username\n";
print STDERR “Jajah Password: $password\n”;
+
print STDERR "Jajah Password: $password\n";
print STDERR “Jajah Number: $jajahnum\n”;
+
print STDERR "Jajah Number: $jajahnum\n";
  
 
if(!$username)
 
if(!$username)
 
{
 
{
print STDERR “No username given. Please set variable JAJAH_USER\n”;
+
  print STDERR "No username given. Please set variable JAJAH_USER\n";
$AGI->exec(’Set’, ‘JAJAH_STATUS=1′);
+
  $AGI->exec('Set', 'JAJAH_STATUS=1');
exit 0;
+
  exit 0;
 
}
 
}
 
if(!$password)
 
if(!$password)
 
{
 
{
print STDERR “No password given. Please set variable JAJAH_PASS\n”;
+
  print STDERR "No password given. Please set variable JAJAH_PASS\n";
$AGI->exec(’Set’, ‘JAJAH_STATUS=2′);
+
  $AGI->exec('Set', 'JAJAH_STATUS=2');
exit 0;
+
  exit 0;
 
}
 
}
 
if(!$jajahnum)
 
if(!$jajahnum)
 
{
 
{
print STDERR “No jajah number given. Please set JAJAH_NUMBER\n”;
+
  print STDERR "No jajah number given. Please set JAJAH_NUMBER\n";
$AGI->exec(’Set’, ‘JAJAH_STATUS=6′);
+
  $AGI->exec('Set', 'JAJAH_STATUS=6');
exit 0;
+
  exit 0;
 
}
 
}
  
my $exten = $input{’agi_extension’};
+
my $exten = $input{'agi_extension'};
  
if($ARGV[1] ne “”)
+
if($ARGV[1] ne "")
 
{
 
{
$exten = $ARGV[1];
+
  $exten = $ARGV[1];
 
}
 
}
  
print STDERR “ToDial: $exten\n”;
+
print STDERR "ToDial: $exten\n";
  
 
if(!$exten)
 
if(!$exten)
 
{
 
{
print STDERR “Don’t know what to dial, sorry\n”;
+
  print STDERR "Don't know what to dial, sorry\n";
$AGI->exec(’Set’, ‘JAJAH_STATUS=3′);
+
  $AGI->exec('Set', 'JAJAH_STATUS=3');
exit 0;
+
  exit 0;
 
}
 
}
  
my $area = ‘43′;
+
my $area = '43';
 
my $number = substr($exten, 1);
 
my $number = substr($exten, 1);
  
if(substr($exten, 0, 2) eq ‘00′)
+
if(substr($exten, 0, 2) eq '00')
 
{
 
{
# fixxme: Was is wenn vorwahl 3-stellig?
+
  # fixxme: Was is wenn vorwahl 3-stellig?
$area = substr($exten, 2, 2);
+
  $area = substr($exten, 2, 2);
$number = substr($exten, 4);
+
  $number = substr($exten, 4);
 
}
 
}
elsif(substr($exten, 0, 1) ne ‘0′)
+
elsif(substr($exten, 0, 1) ne '0')
 
{
 
{
print STDERR “Wrong format. Pleas use prefix 0 for national and prefix 00 for international calls\n”;
+
  print STDERR "Wrong format. Pleas use prefix 0 for national and prefix 00 for international calls\n";
$AGI->exec(’Set’, ‘JAJAH_STATUS=5′);
+
  $AGI->exec('Set', 'JAJAH_STATUS=5');
exit 0;
+
  exit 0;
 
}
 
}
  
$AGI->exec(’Answer’);
+
$AGI->exec('Answer');
$AGI->exec(’Playtones’, ‘ring’);
+
$AGI->exec('Playtones', 'ring');
  
my $html = &PostFormInHTML(’http://www.jajah.com/mini/login.aspx’,
+
my $html = &PostFormInHTML('http://www.jajah.com/mini/login.aspx',
‘theForm’,
+
  'theForm',
{ ‘ctl00$MainContent$Email’ => $username,
+
  { 'ctl00$MainContent$Email' => $username,
‘ctl00$MainContent$Password’ => $password});
+
    'ctl00$MainContent$Password' => $password});
  
 
if($html =~ /Successfully logged in/)
 
if($html =~ /Successfully logged in/)
 
{
 
{
print STDERR “Login success. Trying to dial…\n”;
+
  print STDERR "Login success. Trying to dial...\n";
 +
 
 +
  $html = &PostFormInHTML('http://www.jajah.com/mini/member.aspx?',
 +
  #$html = &PostFormInHTML('http://www.google.com',
 +
    'theForm',
 +
    {'mynumber' => $jajahnum,
 +
    'ctl00$MainContent$CallTo$minidialcode' => $area,
 +
    'ctl00$MainContent$CallTo$mininumber' => $number});
 +
 
 +
  if($html =~ /Active call/)
 +
  {
 +
    print STDERR "Everything seems fine, callback should come shortly\n";
 +
    $AGI->exec('Set', 'JAJAH_STATUS=0');
 +
   
 +
    my $id = time();
 +
   
 +
    $AGI->exec('Set', "DB(jajah/$exten)=$id");
 +
    $AGI->exec('StopPlaytones');
 +
    $AGI->exec('MeetMe', "$id|1Mdqwx");
 +
   
 +
    $AGI->exec('Hangup');
 +
   
 +
    exit 0;
 +
  }
 +
  else
 +
  {
 +
    if(open(DEBUG, ">/tmp/asterisk_jajah_debug.html"))
 +
    {
 +
      print DEBUG $html;
 +
      close(DEBUG);
 +
    }
 +
    print STDERR "Call failed. Maybe you can find debug info in /tmp/asterisk_jajah_debug.html\n";
 +
    $AGI->exec('Set', 'JAJAH_STATUS=7');
 +
    $AGI->exec('StopPlaytones');
 +
  }
 +
}
 +
else
 +
{
 +
  print STDERR "Login failed\n";
 +
  $AGI->exec('Set', 'JAJAH_STATUS=4');
 +
  $AGI->exec('StopPlaytones');
 +
  exit 0;
 +
}
 +
 
 +
sub WebRequest()
 +
{
 +
    my ($url) = @_;
 +
    my $req;
 +
    my $res;
 +
   
 +
    $req = HTTP::Request->new('GET', $url);
 +
   
 +
    $res = $ua->request($req);
 +
   
 +
    if($res->is_error())
 +
    {
 +
      return "";
 +
    }
 +
    return $res->content();
 +
}
 +
 
 +
sub WebPost($;\%;$;)
 +
{
 +
    my ($url, $data, $referer) = @_;
 +
   
 +
    #my $ua;
 +
    my $req;
 +
    my $res;
 +
    my $cookie;
 +
 
 +
    $req = POST $url, $data;
 +
 
 +
    if($referer ne "")
 +
    {
 +
$req->referer($referer);
 +
    }
 +
    $res = $ua->request($req);
 +
    if($res->is_error())
 +
    {
 +
      return "";
 +
    }
 +
   
 +
    if(exists($res->headers->{'location'})) {
 +
return &WebRequest(&UrlGlue($res->headers->{'location'}, $url));
 +
    }
 +
    return $res->content();
 +
}
 +
 
 +
sub UrlGlue()
 +
{
 +
    my ($url, $orig) = @_;
 +
    my $LastDir = substr($orig, 0, rindex($orig, "/"));
 +
    # Get server, if no complete URI is given...
 +
    my $Server = substr($orig, 0, index(substr($orig, 7), "/")+7);
 +
 
 +
    # Niki, 051104
 +
    # one geht nicht, hat offensichtlich auf https umgestellt.
 +
    # handle also also https URLs...hoffentlich
 +
    if(substr($orig, 0, 5) eq "https")
 +
    {
 +
$Server = substr($orig, 0, index(substr($orig, 8), "/")+8);
 +
    }
 +
 
 +
    #print "URL: '$url'\n";
 +
    #print "LastDir: '$LastDir'\n";
 +
    #print "Server: '$Server'\n";
  
$html = &PostFormInHTML(’http://www.jajah.com/mini/member.aspx?’,
+
    if(substr($url, 0, 1) eq "/")
#$html = &PostFormInHTML(’http://www.google.com’,
+
    {
‘theForm’,
+
        # root on server, just add the server!
{’mynumber’ => $jajahnum,
+
        $url = $Server . $url;
‘ctl00$MainContent$CallTo$minidialcode’ => $area,
+
    }
‘ctl00$MainContent$CallTo$mininumber’ => $number});
+
    elsif(substr($url, 0, 4) ne "http")
 +
    {
 +
        # complete relative path...
 +
        $url = $LastDir . "/" . $url;
 +
    }
 +
    return $url;
 +
}
  
if($html =~ /Active call/)
+
sub GetFilename()
 
{
 
{
print STDERR “Everything seems fine, callback should come shortly\n”;
+
    my ($url) = @_;
$AGI->exec(’Set’, ‘JAJAH_STATUS=0′);
+
   
 +
    return substr($url, rindex($url, "/")+1);
 +
}
 +
 
 +
################################### FORMULAR FUNKTIONEN ################################
 +
# Diese Funktionen erlauben es, einfach Zugriff auf ein HTML-Formular zu erlangen und
 +
# abzuschicken, ohne es extra parsen zu muessen
 +
 
 +
my $Form_Name = ""; # Haelt den Namen des Formulars
 +
my $Form_Jump = 0; # Kann auch gegeben viele Formulare ueberspringen!
 +
 
 +
my $Form_Method = ""; # Sendemethode (GET, POST etc)
 +
my $Form_Action = ""; # URL, auf die das Formular geschickt werden soll
 +
my $Form_isOur = 0; # BOOL: Ist true, wenn wir in unserem Formular sind
 +
my $Form_Break = 0; # BOOL: Ist true, wenn wir komplett mit unserem Formular fertig sind
 +
 
 +
# 10.05.2004
 +
my $Form_Submit = ""; # Welches Submitfeld wird genommen? Wenn leer: Standard, sonst das was da drin steht
 +
my $Form_isSubmit = 0; # BOOL: true, wenn es bereits gefunden wurde!
 +
my $Form_SubmitRegexp = 0; # BOOL: Soll mit Hilfe von if ~ gesucht werden (falls z.B. auch der Name Parameter teilweise dynamisch erstellt wurde. Dann dem Parameter ein '~' vorstellen
  
my $id = time();
+
my @Form_Elems = (); # Haelt alle Formularelemente
 +
my $Form_Elems_cnt = 0; # ...und die Anzahl davon
  
$AGI->exec(’Set’, “DB(jajah/$exten)=$id”);
+
my $Form_isTextarea = 0; # BOOL: Befinden wir uns in einer Textarea?
$AGI->exec(’StopPlaytones’);
+
my $Form_isSelect = 0; # BOOL: Befinden wir uns in einer Combobox?
$AGI->exec(’MeetMe’, “$id|1Mdqwx”);
+
my $Form_CatchSelect = 0; # BOOL: falls keine value="" gegeben ist,
 +
# muss zwischen <option> die value stehn...
 +
my $Form_DefaultSelect = ""; # Wenn kein "selected" gegeben, nimm das erste Element
  
$AGI->exec(’Hangup’);
+
# Ruft eine Seite auf, die ein Formular enthaelt, und schickt dieses Formular
 +
# wiederum ab. Gibt die HTML Seite der Zielseite als Skalar zurueck.
 +
# 1. Parameter: URL der Formularseite
 +
# 2. Parameter: Der Formularname, oder das wievielte Formular auf der Seite uns'res ist
 +
# 3. Parameter: Hash-Pointer auf die Elemente, die ausgefuellt/ersetzt werden sollen
 +
# return-Value: HTML Code der Zielseite AS string
  
exit 0;
+
sub PostFormInHTML()
 +
{
 +
    my ($url, $formname, $elems, $submitWith) = @_;
 +
    my $PageContent;
 +
    $PageContent = &WebRequest($url);
 +
    return &__PostFormInHTML($PageContent, $url, $formname, $elems, $submitWith);
 
}
 
}
else
+
 
 +
sub PostFormInHTMLCode()
 +
{
 +
    my ($PageContent, $url, $formname, $elems, $submitWith) = @_;
 +
    return &__PostFormInHTML($PageContent, $url, $formname, $elems, $submitWith);
 +
}
 +
 
 +
sub __PostFormInHTML()
 
{
 
{
if(open(DEBUG, >/tmp/asterisk_jajah_debug.html”))
+
    my ($PageContent, $url, $formname, $elems, $submitWith) = @_;
 +
    #my $PageContent;
 +
    my $p;
 +
    my $i;
 +
    my %PostData;
 +
   
 +
    # Hole mittels normalem GET Request die URL...
 +
    #$PageContent = &WebRequest($url);
 +
   
 +
    # Wenn 2. Parameter eine Zahl ist, ueberspringe soviel Formulare.
 +
    # Wenn nicht, ist das der Name unseres Formulars
 +
    if($formname =~ /^[0-9]+/)
 +
    {
 +
$Form_Jump = ($formname * -1);
 +
$Form_Name = "";
 +
    }
 +
    else
 +
    {
 +
$Form_Name = $formname;
 +
$Form_Jump = 0;
 +
    }
 +
   
 +
    $Form_SubmitRegexp = 0;
 +
    if($submitWith && length($submitWith) > 0)
 +
    {
 +
if(substr($submitWith, 0, 1) eq "~")
 +
{
 +
    $submitWith = substr($submitWith, 1);
 +
    $Form_SubmitRegexp = 1;
 +
}
 +
$Form_Submit = $submitWith;
 +
    } else {
 +
$Form_Submit = "";
 +
    }
 +
    $Form_isSubmit = 0;
 +
   
 +
    # Alle Variablen null setzen
 +
    $Form_isOur = 0;
 +
    $Form_Break = 0;
 +
    $Form_Elems_cnt = 0;
 +
    @Form_Elems = ();
 +
    $Form_isTextarea = 0;
 +
    $Form_isSelect = 0;
 +
    $Form_CatchSelect = 0;
 +
    $Form_DefaultSelect = "";
 +
   
 +
    # Parser anwerfen
 +
    $p = HTML::Parser->new(api_version => 3,
 +
start_h => [\&ParseFormStart, "self,tagname,attr,text"],
 +
text_h => [\&ParseFormText, "text,offset"],
 +
end_h => [\&ParseFormEnd, "tagname"]);
 +
    $p->parse($PageContent);
 +
    $p->eof;
 +
   
 +
    # Uergebene Felder ersetzen / ausfuellen (ins Array)
 +
    for($i = 0; $i < $Form_Elems_cnt; $i++)
 +
    {
 +
my $key;
 +
my $value;
 +
while(($key, $value) = each(%{$elems}))
 +
{
 +
    if($key eq $Form_Elems[$i][0])
 +
    {
 +
$Form_Elems[$i][1] = $value;
 +
    }
 +
}
 +
    }
 +
   
 +
    # Debug! Wenn's bis hier geschafft ist, ist alles getan!
 +
    # Druckt *alle* fertigen Formularelemente aus, incl.
 +
    # Values
 +
    #for($i = 0; $i < $Form_Elems_cnt; $i++)
 +
    #{
 +
    # print STDERR $Form_Elems[$i][0] . " --> " . $Form_Elems[$i][1] . "\n";
 +
    #}
 +
   
 +
    # QND: Das ganze Array in einen Hash kopieren (unnoetig!)
 +
    for($i = 0; $i < $Form_Elems_cnt; $i++)
 +
    {
 +
$PostData{$Form_Elems[$i][0]} = $Form_Elems[$i][1];
 +
    }
 +
   
 +
    # GET Requests werden noch nicht unterstuetzt!
 +
    if($Form_Method =~ /[Gg][Ee][Tt]/)
 +
    {
 +
      # TODO
 +
      return "";
 +
    }
 +
 
 +
    # Falls die action keine komplette URL ist, die URL
 +
    # komplettieren (mit http:// (...))
 +
   
 +
    if($Form_Action eq "")
 +
    {
 +
      $Form_Action = $url;
 +
    }
 +
    else
 +
    {
 +
      $Form_Action = &UrlGlue($Form_Action, $url);
 +
    }
 +
 
 +
    #print STDOUT "FORM-ACTION: $Form_Action\n";
 +
   
 +
    # Den POST Request durchfuehren und den Inhalt der Seite zurueckgeben
 +
    return &WebPost($Form_Action, \%PostData, $url);
 +
}
 +
 
 +
sub DoInputAttr()
 
{
 
{
print DEBUG $html;
+
    my ($attr, $handle_form_submit) = @_;
close(DEBUG);
+
    if($attr->{'name'})
 +
    {
 +
if($attr->{'type'} eq "radio")
 +
{
 +
    my $iFound = 0;
 +
    for(my $i = 0; $i < $Form_Elems_cnt; $i++)
 +
    {
 +
if($Form_Elems[$i][0] eq $attr->{'name'})
 +
{
 +
    $iFound = $i;
 +
    last;
 +
}
 +
    }
 +
   
 +
    # Wenn es das radio noch nicht in der Liste ist, fuege es hinzu
 +
    if(!$iFound)
 +
    {
 +
$Form_Elems[$Form_Elems_cnt][0] = $attr->{'name'};
 +
$Form_Elems[$Form_Elems_cnt][1] = $attr->{'value'};
 +
$Form_Elems_cnt++;
 +
    }
 +
    else
 +
    {
 +
# Wenn es gefunden wurde, aber gecheckt ist, ueberschreibe das Attribut
 +
if($attr->{'checked'})
 +
{
 +
    $Form_Elems[$iFound][1] = $attr->{'value'};
 +
}
 +
    }
 +
}
 +
else
 +
{
 +
        $Form_Elems[$Form_Elems_cnt][0] = $attr->{'name'};
 +
        $Form_Elems[$Form_Elems_cnt][1] = $attr->{'value'};
 +
        $Form_Elems_cnt++;
 +
}
 +
    }
 +
    if($handle_form_submit && $attr->{'type'} eq "submit")
 +
    {
 +
        $Form_isSubmit = 1;
 +
    }
 
}
 
}
print STDERR “Call failed. Maybe you can find debug info in /tmp/asterisk_jajah_debug.html\n”;
+
 
$AGI->exec(’Set’, ‘JAJAH_STATUS=7′);
+
sub ParseFormStart()
$AGI->exec(’StopPlaytones’);
+
{
 +
    my ($self, $tagname, $attr, $src) = @_;
 +
    my $handle_form_submit = 0;
 +
   
 +
    if($Form_Break)
 +
    {
 +
return;
 +
    }
 +
   
 +
    if($tagname eq "form")
 +
    {
 +
if($Form_Name ne "")
 +
{
 +
    if($attr->{'name'} eq $Form_Name)
 +
    {
 +
if($attr->{'method'})
 +
{
 +
    $Form_Method = $attr->{'method'};
 +
}
 +
else
 +
{
 +
    $Form_Method = "";
 +
}
 +
if($attr->{'action'})
 +
{
 +
    $Form_Action = $attr->{'action'};
 +
}
 +
else
 +
{
 +
    print STDERR "WARNING: Das gewaehlte Formular hat keine action-Eigenschaft!\n";
 +
    $Form_Action = '';
 +
}
 +
$Form_isOur = 1;
 +
    }
 +
}
 +
else
 +
{
 +
    $Form_Jump++;
 +
    if($Form_Jump > 0)
 +
    {
 +
if($attr->{'method'})
 +
                {
 +
                    $Form_Method = $attr->{'method'};
 +
                }
 +
                else
 +
                {
 +
                    $Form_Method = "";
 +
                }
 +
                if($attr->{'action'})
 +
                {
 +
                    $Form_Action = $attr->{'action'};
 +
                }
 +
                else
 +
                {
 +
                    die("Das gewaehlte Formular hat keine action-Eigenschaft!\n");
 +
                }
 +
$Form_isOur = 1;
 +
    }
 +
}
 +
    }
 +
   
 +
    if($Form_isOur)
 +
    {
 +
if($tagname eq "input")
 +
{
 +
    if($Form_Submit ne "")
 +
    {
 +
if($Form_SubmitRegexp)
 +
{
 +
    if($attr->{'name'} =~ /$Form_Submit/)
 +
    {
 +
        $handle_form_submit = 1;
 +
    }
 +
    else
 +
    {
 +
        $handle_form_submit = 0;
 +
    }
 +
} else {
 +
    if($attr->{'name'} eq $Form_Submit)
 +
    {
 +
        $handle_form_submit = 1;
 +
    }
 +
    else
 +
    {
 +
        $handle_form_submit = 0;
 +
    }
 +
}
 +
    }
 +
 +
    if($attr->{'type'} ne "submit" || $Form_Submit eq "" || ($handle_form_submit && $Form_isSubmit == 0))
 +
    {
 +
&DoInputAttr($attr, $handle_form_submit);
 +
    }
 +
}
 +
if($tagname eq "textarea")
 +
{
 +
    $Form_isTextarea = 1;
 +
    $Form_Elems[$Form_Elems_cnt][0] = $attr->{'name'};
 +
}
 +
if($tagname eq "select")
 +
{
 +
    $Form_isSelect = 1;
 +
    $Form_Elems[$Form_Elems_cnt][0] = $attr->{'name'};
 +
    $Form_Elems[$Form_Elems_cnt][1] = "";
 +
}
 +
if($Form_isSelect && $tagname eq "option")
 +
{
 +
    if($Form_DefaultSelect eq "")
 +
    {
 +
    $Form_DefaultSelect = $attr->{'value'};
 +
    }
 +
    if($attr->{'selected'})
 +
    {
 +
if($attr->{'value'} ne "")
 +
{
 +
    $Form_Elems[$Form_Elems_cnt][1] = $attr->{'value'};
 +
}
 +
else
 +
{
 +
    $Form_CatchSelect = 1;
 +
}
 +
    }
 +
}
 +
    }
 
}
 
}
 +
 +
sub ParseFormText()
 +
{
 +
    my ($dtext, $offset) = @_;
 +
   
 +
    if($Form_Break)
 +
    {
 +
return;
 +
    }
 +
   
 +
    if($Form_isOur)
 +
    {
 +
if($Form_isTextarea)
 +
{
 +
    $Form_Elems[$Form_Elems_cnt][1] = $dtext;
 +
}
 +
if($Form_CatchSelect)
 +
{
 +
    $Form_Elems[$Form_Elems_cnt][1] = $dtext;
 +
    $Form_CatchSelect = 0;
 +
}
 +
    }
 
}
 
}
else
+
 
 +
sub ParseFormEnd()
 
{
 
{
print STDERR “Login failed\n”;
+
    my ($tagname) = @_;
$AGI->exec(’Set’, ‘JAJAH_STATUS=4′);
+
   
$AGI->exec(’StopPlaytones’);
+
    if($Form_Break)
exit 0;
+
    {
 +
return;
 +
    }
 +
   
 +
    if($Form_isOur)
 +
    {
 +
if($tagname eq "form")
 +
{
 +
    $Form_isOur = 0;
 +
    $Form_Break = 0;
 +
}
 +
if($Form_isTextarea && $tagname eq "textarea")
 +
        {
 +
    $Form_Elems_cnt++;
 +
    $Form_isTextarea = 0;
 +
}
 +
if($Form_isSelect && $tagname eq "select")
 +
{
 +
    if($Form_Elems[$Form_Elems_cnt][1] eq "")
 +
    {
 +
    $Form_Elems[$Form_Elems_cnt][1] = $Form_DefaultSelect;
 +
$Form_DefaultSelect = "";
 +
    }
 +
    $Form_Elems_cnt++;
 +
    $Form_isSelect = 0;
 +
}
 +
    }
 
}
 
}
 +
</source>
  
 
Den ganzen Code hab ich als Attachment hinzugefügt.
 
Den ganzen Code hab ich als Attachment hinzugefügt.
Zeile 254: Zeile 728:
 
Conclusio: Das ganze war lustig zum programmieren, aber verwendet hab ichs nie weil ich erst später draufgekommen bin, das Jajah nur so unwesentlich billiger ist, dass es sich gar nicht auszahlt.
 
Conclusio: Das ganze war lustig zum programmieren, aber verwendet hab ichs nie weil ich erst später draufgekommen bin, das Jajah nur so unwesentlich billiger ist, dass es sich gar nicht auszahlt.
 
[[Media:jajahagi.txt]]
 
[[Media:jajahagi.txt]]
 +
 +
= Kommentare =
 +
 +
<comments />{{:{{TALKSPACE}}:{{PAGENAME}}}}
 +
 +
[[Kategorie:Weblog]]

Aktuelle Version vom 2. Mai 2009, 21:57 Uhr

Jajaah.gif

Wirklich schade, dass es peterzahlt.de nicht für Österreich gibt! So eine Einbindung in Asterisk wär ja wirklich spannend zu machen. Aber dafür hab ich etwas von Jajah gehört (ursprünglich offenbar ein Konkurrenzprodukt zu Skype). Auf der Homepage gibt man seine eigene Nummer an, die Zielnummer und man wird zurück gerufen. Wär einfach interessant, das in Asterisk zu implementieren. Und so hab ich zu hacken begonnen. Ein AGI-Script loggt sich über LWP::UserAgent in Jajah ein, und fordert den Rückruf an.

Und genau da kommt das große Problem: Der Rückruf kommt sehr schnell! Im Regelfall geht sich nicht einmal ein Hangup() aus. So ist für den eingehenden “Callback”-Anruf die Nebenstelle blockiert und er landet im Anrufbeantworter. Nicht schön. Gesucht wäre also eine Möglichkeit, einen eingehenden Anruf mit einem geantworteten Channel zu verbinden. Dazu hab ich aber leider nichts gefunden :-(. Aber über einen kleinen Hack gehts trotzdem...


Um ehrlich zu sein, hab ich dieses Problem am Anfang gar nicht bedacht und einfach einmal angefangen, das Parser-Script zu hacken. Erst beim Testen kam ich drauf, dass ich da was vergessen hatte.

Da es offenbar nicht möglich ist, zwei angenommene Channels zu verbinden, kam mir eine Idee: MeetMe() brauch ich ja sonst zu nix, aber da könnte es sich als nützlich erweisen! Bingo!

Vorgangsweise: Man will jemand anrufen. Asterisk überprüft, ob Jajah für den Anruf die günstigste Methode ist und ruft das AGI-Script auf. Dieses loggt sich ein und fordert den Callback an. Während des AGI-Scripts wird das ring-Signal eingespielt. Sofort danach wird ein Konferenzraum mit MeetMe() geöffnet, der solange MoH (Music On Hold) spielt, bis der “markierte” Anruf den Raum betritt. Dann sind die beiden Gespräche verbunden.

Glücklicherweise (?) spooft Jajah die CallerID, sodass der Callback-Anruf die CallerID meiner Wunschdestination hat. Also speichere ich kurz nach dem AGI-Script einen Unix-Timestamp mit der passenden CallerID in die Datenbank (AstDB).

Kommt nun ein Anruf herein, wird überprüft, ob ein Eintrag in der Datenbank existiert. Falls ja, wird er auf alle Fälle gelöscht. Ist dieser in einem Toleranzzeitraum (z.B. 1 Minute, es wird ja der Timestamp gespeichert), wird ebenfalls als markierte Person MeeMe() aufgerufen mit dem Timestamp als Konferenzraum-ID. Die Anrufer sind verbunden und alles ist normal. Ist das Timeout abgelaufen, so wird ganz einfach der Anruf weitergegeben.

Zusätzlich setzt das AGI-Script eine Variable JAJAH_STATUS. Damit ist es möglich zu prüfen, ob der Anruf ergolgreich war. Falls nein, kann als Fallback ein anderes Netz gewählt werden.

Anfangs hatte ich das ganze als komplizierten Dialplan drinnen und das AGI-Script übernahm nur das Parsing. Mittlerweile hab ich alles in das AGI-Script verpackt und es reichen wenige Funktionen im Dialplan

Seit neustem verwende ich zum Glück (!) AEL, sodass ich die Fragmente hier nur mehr als AEL-Code angib. Im Endeffekt muss folgendes Makro hinzugefügt werden:

macro isJajahCallback() {
	AGI(jajah.agi,in);
};

Man beachte den Parameter “in” für den eingehenden Rückruf. In den Wählplan wird das im Input-Trunk einfach eingebunden:

context capi-in {
	s => {
		&hangupWhenChanBusy();
		&isJajahCallback();
		[...]
	};
};

Für das Wählen legt man sich am besten einen eigenen Context an, zu dem man bei Bedarf springt:

context jajah {
	_9X. => {
		NUM=${EXTEN:1};
		JAJAH_USER=jajah_username;
		JAJAH_PASS=jajah_password;
		JAJAH_NUMBER=registered_jajah_number;
		AGI(jajah.agi,out,${NUM});
		if(${JAJAH_STATUS} != 0) {
			// Hier gehört stattdessen eine Fallbackbehandlung her!
			Answer();
			SayNumber(${JAJAH_STATUS});
			Playtones(info);
			Wait(60);
			StopPlaytones();
			Hangup();
		};

	t => {
		Playtones(info);
		Wait(60);
		StopPlaytones();
		Hangup();
		};
};

Wiederum beachte man den zweiten Parameter “out” für “Herauswahl”. Das ist schon das einzige, was man im Dialplan machen muss. Den Rest erledigt das AGI-Script! Es müdden halt die Module für die Datenbank und MeetMe vorhanden und geladen sein.

Der Hauptcode des AGI-Scripts sieht so aus:

#!/usr/bin/perl

# Asterisk --> Jajah Gateway
# copyright 2006 nikolaus hammler
# licensed under GNU GPL


use strict;
use LWP::UserAgent;
#use LWP::Debug qw(+);
use HTML::Parser;
use HTTP::Cookies;
use HTTP::Request::Common qw(POST);
use Asterisk::AGI;

my $AGI = new Asterisk::AGI;

my %input = $AGI->ReadParse();

if($ARGV[0] eq "in")
{
  print STDERR "Dialin mode\n";

  my $exten = $input{'callerid'};
  
  my $id = $AGI->get_variable("DB(jajah/$exten)");
  if($id)
  {
    print STDERR "Yes, our callback. exten=$exten, id=$id\n";
    
    $AGI->exec('DBDel', "jajah/$exten");
    
    if(time() - $id < 120)
    {
      $AGI->exec('Answer');
      $AGI->exec('MeetMe', "$id|Aqd");
      $AGI->exec('Hangup');
    }
    else
    {
      print STDERR "Warning: time's up!\n";
      exit 0;
    }
  }
  else
  {
    print STDERR "Maybe not our callback, ignoring\n";
    exit 0;
  }
}
elsif($ARGV[0] ne "out")
{
  print STDERR "First argument (mode) must either be 'in' or 'out'\n";
  $AGI->exec('Set', 'JAJAH_STATUS=8');
  exit 0;
}

print STDERR "Dialout mode\n";

my $UserAgent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rev:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1';

my $ua = LWP::UserAgent->new();

$ua->agent($UserAgent);

$ua->cookie_jar(HTTP::Cookies->new);

my $username = $AGI->get_variable('JAJAH_USER');
my $password = $AGI->get_variable('JAJAH_PASS');
my $jajahnum = $AGI->get_variable('JAJAH_NUMBER');

print STDERR "Jajah Username: $username\n";
print STDERR "Jajah Password: $password\n";
print STDERR "Jajah Number: $jajahnum\n";

if(!$username)
{
  print STDERR "No username given. Please set variable JAJAH_USER\n";
  $AGI->exec('Set', 'JAJAH_STATUS=1');
  exit 0;
}
if(!$password)
{
  print STDERR "No password given. Please set variable JAJAH_PASS\n";
  $AGI->exec('Set', 'JAJAH_STATUS=2');
  exit 0;
}
if(!$jajahnum)
{
  print STDERR "No jajah number given. Please set JAJAH_NUMBER\n";
  $AGI->exec('Set', 'JAJAH_STATUS=6');
  exit 0;
}

my $exten = $input{'agi_extension'};

if($ARGV[1] ne "")
{
  $exten = $ARGV[1];
}

print STDERR "ToDial: $exten\n";

if(!$exten)
{
  print STDERR "Don't know what to dial, sorry\n";
  $AGI->exec('Set', 'JAJAH_STATUS=3');
  exit 0;
}

my $area = '43';
my $number = substr($exten, 1);

if(substr($exten, 0, 2) eq '00')
{
  # fixxme: Was is wenn vorwahl 3-stellig?
  $area = substr($exten, 2, 2);
  $number = substr($exten, 4);
}
elsif(substr($exten, 0, 1) ne '0')
{
  print STDERR "Wrong format. Pleas use prefix 0 for national and prefix 00 for international calls\n";
  $AGI->exec('Set', 'JAJAH_STATUS=5');
  exit 0;
}

$AGI->exec('Answer');
$AGI->exec('Playtones', 'ring');

my $html = &PostFormInHTML('http://www.jajah.com/mini/login.aspx',
  'theForm',
  { 'ctl00$MainContent$Email' => $username,
    'ctl00$MainContent$Password' => $password});

if($html =~ /Successfully logged in/)
{
  print STDERR "Login success. Trying to dial...\n";
  
  $html = &PostFormInHTML('http://www.jajah.com/mini/member.aspx?',
  #$html = &PostFormInHTML('http://www.google.com',
    'theForm',
    {'mynumber' => $jajahnum,
     'ctl00$MainContent$CallTo$minidialcode' => $area,
     'ctl00$MainContent$CallTo$mininumber' => $number});
  
  if($html =~ /Active call/)
  {
    print STDERR "Everything seems fine, callback should come shortly\n";
    $AGI->exec('Set', 'JAJAH_STATUS=0');
    
    my $id = time();
    
    $AGI->exec('Set', "DB(jajah/$exten)=$id");
    $AGI->exec('StopPlaytones');
    $AGI->exec('MeetMe', "$id|1Mdqwx");
    
    $AGI->exec('Hangup');
    
    exit 0;
  }
  else
  {
    if(open(DEBUG, ">/tmp/asterisk_jajah_debug.html"))
    {
      print DEBUG $html;
      close(DEBUG);
    }
    print STDERR "Call failed. Maybe you can find debug info in /tmp/asterisk_jajah_debug.html\n";
    $AGI->exec('Set', 'JAJAH_STATUS=7');
    $AGI->exec('StopPlaytones');
  }
}
else
{
  print STDERR "Login failed\n";
  $AGI->exec('Set', 'JAJAH_STATUS=4');
  $AGI->exec('StopPlaytones');
  exit 0;
}

sub WebRequest()
{
    my ($url) = @_;
    my $req;
    my $res;
    
    $req = HTTP::Request->new('GET', $url);
    
    $res = $ua->request($req);
    
    if($res->is_error())
    {
      return "";
    }
    return $res->content();
}

sub WebPost($;\%;$;)
{
    my ($url, $data, $referer) = @_;
    
    #my $ua;
    my $req;
    my $res;
    my $cookie;

    $req = POST $url, $data;

    if($referer ne "")
    {
	$req->referer($referer);
    }
    $res = $ua->request($req);
    if($res->is_error())
    {
      return "";
    }
    
    if(exists($res->headers->{'location'})) {
	return &WebRequest(&UrlGlue($res->headers->{'location'}, $url));
    }
    return $res->content();
}

sub UrlGlue()
{
    my ($url, $orig) = @_;
    my $LastDir = substr($orig, 0, rindex($orig, "/"));
    # Get server, if no complete URI is given...
    my $Server = substr($orig, 0, index(substr($orig, 7), "/")+7);

    # Niki, 051104
    # one geht nicht, hat offensichtlich auf https umgestellt.
    # handle also also https URLs...hoffentlich
    if(substr($orig, 0, 5) eq "https")
    {
	$Server = substr($orig, 0, index(substr($orig, 8), "/")+8);
    }

    #print "URL: '$url'\n";
    #print "LastDir: '$LastDir'\n";
    #print "Server: '$Server'\n";

    if(substr($url, 0, 1) eq "/")
    {
        # root on server, just add the server!
        $url = $Server . $url;
    }
    elsif(substr($url, 0, 4) ne "http")
    {
        # complete relative path...
        $url = $LastDir . "/" . $url;
    }
    return $url;
}

sub GetFilename()
{
    my ($url) = @_;
    
    return substr($url, rindex($url, "/")+1);
}

################################### FORMULAR FUNKTIONEN ################################
# Diese Funktionen erlauben es, einfach Zugriff auf ein HTML-Formular zu erlangen und
# abzuschicken, ohne es extra parsen zu muessen

my $Form_Name = "";		# Haelt den Namen des Formulars
my $Form_Jump = 0;		# Kann auch gegeben viele Formulare ueberspringen!

my $Form_Method = "";		# Sendemethode (GET, POST etc)
my $Form_Action = "";		# URL, auf die das Formular geschickt werden soll
my $Form_isOur = 0;		# BOOL: Ist true, wenn wir in unserem Formular sind
my $Form_Break = 0;		# BOOL: Ist true, wenn wir komplett mit unserem Formular fertig sind

# 10.05.2004
my $Form_Submit = "";		# Welches Submitfeld wird genommen? Wenn leer: Standard, sonst das was da drin steht
my $Form_isSubmit = 0;		# BOOL: true, wenn es bereits gefunden wurde!
my $Form_SubmitRegexp = 0;	# BOOL: Soll mit Hilfe von if ~ gesucht werden (falls z.B. auch der Name Parameter teilweise dynamisch erstellt wurde. Dann dem Parameter ein '~' vorstellen

my @Form_Elems = ();		# Haelt alle Formularelemente
my $Form_Elems_cnt = 0;		# ...und die Anzahl davon

my $Form_isTextarea = 0;	# BOOL: Befinden wir uns in einer Textarea?
my $Form_isSelect = 0;		# BOOL: Befinden wir uns in einer Combobox?
my $Form_CatchSelect = 0;	# BOOL: falls keine value="" gegeben ist,
				# muss zwischen <option> die value stehn...
my $Form_DefaultSelect = "";	# Wenn kein "selected" gegeben, nimm das erste Element

# Ruft eine Seite auf, die ein Formular enthaelt, und schickt dieses Formular
# wiederum ab. Gibt die HTML Seite der Zielseite als Skalar zurueck.
# 1. Parameter: URL der Formularseite
# 2. Parameter: Der Formularname, oder das wievielte Formular auf der Seite uns'res ist
# 3. Parameter: Hash-Pointer auf die Elemente, die ausgefuellt/ersetzt werden sollen
# return-Value: HTML Code der Zielseite AS string

sub PostFormInHTML()
{
    my ($url, $formname, $elems, $submitWith) = @_;
    my $PageContent;
    $PageContent = &WebRequest($url);
    return &__PostFormInHTML($PageContent, $url, $formname, $elems, $submitWith);
}

sub PostFormInHTMLCode()
{
    my ($PageContent, $url, $formname, $elems, $submitWith) = @_;
    return &__PostFormInHTML($PageContent, $url, $formname, $elems, $submitWith);
}

sub __PostFormInHTML()
{
    my ($PageContent, $url, $formname, $elems, $submitWith) = @_;
    #my $PageContent;
    my $p;
    my $i;
    my %PostData;
    
    # Hole mittels normalem GET Request die URL...
    #$PageContent = &WebRequest($url);
    
    # Wenn 2. Parameter eine Zahl ist, ueberspringe soviel Formulare.
    # Wenn nicht, ist das der Name unseres Formulars
    if($formname =~ /^[0-9]+/)
    {
	$Form_Jump = ($formname * -1);
	$Form_Name = "";
    }
    else
    {
	$Form_Name = $formname;
	$Form_Jump = 0;
    }
    
    $Form_SubmitRegexp = 0;
    if($submitWith && length($submitWith) > 0)
    {
	if(substr($submitWith, 0, 1) eq "~")
	{
	    $submitWith = substr($submitWith, 1);
	    $Form_SubmitRegexp = 1;
	}
	$Form_Submit = $submitWith;
    } else {
	$Form_Submit = "";
    }
    $Form_isSubmit = 0;
    
    # Alle Variablen null setzen
    $Form_isOur = 0;
    $Form_Break = 0;
    $Form_Elems_cnt = 0;
    @Form_Elems = ();
    $Form_isTextarea = 0;
    $Form_isSelect = 0;
    $Form_CatchSelect = 0;
    $Form_DefaultSelect = "";
    
    # Parser anwerfen
    $p = HTML::Parser->new(api_version => 3,
	start_h => [\&ParseFormStart, "self,tagname,attr,text"],
	text_h => [\&ParseFormText, "text,offset"],
	end_h => [\&ParseFormEnd, "tagname"]);
    $p->parse($PageContent);
    $p->eof;
    
    # Uergebene Felder ersetzen / ausfuellen (ins Array)
    for($i = 0; $i < $Form_Elems_cnt; $i++)
    {
	my $key;
	my $value;
	while(($key, $value) = each(%{$elems}))
	{
	    if($key eq $Form_Elems[$i][0])
	    {
		$Form_Elems[$i][1] = $value;
	    }
	}
    }
    
    # Debug! Wenn's bis hier geschafft ist, ist alles getan!
    # Druckt *alle* fertigen Formularelemente aus, incl.
    # Values
    #for($i = 0; $i < $Form_Elems_cnt; $i++)
    #{
    #	print STDERR $Form_Elems[$i][0] . " --> " . $Form_Elems[$i][1] . "\n";
    #}
    
    # QND: Das ganze Array in einen Hash kopieren (unnoetig!)
    for($i = 0; $i < $Form_Elems_cnt; $i++)
    {
	$PostData{$Form_Elems[$i][0]} = $Form_Elems[$i][1];
    }
    
    # GET Requests werden noch nicht unterstuetzt!
    if($Form_Method =~ /[Gg][Ee][Tt]/)
    {
      # TODO
      return "";
    }

    # Falls die action keine komplette URL ist, die URL
    # komplettieren (mit http:// (...))
    
    if($Form_Action eq "")
    {
      $Form_Action = $url;
    }
    else
    {
      $Form_Action = &UrlGlue($Form_Action, $url);
    }

    #print STDOUT "FORM-ACTION: $Form_Action\n";
    
    # Den POST Request durchfuehren und den Inhalt der Seite zurueckgeben
    return &WebPost($Form_Action, \%PostData, $url);
}

sub DoInputAttr()
{
    my ($attr, $handle_form_submit) = @_;
    if($attr->{'name'})
    {
	if($attr->{'type'} eq "radio")
	{
	    my $iFound = 0;
	    for(my $i = 0; $i < $Form_Elems_cnt; $i++)
	    {
		if($Form_Elems[$i][0] eq $attr->{'name'})
		{
		    $iFound = $i;
		    last;
		}
	    }
	    
	    # Wenn es das radio noch nicht in der Liste ist, fuege es hinzu
	    if(!$iFound)
	    {
		$Form_Elems[$Form_Elems_cnt][0] = $attr->{'name'};
		$Form_Elems[$Form_Elems_cnt][1] = $attr->{'value'};
		$Form_Elems_cnt++;
	    }
	    else
	    {
		# Wenn es gefunden wurde, aber gecheckt ist, ueberschreibe das Attribut
		if($attr->{'checked'})
		{
		    $Form_Elems[$iFound][1] = $attr->{'value'};
		}
	    }
	}
	else
	{
    	    $Form_Elems[$Form_Elems_cnt][0] = $attr->{'name'};
    	    $Form_Elems[$Form_Elems_cnt][1] = $attr->{'value'};
    	    $Form_Elems_cnt++;
	}
    }
    if($handle_form_submit && $attr->{'type'} eq "submit")
    {
        $Form_isSubmit = 1;
    }
}

sub ParseFormStart()
{
    my ($self, $tagname, $attr, $src) = @_;
    my $handle_form_submit = 0;
    
    if($Form_Break)
    {
	return;
    }
    
    if($tagname eq "form")
    {
	if($Form_Name ne "")
	{
	    if($attr->{'name'} eq $Form_Name)
	    {
		if($attr->{'method'})
		{
		    $Form_Method = $attr->{'method'};
		}
		else
		{
		    $Form_Method = "";
		}
		if($attr->{'action'})
		{
		    $Form_Action = $attr->{'action'};
		}
		else
		{
		    print STDERR "WARNING: Das gewaehlte Formular hat keine action-Eigenschaft!\n";
		    $Form_Action = '';
		}
		$Form_isOur = 1;
	    }
	}
	else
	{
	    $Form_Jump++;
	    if($Form_Jump > 0)
	    {
		if($attr->{'method'})
                {
                    $Form_Method = $attr->{'method'};
                }
                else
                {
                    $Form_Method = "";
                }
                if($attr->{'action'})
                {
                    $Form_Action = $attr->{'action'};
                }
                else
                {
                    die("Das gewaehlte Formular hat keine action-Eigenschaft!\n");
                }
		$Form_isOur = 1;
	    }
	}
    }
    
    if($Form_isOur)
    {
	if($tagname eq "input")
	{
	    if($Form_Submit ne "")
	    {
		if($Form_SubmitRegexp)
		{
		    if($attr->{'name'} =~ /$Form_Submit/)
		    {
		        $handle_form_submit = 1;
		    }
		    else
		    {
		        $handle_form_submit = 0;
		    }
		} else {
		    if($attr->{'name'} eq $Form_Submit)
		    {
		        $handle_form_submit = 1;
		    }
		    else
		    {
		        $handle_form_submit = 0;
		    }
		}
	    }
		
	    if($attr->{'type'} ne "submit" || $Form_Submit eq "" || ($handle_form_submit && $Form_isSubmit == 0))
	    {
		&DoInputAttr($attr, $handle_form_submit);
	    }
	}
	if($tagname eq "textarea")
	{
	    $Form_isTextarea = 1;
	    $Form_Elems[$Form_Elems_cnt][0] = $attr->{'name'};
	}
	if($tagname eq "select")
	{
	    $Form_isSelect = 1;
	    $Form_Elems[$Form_Elems_cnt][0] = $attr->{'name'};
	    $Form_Elems[$Form_Elems_cnt][1] = "";
	}
	if($Form_isSelect && $tagname eq "option")
	{
	    if($Form_DefaultSelect eq "")
	    {
	    	$Form_DefaultSelect = $attr->{'value'};
	    }
	    if($attr->{'selected'})
	    {
		if($attr->{'value'} ne "")
		{
		    $Form_Elems[$Form_Elems_cnt][1] = $attr->{'value'};
		}
		else
		{
		    $Form_CatchSelect = 1;
		}
	    }
	}
    }
}

sub ParseFormText()
{
    my ($dtext, $offset) = @_;
    
    if($Form_Break)
    {
	return;
    }
    
    if($Form_isOur)
    {
	if($Form_isTextarea)
	{
	    $Form_Elems[$Form_Elems_cnt][1] = $dtext;
	}
	if($Form_CatchSelect)
	{
	    $Form_Elems[$Form_Elems_cnt][1] = $dtext;
	    $Form_CatchSelect = 0;
	}
    }
}

sub ParseFormEnd()
{
    my ($tagname) = @_;
    
    if($Form_Break)
    {
	return;
    }
    
    if($Form_isOur)
    {
	if($tagname eq "form")
	{
	    $Form_isOur = 0;
	    $Form_Break = 0;
	}
	if($Form_isTextarea && $tagname eq "textarea")
        {
	    $Form_Elems_cnt++;
	    $Form_isTextarea = 0;
	}
	if($Form_isSelect && $tagname eq "select")
	{
	    if($Form_Elems[$Form_Elems_cnt][1] eq "")
	    {
	    	$Form_Elems[$Form_Elems_cnt][1] = $Form_DefaultSelect;
		$Form_DefaultSelect = "";
	    }
	    $Form_Elems_cnt++;
	    $Form_isSelect = 0;
	}
    }
}

Den ganzen Code hab ich als Attachment hinzugefügt.

Conclusio: Das ganze war lustig zum programmieren, aber verwendet hab ichs nie weil ich erst später draufgekommen bin, das Jajah nur so unwesentlich billiger ist, dass es sich gar nicht auszahlt. Media:jajahagi.txt

Kommentare

<comments />Diskussion:Asterisk und Jajah!