/**
 *  Copyright © 2025, Luis Andrés Lange <https://javacomm.net>
 *
 *  Previously released under Apache License 2.0; now licensed under MPL 2.0.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *  ----------------------------------------------------------------------------
 *
 *  Exhibit B - "Incompatible With Secondary Licenses" Notice
 *
 *  This Source Code Form is "Incompatible With Secondary Licenses",
 *  as defined by the Mozilla Public License, v. 2.0.
 *
 *  In short:
 *  - This file may be used, modified, and distributed under MPL 2.0 only.
 *  - It may NOT be relicensed under GPL, LGPL, AGPL, or any other Secondary License.
 *
 *  Rationale:
 *  - Ensures that the code remains MPL-2.0.
 *  - Avoids legal conflicts with GPL-licensed libraries (e.g., VideoLAN).
 *  - Maximizes usability for commercial and security-critical applications.
 *
 */
package net.javacomm.database;

import jakarta.mail.Authenticator;
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
import jakarta.mail.PasswordAuthentication;
import jakarta.mail.Session;
import jakarta.mail.Transport;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import net.javacomm.database.entity.EntityUser;
import net.javacomm.facade.DatabaseService;
import net.javacomm.multilingual.MultilingualString;
import net.javacomm.multilingual.schema.ISO639;
import net.javacomm.multilingual.schema.KEY;
import net.javacomm.protocol.Benutzerstatus;
import net.javacomm.server.Webserver;



/**
 * 
 * Der Datenbankzugriff wird über ein Servlet hergestellt. Die DataSource muss
 * anders als in der Stand-alone-Variante eingebunden werden.
 * 
 * @author llange
 *
 */
public class WebdatabaseImpl extends DatabaseService {

  private static WebdatabaseImpl instance;

  public synchronized static DatabaseService getInstance() {
    return instance;
  }



  public synchronized static DatabaseService getInstance(String resource) {
    if (instance != null) return instance;
    instance = new WebdatabaseImpl(resource);
    return instance;
  }

  private final Logger log = LogManager.getLogger(WebdatabaseImpl.class);

  private DataSource datasource;

  // public static Thread databaseThread = null;
  private ExecutorService executorDatabase;

  /**
   * Der Resource-Name aus der <b>context.xml</b> muss mit dem Eintrag für die SQL
   * Datasource identisch sein.
   * 
   * @param resource
   *                 die Datenquelle aus der context.xml
   */
  private WebdatabaseImpl(String resource) {
    try {
      log.info("ResourceName    --->  " + resource);
      Context initContext = new InitialContext();
      Context envContext = (Context) initContext.lookup("java:/comp/env");
      datasource = (DataSource) envContext.lookup(resource);
      if (datasource == null) {
        log.fatal("no datasource found");
        throw new RuntimeException("no datasource found");
      }
      else {
        pool = datasource.getPool();
        log.info("Datenbankanbindung hergestellt!");

        executorDatabase = Executors.newSingleThreadExecutor(
            runnable -> new Thread(Thread.currentThread().getThreadGroup(), runnable, "database")
        );

        Runnable runnable = () -> {
          int benachrichtigungszaehler = 0;
          while (true) {

            /**
             * Lösche alle Räume ohne Eigentümer und alle zugehörigen Gruppen, wenn der Raum
             * nicht mehr existiert.
             */
            deleteOrphained();

            // Alle abgelaufenen Telkos löschen
            deleteTelkos();

            // Lösche alle Konferenzteilnehmer ohne Telko
            deleteKonferenzteilnehmerOhneTelko();

            // Finde alle User die offline sind und in einer Telko sein sollen.
            updateKonferenzraumOnhook();

            deletePrivateChatfiles();
            deleteRecord();
            // lösche alle Anhänge, die verwaist sind
            deleteOrphainedChatfiles();
            deleteConfirmationFlag();

            // Alle zu löschenden Nicknames abfragen
            List<EntityUser> allNicknames = toDeleteNicknames();
            resetNicknames(allNicknames);

            List<String> toDeleteChatrooms = fetchForbiddenRooms();
            for (String room : toDeleteChatrooms) {
              deleteForbiddenRoom(room);
            }
            try {
              if (benachrichtigungszaehler >= 10) {
                benachrichtigungszaehler = 0;
                // alle 5 Stunden wird eine Benachrichtigung gesendet
                // 1 Zaehlereinheit = 30 Minuten gegenwärtig
                sendMailToAdmin(readBenutzerAntraege(), getAdminmail());
              }
              List<EntityUser> confirmedUser = fetchConfirmedUser();
              sendConfirmationMail(confirmedUser);
            }
            catch (NamingException | MessagingException e1) {
              log.error(e1.getMessage(), e1);
            }
            catch (MailportException e) {
              log.error(e.getMessage(), e);
            }

            deleteBenutzerstatus();
            try {
              Thread.sleep(1800000); // 30 Minuten
            }
            catch (InterruptedException e) {
              log.error(e.getMessage(), e.getCause());
              break;
            }
            benachrichtigungszaehler++;
          }
        };

        executorDatabase.execute(runnable);

        deleteUserXChat();
        deleteOnline();
        deleteTemprooms();
        deleteAllPrivateChats();
        deleteTransferLib();
        deleteGroupUser();
        clearGroupUser();
        deleteInactiveUser();
        deleteOrphainedRoom();
        deleteToPhone();
        deleteNirvanaSuffixes();
        deleteNirvanaFiletransferConfig();
        checkConfigs();
        deleteScreencast();
        deleteAllPrivateChatfiles();
        deletePrivateChunks();
        updateChatfiles();
        deleteKonferenzraumSessions();
        deleteAllVideo();
        deleteAllVideoSender();
        updateUnmuteAll();
        insertConfigIf();
        switchOffProjectors();
        updateRSA();
        deleteAllToken();
      }
    }
    catch (NamingException e) {
      log.fatal(e.getMessage(), e);
    }
  }



