Autori: Pellitteri Salvatore, Marco Gigliarano, Alessio Sanapo



Progetto Gateway HTTP-POP3-IMAP

Università Degli Studi Parma
Corso di Laurea in Ing. Informatica
Insegnamento: Telematica A



INTRODUZIONE

Questo progetto realizzato in occasione dell'esame di Telematica, riguarda la realizzazione di un client di posta con interfaccia web. La funzionalità principale è quella di visualizzare il contenuto della INBOX della casella di posta ed eliminare velocemente i messaggi indesiderati. Per l'implementazione sono stati utilizzati strumenti open-source quali:

          Tomcat,che funge da http-server e da servlet container per la realizzazione lato server;

          JavaMail, Pacchetto Java che implementa i protocolli standard per l'accesso alla posta;

          Eclipse, come ambiente IDE per scrivere il nostro pacchetto di classi 'Mailer'.

Nella pagina iniziale vi è un form che chiede i dati necessari alla connessione al server di posta, quel server in cui noi abbiamo la casella di posta elettronica. Nella compilazione del form dobbiamo inserire alcuni semplici dati che si inseriscono ogni qualvolta un utente deve accedere ad una risorsa riservata: username, password, ovviamente quelli della nostra posta elettronica perché tramite questo form non ci si può registrare come nuovo utente, l'indirizzo del server a cui ci si vuole connettere e il tipo di protocollo da utilizzare per la connessione, che nel nostro caso sono due: il protocollo IMAP e il protocollo POP3. Premendo il tasto connetti si viene automaticamente proiettati nella INBOX della nostra casella di posta.

A questo punto ci apparirà sulla sinistra un box blu nel quale sono inserite alcune informazioni riguardanti la casella stessa: il nome del server a cui siamo connessi, cioè lo stesso server che abbiamo inserito nel form iniziale; il nome della casella di posta elettronica che il server ci ha restituito una volta connessi (di solito INBOX); la cartella della nostra casella che stiamo leggendo; ci sono infine delle informazioni riguardanti i messaggi contenuti nella casella: ci viene detto il numero di messaggi contenuti, di questi messaggi ci dice quanti messaggi non sono stati letti e quanti messaggi sono nuovi (solo protocollo IMAP). Fuori dal box blu, esattamente sulla destra dello stesso, ci sono tre tasti: Logout, Aggiorna e Cancella Selezionati. Questi tre elementi fanno effettivamente quello che letteralmente ci fanno intendere: il primo ci disconnette dal server in cui ci siamo loggati, riportandoci nella pagina iniziale del form; il secondo tasto ci permette di aggiornare la pagina per vedere se, nel mentre che stiamo controllando la nostra posta, sono arrivati altri messaggi; il terzo ci permette di cancellare eventuali messaggi indesiderati una volta che sono stati selezionati; una volta cliccato sul tasto si aprirà in un'altra pagina in cui vengono rese note informazioni riguardanti i messaggi che si vogliono cancellare e viene chiesta la conferma sulla disponibilità di continuare o meno l'operazione che è stata avviata.     

La pagina è costituita essenzialmente dalla tabella contenente i messaggi della nostra casella. Questa tabella è formata da sette colonne contenenti il numero di ordinamento dei messaggi così come ci arrivano dal nostro server; il mittente dell'e-mail; l'oggetto della stessa; la dimensione indicativa; la data e l'oradi recezione e infine una casella di spuntamento che ci permette di selezionare i messaggi indesiderati e tramite il tasto sopra citato (Cancella Selezionati) ci permette di cancellarli. Per facilitare la lettura lungo le righe della tabella abbiamo ritenuto opportuno colorare, alternatamene, le righe di bianco e verde.

Di default i messaggi sono ordinati nell'ordine in cui sono arrivati al server: l'ultimo messaggio arrivato al server di posta è il primo ad essere visualizzato. Ad ogni messaggio viene assegnato un valore numerico crescente che ci permette, nel nostro codice JAVA, di andare a selezionare proprio quel messaggio quando lo vogliamo leggere o cancellare. I messaggi vengono identificati in modo diverso a seconda che siano nuovi, letti o non letti: i nuovi messaggi vengono visualizzati con un blinking e il numero corrispondente di colore rosso e lo sfondo grigio; i messaggi non letti di colore nero in carattere grassetto .

