forked from IF-LK-2020/mymail
330 lines
9.6 KiB
Java
330 lines
9.6 KiB
Java
|
|
public class MyMail {
|
|
|
|
// public static final String POP3_SERVER = "pop3.neugebauer.cc";
|
|
//
|
|
// public static final int POP3_PORT = 110;
|
|
//
|
|
// public static final String POP3_USER = "informatik@neugebauer.cc";
|
|
//
|
|
// public static final String POP3_PASS = "ifq2_user1";
|
|
|
|
public static void main(String[] args) {
|
|
new MyMail();
|
|
}
|
|
|
|
private String ip;
|
|
|
|
private int port;
|
|
|
|
private Connection con;
|
|
|
|
private MyMailGUI gui;
|
|
|
|
private String user;
|
|
|
|
private String password;
|
|
|
|
private String lastError;
|
|
|
|
private LoginGUI loginGUI;
|
|
|
|
/**
|
|
* Verbindet zu einem lokalen POP3-Server.
|
|
*/
|
|
public MyMail() {
|
|
loginGUI = new LoginGUI(this);
|
|
}
|
|
|
|
public void start(String pIP, int pPort, String pUser, String pPassword) {
|
|
ip = pIP;
|
|
port = pPort;
|
|
user = pUser;
|
|
password = pPassword;
|
|
|
|
// GUI erstellen und Status setzen.
|
|
gui = new MyMailGUI(this);
|
|
gui.setStatus("App gestartet");
|
|
|
|
getAllMails();
|
|
}
|
|
|
|
/**
|
|
* Stellt die Verbindung zum POP3-Server her.
|
|
* <p>
|
|
* Erstellt ein {@link Connection}-Objekt für die Verbindung zum Server mit der
|
|
* IP {@link #ip} und dem Port {@link #port}. Laut RFC1939 sendet der
|
|
* POP3-Server als Erstes eine Begrüßungsnachricht zur Bestätigung der
|
|
* Verbindung:
|
|
*
|
|
* <blockquote> Once the TCP connection has been opened by a POP3 client, the
|
|
* POP3 server issues a one line greeting. This can be any positive response. An
|
|
* example might be: S: +OK POP3 server ready </blockquote>
|
|
* <p>
|
|
* Gibt es beim Verbindungsaufbau einen Fehler, gibt die Methode {@code false}
|
|
* zurück und setzt {@link #lastError} auf eine sinnvolle Fehlermeldung.
|
|
* <p>
|
|
* Das {@code Connection}-Objekt wird in {@link #con} gespeichert.
|
|
*
|
|
* @return {@code true} oder {@code false}
|
|
* @link https://datatracker.ietf.org/doc/html/rfc1939#section-4
|
|
*/
|
|
private boolean connectToServer() {
|
|
// TODO: Connection-Objekt initialisieren
|
|
con = new Connection(ip, port);
|
|
|
|
// Begrüssungsnachricht des Servers empfangen und prüfen
|
|
String mes = con.receive();
|
|
if (mes == null || mes.startsWith("-ERR")) {
|
|
// Keine "positive response" :-(
|
|
// Setze einen Fehler und gib "false" zurück.
|
|
lastError = "Der POP3-Server reagiert nicht!";
|
|
return false;
|
|
}
|
|
|
|
// Verbindung erfolgreich
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Authentifiziert den Nutzer beim POP3-Server.
|
|
* <p>
|
|
* Die Methode nutzt die {@code USER} / {@code PASS} Befehle zur Anmeldung mit
|
|
* dem {@link #user} und {@link #password}. Sie erwartet, dass zuvor erfolgreich
|
|
* eine Verbindung mit {@link #connectToServer()} hergestellt wurde.
|
|
* <p>
|
|
* Hat die Anmeldung Erfolg, wird {@code true} zurückgegeben. Andernfalls
|
|
* {@code false} und {@link #lastError} wird auf eine sinnvolle Fehler- meldung
|
|
* gesetzt.
|
|
*
|
|
* @return {@code true} oder {@code false}
|
|
* @link https://datatracker.ietf.org/doc/html/rfc1939#page-13
|
|
*/
|
|
private boolean login() {
|
|
String mes = ""; // Speicher für die Antworten des Servers
|
|
|
|
// TODO: Implementieren
|
|
// USER Kommando senden und Antwort prüfen
|
|
con.send("USER " + user);
|
|
mes = con.receive();
|
|
if (mes == null || mes.startsWith("-ERR")) {
|
|
lastError = "Ungueltiger Benutzername!";
|
|
return false;
|
|
}
|
|
// PASS Kommando senden und Antwort prüfen
|
|
con.send("PASS " + password);
|
|
mes = con.receive();
|
|
if (mes == null || mes.startsWith("-ERR")) {
|
|
lastError = "Ungueltiges Passwort!";
|
|
return false;
|
|
}
|
|
// Anmeldung war erfolgreich
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Ermittelt die Anzahl an Nachrichten auf dem Server.
|
|
* <p>
|
|
* Die Methode erwartet, dass zuvor erfolgreich eine Verbindung mit
|
|
* {@link #connectToServer()} hergestellt wurde und nutzt dann den {@code STAT}
|
|
* Befehl, um die Anzahl der Mails zu ermitteln.
|
|
*
|
|
* @return Die Anzahl an Mails auf dem Server
|
|
* @link https://datatracker.ietf.org/doc/html/rfc1939#page-6
|
|
*/
|
|
public int getMessageCount() {
|
|
String mes = "";
|
|
|
|
// TODO: Implementieren
|
|
// Sende den STAT Befehl
|
|
// Prüfe, ob die Antwort ein Fehler ist
|
|
// Schneide den Teil zwischen den Leerzeichen aus
|
|
// Finde die Leerzeichen mit indexOf(" ")
|
|
// Ermittele den Text mit substring(von, bis)
|
|
// Wandele mit Integer.parseInt() in eine Zahl um
|
|
con.send("STAT");
|
|
mes = con.receive();
|
|
int space1 = mes.indexOf(" ");
|
|
int space2 = mes.indexOf(" ", space1 + 1);
|
|
return Integer.parseInt(mes.substring(space1, space2).trim());
|
|
|
|
// ---=== Alternativ ===---
|
|
// return Integer.parseInt(mes.split(" ")[1]);
|
|
}
|
|
|
|
/**
|
|
* Ruft alle vorhandenen Mails vom Server ab und fügt sie der {@link #gui}
|
|
* hinzu.
|
|
*/
|
|
public void getAllMails() {
|
|
gui.setStatus("Rufe Mails vom Server ab..");
|
|
gui.clearAllMails(); // Gui leeren
|
|
lastError = null; // Zu Beginn gibt es noch keinen Fehler
|
|
|
|
// Verbindung erstellen und prüfen
|
|
boolean connected = connectToServer();
|
|
if (!connected) {
|
|
// Letzten Fehler anzeigen (wird in connectToServer gesetzt).
|
|
lastError = "Fehler beim Verbinden.";
|
|
return; // Abbrechen
|
|
}
|
|
|
|
// Anmeldung durchführen und prüfen
|
|
// Hinweis: Nutze die login() Methode
|
|
boolean loggedIn = login();
|
|
if (!loggedIn) {
|
|
// Letzten Fehler anzeigen (wird in connectToServer gesetzt).
|
|
lastError = "Fehler beim Einloggen.";
|
|
return; // Abbrechen
|
|
}
|
|
|
|
// Anzahl Mails auf dem Server abfragen
|
|
int mailCount = 0;
|
|
mailCount = getMessageCount();
|
|
|
|
// Abruf der Mails nach fortlaufender Nummer
|
|
for (int i = 1; i <= mailCount; i++) {
|
|
// Mail abrufen (nutze getMail(int))
|
|
// Mail der GUI hinzufügen (nutze gui.addMailToLost(Mail))
|
|
gui.addMailToList(getMail(i));
|
|
}
|
|
|
|
// Verbindung beenden
|
|
con.send("QUIT");
|
|
con.close();
|
|
|
|
if (lastError != null) {
|
|
// Es gab einen Fehler
|
|
gui.setError(lastError);
|
|
} else {
|
|
// Kein Fehler
|
|
gui.setStatus("Liste der Mails erfolgreich geladen.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ruft die Mail mit der Nummer <var>pNumber</var> vom Server ab und gibt sie
|
|
* als {@link Mail}-Objekt zurück.
|
|
* <p>
|
|
* Die Methode erwartet, dass zuvor erfolgreich eine Verbindung mit
|
|
* {@link #connectToServer()} hergestellt wurde.
|
|
* <p>
|
|
* Tritt ein Fehler auf, gibt die Methode {@code null} zurück und setzt
|
|
* {@link #lastError} auf eine sinnvolle Nachricht.
|
|
*
|
|
* @param pNumber Die Nummer einer E-Mail auf dem Server
|
|
* @return Ein Mail-Objekt oder {@code null}.
|
|
*/
|
|
public Mail getMail(int pNumber) {
|
|
String mes = ""; // Speicher für Antworten des Servers
|
|
|
|
// Prüfen, ob es eine Mail mit der Nummer pNumber gibt
|
|
int count = getMessageCount();
|
|
if (pNumber > count) {
|
|
lastError = "Es gibt keine Mail " + pNumber + "!";
|
|
}
|
|
|
|
// Mail abrufen (RETR)
|
|
con.send("RETR " + pNumber);
|
|
mes = con.receive();
|
|
|
|
boolean header = true;
|
|
String date = "";
|
|
String sender = "";
|
|
String subject = "";
|
|
String text = "";
|
|
|
|
while (!mes.equals(".")) {
|
|
// Text der Mail parsen
|
|
// Verarbeite die Metadaten, vor allem:
|
|
// - Nummer der Mail
|
|
// - Subject
|
|
// - From
|
|
// - Date
|
|
// Wenn der Textkörper anfängt, speichere alle Zeilen in einen String
|
|
//
|
|
// Hinweis: Denke daran die Maskierung des Enzeichens "." rückgängig zu
|
|
// machen.
|
|
// Tipp: Merk dir in einem boolean, ob du im Textkörper oder im Header bist.
|
|
mes = con.receive();
|
|
if (header) { // Header werden gesucht
|
|
if (mes.equals("")) { // Header ist nach leerer Zeile zuende
|
|
header = false;
|
|
} else if (mes.startsWith("Delivery-date")) {
|
|
date = mes.substring(15);
|
|
} else if (mes.startsWith("From")) {
|
|
sender = mes.substring(mes.indexOf('<') + 1, mes.indexOf('>'));
|
|
} else if (mes.startsWith("Subject")) {
|
|
subject = mes.substring(9);
|
|
}
|
|
} else { // Nachricht wird gelesen
|
|
if (mes.equals(".")) { // ende
|
|
break;
|
|
} else if (mes.startsWith("--")) { // weirde header MITTEN DRIN EINFACH SO
|
|
header = true;
|
|
} else { // Text der später ausgegeben wird
|
|
mes = mes.replaceAll("=C3=BC", "ü"); // Umlaute werden ersetzt
|
|
mes = mes.replaceAll("=C3=A4", "ä");
|
|
mes = mes.replaceAll("=C3=B6", "ö");
|
|
mes = mes.replaceAll("=C3=9F", "ß");
|
|
text += mes + "\n";
|
|
}
|
|
}
|
|
} // end of while
|
|
|
|
return new Mail(pNumber, date, sender, subject, text);
|
|
}
|
|
|
|
/**
|
|
* Löscht eine Mail vom Server.
|
|
* <p>
|
|
* Die Methode stellt eine Verbindung zum Server her, markiert die übergebene
|
|
* Mail als gelöscht und beendet die Verbindung.
|
|
* <p>
|
|
* Tritt ein Fehler auf, bricht die Methode ab und setzt den Status der GUI auf
|
|
* eine sinnvolle Fehlermeldung.
|
|
*
|
|
* <b>Achtung</b>: Es wird die Mail mit derselben Nummer wie <var>pMail</var>
|
|
* gelöscht. Es wird nicht garantiert, dass dies auch dieselbe Mail ist.
|
|
*
|
|
* @param pMail Das Mailobjekt, das gelöscht werden soll.
|
|
* @todo Vor Löschen prüfen, ob die Mail auf dem Server dieselbe wie pMail ist.
|
|
*/
|
|
public void deleteMail(Mail pMail) {
|
|
// Verbindung erstellen und prüfen
|
|
boolean connected = connectToServer();
|
|
if (!connected) {
|
|
// Letzten Fehler anzeigen (wird in connectToServer gesetzt).
|
|
gui.setStatus("Fehler beim Verbinden.");
|
|
return; // Abbrechen
|
|
}
|
|
|
|
// Anmeldung durchführen und prüfen
|
|
boolean loggedIn = login();
|
|
if (!loggedIn) {
|
|
// Letzten Fehler anzeigen (wird in connectToServer gesetzt).
|
|
gui.setStatus("Fehler beim Einloggen.");
|
|
return; // Abbrechen
|
|
}
|
|
|
|
// Prüfen, ob eine Mail mit der Nummer vorhanden ist
|
|
// Hinweis: Die Nummer der Mail ist über pMail.getNumber() abrufbar
|
|
Mail m = getMail(pMail.getNumber());
|
|
if (m == null) {
|
|
gui.setStatus("Die mail konnte nicht gelöscht werden, da sie nicht existiert.");
|
|
return;
|
|
} else {
|
|
// Mail als gelöscht markieren
|
|
//**** con.send("dele " + pMail.getNumber());
|
|
// Löschung ausführen und Verbindung beenden.
|
|
con.send("quit");
|
|
}
|
|
|
|
gui.setStatus("Mail erfolgreich gelöscht.");
|
|
|
|
// Mail aus der GUI entfernen und neu aufbauen.s
|
|
gui.removeMailFromList(pMail);
|
|
}
|
|
|
|
}
|