  @Override
  public void clearGroupUser() {
    persistence = Persistence.getInstance();
    String sql = persistence.getSQL(Persistence.KEY_CLEAR_GRUPPE);
    logSQLKey(Persistence.KEY_CLEAR_GRUPPE, sql);
    Connection connection = null;
    Statement statement = null;
    try {
      connection = pool.getConnection();
      statement = connection.createStatement();
      statement.executeUpdate(sql);
    }
    catch (SQLException e) {
      log.fatal(e.getMessage(), e.getCause());
    }
    finally {
      try {
        if (statement != null) statement.close();
      }
      catch (SQLException e) {}
      try {
        if (connection != null) connection.close();
      }
      catch (SQLException e) {}
    }
  }



  @Override
  public void connect() {
    log.info("Verbindung wird über META-INF/context.xml hergestellt");
  }



  @Override
  public void connect(PoolProperties props) {
    log.info("Verbindung wird über META-INF/context.xml hergestellt");
  }



  @Override
  public void deleteAllPrivateChats() {
    String sql = persistence.getSQL(Persistence.KEY_DELETE_ALL_PRIVATECHATS);
    logSQLKey(Persistence.KEY_DELETE_ALL_PRIVATECHATS, sql);
    try(
      Connection connection = pool.getConnection();
      Statement statement = connection.createStatement();
    ) {
      statement.executeUpdate(sql);
    }
    catch (SQLException e) {
      log.error(e.getMessage(), e.getCause());
    }

  }



  @Override
  public void deleteForceRecord() {
    throw new UnsupportedOperationException("Die Methode ist nur für Testzwecke.");
  }



  @Override
  public int deleteGroupUser() {
    int result = 0;
    persistence = Persistence.getInstance();
    String sql = persistence.getSQL(Persistence.KEY_DELETE_GRUPPE_USER);
    logSQLKey(Persistence.KEY_DELETE_GRUPPE_USER, sql);
    try(
      Connection connection = pool.getConnection();
      Statement statement = connection.createStatement()
    ) {
      result = statement.executeUpdate(sql);
    }
    catch (SQLException e) {
      log.error(e.getMessage(), e.getCause());
    }
    return result;
  }



  @Override
  public void deleteInactiveUser() {
    String sql = persistence.getSQL(Persistence.KEY_DELETE_INACTIVE_USER);
    logSQLKey(Persistence.KEY_DELETE_INACTIVE_USER, sql);
    try(
      Connection connection = pool.getConnection();
      Statement statement = connection.createStatement()
    ) {
      statement.executeUpdate(sql);
    }
    catch (SQLException e) {
      log.error(e.getMessage(), e.getCause());
    }
  }