Visto che di default noi abbiamo un ordinamento per data di arrivo ci è sembrato opportuno poter riordinare i messaggi secondo altri modo: un semplice clic sul “titolo” delle colonne della tabella ci permette, tramite un classico algoritmo di ordinamentostringhe di riordinare la tabella in funzione del mittente, dell'oggetto o della data. Inoltre c'è la possibilità di riordinare in ordine inverso cliccando ancora una volta sul “titolo” della colonna ordinata .

Ad ogni richiesta dell'utente le singole pagine devono connettersi al server di posta e effetturare e operazioni necessarie. Il protocollo HTTP non è in grado di "ricordare" i passi eseguiti in precedenza, ma le applicazioni basate su un Web Server possono comunque aggirare il problema mantenendo una propria memoria. Ovvero si può usare un blocco di dati associato ad una particolare sequenza di interazioni di un determinato utente del Web. Questo blocco dati viene comunemente chiamato SESSIONE. Queste informazioni devono però essere legate ad uno specifico utente, perché possono essere attivi contemporaneamente più utenti che stanno controllando la posta. Tramite gli che ci offre il server Tomcat abbiamo sfruttato le SESSIONE per memorizzare temporaneamente i dati di connessione per l'accesso alla casella di posta e permettendo all'utente di andare avanti e indietro per le pagine senza dover effettuare la autenticazione ad ogni richiesta, operazione che andrà ripetuta solo nel caso in cui la sessione scada (dopo circa 20minuti).

Nella pagina principale, gate.jsp e nella delete.jsp abbiamo implementato un meccanismo per evitare di cancellare dei messaggi per errore, il tutto per permettere all'utente un adeguato uso della casella di posta. Abbiamo chiamato questo meccanismo “meccanismo delle viste”. Capita molto spesso che l'utente cancelli dei messaggi per poi tornare alla pagina dei messaggi con le funzionalità di history del Browser ( tramite il classico tasto 'torni in dietro'). In questo caso la lista di messaggi mostrata dal Browser nn rispecchia lo stato del server di posta, i messaggi cancellati sono ancora visibili, e questo può portare ad errori.

Nel meccanismo delle viste viene utilizzato un numero incrementale che viene memorizzato nella sessione e inserito nel form di cancellazione, questo numero viene incrementato ogni volta che viene stampata una lista di messaggi o cancellato qualche messaggio. Il numero è contenuto anche nel form di richiesta di cancellazione di un messaggio, e se questo nn corrisponde al valore memorizzato nella sessione nn viene cancellato nessun messaggio.




JAVAMAIL

Dato che abbiamo scelto di programmare in ambiente Java, ci è tornato utile sfruttare a pieno le potenzialità del progetto "JavaMail API”, che consiste di diversi pacchetti: mailapi.jar, imap.jar, pop3.jar e activation.jar.
JavaMail API fornisce una serie di classi astratte e classi concrete che permettono di leggere, scrivere e inviare messaggi elettronici. Le API difiniscono classi quali Messagge, Store e Trasport, che rappresentano i messaggi, le caselle di posta e i protocolli di trasporto. Le API possono essere estese per fornire nuovi protocolli e aggiungere funzionalità quando necessario.

Il nostro progetto consiste di un pacchetto denominato Mailer nel quale abbiamo raccolto i vari sorgenti, le classi e librerie sviluppate e utilizzate. All'interno del pacchetto Mailer si trovano le Interfacce e le relative classi con cui abbiamo implementato un sistema di gestione della posta:

Il sistema di gestione e formato dalle interfacce Server, MailFolder, Messaggio, e una implementazione di queste, basata su JavaMail, nelle classi ServerJM, MailFolderJM, MessaggioJM.

Nella classe OrdinaStringhe abbiamo racchiuso l'algoritmo di ordinamento. I metodi principali delle interfacce sono i seguenti:

Interfaccia Server

int Open(String server, String utente, String password)
 
Metodo che effettua la connessione al server di posta.
void Close()
  Chiude la connessione.
MailFolder getMailerFolder(String name)
 
Restituisce un oggetto di tipo MailFolder

Interfaccia MailFolder

String getName()
 
Restituisce il nome della folder, nel nostro caso sempre 'INBOX'
int getMessageCount()
  Restituisce il numero di messaggio contenuti nella folder.
int getUnreadMessageCount()
 
