Aus Linux-Magazin 01/2011

Perl-Skript analysiert Konversationsinhalte beim Chat (Seite 2)

Listing 1:
»irc2ym«

01 #!/usr/local/bin/perl -w
02 use strict;
03 use local::lib;
04
05 ###########################################
06 package YMBot;
07 ###########################################
08 use base qw( Bot::BasicBot );
09 use FindBin qw($Bin);
10
11 my $ymsend       = "$Bin/ymsend";
12 my($home)        = glob "~";
13 my $KEYWORD_LIST_FILE =
14                   "$home/.irc2ym-keywords";
15 my @KEYWORD_LIST = ();
16
17 keyword_list_read();
18
19 ###########################################
20 sub said {
21 ###########################################
22   my($self, $data) = @_;
23
24   if( keyword_match( $data->{body} ) ) {
25     my $rc = system($ymsend,
26      "$data->{who} said: '$data->{body}'");
27     warn "$ymsend failed: $!" if $rc;
28   }
29
30   return $data;
31 }
32
33 ###########################################
34 sub keyword_list_read {
35 ###########################################
36   if( !open FILE, "<$KEYWORD_LIST_FILE" ) {
37     warn "$KEYWORD_LIST_FILE not found";
38     return;
39   }
40
41   while(<FILE>) {
42     chomp;
43     s/#.*//;
44     next if /^s*$/;
45     push @KEYWORD_LIST, $_;
46   }
47   close FILE;
48 }
49
50 ###########################################
51 sub keyword_match {
52 ###########################################
53   my($said) = @_;
54
55   for my $regex (@KEYWORD_LIST) {
56     return 1 if $said =~ /$regex/i;
57   }
58   return 0;
59 }
60
61 ###########################################
62 package main;
63 ###########################################
64 use Bot::BasicBot;
65
66 my $bot = YMBot->new(
67   server    => "irc.freenode.com",
68   channels  => ["#ymtest"],
69   nick      => "ymbot",
70   name      => "Relay to Y!M",
71   charset   => "utf-8",
72 );
73
74 $bot->run();

In diesem Callback ruft der Bot in Zeile 24 die weiter unten definierte Funktion »keyword_match()« auf, die den Nachrichtentext mit einer Liste vorher eingelesener Schlüsselwörter aus der Datei »~/.irc2ym-keywords« vergleicht. Das Skript liest deren Zeilen zu Beginn in den globalen Array »@KEYWORD_LIST« ein.

Passt einer der im Array »@KEYWORD_LIST« gespeicherten regulären Ausdrücke, triggert Zeile 25 das im selben Verzeichnis liegende Skript »ymsend«. Dieses nimmt den Nachrichtentext auf der Kommandozeile entgegen, loggt sich auf dem Web-API ein, führt einige Autorisierungsschritte nach dem Oauth-Protokoll aus und schickt schließlich den Nachrichtentext an den in der Variablen »$recipient« kodierten User.

Die Interaktion mit dem Yahoo-Web-API erfordert vom Skript einige Bocksprünge mit dem voreingestellten Messenger-User, dessen Passwort sowie einem auf [developer.yahoo.com] einzuholenden API-Key und einem “Shared Secret” für die Applikation.

Oauth-Dschungel

Mit Oauth [4] gibt ein authentifizierter User einen Token an eine Applikation weiter, die dann in seinem Namen für eine bestimmte Zeit Aktionen ausführen kann. Im Fall des Messengers berechtigt der Token die Applikation dazu, eine Stunde lang Nachrichten ins IM-Netzwerk zu senden und Antworten zu empfangen [5]. Da das Skript aber selten anspringt und sich nach dem Abschicken der Nachricht gleich wieder beendet, brächte die Speicherung des Token kaum Vorteile. So authentifiziert es sich auf Yahoos Login-Seite jedes Mal kurzerhand neu mit Username und Passwort (hart kodiert als »$user« und »$password« in Listing 2), holt sich einen neuen Access-Token ab und führt damit den Sendebefehl auf dem Web-API aus.

Listing 2:
»ymsend«