  @Override
  public void deleteOnline() {
    String sql = persistence.getSQL(Persistence.KEY_DELETE_ALL_ONLINE);
    logSQLKey(Persistence.KEY_DELETE_ALL_ONLINE, sql);
    try(
      Connection connection = pool.getConnection();
      PreparedStatement statement = connection.prepareStatement(sql);
    ) {
      statement.executeUpdate();
    }
    catch (SQLException e) {
      log.error(e.getMessage(), e.getCause());
    }
  }



  /**
   * TB_CHAT und TB_GRUPPE_USER werden gemeinsam bereinigt, weil TB_GRUPPE_USER
   * abhängig von TB_CHAT ist. Durch das Löschen eines Raumes wird die Gruppe
   * aufgelöst.
   */
  private void deleteOrphained() {

    // Lösche alle Anwender aus der TB_ONLINE, die nicht mehr in der TB_USER
    // existieren
    deleteOrphainedOnline();

    // Lösche alle Räume ohne Eigentümer
    deleteOrphainedRoom();

    // Lösche eine Gruppe, wenn der Raum nicht mehr existiert
    deleteGroupUser();

    // Lösche alle Telkos deren Organisator nicht mehr existiert.
    deleteOrphainedTelko();

  }



  @Override
  public void deleteOrphainedRoom() {
    String sql = persistence.getSQL(Persistence.KEY_DELETE_ALL_ROOMS_WITHOUT_EXISTING_OWNER);
    logSQLKey(Persistence.KEY_DELETE_ALL_ROOMS_WITHOUT_EXISTING_OWNER, sql);
    try(
      Connection connection = pool.getConnection();
      Statement statement = connection.createStatement()
    ) {
      statement.executeUpdate(sql);
    }
    catch (SQLException e) {
      log.error(e.getMessage(), e.getCause());
    }
  }



  /**
   * Lösche alle Telkos deren Organisator nicht mehr existiert.
   */
  public void deleteOrphainedTelko() {
    String sql = persistence.getSQL(Persistence.KEY_DELETE_ORPHAINED_TB_TELKO);
    logSQLKey(Persistence.KEY_DELETE_ORPHAINED_TB_TELKO, sql);
    try(
      Connection connection = pool.getConnection();
      Statement statement = connection.createStatement()
    ) {
      statement.executeUpdate(sql);
    }
    catch (SQLException e) {
      log.error(e.getMessage(), e.getCause());
    }
  }



  @Override
  public void deletePrivateChatfiles() {
    super.deletePrivateChatfiles();
  }



  /**
   * Lösche alle veralteten Nachrichten. Alle Chaträume werden durchsucht.
   */
  @Override
  public void deleteRecord() {
    String sql = persistence.getSQL(Persistence.KEY_DELETE_RECORDS);
    logSQLKey(Persistence.KEY_DELETE_RECORDS, sql);
    try(
      Connection connection = pool.getConnection();
      Statement statement = connection.createStatement()
    ) {
      statement.executeUpdate(sql);
    }
    catch (SQLException e) {
      log.error(e.getMessage(), e.getCause());
    }
  }



  @Override
  public void deleteScreencast() {
    String sql = persistence.getSQL(Persistence.KEY_DELETE_SCREENCAST);
    logSQLKey(Persistence.KEY_DELETE_SCREENCAST, sql);
    try(
      Connection connection = pool.getConnection();
      Statement statement = connection.createStatement()
    ) {
      statement.executeUpdate(sql);
    }
    catch (SQLException e) {
      log.error(e.getMessage(), e);
    }
  }



  @Override
  public void deleteTemprooms() {
    String sql = persistence.getSQL(Persistence.KEY_DELETE_TEMPROOMS);
    logSQLKey(Persistence.KEY_DELETE_TEMPROOMS, sql);
    try(
      Connection connection = pool.getConnection();
      Statement statement = connection.createStatement()
    ) {
      statement.executeUpdate(sql);
    }
    catch (SQLException e) {
      log.error(e.getMessage(), e.getCause());
    }
  }



  @Override
  public void deleteTransferLib() {
    String sql = persistence.getSQL(Persistence.KEY_CLEAR_TRANSFERLIB);
    logSQLKey(Persistence.KEY_CLEAR_TRANSFERLIB, sql);
    try(
      Connection connection = pool.getConnection();
      Statement statement = connection.createStatement()
    ) {
      statement.executeUpdate(sql);
    }
    catch (SQLException e) {
      log.error(e.getMessage(), e.getCause());
    }
  }