Restituisce il numero di messaggi non letti.
int getNewMessageCount()
 
Restituisce il numero di messaggi nuovi.
Messaggio getMessage(int n)
 
Restituisce l'n-esimo messaggio della folder.
void OrdinaPer(int n)
 
Ordina i messaggi in base a diversi criteri(0=data, 1=mittente, 2=oggettodel messaggio)

Interfaccia Messaggio

int Numero()
 
Restituisce un numero identificativo del messaggio.
String Mittente()
  Stringa del tipo 'Nome Utente(account_utente@domain.tld).
java.util.Date Data()
 
Data di arrivo del messaggio.
String Soggettot()
 
Oggetto del messaggio.
boolean IsNew()
  Restituisce true se il messaggio è nuovo
boolean IsReaded()
 
Restituisce true se il messaggio è già stato letto
void DeleteMsg()
  Cancella il messaggio.
boolean isMultiPart()
  Restituisce true se il messaggio e di Tipo MIME.
int getPartNumber()
  Restituisce il numero di parti del messaggio.
String PartGetType(int n)
  Restituisce il Tipo MIME della parte n-esima
String PartGetContent(int n)
  Restituisce il contenuto della parte n-esima (sono se la parte e di tipo TEXT/PLAIN)
boolean PartIsAttachedFile(int n)
  true se la parte n e un file allegato.
boolean PartIsInLineFile(int n)
  Allegato in Linea.
String PartGetFileName(int n)
  Nome del file allegato (sole se la Parte n-esima e un attached).
InputStream PartGetInputStream(int n)
 
Se la parte e un file (in linea o attached) viene restituito un InputStream per leggere il file.



 

TOMCAT

Tomcat contiene al suo interno tutte le funzionalità tipiche di un web server, ovvero ha la capacità di interpretare una richiesta di una risorsa veicolata su protocollo HTTP, indirizzarla ad un opportuno gestore (o prenderla dal filesystem) e restituire poi il risultato (codice HTML o contenuto multimediale che sia). In questo aspetto non differisce molto da altri web server, come Apache, se non che spesso si rivela meno prestante. La caratteristica innovativa di Tomcat non è quindi quella di essere un veloce web server, ma piuttosto quella di fornire allo sviluppatore un vero e proprio ambiente nel quale girano applicazioni Java (le servlet). In questo ambiente Java prenderanno vita le nostre applicazioni latoserver.

Come nelle normali applicazioni, anche nella programmazione lato server gli oggetti creati devono avere uno scopo, ovvero essere definiti ed accessibili in un determinato contesto. Utilizzare Tomcat equivale a suddividere lo spazio delle risorse in contenitori sostanzialmente indipendenti nei quali possono essere depositati oggetti Java, secondo una logica orientata al web. Per comprendere appieno questo concetto analizziamo nel dettaglio i singoli contenitori che sono tra loro strutturati in maniera abbastanza gerarchica.


Organizzazione delle risorse

TOMCAT --- Chiaramente il primo livello corrisponde al web server stesso che avrà un insieme di variabili ad esso associate. Ad esempio qui dentro vi sarà indicazione del numero di thread attualmente in esecuzione, della versione di Tomcat o altre proprietà globali generalmente di poco interesse nella programmazione.

CONTESTO --- Quando un utente accede al web server accede in realtà ad una sezione specifica del web server (a un certo dominio virtuale o directory, ad esempio) identificata sostanzialmente dalla URL. Nel gergo di Tomcat la sezione viene chiamata contesto (context). All'interno di questo contenitore si troveranno quindi oggetti comuni a tutta la sezione, che saranno gli stessi per tutti gli utenti e tutte le applicazioni del contesto. Questo contenitore viene generato all'avvio di Tomcat e rimane attivo indipendentemente dal fatto che qualcuno lo stia interrogando in quel momento. Questo non vuol dire che rimanga invariato, anzi, il suo contenuto cambierà in funzione delle richieste ricevute ed ogni elemento contribuirà a definire l'ambiente di tutta la sezione.

SESSIONE --- Il primo contenitore con caratteristiche fortemente orientate al web è quello associato alla sessione (Session). Come dice il nome questo contenitore viene associato ad un utente (o, meglio, ad un client) per tutto il tempo per il quale rimane connesso ad un contesto specifico. Al suo interno verranno memorizzati oggetti che saranno accessibili solo a quell'utente e ne personalizzeranno l'ambiente rispetto ad altri client che utilizzino risorse dello stesso contesto nello stesso momento.

