MokaByte Numero 02 - Novembre 1996

 
 Programmazione dei socket
di
 Luca Bertoncello 
lettura della posta sul server mail in Java

 



Dopo che il mese scorso abbiamo visto come inviare messaggi di posta elettronica in Java, in questo numero Bertoncello ci insegna come leggere i messaggi da un server di mail attraverso un semplice esempio scritto in Java.



 
 

Ricezione di messaggi dal server POP3

Il mese scorso si era parlato di come spedire mail usando il protocollo SMTP. Questa volta si parlerà di un protocollo “complementare”: POP3. POP3, che sta per Post Office Protocol version 3 è un insieme di comandi come SMTP che serve per ricevere la posta da quei server che accettano collegamenti via modem (ciò vuol dire che, in buona parte dei casi, sono esclusi quei server NON usati come provider, come ad esempio ditte private o università). Anche in questo caso è necessario collegarsi con il proprio provider utilizzando una porta Socket. Per essere precisi occorre usare la porta 110. POP3 dispone di alcuni semplici comandi che consentono all’utente di loggarsi e richiedere i messaggi. I principali sono:

Essi servono rispettivamente per dare il proprio Login, la propria Password, richiedere quanti messaggi sono presenti nel server, richiedere le prime n righe del messaggio msg, richiedere tutto il messaggio msg e uscire. Può sembrare una panoramica molto affrettata, ma in effetti non c’è molto altro da dire. Le risposte ritornate da questi comandi sono di due tipi: Tutto bene (+OK) e Errore (-ERR). È quindi necessario, dopo aver spedito un qualsiasi comandi controllare la sua risposta ed agire di conseguenza. Come nel precedente articolo, spiegherò i vari pezzi di codice e fornirò, alla fine, il codice completo.

Importante però notare una cosa: questo NON è un’Applet, quindi non gira da Netscape, ma da riga di comando lanciando il comando Java POP3 <Host> <User> <Passwd>, dove Host è il nome del vostro server, User è il vostro login e Passwd la vostra password.

Vediamo dunque la prima procedura, quella che chiama tutte le altre. Questa funzione (Popper) si connette via socket al vostro provider e chiama la OpenComm per connettersi e, se non ci sono stati errori, la List per richiamare l’header dei messaggi. Questo header è composto da Dimensione del messaggio, Mittente, Data e Soggetto. La procedura Popper è descritta di seguito:

public static void Popper(String Host,String User,String Passwd) throws IOException { 

// Procedura che legge l’header della mail.  Questa procedura apre un

// socket  sulla  porta  110  (quella di POP3)  e  lancia la funzione 

// List, la quale provvede fisicamente all’azione  di lettura Header.





// Apertura Socket e inizializzazione degli Stream di Input e Output 

Socket mailSocket=new Socket(Host,110); 

os=new PrintStream(mailSocket.getOutputStream()); 

is=new DataInputStream(mailSocket.getInputStream());



// Se l’utente e’ loggato correttamente, legge gli Header 

if(OpenComm(User,Passwd)==true) 

        List();



// Chiude la comunicazione con POP3 e si disconnette

os.println(“QUIT”); 

is.readLine();



is.close(); 

os.close(); 

mailSocket.close();

}

Come si può vedere è tutto molto semplice. Si apre il socket, come per l’applet del mese scorso, si chiamano le funzioni per comunicare e si chiude la comunicazione (QUIT). Fin qui non c’è nulla di strano, vediamo ora la funzione OpenComm. Questa funzione provvede a mandare al provider al quale si è connessi il proprio identificativo (Login) e la propria Password. La funzione, inoltre, provvede a verificare se non ci sono errori (Utente non presente nel sistema, Password non valida) e ritorna true se tutto è andato bene, false in caso contrario. La OpenComm è descritta di seguito:
public static boolean OpenComm(String User,String Passwd) throws IOException { 

// Questa procedura si “logga” con il server, fornendo UserName e Password. 

// Visualizza messaggi di errore nel caso UserName o Password siano errati 

// Ritorna TRUE se si e’ loggato, FALSE altrimenti



String s; 

boolean Ret=true;

s=is.readLine(); 

os.println(“USER “+User);

s=is.readLine(); 

if(s.substring(0,3).compareTo(“+OK”)==0) { 

        os.println(“PASS “+Passwd); 

        s=is.readLine(); 

        if(s.substring(0,3).compareTo(“+OK”)!=0) {

                System.out.println(“Errore: Password Errata”); 

                Ret=false; 

        } 

        else 

                System.out.println(“Connesso come “+User); 

} 

else { 

        System.out.println(“Errore: User-ID Errato”); 

        Ret=false;

}



return(Ret); 

}