  @Override
  public void deleteUserXChat() {
    String sql = persistence.getSQL(Persistence.KEY_DELETE_USER_CHATS);
    logSQLKey(Persistence.KEY_DELETE_USER_CHATS, sql);
    try(
      Connection connection = pool.getConnection();
      Statement statement = connection.createStatement();
    ) {
      statement.executeUpdate(sql);
    }
    catch (SQLException e) {
      log.error(e.getMessage(), e.getCause());
    }
  }



  /**
   * An diesen Administrator wird die Mail gesendet.
   * 
   * @return diese Mailadresse
   * 
   * @throws NamingException
   *                         die Mailadresse wurde nicht gefunden
   */
  public final String getAdminmail() throws NamingException {
    Context initContext = new InitialContext();
    return (String) initContext.lookup("java:comp/env/adminmail");
  }



  @Override
  public PoolProperties getDefaultPoolProperties() {
    log.warn("PoolProperties noch füllen");
    return new PoolProperties();
  }



  /**
   * Der Webserver erstellt eine Mailsession für den Versand.
   * 
   * @param host
   *             dieser SMTP Server
   * @param user
   *             dieser Mailbenutzer
   * @param port
   *             dieser SMTP Port
   * 
   * @return diese Mailsession kann gesendet werden
   * 
   * @throws NamingException
   *                           in der context.xml fehlt das Benutzerpassort
   * @throws MailportException
   *                           Port wird nicht unterstützt
   */
  public Session getMailSession(String host, String user, Integer port)
      throws NamingException, MailportException {
    return getMailSession(host, user, port, getSmtpPassword());
  }



  public Session getMailSession(String host, String user, Integer port, String smtpPassword)
      throws NamingException, MailportException {

    Properties props = new Properties();
    if (port == 465) {
      props.put("mail.smtp.port", port); // aus AdminGUI
      props.put("mail.smtp.auth", true); // aus context.xml
      props.put("mail.smtp.starttls.enable", false);
      props.put("mail.smtp.host", host); // aus context.xml Env
      props.put("mail.smtp.ssl.enable", true); // aus context.xml Env
    }
    else if (port == 587) {
      props.put("mail.smtp.host", host); // aus context.xml Env
      props.put("mail.smtp.port", port); // aus AdminGUI

      props.put("mail.smtp.starttls.enable", true);
      props.put("mail.smtp.starttls.required", true); // aus context.xml
      props.put("mail.smtp.auth", true); // aus context.xml
      props.put("mail.smtp.ssl.enable", false); // aus context.xml Env
      props.put("mail.smtp.ssl.checkserveridentity", false); // aus context.xml Env
    }
    else {
      StringBuilder builder = new StringBuilder("SMTP port ").append(port)
          .append(" is not supported. Use port 465 or 587.");
      throw new MailportException(builder.toString());
    }

//    props.put("mail.smtp.port", 465);
//    props.put("mail.smtp.auth", true);
//    props.put("mail.smtp.starttls.enable", false);
//    props.put("mail.smtp.host", "mail.javacomm.de");
//    props.put("mail.smtp.ssl.enable", true);

    final PasswordAuthentication pw = new PasswordAuthentication(
        user, smtpPassword // username/Passwort aus context.xml, user aus AdminGUI
    );

    props.put(props, pw);

    Session newSession = Session.getInstance(props, new Authenticator() {
      @Override
      protected PasswordAuthentication getPasswordAuthentication() {
        return pw;
      }
    });

    return newSession;

  }



  @Override
  public final String getSmtpHost() throws NamingException {
    Context initContext = new InitialContext();
    return (String) initContext.lookup("java:comp/env/mail.smtp.host");
  }



  /**
   * Hole das {@code mail.smtp.password} aus der {@code context.xml}.
   * 
   * @return dieses Passwort
   * 
   * @throws NamingException
   *                         das Passwort wurde nicht gefunden
   */
  @Override
  public final String getSmtpPassword() throws NamingException {
    Context initContext = new InitialContext();
    return (String) initContext.lookup("java:comp/env/mail.smtp.password");
  }



  @Override
  public Integer getSmtpPort() throws NamingException {
    Context initContext = new InitialContext();
    return (Integer) initContext.lookup("java:comp/env/mail.smtp.port");
  }



  @Override
  public final String getSmtpUser() throws NamingException {
    Context initContext = new InitialContext();
    return (String) initContext.lookup("java:comp/env/mail.smtp.user");
  }