RICHIESTA --- Il contenitore con la vita più breve è la richiesta (Request) che nasce e muore nell'ambito della singola transazione web. Raramente questo contenitore viene riempito da applicazioni anche se svolge un ruolo fondamentale nel flusso dei dati che attraversano Tomcat.


Il flusso dei dati

Abbiamo visto che l'oggetto Context viene creato all'avvio di Tomcat mentre l'oggetto Request nasce muore ad ogni richiesta. Andiamo ad analizzare un po' più in dettaglio il flusso logico che segue Tomcat nel processare le singole richieste web che riceve.

RICHIESTA DI UNA RISORSA --- Supponiamo che un client acceda a una risorsa su di un server su cui gira Tomcat. Innanzi tutto viene instanziato un oggetto Request, in Tomcat nel quale vengono inserite tutte le informazioni ricevute tramite HTTP (dalla url richiesta sino ai cookies) e "al suo fianco" viene instanziato un oggetto risposta (Response) nel quale costruire pian piano la risposta da restituire al client. Leggendo la url all'interno della richiesta Tomcat è quindi in grado di comprendere a quale dei contesti residenti in memoria debbano essere consegnati questi due oggetti Request e Response.

CONTESTO E SESSIONE --- Il contesto invocato da Tomcat provvederà a vedere se esiste già una sessione attiva per quel tipo di client leggendone la "firma" nella richiesta (sotto forma di cookie o nella url, a seconda del metodo usato). Se la sessione, esiste già tra quelle immagazzinate nel context, il contesto la riprende e la affianca agli oggetti Request e Response. A questo punto l'ambiente è stato completamente definito e il web server può passare il controllo all'applicazione associata alla risorsa in questione.

LE SERVLET --- A questo punto del percorso logico, il contesto è in grado di decidere (sulla base del suo file di configurazione) a quale applicazione passare il controllo all'interno dell'ambiente di lavoro definito in tutto il percorso (la più semplice delle applicazioni è chiaramente quella che si occupa di restituire un file presente sul disco del server). L'applicazione Java (le servlet) potrà quindi svolgere tutte le sue funzioni attingendo agli oggetti già presenti nei vari contenitori (nella sessione, ad esempio) o mettendocene di nuovi.

RISPOSTA --- Al termine del proprio lavoro la Servlet deve dare un esito al proprio lavoro tramite la risposta Res. Le uniche due modalità per farlo sono o riempirla con dei contenuti che il client sia in grado di comprendere (codice HTML, ad esempio) oppure inserire un ordine per il contesto di redirigere il controllo ad un'altra risorsa (forward). Nel primo caso il contesto ripasserà tutto l'oggetto a Tomcat che si occuperà di generare l'output per il client. Nel secondo caso, se la risorsa è esterna al contesto il controllo verrà restituito a Tomcat che ricomincerà il percorso logico con questa nuova risorsa. Se invece la risorsa è interna al contesto un'operazione di forward equivale a fare un passo indietro nel percorso logico per poi tornare avanti su un altro sentiero o, in altri termini, chiamare la Servlet associata alla risorsa indicata nell'istruzione di forward, passandole nuovamente tutto l'ambiente.


Servlet

La crescente richiesta di pagine web con contenuti dinamici e di servizi su web, ha portato allo sviluppo di una particolare tipologia di software che collabora con il server web per estenderne le funzionalità e poter interagire con basi di dati. Le tecniche per realizzare questo tipo di software, sono tante, tra cui le più conosciute sono sicuramente le estensioni CGI (Common Gateway Interface), realizzate principalmente in C o in Perl. Anche Java mette a disposizione una API, le Servlet, appunto, che permette di sviluppare applicazioni lato server.

Le Servlet sono moduli software scritti in Java che vengono eseguiti in applicazioni lato server per elaborare le richieste dei client. Esse non sono legate ad un particolare protocollo per la comunicazione tra client e server, anche se più comunemente si utilizza il protocollo HTTP ed infatti si parla di http Servlet. Per scrivere una Servlet si fa uso delle classi del package javax.servlet che è il framework di base per la scrittura delle servlet e del package javax.servlet.http che è l'estensione del framework di base, per la comunicazione via http. Utilizzando un linguaggio portabile come Java, le Servlet consentono di realizzare soluzioni per estendere le funzionalità dei server web, indipendenti dal sistema operativo su cui esse vengono eseguite.




