Perl - programska izvedba poštnega odjemalca in odjemalca FTP
Perl (Practical Extraction and Report Langauge) je programski jezik, ki je bil prvotno namenjen pregledovanju in obdelavi tekstovnih datotek ter ustvarjanju poročil iz pridobljenih podatkov, vendar danes ponuja veliko več. Prosto dostopni perlovski moduli nadgradijo obstoječo funkcionalnost z vnaprej pripravljenimi razredi, funkcijami in rutinami. Z vključevanjem teh v kodo lahko povsem preprosto pošljemo sporočilo elektronske pošte ali preslikamo datoteko v oddaljeni računalnik s prenosom FTP.
Prvo različico perla je izdal gospod Larry Wall leta 1987. Sintaksa perla je zelo jasna in učinkovita ter zajema najboljše lastnosti programov za obdelavo besedil v Linuxu, na primer sed in awk, in programskega jezika C. Perl je ponavadi že del standardnih distribucij Linuxa, razen določenih modulov, katerih namestitev izvedemo posebej.
Perlovski moduli
Perlovski moduli so prosto dostopni. Najdemo jih v spletnem arhivu CPAN (Comprehensive Perl Archive Network) na spletni strani http://www.cpan.org/. Arhiv CPAN ponuja veliko raznovrstnih perlovskih modulov, na primer: omrežni moduli, moduli za obdelavo podatkov in razhroščevanje, moduli za upravljanje časa, matematični moduli itn. V arhivu CPAN so tudi dokumentacija in navodila za perl ter distribucije perla za različne operacijske sisteme.
V nadaljevanju bomo opisali uporabo modulov perl za branje in pošiljanje sporočil elektronske pošte ter prenos datotek v oddaljen računalnik s protokolom FTP. Za tako funkcionalnost potrebujemo naslednje module:
Net::FTP
modul za izvedbo odjemalca FTP
Net::SMTP
modul za povezovanje s strežnikom za odhajajočo pošto SMTP
Mail::POP3Client
modul za povezovanje s strežnikom za prihajajočo pošto POP3
IO::Handle
modul vhodno/izhodnih funkcij
Več informacij o modulih dobimo z uporabo ukaza perldoc v ukazni lupini (podobno kot ukaz man).
Zgled uporabe ukaza perldoc v ukazni lupini:
# perldoc Net::FTP
NAME
Net::FTP - FTP Client class
SYNOPSIS
use Net::FTP;
$ftp = Net::FTP->new("some.host.name", Debug => 0);
$ftp->login("anonymous",'me@here.there');
$ftp->cwd("/pub");
$ftp->get("that.file");
$ftp->quit;
(Izsek izpisa ukaza perldoc).
Namestitev perlovskih modulov
Na glavni spletni strani arhiva CPAN kliknemo povezavo PerlModules. Odprla se bo spletna stran, na kateri izberemo iskalnik modulov Randy Kobe's serach. V vnosno polje Find vpišemo ime modula, na primer Net::FTP. V precejšnjem številu izpisov izberemo samo povezavo Net::FTP. Modul prenesemo k sebi s klikom povezave Download.
Preneseno datoteko v formatu tar.gz raztegnemo v ukazni lupini z ukazom tar:
# tar -xzvf perl_modul.tar
Nato v ukazni lupini vpišemo še naslednje ukaze:
# perl Makefile.PL
# make
# make test
# make install
Zgornji postopek ni rutina za vse namestitve modulov. Pred vsako namestitvijo se svetuje predhodno branje datotek INSTALL in README, ki sta sestavni del datoteke za namestitev modula.
Zagon programa v perlu
Perl navadno deluje kot tolmač (interpreter), ki vsak ukaz, zapisan v navadni datoteki, sproti prevaja v strojno kodo in sproti izvaja.
Program oziroma datoteko, ki vsebuje ukaze programskega jezika perl, lahko "zaženemo" v ukazni lupini z ukazom perl, ki mu sledi ime te datoteke.
Zgled:
# perl ./ime_datoteke
ali pa
# /Pot_do_ukaza_perl/perl ./ime_datoteke
Zagon programa v perlu je mogoč tudi le s sklicevanjem na ime datoteke (programa) v ukazni lupini. V ta namen na začetku datoteke dodamo vrstico #!/usr//bin/perl, ki določa pot do izvršljive datoteke oziroma ukaza perl.
#!/usr/bin/perl
# Komentar: To je program oziroma datoteka ping, ki vsebuje ukaze jezika perl.
# Komentar: Program ping preveri, ali je racunalnik v krajevnem omrezju viden.
use Net::Ping;
$host='Naslov_IP ali_gostiteljsko ime';
$p = Net::Ping->new();
print "$host je ziv.\n" if $p->ping($host);
$p->close();
Z ukazom chmod najprej nastavimo dovoljenje za izvajanje zgornjega programa in ga nato zaženemo v ukazni lupini kot uporabnik root:
# chmod a+x ping
#./ping
Poštni odjemalec
V nadaljevanju bomo opisali program mailclient, ki izvaja branje zadnjih sporočil elektronske pošte, prispelih v poštni strežnik za prihajajočo pošto POP3. Vsaka vrstica kode, ki jo začnemo z znakom #, predstavlja komentar. Takoj za prvotnimi komentarji sledi vrstica use strict, poimenovana še pragma, ki poudarja uporabo najbolj striktnih pravil za prevajanje kode. Nadaljujemo še s pragmo use warnings, ki poskrbi za izpis vseh možnih opozorilnih sporočil. Ukazi use se prav tako uporabljajo za vključevanje modulov perl v kodo:
use Mail::POP3Client; - Modul za povezovanje s poštnim strežnikom POP3.
use IO::Handle; - Zbirka metod za izvajanje vhodno/izhodnih operacij.
Konstante v perlu so deklarirane s pragmo use constant. Za deklaracijo spremenljivk uporabimo ključno besedo my. Znak $ pred spremenljivko označuje skalarni značaj spremenljivke.
Sporočila beremo v zanki do-while s časovnimi premori, ki so določeni s parametrom TIME. Pogoj zanke je, da število trenutnega poštnega sporočila $cnt ne preseže števila vseh prispelih poštnih sporočil, ki ga dobimo z metodo $pop->Count.
Pred vstopom v zanko ustvarimo povezavo na strežnik POP3 z metodo $pop->new:
$pop = Mail::POP3Client -> new (ACCOUNT, PASSWORD, HOSTNAME, PORT, DEBUG);
Uporabljeni so naslednji parametri povezave:
HOSTNAME
Gostiteljsko ime poštnega strežnika.
ACCOUNT
Uporabniško ime za povezavo na poštni strežnik.
PASSWORD
Geslo za povezavo na poštni strežnik.
MAILFILE
Datoteka, v katero se vpisujejo prebrana sporočila.
PORT
Vrata za povezovanje na strežnik POP3.
DEBUG
Vrednost, večja od 1, pomeni, da je razhroščevanje ob povezovanju vključeno.
V zanki najprej izvedemo odpiranje datoteke MAILFILE z ukazom open. Datoteka MAILFILE bo zdaj označena z ročico datoteke MESSAGE. V nadaljevanju ustvarimo nov objekt razreda IO::Handle oziroma modula vhodno/izhodnih funkcij. Objektu priredimo datoteko MAILFILE z metodo fdopen, ki ji kot argument posredujemo datotečni deskriptor. Pretvorbo ročice datoteke MESSAGE v datotečni deskriptor izvede metoda fileno. Sporočila preberemo z metodo $pop->BodyToFile. Vhodna parametra te metode sta objekt $fd in številka poštnega sporočila.
#!/usr/bin/perl
# Program mailclient - To je pravi postni odjemalec.
# Program vpise zadnja prispela sporocila v
# postni streznik POP3 v datoteko MAILFILE.
use strict;
use warnings;
# *** Moduli ***
# Modul za povezovanje s streznikom POP3
use Mail::POP3Client;
# Modul vhodno/izhodnih funkcij
use IO::Handle;
# *** Konstantni parmetri ***
# Ime postnega streznika
use constant HOSTNAME => 'pop3.company.net';
# Uporabnisko ime
use constant ACCOUNT => 'uporabnisko_ime';
# Geslo
use constant PASSWORD => 'geslo';
# Datoteka v katero se vpisujejo sporocila
use constant MAILFILE => '/home/uporabnik/mail';
# Casovni interval branja sporocila
use constant TIME => 5;
# Vrata streznika POP3
use constant PORT => 110;
# Razhroscevanje ob povezavi je vkljuceno
use constant DEBUG => 1;
# Deklaracija spremenljivk
# Spremenljivka streznika POP3 (objekta Mail::POP3)
my $pop;
# Stevilka sporocila elekt. poste (trenutna)
my $cnt=1;
# Pa zacnemo...
# Ustvarimo novo povezavo na streznik POP3 (konstruktor)
$pop = Mail::POP3Client -> new
(ACCOUNT, PASSWORD, HOSTNAME, PORT, DEBUG);
# Prebere zadnja prispela sporocila
do {
# Odpiranje datoteke MAILFILE, v katero se pisejo postna sporocila
open(MESSAGE, """, MAILFILE) or die
"Ni mozno odpiranje datoteke za pisanje !\n";
# Konstruktor:Ustvarimo novi objekt razreda IO::Handle
my $fd = new IO::Handle();
# Objektu priredimo datoteko, ki je dolocena
# z rocico datoteke MESSAGE. Funkcija fileno izvede
# pretvorbo rocice datoteke MESSAGE v datotecni deskriptor
$fd->fdopen(fileno(MESSAGE) , "w");
# Pisanje postnega sporocila pod
# stevilko $cnt v datoteko MAILFILE
$pop->BodyToFile($fd, $cnt);
# Zapiranje datoteke
close(MESSAGE);
# Povecaj stevec za 1
$cnt++;
# Casovna pavza
sleep(TIME);
# Izvajaj od ukaza "do" do sem, vse dokler je
# trenutna st. sporocila manjsa od celotnega
# st. zadnjih prispelih sporocil v streznik
} while ($cnt <= $pop->Count);
# Zapremo povezavo s streznikom POP3
$pop->Close;
# Ocitno konec
Odjemalec FTP
Podali bomo zgled izvedbe odjemalca FTP v perlu s programom ftpclient. Program vključuje dvojno funkcionalnost: prenos datoteke v oddaljeni računalnik s protokolom FTP in obveščanje o morebitnem neuspešnem prenosu s pošiljanjem sporočila elektronske pošte. V tem smislu sta v kodo vključena modul za izvedbo odjemalca FTP (Net::FTP) in modul za izvedbo odjemalca za komunikacijo s strežnikom odhajajoče pošte SMTP (Net:SMTP).
Za povezovanje na strežnika uporabimo naslednje parametre:
FTPSERVER
Gostiteljsko ime ali naslov IP strežnika FTP.
USER
Uporabniško ime za povezavo na strežnik FTP.
PASSWORD
Geslo za povezavo na strežnik FTP.
DIR
Mapa na strežniku FTP, v katero bo preslikana datoteka FILE.
FILE
Datoteka, ki jo preslikamo v strežnik FTP.
TIME
Časovni premor med pošiljanjem datoteke FILE.
SMTPSERVER
Gostiteljsko ime ali naslov IP strežnika SMTP.
MAILFROM
Naš naslov elektronske pošte.
MAILTO
Naslov prejemnika sporočil elektronske pošte.
Prenos datoteke v strežnik se izvaja ciklično v zanki while s časovnimi premori, ki so določeni s parametrom TIME. Najprej izvedemo povezavo na strežnik FTP s pomočjo metode Net::FTP->new, ki nastopa kot izraz v kontrolni strukturi unless. Ukaz znotraj te kontrolne strukture se izvede samo, če je pogoj, ki ga preverjamo, neveljaven, oziroma če je bilo ustvarjanje nove povezave neuspešno. V nasprotnem primeru temu sledi izvajanje ukazov za prijavo na strežnik, premik v mapo, prenos datoteke in zaključevanje seje FTP (login, cwd, put in quit). Pri vsakem ukazu, ki se posreduje v strežnik FTP, preverjamo, ali se je pravilno zaključil s pomočjo ključnih besed or die, ki jim sledi logična spremenljivka, ki jo preverjamo v nadaljevanju. Ob neuspešni prijavi neuspešnega dostopa do mape in neuspešnega prenosa datoteke ali zaključevanja seje program izpiše opozorilo in pošlje poštno sporočilo s funkcijo sendmail.
Funkcija sendmail uporablja naslednje metode za pošiljanje poštnega sporočila:
new (SMTP_streznik)
Konstruktor - ustvarimo nov objekt Net::SMTP, pri čemer je SMTP_streznik gostiteljsko ime ali naslov IP strežnika SMTP.
mail (Posiljatelj)
Začetek prenosa za dostavo poštnega sporočila - pošlje ukaz MAIL v strežnik.
to (Prejemniki)
Obvestilo strežniku o prejemnikih poštnega sporočila.
data
Pove strežniku, da vrstice, ki sledijo, predstavljajo poštno sporočilo - pošlje ukaz DATA v strežnik.
datasend
Ukaz za pošiljanje glave (Head) in telesa (Body) poštnega sporočila.
quit
Pošlje ukaz QUIT v oddaljeni strežnik SMTP in zapre povezavo.
#!/usr/bin/perl
# Program je odjemalec FTP, ki prenasa datoteko FILE
# na streznik FTP. Ob napaki pri prenosu FTP
# program poslje sporocilo na postni naslov MAILTO
use strict;
use warnings;
# *** Moduli ***
# Modul za izvedbo odjemalca FTP
use Net::FTP;
# Modul za izvedbo protokola SMTP
use Net::SMTP;
# *** Konstantni parametri ***
# Ime streznika FTP
use constant FTPSERVER => 'ftp.server.com';
# Uporabnisko ime za dostop v streznik FTP
use constant USER => 'uporabnik';
# Geslo za dostop v streznik FTP
use constant PASS => 'geslo';
# Mapa v strezniku FTP, v katero preslikamo datoteko
use constant DIR => '/home/uporabnik/dir';
# Datoteka, ki jo prenasamo v streznik FTP
use constant FILE => '/home/uporabnik/values';
# Cas ponovitve prenosa datoteke FILE
use constant TIME => 5;
# Ime streznika SMTP
use constant SMTPSERVER => 'smtp.random.net';
# Nas naslov elektronske poste
use constant MAILFROM => 'ime.priimek\@random.net';
# Naslov prejemnika sporocil
use constant MAILTO => 'ime.priimek\@company.net';
# Logicne konstante
use constant FALSE => 0;
use constant TRUE => 1;
# Deklaracija spremenljivk
my $no_conn;
my $no_login;
my $no_dir;
my $no_transfer;
my $no_quit;
my $smtp;
my $ftpobj;
# Inicializacija spremenljivk
$no_conn = $no_login = $no_dir = $no_transfer = $no_quit = FALSE;
# Neskoncna zanka
while (TRUE) {
# Konstruktor: ustvarimo nov objekt Net::FTP
unless($ftpobj = Net::FTP->new(FTPSERVER, Timeout=>30, Debug=>1)) {
$no_conn = TRUE;
} else {
# Prijava na streznik FTP
$ftpobj-> login(USER, PASS) or $no_login = TRUE;
# Premik v mapo DIR
$ftpobj-> cwd (DIR) or $no_dir = TRUE;
# Preslikava datoteke FILE na streznik FTP
$ftpobj-> put (FILE) or $no_transfer = TRUE;
# Konec seje FTP
$ftpobj-> quit or $no_quit = TRUE;
}
#****************************************************
# Preverjanje uspesnosti prenosa: ob
# neuspesni prijavi, zavrnjenem dostopu do mape
# in neuspesnem prenosu datoteke posljemo sporocilo
# elektronske poste s pomocjo funkcije sendmail.
#****************************************************
if ($no_conn == TRUE) {
&sendmail("Ni povezave s streznikom!");
} elsif ($no_login == TRUE) {
&sendmail("Ni mozna prijava v streznik!");
} elsif ($no_dir == TRUE) {
&sendmail("Ni mozen dostop do mape v strezniku!");
} elsif ($no_transfer == TRUE) {
&sendmail("Ni mozen prenos datoteke v streznik ali
datoteka ne obstaja!");
} elsif ($no_quit == TRUE) {
&sendmail("Ne morem koncati ftp seje!");
} else {
print "Ocitno vse OK. \n";
}
# Ponastavi
$no_conn = $no_login = $no_dir = $no_transfer = $no_quit = FALSE;
# Casovna pavza - interval vnovicnega posiljanja datoteke
sleep (TIME);
}
# Funkcija posilja sporocilo elektronske poste
# msg - besedilo sporocila elektronske poste
sub sendmail {
my ($msg) = @_;
# Konstruktor::Ustvarimo nov objekt Net::SMTP
$smtp = Net::SMTP->new(SMTPSERVER, Debug => 1) or
die "Ne morem ustvariti povezave na streznik SMTP!";
$smtp->mail(MAILFROM);
$smtp->to(MAILTO);
# Zacetek sporocila
$smtp->data();
# Ustvarjanje glave postnega sporocila
$smtp->datasend("To: ", MAILTO, "\n");
$smtp->datasend("From: ", MAILFROM, "\n");
$smtp->datasend("Subject: Vase pojasnilo... \n");
$smtp->datasend("\n");
# Vsebina postnega sporocila
$smtp->datasend($msg);
# Konec sporocila
$smtp->dataend();
# Zapiranje povezave
$smtp->quit();
}