001 #!/usr/local/bin/perl -w
002 use strict;
003 use LWP::UserAgent;
004 use Sysadm::Install qw(qquote);
005 use URI;
006 use JSON;
007
008 my $user         = "zangzongzing";
009 my $passwd       = "*********";
010 my $recipient    = "mikeschi1li";
011
012 my $api_key      = "******************";
013 my $secret       = "*************";
014
015 my $login_url      = "https://login.yahoo.com/WSLogin/V1/get_auth_token";
016 my $auth_token_url = "https://api.login.yahoo.com/oauth/v2/get_token";
017 my $session_url    = "http://developer.messenger.yahooapis.com/v1/session";
018 my $message_url    = "http://developer.messenger.yahooapis.com/v1/message/yahoo/$recipient";
019
020 my($msg) = join ' ', @ARGV;
021
022 die "usage: $0 message" unless
023   length $msg;
024
025 my $ua = LWP::UserAgent->new();
026
027 my $url = URI->new( $login_url );
028
029 $url->query_form(
030   login              => $user,
031   passwd             => $passwd,
032   oauth_consumer_key => $api_key );
033
034 my $resp = $ua->get( $url );
035
036 if( $resp->is_error() ) {
037   die "Can't get request token: ",
038   $resp->message(), " ", $resp->content();
039 }
040
041 my($request_token) =
042  ($resp->content() =~ /RequestToken=(.*)/);
043
044 $url = URI->new($auth_token_url);
045
046 $url->query_form(
047   oauth_consumer_key => $api_key,
048   oauth_nonce => int( rand 10000000 ),
049   oauth_signature => "$secret&",
050   oauth_signature_method => "PLAINTEXT",
051   oauth_timestamp => time(),
052   oauth_token => $request_token,
053   oauth_version => "1.0"
054 );
055
056 $resp = $ua->get( $url );
057
058 if( $resp->is_error() ) {
059   die "Can't get access token: ",
060   $resp->message(), " ", $resp->content();
061 }
062
063 my $u = URI->new();
064 $u->query( $resp->content() );
065 my %form = $u->query_form;
066
067 $session_url = URI->new( $session_url );
068
069 $session_url->query_form(
070   oauth_consumer_key => $api_key,
071   oauth_nonce => int( rand 10000000 ),
072   oauth_signature =>
073        "$secret&$form{oauth_token_secret}",
074   oauth_signature_method => "PLAINTEXT",
075   oauth_timestamp  => time(),
076   oauth_token => $form{oauth_token},
077   oauth_version => "1.0"
078 );
079
080 $resp = $ua->post( $session_url,
081   Content_Type =>
082          'application/json; charset=utf-8',
083   Content =>
084   q[ {"presenceState"   : 0,
085       "presenceMessage" : "I'm alive!" }] );
086
087 if( $resp->is_error() ) {
088   die "Can't get session: ",
089   $resp->message(), " ", $resp->content();
090 }
091
092 my $data = from_json( $resp->content() );
093
094 $message_url = URI->new( $message_url );
095
096 $message_url->query_form(
097   oauth_consumer_key => $api_key,
098   oauth_nonce => int( rand 10000000 ),
099   oauth_signature =>
100        "$secret&$form{oauth_token_secret}",
101   oauth_signature_method => "PLAINTEXT",
102   oauth_timestamp => time(),
103   oauth_token => $form{oauth_token},
104   oauth_version => "1.0",
105   sid => $data->{sessionId},
106 );
107
108 $resp = $ua->post( $message_url,
109   Content_Type =>
110          'application/json; charset=utf-8',
111   Content =>
112   '{"message" : ' . qquote($msg) . ' }'
113 );
114
115 if( $resp->is_error() ) {
116   die "Can't send message: ",
117   $resp->message(), " ", $resp->content();
118 }

In Zeile 34 von Listing 2 loggt das Skript den User mit »$user« und »$passwd« auf der in »$login_url« gespeicherten URL ein, von wo Yahoo im Body der Antwort einen Request-Token zurückschickt. Diesen leitet das Skript dann zusammen mit dem API-Key und einem zugehörigen Geheimstring »secret« an die nächste URL, also »$auth_token_url«, weiter, die daraus einen Access-Token »oauth_token« samt einem »oauth_token_secret« fabriziert. Die Antwort des Webservers kommt im Format »field=value&field=value…«, die das Skript in Zeile 64 einfach als »query« in ein URI-Objekt einspeist und die Methode »query_form()« dann parsen lässt – das funktioniert, da die Daten exakt wie in einer URL mit Formparametern vorliegen.

Die Kombination aus Token und Secret identifiziert die Applikation als vom User autorisiert gegenüber dem Webservice. Das Skript »ymsend« leitet sie dann an den Messenger-Webservice unter der »$session_url« weiter, die eine neue Messenger-Session einläutet und den User »$user« im Yahoo-Messenger-Netzwerk anmeldet. Geschieht das, sehen andere IM-Nutzer den User in ihren Buddy-Listen auftauchen und das Skript schickt ab Zeile 108 mit der Post-Methode die vorher per Kommandozeile hereingereichte Nachricht an den in »$recipient« definierten (und hoffentlich eingeloggten) Messenger-Nutzer ab.

Dieser letzte Schritt verlangt die Kodierung des Request im Json-Format nach:

{ message : "Die  Nachricht" }

Was, falls der Nachrichtentext ebenfalls Anführungszeichen enthält, eine saubere Kodierung dieser Sonderzeichen erfordert, »qquote()« erledigt das.

Um einen Auth-Token mit Secret für die neu geschaffene Applikation, also das Skript »ymsend«, zu erzeugen, klickt sich der API-Entwickler auf [developer.yahoo.com] durch »My Projects« und »New Project« (Yahoo-Account erforderlich), woraufhin die Pop-up-Box in Abbildung 5 erscheint. Da es sich nicht um eine Webapplikation im Browser handelt, sondern um einen Desktop-Client, ist hier »Or an application using these APIs: BOSS, Contacts, Mail …« zu wählen.

Abbildung 5: Der Entwickler fordert einen Consumer Key für eine Desktop-Client-Applikation an.

Abbildung 5: Der Entwickler fordert einen Consumer Key für eine Desktop-Client-Applikation an.

Im daraufhin erscheinenden Formular verpasst der Entwickler der Applikation ein Namenskürzel, etwa »irc2ymessenger«, und fügt als Description ein paar erläuternde Worte ein. Die Auswahlbox »Kind of Application« ist auf »Client/Desktop« (nicht »Web-based«) zu stellen. Unter »Access Scopes« ist dann »This app requires access to private user data.« zu wählen und unter dem Wust der aufklappenden Unterpunkte die Option »Read/Write« unter »Yahoo! Messenger«.

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben