Ein Skript zapft einen POP3-Mailserver an, fängt Emails aus einer Mailingliste ab und lässt sie einen Newsreader sortiert anzeigen.
Neulich gelang es mir doch glatt, ein paar Codezeilen per Vorschlag und Patch in die Perl-Distribution einzubringen. Um allerdings mit den Herren Bundesligaspielern der Perlwelt in Kontakt zu treten, muss man sich auf die Mailingliste Perl5-Porters (kurz P5P) einschreiben ([2]) oder diese auf dem Web [3] verfolgen. Simon Cozens schreibt übrigens seit einiger Zeit hochinformative wöchentliche Zusammenfassungen darüber, was in dieser äußerst regen Gemeinde so passiert ([4]).
Um nun das Geschehen auf P5P zu verfolgen ohne meine Mailbox aufzufüllen,
kam mir folgende Idee: Wie wär's damit, P5P zu abonnieren, in
eine POP3-Mailbox meines Hosting-Services umzuleiten, diese
in regelmäßigen Zeitabständen automatisch mittels eines Skripts
abzufragen, die eingegangenen Emails als Postings in einen lokalen
Newsserver einzuspeisen und die so entstehenden Nachrichtenstränge
(Threads) dann schön thematisch geordnet
mittels meines Lieblings-Newsreaders tin
zu lesen?
tin
stammt ja noch aus der Prä-Web-Ära und ist textbasiert --
und er erinnert mich noch an die Zeiten, als nur die Coolsten der Coolen
über einen Internetanschluss verfügten. Seufz!
Abbildung 1: Der gute alte tin liest die P5P-Mailingliste. |
Wie immer stehen zwischen einer noch so abgefahrenen Idee und deren
Verwirklichung nur eine halbe Stunde fröhlicher Entwicklungsarbeit,
wenn man Perl in seiner Werkzeugkiste führt.
Das heute vorgestellte Skript
pop2news.pl
holt alle neu eingegangenen Emails von einem
POP3-Mail-Account
ab, löscht sie von dort und speist sie als Postings in einen Newsserver
ein.
01 #!/usr/bin/perl 02 03 use strict; 04 use warnings; 05 06 my $POPHOST = 'my.mail.server.com'; 07 my $POPPORT = 110; 08 my $POPTIMEOUT = 60; 09 my $POPUSERID = 'myuserid'; 10 my $POPPASSWD = 'topsecret'; 11 my $NNTPSERVER = 'localhost'; 12 13 use Net::POP3; 14 use Mail::Internet; 15 use Net::NNTP; 16 17 my $nntp = Net::NNTP->new($NNTPSERVER); 18 die "News Server down\n" unless $nntp; 19 $nntp->quit; 20 21 # Verbindung zum POP-Server aufbauen 22 my $pop = Net::POP3->new($POPHOST, 23 Timeout => $POPTIMEOUT, 24 Port => $POPPORT); 25 26 die "Cannot connect to $POPHOST ($pop)\n" unless $pop; 27 28 my $nof_messages = $pop->login($POPUSERID, 29 $POPPASSWD) or 30 die "$POPHOST rejected our login\n"; 31 32 # Wortlos abbrechen, falls keine Nachrichten 33 # vorliegen 34 exit 0 if $nof_messages == 0; 35 36 foreach my $mesgno (keys %{$pop->list()}) { 37 38 my $message = $pop->get($mesgno); 39 my $mail = Mail::Internet->new($message); 40 41 # Newsgroups-Header einfügen 42 $mail->add("Newsgroups", "p5p"); 43 44 # An den Newsserver senden 45 $mail->nntppost(Host => $NNTPSERVER) or 46 warn "Cannot post to news server ($!)"; 47 48 $pop->delete($mesgno); 49 } 50 51 $pop->quit();
Die Pragmas
use strict
und use warnings
(-w
in prä-5.6.0
-Versionen)
in den Zeilen 3 und 4
sollten jedes Skript einleiten, um zu gewährleisten, dass sich keine
Leichtsinnsfehler einschleichen. Die Konfigurationssektion zwischen
den
Zeilen 6 und 11 definiert Parameter für die verwendeten POP3- und
Newsserver. $POPHOST
ist der Rechner, auf dem der POP3-Server läuft
und Port 110 ist Standard für den POP3-Service. (Während
die Portangabe normalerweise entfallen kann, enthält die schon etwas
veraltete Perl-Distribution 5.6.0 einen Fehler, der den Port doch notwendig
macht). $POPTIMEOUT
bestimmt,
dass das Skript den POP3-Kontakt nach 60 Sekunden abbricht, falls
sich bis dahin nichts rührt.
$POPUSERID
und $POPPASSWD
legen fest,
mit welcher User-Id und mit welchem Passwort sich der Benutzer auf
dem POP3-Account einloggt. Als Newsserver verwenden wir einen
lokalen, dessen Installation weiter unten im Abschnitt Installation
besprochen wird.
Mit den Modulen Net::POP3
, dem implizit damit verwendeten
Net::NNTP
und schließlich Mail::Internet
ist das Skript
keine Kunst mehr: Zeile 17 baut die Verbindung zum POP3-Server
auf und gibt eine Referenz auf ein Net::POP3
-Objekt zurück --
oder undef
, falls etwas nicht klappt. Die
login()
-Methode aus Zeile 23 gibt dem POP3-Server die
Benutzerkennung und das Passwort. Sie antwortet im Fehlerfall mit
undef
und gibt sonst die Anzahl der zur Verfügung stehenden
Nachrichten zurück. Ist diese 0
, bricht Zeile 29 ordnungsgemäß
mit exit 0
ab, denn dann gibt es nichts zu tun.
Die foreach
-Schleife ab Zeile 31 iteriert über alle
Schlüssel des Hashs, den die list()
-Methode des Net::POP3
-Objekts
als Referenz zurückliefert. Heraus kommen
die Nachrichtennummern der auf dem POP3-Server vorliegenden Emails,
die zugehörigen Hash-Werte geben die Nachrichtenlänge in Zeichen an.
Die get()
-Methode des Net::POP3
-Objekts in Zeile 33 holt den
Header und den Body der eingegangenen Email ein. Zeile 34 erzeugt daraus
zur weiteren Bearbeitung ein Mail::Internet
-Objekt. Die anschließend
aufgerufene add
-Methode fügt als neuen Header den Namen der
Newsgroup auf dem lokalen Newsserver ein: p5p
.
Die in Zeile 41 aufgerufene nntppost()
-Methode des
Mail::Internet
-Objekts nutzt implizit das Net::NNTP
-Modul und
sendet die Nachricht an den Newsserver. Klappt dies, löscht
die delete
-Methode in Zeile 43 die Nachricht vom POP3-Server.
Am Ende bricht die quit
-Methode in Zeile 46 die Verbindung ab.
Die verwendeten Zusatzmodule installieren sich wie immer am einfachsten mit der CPAN-Shell:
perl -MCPAN -eshell cpan> install Net::POP3 cpan> install Mail::Internet
Net::POP3
liegt der libwww
-Bibliothek bei und Mail::Internet
der MailTools
-Distribution.
Das Skript pop2news.pl
wandert in irgendein bin
-Verzeichnis, aus
dem es der weiter unten beschriebene Crontab-Prozess aufruft.
Nun zum lokalen News-Server:
Falls der News-Dämon innd
der verwendeten Linux-Installation noch nicht
beiliegt, kann man ihn von http://www.redhat.com/apps/download
abholen.
Damit lokale Benutzer (also auch unser Skript) dem Server beliebig viele
Nachrichten aufdrängen dürfen, muss etwa folgendes nach
/etc/news/nnrp.access
:
# Default to no access *::::!*
# Allow access from localhost localhost:Read Post:::* 127.0.0.1:Read Post:::*
Falls innd
noch nicht läuft (was man leicht mit ps aux | grep innd
herausfindet), wird er mittels
/usr/bin/inndstart
gestartet. Damit dies automatisch beim Systemstart geschieht, kann man
diese Zeile auch nach /etc/rc.d/rc.local
einhängen. Dem laufenden
Newsserver drängen wir dann mit
/usr/bin/ctlinnd newgroup \ p5p y Mike
die neue Newsgroup p5p
auf. Der Parameter y
erlaubt lokales
Posten und Mike
ist derjenige, der die Newsgroup aus der Taufe hob.
Einen Cronjob, der alle 10 Minuten pop2news.pl
aufruft, erzeugt
schließlich folgende Eingabe in dem mittels crontab -e
aufgerufenen Editor:
00,10,20,30,40,50 * * * * \ /home/mschilli/bin/p2n.pl
Den Newsreader tin
, den ich aus nostalgischen Gründen immer
noch benutze, startet ein kleines Shell-Skript rn
, in dem folgende
Kommandos (für die Bash-Shell) stehen:
export NNTPSERVER=localhost tin -f /home/mschilli/.localnewsrc
Den Status, also welche Newsgruppen er angezeigt und welche
Nachrichten bereits gelesen wurden, speichert tin
hier nicht im
sonst üblichen ~/.newsrc
, sondern in einem eigenen .localnewsrc
,
damit es nicht mit den Nachrichtennummern des sonst benutzten
externen Newsservers kollidiert.
Der Newsserver sollte sich dann durch den Cronjob langsam mit eintrudelnden Nachrichten aus der Perl-Bundesliga füllen. Per Newsreader gesendete Nachrichten gelangen natürlich nicht zurück auf die P5P-Mailingliste -- aber man kann damit herrlich Heute bin ich Larry Wall spielen. Viel Spaß damit!
Michael Schilliarbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com. |