Java Server Pages

JSP (Java Server Pages) è una tecnologia semplice ma potente, che permette di creare Pagine HTML dinamiche lato server. Questa tecnologia agli occhi del programmatore viene gestita per mezzo di un linguaggio di script che è in grado di mescolare codice HTML, componenti riusabili (JavaBeans), applicazioni remote (Servlet), codice Java e script Java-like. Le Pagine JSP sono un'estensione diretta dei Servlet Java e offrono, rispetto ad altre attuali tecnologie Server-Side, il vantaggio e la possibilità di separare la sezione di gestione delle operazioni e di produzione dei contenuti, da quello di visualizzazione vera e propria. Normalmente una Pagina JSP è composta da:

  • porzioni di codice HTML, JavaScript, CSS e cosė via, non compilati dal motore Jsp (Jsp Engine) e comunemente definiti blocchi di codice statico;
  • porzioni di codice Java, compilati dal motore Jsp, che prendono il nome di blocchi di codice dinamico.

Perchè le JSP sono una tecnologia direttamente derivate dalle Servlet?
Quando viene richiesta una pagina JSP, Tomcat effettua la traduzione della pagina in una classe che implementa l'interfaccia javax.servlet.Servlet, la compila e la carica. Tra l'altro la traduzione e molto semplice. I pezzi di codice html vengono stampati tramite una out.prinln("") e i pezzi di codice Java rimangono invariati.

 

Per quanto riguarda le nostre pagine JSP la struttura principale in pseudo-codice è questa:

gate.jsp

     LOGIN = Session.Login
     If ( LOGIN <> null ) - Leggi dati per la connessione dalla sessione
     Else                          - Leggi i dati dal form di login
     
     Server= new Server (Protocollo);
     Server.Connet(Server,Utente,Password);
     MailFolder = Server.getMailFolder("INBOX");
     int n= MailFolder.getMessageCount();

     for (i =0 ; i<n; i++)
     (
             StampaMessaggio( i );

     )
     MailFolder.close();
     Server.close();


delete.jsp

     LOGIN = Session.Login
     If ( LOGIN <> null ) - Leggi dati per la connessione dalla sessione
     Else                          - Redirezione alla pagina di login
     
     Vista= form.Vista
     If ( Vista<> Session.VistaCorrente) - Stampa Messaggio di errore.

     Server = new Server (Protocollo);
     Server.Connet(Server, Utente, Password);
     MailFolder = Server.getMailFolder("INBOX");
     int n = MailFolder.getMessageCount();

     X = form.numeroMessaggi;

     for (i =0 ; i<X; i++)
     (
             Y= form.Cancella( i );
             If ( Y = true ) (
                     Messaggio=MailFolder.getMessaggio( i );
                     Messaggio.DeleteMsg();
              )
     )

     MailFolder.close();
     Server.close();


messaggio.jsp

     LOGIN = Session.Login
     If ( LOGIN <> null ) - Leggi dati per la connessione dalla sessione
     Else                          - Redirezione alla pagina di login
     
     Server= new Server (Protocollo);
     Server.Connet(Server,Utente,Password);
     MailFolder = Server.getMailFolder("INBOX");
     int n= MailFolder.getMessageCount();
     
     int M = form.NumeroMessaggio;
     If ( M>n || M< 0)     - Stampa Messaggio di errore
     
     Messaggio = MailFolder.getMessaggio(M);
          - Stampa Informazioni Generali del messaggio. (mittente,data, tipo, ecc..)
          - Stampa Numero di Parti contenute nel messaggio.

     X=Messaggio.NumeroDiParti;

     for( i = 0; i< X ; i++)(
          Parte = Messaggio.getPart( i );
               - Stampa Info di Parte
               - Stampa il contenuto della parte(se TEXT/PLAIN o HTML)
     )

     MailFolder.close();
     Server.close();



NOTE:

  E consigliato l'utilizzo del browser Mozilla Firefox.

Link:
  JavaMail
  Eclipse
  Jakarta Tomcat

 

 


Autori: Pellitteri Salvatore, Marco Gigliarano, Alessio Sanapo