Qui c’è qualcosa da dire. Per prima cosa si manda, tramite lo Stream aperto dalla Popper la stringa USER seguita dal nome utente, poi si controlla, tramite l’altro Stream aperto, se il messaggio di ritorno è un errore o meno. Nel caso tutto sia andato a buon fine si procede a spedire la password, eseguendo gli stessi controlli. Dopo essersi loggati nel sistema è possibile quindi agire sulla propria casella postale. Nel caso di questo esempio ci limiteremo a prendere le prime righe del messaggio e costruire l’header, ma se si volesse leggerlo tutto non c’è nient’altro da fare che spedire un comando RETR al posto del comando TOP. Vediamo ora nel dettaglio il comportamento della funzione List, che è il cuore di tutto il programma. Il listato è il seguente:
public static void List() throws IOException { 

// Questa procedura e’ il cuore del programma. 

// Provvede a spedire i comandi POP3 e a visualizzarne i risultati. 

// Si veda l’apposita sezione dove spiego i comandi POP3 per 

// comprendere il flusso dei dati.



String s,s1,From,Date,Subj; 

int NMsg,l; 

long Dim;

From=Date=Subj=””;



// Chiede quanti messaggi ci sono nel server 

os.println(“LIST”); 

s=is.readLine(); 

s1=s.substring(4); 

NMsg=atoi(s1);

for(l=0;l<NMsg;l++) 

        s=is.readLine(); 

s=is.readLine(); 

System.out.println(“”+NMsg+”Messaggi”); 

System.out.println();



// Cicla per ogni messaggio 

for(l=0;l<NMsg;l++) { 

        System.out.println(“Messaggio n “+(l+1));



        // Prende le prime 13 righe del messaggio

        numero (l+1)

        os.println(“TOP “+(l+1)+” 13"); 

        s=is.readLine();



        // Viene subito ritornata anche la dimensione della Mail

        s1=s.substring(4); 

        Dim=atol(s1); 

        s=is.readLine();

        while(is.available()!=0) { 

                s=is.readLine(); 

                // Cerca i campi From, Date e Subject 

                if(s.length()>5) { 

                        if(s.substring(0,6).compareTo(“From: “)==0)

                                From=s.substring(6); 

                                if(s.substring(0,6).compareTo(“Date: “)==0) 

                                        Date=s.substring(6);

                } 

                if(s.length()>8) 

                        if(s.substring(0,9).compareTo(“Subject: “)==0) 

                                Subj=s.substring(9);

        } 

}

System.out.println(“Da: “+From); 

System.out.println(“Data: “+Date); 

System.out.println(“Soggetto: “+Subj); 

System.out.println(“Dimensione: “+Dim+” bytes”); 

System.out.println();



}

Come si può notare le operazioni sono piuttosto semplici. Per prima cosa mando il comando LIST, che mi ritorna il numero di messaggi presenti, mi salvo quindi questo numero in una variabile. Da notare che vengono usate due funzioni, atoi e atol, che NON sono comprese nel pacchetto di classi forniti a corredo del linguaggio, ma che ho scritto io, prendendo spunto dalle loro omonime del linguaggio C. Sarà possibile vederle nel listato in fondo a questo articolo, in ogni caso, dirò che la atoi converte una stringa in un intero, mentre le atol converte la stringa in un long. Dopo questa breve considerazione cicliamo per tutti i messaggi, chiedendo al server le prime 13 righe del messaggio. In queste righe, in posizioni che variano con il provider e il tipo di mailer usato per la spedizione, troviamo il Mittente, la Data e il Soggetto, mentre la dimensione è sempre ritornata subito. Quindi ci si limita a controllare tutte le righe che ci vengono passate e verificare se contengono le informazioni richieste. In ogni caso, il prefisso (From, Date, Subject) è standard, quindi è sufficiente controllare se la riga inizia con uno di questi per concludere che si ha l’informazione desiderata. Alla fine di tutto si stampano le informazioni e si conclude il ciclo.

Bene, questo è tutto! Come si può vedere, anche il protocollo utilizzato per richiamare i messaggi è semplice quasi quanto quello per spedirlo e, comunque, non presenta nessuna particolare difficoltà di implementazione. Anche in questo caso, gran parte del lavoro è svolto dalle classi che gestiscono i Socket e gli Stream, quindi dobbiamo ancora ringraziare i tecnici della Sun.

Di seguito riporto, per completezza, il listato commentato del programma. Per ogni dubbio o problema è possibile consultare la RFC1225, oppure contattarmi direttamente.

Listato completo del programma POP3


import java.awt.*; 

import java.io.*; 

import Java.net.*;



public class POP3 { 

        public static long atol(Strings) { 

        // Converte la string passato in un long



        Long tempInt; 

        String s1; 

        int l,k; 

        long q=0;



        for(l=-1,k=0;(k<s.length()) &&(l==-1);k++) 

                if((s.charAt(k)<‘0’) || (s.charAt(k)>’9')) 

                        l=k;

                if(l==-1) 

                        s1=s; 

                else 

                        if(l!=0) {

                                s1=s.substring(0,l);

                                tempInt = Long.valueOf(s1); 

                                q=tempInt.longValue(); 

                        }



        return(q); 

        } 



        public static int atoi(Strings){ 

                // Converte la string passato in un integer

                Integer tempInt; 

                String s1; 

                int k,l;



                for(l=-1,k=0;(k<s.length()) &&(l==-1);k++) 

                        if((s.charAt(k)<‘0’) || (s.charAt(k)>’9')) 

                                l=k;

                        if(l==-1) 

                                s1=s; 

                        else 

                                if(l!=0) {

                                        s1=s.substring(0,l);

                                        tempInt = Integer.valueOf(s1); 

                                        k=tempInt.intValue(); 

                                } 

                                else k=0;

        

                return(k); 

                }



        public static void List() throws IOException { 

                // Questa procedura e’ il cuore del programma. 

                // Provvede a spedire i comandi POP3 e a visualizzarne 

                // i risultati. Si veda l’apposita sezione dove spiego 

                // i comandi POP3 per  comprendere  il flusso dei dati

        

                String s,s1,From,Date,Subj; 

                int NMsg,l; 

                long Dim;

        

                From=Date=Subj=””;

        

                // Chiede quanti messaggi ci sono nel server 

                os.println(“LIST”); 

                s=is.readLine(); 

                s1=s.substring(4); 

                NMsg=atoi(s1);

                for(l=0;l<NMsg;l++) 

                        s=is.readLine(); 

                s=is.readLine(); 

                System.out.println(“”+NMsg+”Messaggi”); 

                System.out.println();

        

                // Cicla per ogni messaggio 

                for(l=0;l<NMsg;l++){ 

                        System.out.println(“Messaggio n “+(l+1));

        

                // Prende le prime 13 righe del messaggio 

                numero (l+1)

        

                os.println(“TOP “+(l+1)+” 13"); 

                s=is.readLine();

        

                // Viene subito ritornata anche la dimensione della MaiL

                s1=s.substring(4);      

                Dim=atol(s1); 

                s=is.readLine();

                while(is.available()!=0) { 

                        s=is.readLine();        

                        // Cerca i campi From, Date e Subject 

                        if(s.length()>5) { 

                                if(s.substring(0,6).compareTo(“From: “)==0)

                                        From=s.substring(6); 

                                        if(s.substring(0,6).compareTo(“Date: “)==0) 

                                                Date=s.substring(6);

                        } 

                                if(s.length()>8) 

                                        if(s.substring(0,9).compareTo(“Subject: “)==0) 

                                                Subj=s.substring(9);

                } 

                System.out.println(“Da: “+From); 

                System.out.println(“Data: “+Date); 

                System.out.println(“Soggetto:“+Subj); 

                System.out.println(“Dimensione: “+Dim+” bytes”); 

                System.out.println();

                } 

        

        public static DataInputStream is; 

        public static PrintStream os; 

        public static boolean OpenComm(String User,String Passwd) throws IOException {



                // Questa procedura si “logga” con il server,fornendo 

                // UserName e Password. Visualizza messaggi di errore 

                // nel caso UserName o Password siano errati

                // Ritorna TRUE se si e’ loggato, FALSE altrimenti

        

                String s; 

                boolean Ret=true;

        

                s=is.readLine(); 

                os.println(“USER “+User);

                s=is.readLine(); 

                if(s.substring(0,3).compareTo(“+OK”)==0) { 

                        os.println(“PASS“+Passwd); 

                        s=is.readLine(); 

                        if(s.substring(0,3).compareTo(“+OK”)!=0) {

                                System.out.println(“Errore: Password Errata”); 

                                Ret=false; 

                        } 

                        else 

                                System.out.println(“Connesso come “+User); 

                        } 

                else { 

                        System.out.println(“Errore: User-ID Errato”); 

                        Ret=false;

                }

        

                return(Ret); 

        } 

        public static void Popper(String Host,String User,String Passwd) throws IOException { 

                

                // Procedura che legge l’header della mail. 

                // Questa procedura apre un socket sulla porta 110  

                // (quella di POP3) e lancia la funzione List, la 

                // quale provvede fisicamente all’azione di lettura Header.



                // Apertura Socket e inizializzazione degli Stream di Input e   Output 

                Socket mailSocket=new Socket(Host,110); 

                os=new PrintStream(mailSocket.getOutputStream()); 

                is=new DataInputStream(mailSocket.getInputStream());



                // Se l’utente e’ loggato correttamente, legge gli Header 

                if(OpenComm(User,Passwd)==true) 

                        List();



                // Chiude la comunicazione con POP3 e si disconnette

                os.println(“QUIT”); 

                is.readLine();

                is.close(); 

                os.close(); 

                mailSocket.close();

        }



        public static void main(String args[]) { 

                try{ 

                        // Chiama la funzione Popper passando Host, 

                        //UserName e Password

                

                        Popper(args[0],args[1],args[2]); 

                }

                catch(Exception e) {

                        System.out.println(“Eccezione “+e); 

                } 

        } 

}

Luca Bertoncello è un programmatore in C++ e Java (da poco dopo i suoi esordi). Diplomato in Informatica all'ITIS di Ivrea, lavora presso una ditta che ha creato due anni fa. È specializzato in programmi sistemistici per il gioco del Lotto, ma non disdegna altri programmi e speculazioni mentali sui vari sistemi. Può essere contattato a: lucabert@biella.alpcom.it (per messaggi privati) bdb@usa.net softserv@biella.alpcom.it (per lavoro) 

 
 
  
 

MokaByte rivista web su Java

MokaByte ricerca nuovi collaboratori
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it