  @Override
  public void init() {

  }



  /**
   * Der Anwender bekommt eine Bestätigungsmail, dass er Vollmitglied ist.
   * 
   * @param userlist
   *                 eine Liste bestätigter Mitglieder
   * @param config
   *                 JNDI Referenz aus der context.xml für eine
   *                 Mailserververbindung sowie Verbindungsdaten
   * @throws NamingException
   * @throws MailportException
   */
  public void sendConfirmationMail(List<EntityUser> userlist) throws NamingException, MailportException {
    // TODO vor dem Absenden der Mail wird ein Password erzeugt.

    // TODO Ticket erzeugen für eingeschränkten Anmeldevorgang / Vollmitgliedschaft

    // Nach dem Absenden der Mail wird der Benutzerstatus auf 1 umgestellt.
    if (userlist.size() == 0) return;

    Session session = getMailSession(this.getSmtpHost(), this.getSmtpUser(), this.getSmtpPort());

    Message message = new MimeMessage(session);
    try {

      for (EntityUser user : userlist) {
        // TODO Sinn prüfen, weil anschließend ein neuese Passwort mit BCRYPT erzeugt
        // wird
        if (!checkPassword(user.getUid(), user.getPassword())) continue; // Wenn User nicht vorhanden oder
                                                                         // nicht gültig
        // bestätigt
        EntityUser userdata = createPassword(user.getUid());
        updateBenutzerstatus(Benutzerstatus.VOLLMITGLIED, userdata.getUid());

        InternetAddress from = new InternetAddress(this.getSmtpUser());
        message.setFrom(from);
        message.setRecipient(Message.RecipientType.TO, new InternetAddress(user.getMail()));
        message.setSubject("Javacomm Registrierung");

        StringBuilder buffer = new StringBuilder();
        buffer.append("Hallo Anwender,");
        buffer.append("\r\n");
        buffer.append("\r\n");
        buffer.append("der Registrierungsvorgang ist erfolgreich abgeschlossen.");
        buffer.append("\r\n");
        buffer.append("Deine Benutzer-ID und dein Passwort beginnen nach dem Doppelpunkt.");
        buffer.append("\r\n");
        buffer.append("Ändere nach der Anmeldung das Passwort.");
        buffer.append("\r\n");
        buffer.append("\r\n");
        // TODO das Anfangspasswort setzen
        // Ein Initialpassword muss erzeugt werden
        buffer.append("Benutzer-ID:").append(userdata.getUid()).append("\r\n").append("Passwort:")
            .append(userdata.getPassword());

        buffer.append("\r\n");
        buffer.append("\r\n");
        buffer.append("Diese Nachricht wurde automatisch erzeugt.");

        // TODO Bestätigungsgmail versenden
        message.setText(buffer.toString());
        Transport.send(message);
      }
      return;
    }
    catch (MessagingException e) {
      log.error(e.getMessage(), e.getCause());
    }
  }



  /**
   * Alle Benutzeranträge auf eine Mitgliedschaft werden an den Administrator
   * gesendet.
   * 
   * @param userlist
   *                  alle offenen Benutzeranträge mit dem Status 'möchte
   *                  Vollmitglied werden'
   * @param adminmail
   *                  an diese Mailadresse wird gesendet
   * @throws NamingException
   * @throws MessagingException
   * @throws MailportException
   */
  public void sendMailToAdmin(List<EntityUser> userlist, String adminmail)
      throws NamingException, MessagingException, MailportException {
    if (userlist.size() == 0) return;
    StringBuilder buffer = new StringBuilder();
    for (EntityUser antrag : userlist) {
      buffer.append("\r\n");
      buffer.append("UID:");
      buffer.append(antrag.getUid());
      buffer.append("\r\n");
      buffer.append("Mail:");
      buffer.append(antrag.getMail());
      buffer.append("\r\n");
      buffer.append("--");
      buffer.append("\r\n");
      log.info(buffer.toString());
    }

    Session mailsession = getMailSession(this.getSmtpHost(), this.getSmtpUser(), this.getSmtpPort());

    Message message = new MimeMessage(mailsession);

    InternetAddress from = new InternetAddress(this.getSmtpUser());
    message.setFrom(from);
    message.setRecipient(Message.RecipientType.TO, new InternetAddress(adminmail));
    message.setSubject("Javacomm - Neue Benutzeranträge sind eingegangen");

    message.setText(buffer.toString());
    Transport.send(message);

  }



