/*
** This file is part of Filius, a network construction and simulation software.
**
** Originally created at the University of Siegen, Institute "Didactics of
** Informatics and E-Learning" by a students' project group:
** members (2006-2007):
** André Asschoff, Johannes Bade, Carsten Dittich, Thomas Gerding,
** Nadja Haßler, Ernst Johannes Klebert, Michell Weyer
** supervisors:
** Stefan Freischlad (maintainer until 2009), Peer Stechert
** Project is maintained since 2010 by Christian Eibl <filius@c.fameibl.de>
** and Stefan Freischlad
** Filius is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) version 3.
**
** Filius is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
** PURPOSE. See the GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Filius. If not, see <http://www.gnu.org/licenses/>.
*/
package filius.software.email;
import java.util.LinkedList;
import java.util.ListIterator;
import filius.Main;
import filius.software.clientserver.ServerMitarbeiter;
import filius.software.transportschicht.TCPSocket;
/** Der Mitarbeiter dient dazu, den Datenaustausch mit einem Client durchzufuehren. <br />
* Dazu durchlaeuft er folgende Zustaende:
* <ol>
* <li> START: Empfang des Begruessungskommandos (HELO oder EHLO) </li>
* <li> ENVELOPE: Empfang der 'Briefumschlags'-Informationen (Sender, Empfaenger etc) </li>
* <li> DATA: Empfang der eigentlichen E-Mail mit Kopfdaten und Nutzdaten, die
* mit einem Zeilenumbruch, einem Punkt, einem Zeilenumbruch beendet werden
* (<CR><LF>.<CR><LF>) </li>
* <li> END: Der Datenaustausch wurde beendet. (Das ist der einzig gueltige
* Endzustand!) </li>
* </ol>
* Nachdem eine Nachricht ordnungsgemaess empfangen wurde, befindet sich der
* Mitarbeiter im END-Zustand. Das heisst, dass dieser Mail-Server es nicht ermoeglicht
* mit einer Verbindung mehrere E-Mails zu uebertragen.
*
*/
public class SMTPMitarbeiter extends ServerMitarbeiter
{
private static final int START=0, ENVELOPE=1, DATA=2, END=3;
private EmailServer emailServer;
private int zustand = START;
private LinkedList rcptTo = new LinkedList();
private String mailFrom = "";
private String quelltext="";
private Email email = null;
private EmailKonto empfaengerKonto = new EmailKonto();
// Konstruktor(en)
public SMTPMitarbeiter(//Betriebssystem bs,
TCPSocket socket, SMTPServer server)
{
super(server, socket);
Main.debug.println("INVOKED-2 ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (SMTPMitarbeiter), constr: SMTPMitarbeiter("+socket+","+server+")");
this.socket = socket;
this.emailServer = server.holeEmailServer();
senden(messages.getString("sw_smtpmitarbeiter_msg1") + " " + emailServer.getMailDomain());
}
// Methoden
/** In dieser Methode werden die ankommenden Befehle und
* Daten zur Uebertragung einer E-Mail verarbeitet.
*/
protected void verarbeiteNachricht(String nachricht) {
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (SMTPMitarbeiter), verarbeiteNachricht("+nachricht+")");
String[] tokens;
String tmp;
int pos, pos2;
emailServer.benachrichtigeBeobachter(socket.holeZielIPAdresse()+"< "+nachricht);
// Verarbeitung der vom Client ankommenden Daten
if (nachricht.trim().equalsIgnoreCase("QUIT")) {
senden(messages.getString("sw_smtpmitarbeiter_msg2"));
socket.schliessen();
}
else if (zustand == START) {
pos = nachricht.indexOf(" ");
if (pos > 0) tmp = nachricht.substring(0, pos).trim();
else tmp = nachricht.trim();
if (tmp.equalsIgnoreCase("HELO") || tmp.equalsIgnoreCase("EHLO"))
{
if (pos > 0) tmp = nachricht.substring(pos, nachricht.length()).trim();
else tmp = "";
senden("250 Hello "+ tmp);
zustand = ENVELOPE;
}
else if (tmp.equalsIgnoreCase("NOOP")) {
senden(messages.getString("sw_smtpmitarbeiter_msg3"));
}
}
else if (zustand == ENVELOPE) {
pos = nachricht.indexOf(":");
if (pos > 0) tmp = nachricht.substring(0, pos).trim();
else tmp = nachricht.trim();
if (tmp.equalsIgnoreCase("MAIL FROM")) {
pos = nachricht.indexOf("<");
pos2 = nachricht.indexOf(">");
if (pos > 0 && pos2 > pos) {
mailFrom = nachricht.substring(pos+1, pos2).trim();
senden(messages.getString("sw_smtpmitarbeiter_msg4"));
}
else {
senden(messages.getString("sw_smtpmitarbeiter_msg5"));
}
}
else if (tmp.equalsIgnoreCase("RCPT TO")) {
pos = nachricht.indexOf("<");
pos2 = nachricht.indexOf(">");
if (pos > 0 && pos2 > pos) {
rcptTo.add(nachricht.substring(pos+1, pos2).trim());
senden(messages.getString("sw_smtpmitarbeiter_msg6"));
}
else {
senden(messages.getString("sw_smtpmitarbeiter_msg7"));
}
}
else if (tmp.equalsIgnoreCase("DATA")) {
if (!mailFrom.equals("") && rcptTo.size() > 0) {
senden(messages.getString("sw_smtpmitarbeiter_msg8"));
zustand = DATA;
}
else {
senden(messages.getString("sw_smtpmitarbeiter_msg9"));
}
}
else if (tmp.equalsIgnoreCase("NOOP")) {
senden("250 OK");
}
}
else if (zustand == DATA) {
tokens = nachricht.split("\n");
if ((tokens.length > 0 && tokens[tokens.length-1].trim().equals("."))
|| (tokens.length > 1 && tokens[tokens.length-2].trim().equals(".") && tokens[tokens.length-2].trim().equals(""))) {
quelltext = quelltext + nachricht.substring(0, nachricht.lastIndexOf("."));
email = new Email(quelltext);
senden(messages.getString("sw_smtpmitarbeiter_msg10"));
verarbeiteEmail();
zustand = END;
}
else {
quelltext = quelltext + nachricht;
}
}
else if (zustand == END) {
senden(messages.getString("sw_smtpmitarbeiter_msg11"));
zustand = ENVELOPE;
}
}
/** Nachdem eine E-Mail erfolgreich empfangen wurde, wird sie in dieser
* Methode in Abhaengigkeit der angegebenen Empfaenger in einem lokalen Postfach
* abgelegt bzw. an einen neuen Empfaenger weiter geleitet.
*/
private void verarbeiteEmail()
{
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (SMTPMitarbeiter), verarbeiteEmail()");
String aktuellerEmpfaenger = "";
String weitereEmpfaenger = "";
ListIterator it;
Email kopie = new Email(email.toString());
it = rcptTo.listIterator();
while (it.hasNext())
{
aktuellerEmpfaenger = (String)it.next();
String [] temp = aktuellerEmpfaenger.split("@");
String benutzer = temp[0];
if(pruefeAufSelbeDomain(aktuellerEmpfaenger))
{
empfaengerKonto = emailServer.sucheKonto(benutzer);
empfaengerKonto.getNachrichten().add(kopie);
emailServer.benachrichtigeBeobachter(messages.getString("sw_smtpmitarbeiter_msg12")+" "+empfaengerKonto.getBenutzername()+" "+ messages.getString("sw_smtpmitarbeiter_msg13"));
}
else
{
weitereEmpfaenger = weitereEmpfaenger + aktuellerEmpfaenger + ",";
//Main.debug.println("=================================WeiterleitungsEmpfaenger sieht so aus: "+weitereEmpfaenger+" =========================");
}
}
if (!weitereEmpfaenger.equals("")) emailServer.emailWeiterleiten(kopie, mailFrom, weitereEmpfaenger);
}
/**
* Methode prüft, ob die Domain, an die die Email geschickt werden soll, mit der
* des eigenen MailServers übereinstimmt.
* @param str
* @return boolean
*/
private boolean pruefeAufSelbeDomain(String str)
{
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (SMTPMitarbeiter), pruefeAufSelbeDomain("+str+")");
boolean check = false;
String [] emailAdresse = str.split("@");
String pruefdomain = emailAdresse[1].substring(0, emailAdresse[1].length());
if(pruefdomain.equalsIgnoreCase(emailServer.getMailDomain()))
{
check = true;
}
return check;
}
private void zeigeEmail(Email email)
{
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (SMTPMitarbeiter), zeigeEmail("+email+")");
//Main.debug.println("********************************************************");
//Main.debug.println("Email Absender: "+email.getAbsender());
for(ListIterator iter = email.getEmpfaenger().listIterator(); iter.hasNext();){
//Main.debug.println("Email Empfaenger: "+(String)iter.next());
}
for(ListIterator iterc = email.getCc().listIterator(); iterc.hasNext();){
//Main.debug.println("Email Cc: "+(String)iterc.next());
}
for(ListIterator iterb = email.getBcc().listIterator(); iterb.hasNext();){
//Main.debug.println("Email Bcc: "+(String)iterb.next());
}
//Main.debug.println("Email Betreff: "+email.getBetreff());
//Main.debug.println("Email Datum erhalten: "+email.getDateReceived());
//Main.debug.println("Email Text: "+email.getText());
//Main.debug.println("*********************************************************");
}
/** Methode zum Senden von Nachrichten. Gleichzeitig wird der Beobachter des
* Mail-Servers ueber die verschickte Nachricht informiert!
*/
private void senden(String nachricht) {
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (SMTPMitarbeiter), senden("+nachricht+")");
try {
socket.senden(nachricht);
emailServer.benachrichtigeBeobachter(socket.holeZielIPAdresse()+"> "+nachricht);
}
catch (Exception e) {
e.printStackTrace(Main.debug);
emailServer.benachrichtigeBeobachter(messages.getString("sw_smtpmitarbeiter_msg14") + " " + socket.holeZielIPAdresse());
}
}
}