  @Override
  public void shutdown() {
    Logger log3 = LogManager.getLogger(Webserver.class);
    executorDatabase.shutdown();
    try {
      boolean done = executorDatabase.awaitTermination(1, TimeUnit.SECONDS);
      if (!done) {
        executorDatabase.shutdownNow();
      }
    }
    catch (InterruptedException e) {
      log3.error(e.getMessage(), e.getCause());
    }

    datasource.close();

    log3.info("Databaseservice is down");
  }



  /**
   * Sende eine Testmail an ein Administratorpostfach.
   * 
   * 
   * @param host
   *                      an diesen SMTP Host wird gesendet
   * @param user
   *                      dieser SMTP User
   * @param port
   *                      dieser SMTP Port
   * @param smptPassword
   *                      dieses SMTP Password
   * @param adminPostfach
   *                      an dieses Adminpostfach wird gesendet
   * @param isocode
   *                      diese Sprache soll in der Mail verwendet werden
   * 
   * @return im Erfolgsfall wird das Adminpostfach zurückgegeben
   * @throws NamingException
   *                            mindestens 1 Konfigurationsparameter konnte nicht
   *                            gefunden werden
   * @throws MessagingException
   *                            diese Mail konnte nicht versendet werden
   * @throws MailportException
   *                            dieser Port wird nicht unterstützt
   */
  public String testMail(String host, String user, Integer port, String smptPassword, String adminPostfach,
      String isocode) throws NamingException, MessagingException, MailportException {

    Session mailsession = getMailSession(host, user, port, smptPassword);
    MimeMessage message = new MimeMessage(mailsession);
    InternetAddress from = new InternetAddress(user);

    MultilingualString subject = new MultilingualString(
        KEY.SERVER_BETREFF_TESTMAIL, ISO639.fromValue(isocode)
    );
    MultilingualString mailtext = new MultilingualString(KEY.SERVER_TESTMAIL, ISO639.fromValue(isocode));

    StringBuilder buffer = new StringBuilder(mailtext.toString());
    buffer.append("\r\n");
    buffer.append("\r\n");

    String context = "<Environment name=\"adminmail\"\n" + "             value="
        + adminPostfach
        + "\"\n"
        + "             type=\"java.lang.String\" />\n"
        + "\n"
        + "<Environment name=\"mail.smtp.password\"\n"
        + "             value="
        + smptPassword
        + "\"\n"
        + "             type=\"java.lang.String\" />\n"
        + "\n"
        + "<Environment name=\"mail.smtp.user\"\n"
        + "             value="
        + user
        + "\"\n"
        + "             type=\"java.lang.String\" />\n"
        + "\n"
        + "<Environment name=\"mail.smtp.host\"\n"
        + "             value="
        + host
        + "\"\n"
        + "             type=\"java.lang.String\" />\n"
        + "\n"
        + "<Environment name=\"mail.smtp.port\"\n"
        + "             value=\""
        + port
        + "\"\n"
        + "             type=\"java.lang.Integer\" />\n";

    buffer.append(context);

    message.setFrom(from);
    message.setRecipient(Message.RecipientType.TO, new InternetAddress(adminPostfach));
    message.setSubject(subject.toString());
    message.setText(buffer.toString());

    Transport.send(message);
    return adminPostfach;

  }



  /**
   * Sende eine Testmail an ein Administratorpostfach.
   * 
   * 
   * @param host
   *                      an diesen SMTP Host wird gesendet
   * @param user
   *                      dieser SMTP User
   * @param port
   *                      dieser SMTP Port
   * @param smptPassword
   *                      dieses SMTP Password
   * @param adminPostfach
   *                      an dieses Adminpostfach wird gesendet
   * 
   * @return im Erfolgsfall wird das Adminpostfach zurückgegeben
   * @throws NamingException
   *                            mindestens 1 Konfigurationsparameter konnte nicht
   *                            gefunden werden
   * @throws MessagingException
   *                            diese Mail konnte nicht versendet werden
   * @throws MailportException
   *                            dieser Port wird nicht unterstützt
   */
  public String testMail(String host, String user, Integer port, String smptPassword, String adminPostfach)
      throws NamingException, MessagingException, MailportException {
    return testMail(host, user, port, smptPassword, adminPostfach, "en");
  }

}
