Package sos.net

Source Code of sos.net.SOSFTPCommand$RemoteConsumer

/********************************************************* begin of preamble
**
** Copyright (C) 2003-2010 Software- und Organisations-Service GmbH.
** All rights reserved.
**
** This file may be used under the terms of either the
**
**   GNU General Public License version 2.0 (GPL)
**
**   as published by the Free Software Foundation
**   http://www.gnu.org/licenses/gpl-2.0.txt and appearing in the file
**   LICENSE.GPL included in the packaging of this file.
**
** or the
** 
**   Agreement for Purchase and Licensing
**
**   as offered by Software- und Organisations-Service GmbH
**   in the respective terms of supply that ship with this file.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
** IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
** THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
********************************************************** end of preamble*/
package sos.net;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

import sos.configuration.SOSConfiguration;
import sos.util.SOSArguments;
import sos.util.SOSClassUtil;
import sos.util.SOSCommandline;
import sos.util.SOSLogger;
import sos.util.SOSStandardLogger;
import sos.util.SOSString;

import com.sos.JSHelper.Basics.JSVersionInfo;
import com.trilead.ssh2.Connection;
import com.trilead.ssh2.HTTPProxyData;
import com.trilead.ssh2.SFTPException;
import com.trilead.ssh2.SFTPv3Client;
import com.trilead.ssh2.SFTPv3FileAttributes;
import com.trilead.ssh2.SFTPv3FileHandle;
import com.trilead.ssh2.Session;
import com.trilead.ssh2.StreamGobbler;

/**
*
* Send/Receive files by FTP/FTPS/SFTP and execute commands by SSH
*
* This program is used as a standalone, synchroneous File Transfer solution.
* For asynchroneous file transfer see the respective standard jobs with the Job Scheduler.
*
* File Transfer Features
*
*  - Send and receive files by FTP to/from some target host.
*  - Send and receive files by SFTP to/from some target host.
*  - Execute commands by SSH on some host.
*  - Send files by FTP or SFTP to a "jump host" and forward them by FTP or SFTP to a target host.
*    Different transfer protocols can be used between localhost and "jump_host" and between "jump_host" and target host.
*  - Receive files from a remote host by FTP or SFTP to a "jump host" and forward them by FTP or SFTP to the local host.
*    Different protocols can be used for transfer between the hosts.
*  - Both password and publickey authentication are supported for SFTP.
*  - The parameterization is effected by command line parameters and by configuration files.
*  - All parameters are specified on the localhost exclusively, this applies in the same way when using
*    a "jump host" as local parameters are dynamically forwarded to the "jump host".
*  - Logging and error handling are provided, errors are detected on a per file basis.
*  - Security: no configuration files are used on the "jump host" (except for private key files that were used to access a target host);
*              no passwords are stored on the "jump host"; no use is made of system proxy functionalities.
*
* @author andreas.pueschel@sos-berlin.com
* @author mueruevet.oeksuez@sos-berlin.com
* @version 2009-09-22
* @see documentation ./doc/sosftp.xml
*/

abstract public class SOSFTPCommand {

  public static final String    USE_PATH_AND_FILE_NAME_4_MATCHING        = "use_path_and_file_name_4_matching";
  public static final String    CHECK_SERVER_FEATURES              = "check_server_features";
  public static final String    CONVERT_UMLAUTE                  = "convert_umlaute";
  public static final String    FILENAME_ENCODING                = "Filename_encoding";
  public static final String    CONTROL_ENCODING                = "control_encoding";
  public static final String    PRE_FTP_COMMANDS                = "pre_ftp_commands";

  private static String      conClassName                  = "SOSFTPCommandReceive";

  protected static final String  conNewLine                    = "\n";
  protected static final String  conRegExpBackslash                = "\\\\";
  protected static final String  conRegExpAllChars                = ".*";

  protected SOSFTP        sosftp                      = null;
  protected String        strPreFtpCommands                = "";
  protected boolean        flgCheckServerFeatures              = false;
  protected boolean        flgUsePathAndFileName4Matching          = false;

  protected String        strControlEncoding                = "";
  protected String        strFileNameEncoding                = "";
  protected boolean        flgConvertUmlaute                = false;

  /** The FTP server will always reply the ftp error codes,
   * see http://www.the-eggman.com/seminars/ftp_error_codes.html */
  public static final int      ERROR_CODE                    = 300;

  /** default command delimiter */
  protected final static String  DEFAULT_COMMAND_DELIMITER            = "%%";

  /** sos.util.SOSString Object */
  protected static SOSString    sosString                    = new SOSString();

  /** sos.util.SOSLogger Object */
  private static SOSLogger    logger                      = null;

  /** optional mail configuration */
  protected String        mailSMTP                    = "localhost";
  protected String        mailPortNumber                  = "25";
  protected String        mailFrom                    = "SOSFTP";
  protected String        mailQueueDir                  = "";

  /** array of commands that have been separated by the commandDelimiter */
  protected String[]        commands                    = {};

  /** ignore errors reported by the exit status of commands */
  protected boolean        ignoreError                    = false;

  /** ignore signals terminating remote execution */
  protected boolean        ignoreSignal                  = false;

  /** ignore output to stderr */
  protected boolean        ignoreStderr                  = false;

  /** timestamp of the last text from stdin or stderr **/
  protected long          lasttime                    = 0;

  /** regular expression for delimiter of multiple commands specified as job or order parameter */
  protected String        commandDelimiter                = DEFAULT_COMMAND_DELIMITER;

  /** ssh connection object */
  private Connection        sshConnection                  = null;

  /** ssh session object */
  protected Session        sshSession                    = null;

  /** Inputstreams for stdout and stderr **/
  protected InputStream      stdout                      = null;
  protected InputStream      stderr                      = null;

  /** Script for a command which will be submitted and then executed **/
  protected String        commandScript                  = "";

  /** Line currently being displayed on the shell **/
  protected String        currentLine                    = "";

  /** remote host name or ip address */
  protected String        host                      = "";

  /** remote ssh2 port */
  // protected int port = 0;
  protected int          port                      = 21;                                                                                                                            // JS-649

  /** user name on remote host */
  protected String        user                      = "";

  /** for publickey authentication this password secures the authentication file, for password authentication this is the password */
  protected String        password                    = "";

  /** optional proxy configuration */
  protected String        proxyHost                    = "";
  protected int          proxyPort                    = 0;
  protected String        proxyUser                    = "";
  protected String        proxyPassword                  = "";

  /** key file: ~/.ssh/id_rsa or ~/.ssh/id_dsa */
  protected String        authenticationFilename              = "";

  /** authentication method: publickey, password */
  protected String        authenticationMethod              = "publickey";

  /** Program Arguments */
  protected Properties      arguments                    = null;

  /** hilfgsvariable, gibt an ob ein jump Host existiert */
  protected boolean        jump                      = false;

  /** temporary Directory of jump host:
   * Security: no configuration files are used on the "jump host"
   * (except for private key files that were used to access a target host);
   * no passwords are stored on the "jump host"; no use is made of system proxy functionalities.
   */
  protected static String      tempJumpRemoteDir                = "";

  /**
   * The value of this parameter specifies an post command that is executed by the remote host.
   */
  protected String        postCommands                  = "";

  /**
   * Anlegen einer tempor�ren Historien Datei, die anschliessend in der globalen Historie Datei (siehe historyFile)
   * angeh�ngt wird
   */
  private static File        tempHistoryFile                  = null;

  /**
   * Diese Parameter gibt die globale Historien Dateinamen an.
   */
  private static File        historyFile                    = null;

  /**
   *  java.io.BufferedWriter Objekt for history
   */
  private static BufferedWriter  history                      = null;

  /**
   * Angabe einer Default Mandatory, wenn keine Parameter mandator angegeben wurde.
   * Der Mandator wird in die Historie geschrieben
   */
  private String          defaultMandator                  = "SOS";

  /**
   * Felder der Historiendatei
   */
  private String          historyFields                  = "guid;mandator;transfer_timestamp;pid;ppid;operation;localhost;localhost_ip;local_user;remote_host;remote_host_ip;remote_user;protocol;port;local_dir;remote_dir;local_filename;remote_filename;file_size;md5;status;last_error_message;log_filename";

  /**
   * neue Felder der Historiendatei. Der Aufbau ist wie folgt: historyFields;<history_entry_>;newHistoryFields
   */
  private String          newHistoryFields                = "jump_host;jump_host_ip;jump_port;jump_protocol;jump_user";

  /**
   * Alle Parameter, die mit history_entry_ anfangen werden mit in historie geschrieben.
   */
  @SuppressWarnings("rawtypes")
  private static ArrayList    historyEntrys                  = new ArrayList();

  /**
   * hilfsbariable, damit der banner header einmal geschrieben wird
   */
  private boolean          writeBannerHeader                = false;

  /**Es wird eine scheduler Signal geschickt wenn ein Parameter scheduler_host, scheduler_port, scheduler_messages angegeben wurde */
  private boolean          sendSchedulerSignale              = false;

  /**Account for authorization at the FTP server */
  protected String        account                      = "";

  /** sos.net.SOSFileTransfer */
  protected SOSFileTransfer    ftpClient                    = null;

  /** check is ftp Connect*/
  protected boolean        isLoggedIn                    = false;

  /** Default Bannerheader*/
  protected String        bannerHeader                  =

                                          "\n*************************************************************************"
                                              + "\n*                                                                       *"
                                              + "\n*                SOSFTP - Managed File Transfer Utility                 *"
                                              + "\n*                --------------------------------------                 *"
                                              + "\n*                                                                       *"
                                              + "\n*************************************************************************"
                                              + "\nversion              = %{version}"
                                              + "\ndate                 = %{date} %{time}"
                                              + "\noperation            = %{operation}"
                                              + "\nprotocol             = %{protocol}"
                                              + "\nport                 = %{port}"
                                              + "\nfile specification   = %{file_spec}"
                                              + "\nfile path            = %{file_path}"
                                              + "\nsource host          = %{localhost} (%{local_host_ip})"
                                              + "\nlocal directory      = %{local_dir}"
                                              + "\njump host            = %{jump_host}"
                                              + "\ntarget host          = %{host} (%{remote_host_ip})"
                                              + "\ntarget directory     = %{remote_dir}"
                                              + "\npid                  = %{current_pid}"
                                              + "\nppid                 = %{ppid}"
                                              + "\n*************************************************************************";

  /** Default Banner Footer*/
  protected String        bannerFooter                  = "\n*************************************************************************"
                                              + "\n execution status     = %{status}"
                                              + "\n successful transfers = %{successful_transfers}"
                                              + "\n failed transfers     = %{failed_transfers}"
                                              + "\n last error           = %{last_error}"
                                              + "\n*************************************************************************";

  protected boolean        utf8Supported                  = false;
  protected boolean        restSupported                  = false;
  protected boolean        mlsdSupported                  = false;
  protected boolean        modezSupported                  = false;
  protected boolean        dataChannelEncrypted              = false;
  // /** 1. Stelle: ist die Major Version. wir erh�hen Sie nur nach Absprache */
  // private static int major = 1;
  // /** 2. Stelle: ist die Minor Version: wir erh�hen Sie nur nach Absprache */
  // private static int minor = 0;
  // /**3. Stelle: ist die Bug Fix Nummer: Sie erh�hen Sie automatisch bei jeder Auslieferung
  // * 1 = 23.01.2009
  // * a) Erstellen der Versionsnummer;
  // * b) Jeweils beim polling interval soll die Meldung ausgegeben werden.
  // * c) -skip_transfer: falsche Ausgabe im Protokoll
  // *
  // * 2 = 26.01.2009
  // * a) File Transfer Transactions -> transaktionsabh�ngige �bertragung, d.h. l�schen oder umbennen der transferierten dateien (atomic
  // suffx)
  // * erfolgt erst dann, wenn alle Dateien transferiert wurden.
  // *
  // * 3 = 11.02.2009
  // * a) Different file operations within one session.
  // *
  // * 4 = 12.02.2009
  // * a) Substitution von Environment-Variablen in Konfigurationsdateien
  // *
  // * 5 = 19.02.2009
  // * a)-file_spec2=.*\.xml$::parameter_set_2 sollen jetzt mit doppelpunkt
  // * b) Korrektur von Polling
  // *
  // * 6 = 20.02.2009
  // *
  // * a) schedulerMessages -> die mandantenspezifische Parameter werden an scheduler_meaages ohne den Pr�fix
  // * history_entry_ �bergeben
  // *
  // * 7 = 24.02.2009
  // *
  // * a) Die Integration eines neuen Mechanismus, um Kennw�rter via Shell Script dynamisch einzulesen.
  // *
  // * 8 = 09.03.2009
  // *
  // * a) Erweiterung f�r 3: unterschiedliche Parametrisierun mit unterschiedliche operation (z.B. einmal mit send und einmal mit receive)
  // *
  // * 9 = 12.03.2009
  // *
  // * a) neue Parameter: -transfer_success=parameter_set_1 und -transfer_error=parameter_set_1; Beim erfolgreichen transfer soll
  // transfer_success
  // * durchgef�hrt werden im Fehlerfall soll transfer_error durchgef�hrt werden
  // *
  // * 10 = 17.04.2009
  // *
  // * a) operation = install -> neues Unterordner "doc" f�r das Installieren der Unterverzeichnis;
  // * b) operation = install -> neue Dateien readme.txt und ThirdParty.txt
  // * c) Realisierung der Gross und Kleinschreiben der transferierten Dateinamen: Parameter -replacement=[filename:uppercase] bzw.
  // -replacement=[filename:lowercase]
  // *
  // * 11 = 28.07.2009
  // *
  // * a) operation = send -> Parameter poll_interval und poll_timeout werden jetzt auch f�r operation=send verwendet
  // * b) neue Parameter: testmode=yes|no
  // *
  // * 12 = 04.09.2009
  // * a) neue History Felder jump_host;jump_host_ip;jump_port;jump_protocol;jump_user
  // * b) file_spec_num -> Abarbeitung nach Reigenfolge
  // *
  // * 13 = 16.09.2009
  // * a) JIRA-6: jump host: remove_files/delete don't work
  // *
  // * 14 = 24.09.3009
  // * a) JIRA-5 history lock file
  // *
  // * 15 = 29.09.3009
  // * a) JIRA-5 history lock file funktioniert jetzt auch unter windows
  // *
  // * 16 = 27.10.3009
  // * a) JIRA-5 getParentId.exe wird jetzt verwendet
  // *
  // * 17 = 19.11.2009
  // * a) mergen von Scheduler Parameter
  // *
  // * 18 = 19.11.2009
  // * a) parameter simulate_shell ... l�schen
  // *
  // * 18 -> 19 in sf 05.01.2010
  // * a) Parameter include funktioniert nicht
  // *
  // * 19 = 15.12.2009
  // * a) Redesign auf Configuration/Parametern
  // *
  // * 20 = 29.01.2010
  // * a) SOSFTPCommand so anpassen, das es auch im SchedulerBetrieb arbeitet
  // * sos.scheduler.ftp.SOSSchedulerFTPSend.java
  // * sos.scheduler.ftp.SOSSchedulerFTPReceive.java
  // * sos.scheduler.job.JobSchedulerSSHJob.java
  // * 21 = 10.02.2010
  // * a)Anpassung der operation=install
  // * -> wegen Redesign sind 4 neue Bibliotheken hinzugekommen: sos.xml.jar; xercesImpl.jar; xml-apis.jar; sos.connection.jar;
  // * -> diese Bibliotheken werden bei der operation=install mitgeliefert.
  // *
  // * 22 = 29.03.2009
  // * a) die Bibliotheken haben jetzt revisionsnummer und datum. operation=install muss angepasst werden
  // * b) neue Bibiliothek com.sos.configuration.jar
  // *
  // *
  // */
  // private static int bugFix = 22;

  @SuppressWarnings("rawtypes")
  protected static ArrayList    transactionalHistoryFile            = null;

  protected ArrayList        transactionalSchedulerRequestFile        = null;

  /** Hilfsvariable. Hier werden alle urspr�ngliche/unver�nderte Parametern zum Historienschreiben geschrieben.
   * Es geht mehr um die Jump Parameter*/
  private static Properties    originalParam                  = null;

  /**
   * All files should appear in the target system as one atomic transaction.
   * Approach: Transfer all files using the �atomic_transfer parameter that
   * add a suffix to the file names. Then, having transferred all files
   * successfully, they would be renamed. This is approx.
   * the same as the current operation for atomic transfers, however,
   * the renaming should be done for all files and not on a per file basis.
   *
   * This feature should consider the �remove_files parameter,
   * i.e. files should be removed after successfule transfer of all files,
   * not on a per file basis
   */
  protected static boolean    transActional                  = false;

  /**
   * Parameter die nicht an jum Host �bergeben werden d�rfen
   */
  private static ArrayList    noJumpParameter                  = new ArrayList();

  /**
   *  Substitution von Environment-Variablen in Konfigurationsdateien
   */
  private static Properties    environment                    = null;

  /**
   * -transfer_success=parameter_set_1 und -transfer_error=parameter_set_1; Beim erfolgreichen transfer soll transfer_success
   * durchgef�hrt werden im Fehlerfall soll transfer_error durchgef�hrt werden.
   * Die Argumente werden hier im listen gesammelt um im Fehlerfall bzw. Erfolgsplan alles auszuf�hren.
   */
  protected static ArrayList    listOfSuccessTransfer              = null;
  protected static ArrayList    listOfErrorTransfer                = null;

  private static SOSFTPCommand  ftpCommand                    = null;

  protected static boolean    banner                      = true;
  /** */
  private File          lockHistoryFile                  = null;

  /**
   * Falls der SOSFTP im scheduler umgebung betrieben wird, werden alle Scheduler parameter aus der Umgebungsvariable
   * SCHEDULER_PARAMS_<parameter> ausgelesen und den sosftp als Argument �bergeben
   */
  private static Properties    schedulerParams                  = new Properties();

  private static SOSConfiguration  sosConfiguration                = null;

  // Liste der transferierten Dateien
  protected Vector<File>      transferFileList                = new Vector<File>();

  public static Vector<String>  filelist                    = null;
  protected Vector<String>    filelisttmp                    = null;
  protected static Object      schedulerJob                  = null;

  protected static String      SSHJOBNAME                    = "sos.scheduler.job.JobSchedulerSSHJob";

  // Does not work with includes. ur 20101117
  // public static String REQUIRED_DEFAULT_PARAMETERS_FILENAME = "sos/net/sosftp/Configuration.xml";
  public static String      REQUIRED_DEFAULT_PARAMETERS_FILENAME      = "sos/net/sosftp/Configuration_norequire.xml";
  private static String      REQUIRED_DEFAULT_PARAMETERS_FILENAME_NOREQUIRE  = "sos/net/sosftp/Configuration_norequire.xml";

  private static Integer      exitStatus                    = null;

  /**
   * Constructor
   * @param settingsFile
   * @param settingsSection
   * @param logger
   * @param arguments_
   */
  public SOSFTPCommand(SOSLogger logger, Properties arguments_) throws Exception {
    this.setLogger(logger);
    this.arguments = arguments_;
    arguments.put("version", getVersion());
    try {
      String pid = getPids();
      if (sosString.parseToString(pid).length() > 0)
        arguments.put("current_pid", pid);

    }
    catch (Exception e) {
      try {
        // getLogger().info("could not get PID, cause: " + e.toString());
      }
      catch (Exception ex) {
      }
      // throw new Exception("could not get PID, cause: " + e.toString());
    }
  }

  public SOSFTPCommand(SOSConfiguration sosConfiguration_, SOSLogger logger) throws Exception {
    this.setLogger(logger);
    sosConfiguration = sosConfiguration_;
    this.arguments = sosConfiguration.getParameterAsProperties();
    arguments.put("version", getVersion());
    try {
      String pid = getPids();
      if (sosString.parseToString(pid).length() > 0)
        arguments.put("current_pid", pid);

    }
    catch (Exception e) {
      try {
        // getLogger().info("could not get PID, cause: " + e.toString());

      }
      catch (Exception ex) {
      }
      // throw new Exception("could not get PID, cause: " + e.toString());

    }
  }

  public void setSchedulerJob(Object schedulerJob_) {
    schedulerJob = schedulerJob_;

  }

  /**
   * Receive files by FTP/SFTP from a remote server
   *
   * @return boolean
   * @throws Exception
   */
  protected boolean receive() throws Exception {
    return false;
  }

  /**
   * Sends files by FTP/SFTP to a remote server 
   *
   * @return boolean
   * @throws Exception
   */
  protected boolean send() throws Exception {
    return false;
  }

  /**
   * Execute a command by SSH on a remote server 
   *
   * @return boolean
   * @throws Exception
   */
  public boolean execute() throws Exception {
    StringBuffer stderrOutput = new StringBuffer();
    String commandScriptFileName = "";

    try {
      getLogger().debug1("calling " + sos.util.SOSClassUtil.getMethodName());

      try { // to fetch parameters, order parameters have precedence to job parameters
        if (this.getLogger() == null)
          this.setLogger(new SOSStandardLogger(0));

        readSettings(false);

        // get basic authentication parameters
        this.getBaseParameters();

        if (!jump) {
          if (sosString.parseToString(arguments.get("jump_command_delimiter")).length() > 0) {
            this.setCommandDelimiter(sosString.parseToString(arguments.get("jump_command_delimiter")));
            getLogger().debug1(".. parameter [jump_command_delimiter]: " + this.getCommandDelimiter());
          }
          else {
            this.setCommandDelimiter(DEFAULT_COMMAND_DELIMITER);
          }

          if (sosString.parseToString(arguments.get("jump_command_script")).length() > 0) {
            commandScript = sosString.parseToString(arguments.get("jump_command_script"));
            getLogger().debug1(".. parameter [jump_command_script]: " + commandScript);
          }

          if (sosString.parseToString(arguments.get("jump_command_script_file")).length() > 0) {
            commandScriptFileName = sosString.parseToString(arguments.get("jump_command_script_file"));
            getLogger().debug1(".. parameter [jump_command_script_file]: " + commandScriptFileName);
          }

          if (arguments.containsKey("xx_make_temp_directory_success_transfer_xx")) {
            if (sosString.parseToString(arguments.get("command")).length() > 0) {
              this.setCommands(sosString.parseToString(arguments.get("command")).split(this.getCommandDelimiter()));
              getLogger().debug1(".. parameter [jump_command]: " + sosString.parseToString(arguments.get("command")));
            }
          }
          else
            if (!arguments.contains("xx_make_temp_directory_xx")) {

              if (sosString.parseToString(arguments.get("jump_command")).length() > 0) {
                this.setCommands(sosString.parseToString(arguments.get("jump_command")).split(this.getCommandDelimiter()));
                getLogger().debug1(".. parameter [jump_command]: " + sosString.parseToString(arguments.get("jump_command")));
              }
              else
                if (commandScript.length() == 0 && commandScriptFileName.length() == 0) {
                  throw new Exception(
                      "no command (or jump_command_script or jump_command_script_file) has been specified for parameter [jump_command]");
                }
            }
        }

        if (sosString.parseToString(arguments.get("jump_ignore_error")).length() > 0) {

          if (sosString.parseToBoolean(arguments.get("jump_ignore_error"))) {
            ignoreError = true;
          }
          else {
            ignoreError = false;
          }
          getLogger().debug1(".. parameter [jump_ignore_error]: " + ignoreError);
        }
        else {
          ignoreError = false;
        }

        if (sosString.parseToString(arguments.get("jump_ignore_signal")).length() > 0) {
          if (sosString.parseToBoolean(sosString.parseToString(arguments.get("jump_ignore_signal")))) {
            ignoreSignal = true;
          }
          else {
            ignoreSignal = false;
          }
          getLogger().debug1(".. parameter [jump_ignore_signal]: " + ignoreSignal);
        }
        else {
          ignoreSignal = false;
        }

        // TODO
        if (sosString.parseToString(arguments.get("jump_ignore_stderr")).length() > 0) {
          if (sosString.parseToBoolean(sosString.parseToString(arguments.get("jump_ignore_stderr")))) {
            ignoreStderr = true;
          }
          else {
            ignoreStderr = false;
          }
          getLogger().debug1(".. parameter [jump_ignore_stderr]: " + ignoreStderr);
        }
        else {
          ignoreStderr = false;
        }

      }
      catch (Exception e) {
        throw new Exception("error occurred processing parameters: " + e.getMessage());
      }
      RemoteConsumer stdoutConsumer = null;
      RemoteConsumer stderrConsumer = null;

      try { // to connect, authenticate and execute commands
        this.getBaseAuthentication();
        boolean windows = remoteIsWindowsShell();
        String remoteCommandScriptFileName = "";
        if (commandScript.length() > 0 || commandScriptFileName.length() > 0) {

          File commandScriptFile = null;
          if (commandScript.length() > 0) {
            commandScriptFile = createCommandScript(windows);
          }
          else {
            commandScriptFile = createCommandScript(new File(commandScriptFileName), windows);
          }
          transferCommandScript(commandScriptFile, windows);
          remoteCommandScriptFileName = commandScriptFile.getName();
          // change commands to execute transferred file

          commands = new String[1];
          if (windows) {
            commands[0] = commandScriptFile.getName();
          }
          else {
            commands[0] = "./" + commandScriptFile.getName();
          }
          // delete local file
          if (commandScript.length() > 0) {
            commandScriptFile.delete();
          }
        }

        Class cl_ = null;
        // execute commands
        for (int i = 0; i < this.getCommands().length; i++) {
          try {
            exitStatus = null;
            String exitSignal = null;

            if (sosString.parseToString(getCommands()[i]).trim().length() == 0)
              continue;

            getLogger().debug1("executing remote command: " + normalizedPassword(this.getCommands()[i]));

            this.setSshSession(this.getSshConnection().openSession());

            String currentCommand = this.getCommands()[i];

            if (!windows && schedulerJob != null && Class.forName(SSHJOBNAME) != null) {
              currentCommand = "echo $$ && " + currentCommand;
              cl_ = Class.forName(SSHJOBNAME);
              if (schedulerJob.getClass().getName().equals(cl_.getName())) {
                Method method = cl_.getMethod("initKillJob", new Class[] {});
                method.invoke(schedulerJob, new Class[] {});
              }
            }

            this.getSshSession().execCommand(currentCommand);

            getLogger().debug("output to stdout for remote command: " + normalizedPassword(this.getCommands()[i]));
            stdout = new StreamGobbler(this.getSshSession().getStdout());
            stderr = new StreamGobbler(this.getSshSession().getStderr());
            BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(stdout));
            int pid = 0;
            while (true) {
              String line = stdoutReader.readLine();
              if (line == null)
                break;
              if (!windows && pid == 0 && schedulerJob != null && Class.forName(SSHJOBNAME) != null) {
                if (schedulerJob.getClass().getName().equals(cl_.getName())) {
                  pid = Integer.parseInt(line);
                  if (cl_ != null) {

                    Method method = cl_.getMethod("setSchedulerSSHKillPid", new Class[] { int.class });
                    method.invoke(schedulerJob, new Object[] { new Integer(pid) });

                  }
                  getLogger().debug5("Parent pid: " + pid);
                  continue;
                }
              }

              if (sosString.parseToString(arguments.get("operation")).equalsIgnoreCase("execute") && banner)
                getLogger().info(line);
              else
                if (sosString.parseToString(arguments.get("operation")).equalsIgnoreCase("receive")
                    && sosString.parseToString(line).indexOf("files found.") > -1
                    && sosString.parseToBoolean(sosString.parseToString(arguments.get("skip_transfer"))))
                  getLogger().info(line.substring(line.indexOf("[info]") + "[info]".length()));
                else
                  if (sosString.parseToString(arguments.get("operation")).equalsIgnoreCase("receive")
                      && sosString.parseToString(line).indexOf("Processing file") > -1
                      && sosString.parseToBoolean(sosString.parseToString(arguments.get("skip_transfer")))) {
                    String s = line.substring(line.indexOf("Processing file") + "Processing file".length() + 1);

                    if (filelisttmp == null)
                      filelisttmp = new Vector<String>();
                    filelisttmp.add(s);
                  }
                  else
                    if (line.indexOf("[warn]") > -1 || line.indexOf("[error]") > -1) {
                      getLogger().warn("remote execution reports error : " + line);

                    }
                    else {
                      getLogger().debug1(line);
                    }
              // Die Schreibweise bitte nicht ver�ndern, da hier String vergleiche gemacht werden
              if (line.indexOf("*******ftp transfer directory is:") > -1) {
                int pos1 = line.indexOf("*******ftp transfer directory is:") + "*******ftp transfer directory is:".length();
                int pos2 = line.indexOf("******************");
                tempJumpRemoteDir = line.substring(pos1, pos2);
              }

              if (line.indexOf("[info]") > -1 && line.indexOf("files found.") > -1 && sosString.parseToBoolean(arguments.get("testmode"))
                  && sosString.parseToString(arguments.get("operation")).equals("receive")) {
                getLogger().info(line.substring(line.indexOf("[info]") + "[info]".length()));
              }

              if (line.indexOf("[info]") > -1
                  && (line.indexOf("removing remote file:") > -1 || line.indexOf("files remove.") > -1)
                  && (sosString.parseToString(arguments.get("operation")).equals("remove") || sosString.parseToString(
                      arguments.get("operation")).equals("receive"))) {
                getLogger().info(line.substring(line.indexOf("[info]") + "[info]".length()));
              }
            }
            if (!windows && schedulerJob != null) {
              if (cl_ != null && Class.forName(SSHJOBNAME) != null) {
                if (schedulerJob.getClass().getName().equals(cl_.getName())) {
                  Method method = cl_.getMethod("setSchedulerSSHKillPid", new Class[] { int.class });
                  method.invoke(schedulerJob, new Object[] { new Integer(0) });
                }
              }

            }

            getLogger().debug1("output to stderr for remote command: " + normalizedPassword(this.getCommands()[i]));
            // Beide StreamGobbler m�ssen hintereinander instanziiert werden
            BufferedReader stderrReader = new BufferedReader(new InputStreamReader(stderr));
            stderrOutput = new StringBuffer();
            while (true) {
              String line = stderrReader.readLine();
              if (line == null)
                break;
              getLogger().error(line);
              stderrOutput.append(line + conNewLine);
            }

            if (stderrOutput != null && stderrOutput.length() > 0) {
              if (ignoreStderr) {
                if (jump) {
                  // testen
                  getLogger().error("output to stderr is ignored: " + stderrOutput);
                  return false;
                }
                else {
                  getLogger().info("output to stderr is ignored: " + stderrOutput);
                }

              }
              else {
                throw new Exception("remote execution reports error: " + stderrOutput);
              }
            }

            try {
              exitStatus = this.getSshSession().getExitStatus();
            }
            catch (Exception e) {
              getLogger().debug1("could not retrieve exit status, possibly not supported by remote ssh server");
            }

            if (exitStatus != null) {
              if (!exitStatus.equals(new Integer(0))) {
                if (ignoreError) {
                  getLogger().debug1("exit status is ignored: " + exitStatus);
                }
                else {
                  throw new Exception("remote command terminated with exit status: " + exitStatus
                      + (logger.hasWarnings() ? " error: " + logger.getWarning() : ""));
                }
              }
            }

            try {
              exitSignal = this.getSshSession().getExitSignal();
            }
            catch (Exception e) {
              getLogger().debug1("could not retrieve exit signal, possibly not supported by remote ssh server");
            }

            if (exitSignal != null) {
              if (exitSignal.length() > 0) {
                if (ignoreSignal) {
                  getLogger().debug1("exit signal is ignored: " + exitSignal);
                }
                else {
                  throw new Exception("remote command terminated with exit signal: " + exitSignal);
                }
              }
            }

          }
          catch (Exception e) {
            throw e;
          }
          finally {
            if (remoteCommandScriptFileName != null && remoteCommandScriptFileName.length() > 0) {
              deleteCommandScript(remoteCommandScriptFileName);
            }
            if (this.getSshSession() != null)
              try {
                this.getSshSession().close();
                this.setSshSession(null);
              }
              catch (Exception ex) {
              } // gracefully ignore this error
          }
        }

      }
      catch (Exception e) {

        throw new Exception("error occurred processing ssh command: " + e.getMessage());
      }
      finally {
        if (stderrConsumer != null)
          stderrConsumer.end();
        if (stdoutConsumer != null)
          stdoutConsumer.end();
        if (this.getSshConnection() != null)
          try {
            this.getSshConnection().close();
            this.setSshConnection(null);
          }
          catch (Exception ex) {
          } // gracefully ignore this error
      }

      return true;

    }
    catch (Exception e) {
      try {
        getLogger().warn(e.getMessage());
      }
      catch (Exception ex) {
      }
      return false;
    }

  }

  public File transferCommandScript(File commandFile, boolean isWindows) throws Exception {
    try {
      SFTPv3Client sftpClient = new SFTPv3Client(this.getSshConnection());
      SFTPv3FileAttributes attr = new SFTPv3FileAttributes();
      attr.permissions = new Integer(0700);

      boolean exists = true;
      // check if File already exists
      while (exists) {
        try {
          SFTPv3FileAttributes attribs = sftpClient.stat(commandFile.getName());
        }
        catch (SFTPException e) {
          getLogger().debug9("Error code when checking file existence: " + e.getServerErrorCode());
          exists = false;
        }
        if (exists) {
          getLogger().debug1("file with that name already exists, trying new name...");
          String suffix = (isWindows ? ".cmd" : ".sh");
          File resultFile = File.createTempFile("sos", suffix);
          resultFile.delete();
          commandFile.renameTo(resultFile);
          commandFile = resultFile;
        }
      }

      // set execute permissions for owner
      SFTPv3FileHandle fileHandle = sftpClient.createFileTruncate(commandFile.getName(), attr);

      FileInputStream fis = null;
      long offset = 0;
      try {
        fis = new FileInputStream(commandFile);
        byte[] buffer = new byte[1024];
        while (true) {
          int len = fis.read(buffer, 0, buffer.length);
          if (len <= 0)
            break;
          sftpClient.write(fileHandle, offset, buffer, 0, len);
          offset += len;
        }
        fis.close();
        fis = null;

      }
      catch (Exception e) {
        throw new Exception("error occurred writing file [" + commandFile.getName() + "]: " + e.getMessage());
      }
      finally {
        if (fis != null)
          try {
            fis.close();
            fis = null;
          }
          catch (Exception ex) {
          } // gracefully ignore this error
      }
      sftpClient.closeFile(fileHandle);

      fileHandle = null;
      sftpClient.close();
      return commandFile;
    }
    catch (Exception e) {
      throw new Exception("Error transferring command script: " + e, e);
    }
  }

  public File createCommandScript(boolean isWindows) throws Exception {
    try {

      if (!isWindows)
        commandScript = commandScript.replaceAll("(?m)\r", "");
      String suffix = (isWindows ? ".cmd" : ".sh");
      File resultFile = File.createTempFile("sos", suffix);
      BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(resultFile)));
      out.write(commandScript);
      out.close();
      return resultFile;
    }
    catch (Exception e) {
      throw new Exception("Error creating command script: " + e, e);
    }
  }

  public File createCommandScript(File scriptFile, boolean isWindows) throws Exception {
    try {
      commandScript = sos.util.SOSFile.readFileUnicode(scriptFile);
      return createCommandScript(isWindows);
    }
    catch (Exception e) {
      throw new Exception("Error creating command script: " + e, e);
    }
  }

  private void deleteCommandScript(String commandFile) throws Exception {
    try {
      SFTPv3Client sftpClient = new SFTPv3Client(this.getSshConnection());
      sftpClient.rm(commandFile);
      sftpClient.close();
    }
    catch (Exception e) {
      getLogger().warn("Failed to delete remote command script: " + e);
    }
  }

  /**
   * @return Returns the sshSession.
   */
  private Session getSshSession() {
    return sshSession;
  }

  /**
   * @param sshSession The sshSession to set.
   */
  private void setSshSession(Session sshSession) {
    this.sshSession = sshSession;
  }

  /**
   * Remove files by FTP/SFTP on a remote server.
   *
   * @return boolean
   * @throws Exception
   */
  public boolean remove() throws Exception {
    getLogger().debug1("calling " + sos.util.SOSClassUtil.getMethodName());
    // Das L�schen der Dateien per ftp ist identisch wie die Methode receive mit den Parameter
    // skip_trasfer=yes (-> unterdr�cken der transferieren der Dateien) und remove_files=yes
    arguments.put("skip_transfer", "yes");
    arguments.put("remove_files", "yes");

    return receive();

  }

  /**
   * send mail
   *
   * @param recipient
   * @param recipientCC carbon copy recipient
   * @param recipientBCC blind carbon copy recipient
   * @param subject
   * @param body
   * @throws Exception
   */
  protected void sendMail(String recipient, String recipientCC, String recipientBCC, String subject, String body) throws Exception {

    try {
      SOSMail sosMail = new SOSMail(this.mailSMTP);

      sosMail.setQueueDir(this.mailQueueDir);
      sosMail.setFrom(this.mailFrom);
      sosMail.setContentType("text/plain");
      sosMail.setEncoding("Base64");
      sosMail.setPort(mailPortNumber);

      String recipients[] = recipient.split(",");
      for (int i = 0; i < recipients.length; i++) {
        sosMail.addRecipient(recipients[i].trim());
      }

      String recipientsCC[] = recipientCC.split(",");
      for (int i = 0; i < recipientsCC.length; i++) {
        sosMail.addCC(recipientsCC[i].trim());
      }

      String recipientsBCC[] = recipientBCC.split(",");
      for (int i = 0; i < recipientsBCC.length; i++) {
        sosMail.addBCC(recipientsBCC[i].trim());
      }

      sosMail.setSubject(subject);
      sosMail.setBody(body);
      sosMail.setSOSLogger(this.getLogger());

      this.getLogger().debug1("sending mail: \n" + sosMail.dumpMessageAsString());

      if (!sosMail.send()) {
        this.getLogger().warn(
            "mail server is unavailable, mail for recipient [" + recipient + "] is queued in local directory [" + sosMail.getQueueDir() + "]:"
                + sosMail.getLastError());
      }

      sosMail.clearRecipients();
    }
    catch (Exception e) {
      throw new Exception("error occurred sending mai: " + e.getMessage());
    }
  }

  protected String getAlternative(String param, String alternativeParam) throws Exception {
    try {
      if (sosString.parseToString(alternativeParam).length() > 0) {
        return alternativeParam;
      }
      else {
        return param;
      }
    }
    catch (Exception e) {
      this.getLogger().warn("error in getAlternative(): " + e.getMessage());
      return param;
    }
  }

  protected int getAlternative(int param, int alternativeParam) throws Exception {
    try {
      if (alternativeParam > 0) {
        return alternativeParam;
      }
      else {
        return param;
      }
    }
    catch (Exception e) {
      this.getLogger().warn("error in getAlternative(): " + e.getMessage());
      return param;
    }
  }

  /**
   * @return Returns the logger.
   */
  public SOSLogger getLogger() {
    return logger;
  }

  /**
   * @param logger The logger to set.
   */
  public void setLogger(SOSLogger logger_) {
    logger = logger_;
  }

  protected URI createURI(String fileName) throws Exception {
    URI uri = null;
    try {
      uri = new URI(fileName);
    }
    catch (Exception e) {
      try {
        File f = new File(fileName);
        String path = f.getCanonicalPath();
        if (fileName.startsWith("/")) {
          path = fileName;
        }

        String fs = System.getProperty("file.separator");
        if (fs.length() == 1) {
          char sep = fs.charAt(0);
          if (sep != '/')
            path = path.replace(sep, '/');
          if (path.charAt(0) != '/')
            path = '/' + path;
        }
        if (!path.startsWith("file://")) {
          path = "file://" + path;
        }
        uri = new URI(path);
      }
      catch (Exception ex) {
        throw (new Exception("error in createURI(): " + e.getMessage()));
      }
    }
    return uri;
  }

  protected File createFile(String fileName) throws Exception {
    try {
      if (fileName == null || fileName.length() == 0) {
        throw new Exception("empty file name provided");
      }
      if (fileName.startsWith("file://")) {
        return new File(createURI(fileName));
      }
      else {
        return new File(fileName);
      }
    }
    catch (Exception e) {
      throw new Exception("error in createFile() [" + fileName + "]: " + e.getMessage());
    }
  }

  protected static String getErrorMessage(Exception ex) throws Exception {
    String s = "";
    try {
      Throwable tr = ex.getCause();
      if (ex.toString() != null)
        s = ex.toString();
      while (tr != null) {
        if (s.indexOf(tr.toString()) == -1)
          s = (s.length() > 0 ? s + ", " : "") + tr.toString();
        tr = tr.getCause();
      }
    }
    catch (Exception e) {
      throw ex;
    }
    return s;
  }

  /**
   * @return Returns the commands.
   */
  protected String[] getCommands() {
    return commands;
  }

  /**
   * @param commands The commands to set.
   */
  protected void setCommands(String[] commands) {
    this.commands = commands;
  }

  /**
   * Mergen von Programm Argumente und Settings Eistellungen.
   *
   * @throws Exception
   */
  protected void mergeSettings() throws Exception {
    Properties retVal = new Properties();
    try {

      // Umgebungsvariable, die alle mit SOSFTP anfangen
      Properties arg = getEnvVars(logger);
      retVal.putAll(arg);

      // zus�tzliche Parametern generieren
      retVal.put("date", sos.util.SOSDate.getCurrentDateAsString());
      retVal.put("time", sos.util.SOSDate.getCurrentTimeAsString("hh:mm:ss"));
      retVal.put("transfer_timestamp", sos.util.SOSDate.getCurrentTimeAsString());
      retVal.put("local_user", sosString.parseToString(System.getProperty("user.name")));

      // zuweisen von Defaults bei leeren Parametern
      if (sosString.parseToString(arg, "current_pid").length() > 0)
        retVal.put("current_pid", sosString.parseToString(arg, "current_pid"));
      if (sosString.parseToString(arg, "ppid").length() > 0)
        retVal.put("ppid", sosString.parseToString(arg, "ppid"));

      try {
        java.net.InetAddress localMachine = java.net.InetAddress.getLocalHost();
        if (sosString.parseToString(localMachine.getHostName()).length() > 0)
          retVal.put("localhost", localMachine.getHostName());
        retVal.put("local_host_ip", localMachine.getHostAddress());
      }
      catch (java.net.UnknownHostException uhe) {
      } // tu nichts

      if (arguments != null)
        retVal.putAll(arguments);

      if (originalParam == null || originalParam.isEmpty())
        originalParam = (Properties) retVal.clone();
      arguments = retVal;

      try {
        String host = sosString.parseToString(arguments, "host");
        if (host.length() > 0)
          arguments.put("remote_host_ip", java.net.InetAddress.getByName(host).getHostAddress());
      }
      catch (java.net.UnknownHostException uhe) {
      }

      if (!writeBannerHeader && !sosString.parseToString(arguments, "operation").startsWith("install")) {
        if (banner)
          getLogger().info(getBanner(true));
        else
          getLogger().debug1(getBanner(true));
        writeBannerHeader = true;// header nur einmal schreiben
      }

      int jumpParameterLength = sosString.parseToString(arguments.get("jump_host")).length()
          + sosString.parseToString(arguments.get("jump_port")).length() + sosString.parseToString(arguments.get("jump_user")).length();
      if (jumpParameterLength > 0 && !sosString.parseToString(arguments.get("operation")).equals("execute"))
        jump = true;

      createHistoryFile();
      checkSchedulerRequest();
    }
    catch (Exception e) {
      throw new Exception("Failed to merge program arguments and settings: " + e);
    }
  }

  /**
   *  Substitution von Environment-Variablen in Konfigurationsdateien
   * 
   *  F�r Unix und Windows soll bei allen Einstellungen in einer Konfigurationsdatei
   *  Substitution von Environment-Variablen unterst�tzt werden.
   *  Variablen m�ssen in der Form %VAR% bzw. ${VAR} geschrieben sein.
   * 
   */
  private static Properties substituteEnvironment(Properties prop) throws Exception {
    Properties newProp = new Properties();
    try {
      Iterator it = prop.keySet().iterator();
      String key = "";
      String value = "";
      while (it.hasNext()) {
        key = sosString.parseToString(it.next());
        if (!key.startsWith(";")) {
          value = sosString.parseToString(prop.get(key));
          // if(key.indexOf("password") == -1 || !sosConfiguration.getPasswordnames().contains(key))
          String msg = ".." + key + "=" + normalizedPassword(value) + " ";
          // logger.debug9(".." + key + "=" + normalizedPassword(value) + " wird ersetz mit ");
          value = normalizedFields(value, environment, "${", "}");
          value = normalizedFields(value, environment, "%", "%");
          // if(key.indexOf("password") == -1 || !sosConfiguration.getPasswordnames().contains(key))
          // logger.debug9(msg + " is normalized in " + key + "  --> " + normalizedPassword(value));
          newProp.put(key, value);
        }
      }
    }
    catch (Exception e) {
      logger.warn("Failed to substitute environment variables in configuration file, cause: " + e.toString());
      return prop;
    }
    return newProp;
  }

  /**
   * Create History File if not exist
   * @throws Exception
   */
  private void createHistoryFile() throws Exception {
    boolean writeHeaderFields = false;
    getLogger().debug1("calling " + sos.util.SOSClassUtil.getMethodName());
    try {
      if (sosString.parseToBoolean(arguments.get("testmode")))
        return;

      if (tempHistoryFile != null && tempHistoryFile.exists())
        return;

      if (sosString.parseToString(arguments, "history").length() > 0) {
        if (sosString.parseToString(arguments, "operation").equals("send") || sosString.parseToString(arguments, "operation").equals("receive")) {
          historyFile = new File(sosString.parseToString(arguments, "history"));
          if (!historyFile.exists()) {
            if (historyFile.createNewFile()) {
              getLogger().info("creating global history file " + historyFile.getAbsolutePath());
            }
            else {
              getLogger().warn("could not create history file : " + historyFile.getAbsolutePath());
            }
          }

          if (historyFile.length() == 0)
            writeHeaderFields = true;

          if (!historyFile.canWrite()) {
            getLogger().warn("history file is read only: " + historyFile.getAbsolutePath());
            return;
          }

          tempHistoryFile = File.createTempFile("sosftp_history", ".csv", new File(System.getProperty("java.io.tmpdir")));

          tempHistoryFile.deleteOnExit();

          // �berpr�fen ob die Historien Felder Reihenfolge anders ist als in der Historiendatei.
          checkHistoryField(historyFields);

          history = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tempHistoryFile)));

          if (writeHeaderFields) {
            historyFields = historyFields + ";" + newHistoryFields;
            for (int i = 0; i < historyEntrys.size(); i++) {
              String key = sosString.parseToString(historyEntrys.get(i));
              historyFields = historyFields + ";" + sosString.parseToString(key).substring("history_entry_".length()); //
            }

            history.write(historyFields);
            history.newLine();
          }

        }
      }
      else {

        if (getHistory() != null) {
          getHistory().close();
          history = null;
        }
      }

    }
    catch (Exception e) {
      throw new Exception("error in  " + sos.util.SOSClassUtil.getMethodName() + " could not create history file, cause: " + e);
    }
  }

  private boolean existHistoryLockFile() throws Exception {
    BufferedReader bra = null;
    BufferedReader procout = null;
    int countOfDelay = 3;
    String pid = "";
    int delay = 5;
    boolean existPID = false;
    try {
      if (sosString.parseToBoolean(arguments.get("testmode"))) {
        return false;
      }
      // �berpr�fen, ob eine lock Datei existiert
      lockHistoryFile = new File(System.getProperty("java.io.tmpdir"), historyFile.getName() + ".lock");

      if (lockHistoryFile.exists()) {
        getLogger().debug9("..history lock File exists.");
        getLogger().debug("timestamp of last modification of history file: " + lockHistoryFile.lastModified());
        // delay einbauen
        for (int i = 0; i < countOfDelay; i++) {
          getLogger().debug5("..history lock file exist. wait 5 Seconds.");
          Thread.sleep(delay + 1000);
          if (!lockHistoryFile.exists()) {
            break;
          }
        }
        // gucken ob die lockdatei weiterhin existiert
        if (lockHistoryFile.exists()) {
          getLogger().debug5("..history lock file exist.");
          // wenn ja, pid ermitteln
          bra = new BufferedReader(new FileReader(lockHistoryFile));
          // �berpr�fen, ob dieser pid existiert

          if ((pid = bra.readLine()) != null) {
            getLogger().debug("reading from history lock file: pid = " + pid);
            // F�r Window
            Process proc = null;
            if (System.getProperty("os.name").toLowerCase().indexOf("windows") > -1)
              proc = Runtime.getRuntime().exec("tasklist /FI \"PID eq " + pid + "\"");
            else
              proc = Runtime.getRuntime().exec("ps -p " + pid);

            procout = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String s;

            while ((s = procout.readLine()) != null) {
              getLogger().debug5("command output =\t" + s);
              if (s.indexOf(pid) > -1) {// process ist aktuell
                existPID = true;
                break;
              }
            }

            if (bra != null)
              bra.close();
            if (procout != null)
              procout.close();
          }
        }
      }

      if (!existPID && sosString.parseToString(pid).trim().length() > 0) {
        getLogger().debug("History lock File is deleting cause Process ID not exist.");
        // Es existiert eine History Lock datei aber keine PID. Die Lock Datei kann gel�scht werden
        if (lockHistoryFile.delete()) {
          getLogger().info("History lock File successfully deleted, cause Process ID not exist.");
        }
        else {
          throw new Exception("History lock File " + lockHistoryFile.getCanonicalPath() + " could not delete. There is no Process Id exist[pid="
              + pid + "]");
        }
        existPID = false;

      }

      if (existPID)// History Datei existiert und der entsprechende pid ist aktuell. Andere Instanzen d�rfen nicht schreiben.
        throw new Exception("Could not write in History File, cause there is existing History Lock File.");

      return existPID;
    }
    catch (Exception e) {
      throw new Exception("error in  " + sos.util.SOSClassUtil.getMethodName() + " while looking-up existing history lock file, cause: " + e);
    }
    finally {
      if (bra != null)
        bra.close();
      if (procout != null)
        procout.close();
    }
  }

  /**
   * �berpr�ft, ob die Historienfelder in der Historien datei identisch sind.
   */
  private void checkHistoryField(String historyFields_) throws Exception {

    BufferedReader br = null;
    BufferedWriter bw = null;
    String thisLine = "";
    boolean historyFilesChanged = false;

    try {
      getLogger().debug1("calling " + sos.util.SOSClassUtil.getMethodName());

      br = new BufferedReader(new FileReader(historyFile));

      int line = 0;
      while ((thisLine = br.readLine()) != null) { // while loop begins here
        if (line > 0 && !historyFilesChanged) {
          return;// es hat sich nichts ge�ndert, abbruchbedingung
        }

        if (line == 0) {// erste zeile, Historienfelder aus der Datei lesen und vergleichen, ob alle Felder vorhanden sind

          for (int i = 0; i < historyEntrys.size(); i++) {
            newHistoryFields = newHistoryFields + ";" + historyEntrys.get(i).toString().substring("history_entry_".length());
          }

          String[] splitnewHistoryFields = newHistoryFields.split(";");
          for (int i = 0; i < splitnewHistoryFields.length; i++) {

            // �berpr�fe, ob die neuen Felder bereits in der HistorienDatei vorhanden sind
            if (thisLine.indexOf(";" + splitnewHistoryFields[i] + ";") == -1 && !thisLine.startsWith(splitnewHistoryFields[i] + ";")
                && !thisLine.endsWith(splitnewHistoryFields[i])) {

              // neue Felder sind hinzugekommen
              thisLine = thisLine + ";" + splitnewHistoryFields[i];
              historyFilesChanged = true;
            }
          }

          this.historyFields = thisLine;

          if (historyFilesChanged) {
            if (!existHistoryLockFile()) {
              // lock Datei erzeugen, der verhindert, historien Eintr�ge zu schreiben
              createHistoryLockFile();
              bw = new BufferedWriter(new FileWriter(historyFile));
              bw.write(thisLine);
              bw.newLine();
            }

          }
        }
        else {

          bw.write(thisLine);
          bw.newLine();

        }
        line++;
      }

    }
    catch (Exception e) {
      throw new Exception("\n -> ..error in " + SOSClassUtil.getMethodName() + " " + e);
    }
    finally {

      if (bw != null)
        bw.close();
      if (br != null)
        br.close();

      if (historyFilesChanged) {
        removeHistoryLockFile();

      }
    }

  }

  /**
   * Beim Schreiben in die Historien Datei wird vorher eine lock Datei generiert. Das soll parallele
   * SOSFTP Instanzen verhindert gleichzeitig in die Historie Datei zu schreiben.
   * @throws Exception
   */
  private void createHistoryLockFile() throws Exception {
    BufferedWriter lockBW = null;
    try {

      lockBW = new BufferedWriter(new FileWriter(lockHistoryFile));

      lockBW.write(sosString.parseToString(arguments, "current_pid"));

    }
    catch (Exception e) {
      throw new Exception("could not create a history lock file, cause: " + e.toString());
    }
    finally {
      if (lockBW != null)
        lockBW.close();
    }

  }

  /**
   * Beim Schreiben in die Historien Datei wird vorher eine lock Datei generiert. Das soll parallele
   * SOSFTP Instanzen verhindert gleichzeitig in die Historie Datei zu schreiben.
   * Hier soll die Lock Datei gel�scht werden, damit parallele SOSFTP Instanzen in die Historie schreiben k�nnen.
   * @throws Exception
   */
  private void removeHistoryLockFile() throws Exception {
    try {
      getLogger().debug1("calling " + sos.util.SOSClassUtil.getMethodName());
      getLogger().debug9("lockHistoryFile=" + lockHistoryFile.getCanonicalPath());
      if (lockHistoryFile != null && lockHistoryFile.exists()) {

        if (!lockHistoryFile.delete()) {
          getLogger().debug3("history lock file could not be deleted: " + lockHistoryFile.getCanonicalPath());
          Thread.sleep(1000);
          if (!lockHistoryFile.delete()) {
            throw new Exception("history lock file could not be deleted: " + lockHistoryFile.getCanonicalPath());
          }
        }
      }
    }
    catch (Exception e) {
      throw new Exception("could not delete a history lock file, cause: " + e.toString());
    }
  }

  /**
   * �berpr�ft ob ein Jump Host angegeben wurde.
   * Hier wird auf der jump host ein tempor�res Verzeichnis erzeugt,
   * indem die Verzeichnisse tempor�r transferiet werden. Dieses verzecinis wird anschliessend
   * gel�scht.
   *
   * Hier werden neue Kommandos generiert.
   */
  protected void hasJumpArguments() throws Exception {
    String curCommands = "";
    try {

      if (!jump)
        return;

      // Parameter die nicht an die SSH Commands �bergeben werden sollen
      noJumpParameter.add("transfer_timestamp");
      noJumpParameter.add("date");
      noJumpParameter.add("time");
      noJumpParameter.add("current_pid");
      noJumpParameter.add("ppid");
      noJumpParameter.add("pid");
      noJumpParameter.add("local_user");
      noJumpParameter.add("status");
      noJumpParameter.add("successful_transfers");
      noJumpParameter.add("failed_transfers");
      noJumpParameter.add("last_error");
      noJumpParameter.add("history");
      noJumpParameter.add("history");
      noJumpParameter.add("history_repeat");
      noJumpParameter.add("history_interval");
      noJumpParameter.add("localhost");
      noJumpParameter.add("include");
      noJumpParameter.add("remote_host_ip");
      noJumpParameter.add("local_host_ip");
      noJumpParameter.add("mandator");
      noJumpParameter.add("scheduler_host");
      noJumpParameter.add("scheduler_port");
      noJumpParameter.add("scheduler_message");
      noJumpParameter.add("scheduler_job_chain");
      noJumpParameter.add("file_size");
      noJumpParameter.add("log_filename");
      noJumpParameter.add("command");
      noJumpParameter.add("remove_after_jump_transfer");
      noJumpParameter.add("root");
      noJumpParameter.add("version");
      noJumpParameter.add("replacing");
      noJumpParameter.add("replacement");
      noJumpParameter.add("getpidsexe");
      noJumpParameter.add("verbose");

      if (sosString.parseToString(arguments.get("ssh_auth_file")).startsWith("local:")) {
        String filename = sosString.parseToString(arguments.get("ssh_auth_file")).substring("local:".length());
        String text = sos.util.SOSFile.readFile(new File(filename));
        arguments.put("ssh_auth_file", "filecontent:" + text);
      }

      if (sosString.parseToString(arguments.get("operation")).startsWith("install"))
        noJumpParameter.add("operation");

      if (!sosString.parseToString(arguments.get("operation")).equals("remove") && !sosString.parseToString(arguments.get("operation")).equals("receive"))
        noJumpParameter.add("file_spec");

      arguments.put("xx_make_temp_directory_xx", "ok");// hilfsvariable, wenn dieses key existiert, dann gilt im execute diese
                                // jump_command Parameter
      // jump_command nicht ausgelesen
      curCommands = sosString.parseToString(arguments.get("jump_command")) + " -operation=make_temp_directory -root="
          + sosString.parseToString(arguments, "root");

      this.setCommands(curCommands.split(getCommandDelimiter()));
      if (!execute()) {
        throw new Exception("error occurred processing command: " + normalizedPassword(curCommands));
      }
      arguments.remove("xx_make_temp_directory_xx");
      curCommands = sosString.parseToString(arguments.get("jump_command"));
      String arg = "";
      String arg4postCommands = "";
      java.util.Iterator keys = arguments.keySet().iterator();
      while (keys.hasNext()) {
        String key = sosString.parseToString(keys.next());
        // System.out.println("test: " + key);
        if (!key.startsWith("jump") && !key.startsWith(";") && !key.startsWith("history_entry_") && !key.equals("profile") && !key.equals("settings")
            && !key.equals("local_dir") && !key.equals("file_path") && !key.equals("remove_files") && !noJumpParameter.contains(key))

        {

          String val = sosString.parseToString(arguments, key);

          if (val.length() == 0)
            continue;

          if (key.equals("password")) {
            val = SOSCommandline.getExternalPassword(val, logger);

          }

          /*if(!(key.equals("atomic_suffix") &&
                sosString.parseToBoolean(sosString.parseToString(arguments.get("transactional"))) &&
                sosString.parseToString(arguments.get("operation")).equals("send")))
                */
          arg = arg + " -" + key + "=" + "\"" + val + "\"";

          if (!key.equals("operation") && !key.equals("make_dirs") && !key.equals("root")
              && !((key.equals("transactional") && sosString.parseToString(arguments.get("operation")).equals("receive")))) {
            // System.out.println(key);
            arg4postCommands = arg4postCommands + " -" + key + "=" + "\"" + val + "\"";
          }

        }

      }

      if (sosString.parseToString(arguments.get("operation")).equalsIgnoreCase("receive")
          && sosString.parseToBoolean(sosString.parseToString(arguments.get("skip_transfer")))
          && sosString.parseToBoolean(sosString.parseToString(arguments.get("remove_files")))) {
        arg = arg + " -remove_files=\"yes\"";
      }

      if (sosString.parseToString(arguments.get("operation")).startsWith("receive")
          && sosString.parseToBoolean(sosString.parseToString(arguments.get("skip_transfer")))) {
        // wenn jump host �berpr�fen soll, welche Dateien es im target host liegen, dann wird dieser in execute
        // mit Hilfe String operationen ausgelesen. Damit sparen wird das �bertragen der Dateien auf jump Host um von Lokal Host
        // die Dateien zu �berpr�fen. Diese �nderung ist notwendig, wenn SOSFTP vom JobSchedulerReceive.java mit der Parameter
        // parallel = yes aufgerufen wird.
        arg = arg + " -verbose=\"9\"";

      }
      else {
        arg = arg + " -verbose=\"" + getLogger().getLogLevel() + "\"";
      }

      if (sosString.parseToString(arguments.get("operation")).startsWith("install"))
        arg = arg + " -operation=\"send\"";

      arg = arg + " -local_dir=\"" + tempJumpRemoteDir + "\"";
      if ((sosString.parseToString(arguments.get("operation")).equalsIgnoreCase("remove") || (sosString.parseToString(arguments.get("operation")).equalsIgnoreCase("receive")))
          && sosString.parseToString(arguments, "file_path").length() > 0) {
        arg = arg + " -file_path=\"" + sosString.parseToString(arguments, "file_path") + "\"";
      }

      if (sosString.parseToString(arguments.get("operation")).equalsIgnoreCase("send")
          || sosString.parseToString(arguments.get("operation")).startsWith("install")
          || sosString.parseToString(arguments.get("operation")).equalsIgnoreCase("remove")) {
        arg = arg + " -remove_files=yes";
        // - niemals bei 1. Transfer-Operation zum jump_host lokal l�schen
        // - erst nach 2. Transfer-Operation l�schen, wenn erfolgreich
        curCommands = curCommands + " " + arg;
        if (!sosString.parseToString(arguments.get("operation")).equalsIgnoreCase("remove"))
          postCommands = curCommands;

      }
      else {

        curCommands = curCommands + " " + arg;
        if (sosString.parseToBoolean(arguments.get("remove_files")))
          postCommands = sosString.parseToString(arguments.get("jump_command")) + " -operation=\"remove\" " + arg4postCommands + " -file_path=\""
              + sosString.parseToString(arguments, "file_path") + "\"";

      }

      if (sosString.parseToString(postCommands).length() > 0) {
        if (sosString.parseToString(arguments.get("replacement")).length() > 0 || sosString.parseToString(arguments.get("replacing")).length() > 0) {
          postCommands = postCommands + " -replacement=\"" + sosString.parseToString(arguments, "replacement") + "\"" + " -replacing=\""
              + sosString.parseToString(arguments, "replacing") + "\"";

        }
        postCommands = postCommands + commandDelimiter;
      }

      curCommands = curCommands + commandDelimiter;

      this.setCommands(curCommands.split(this.getCommandDelimiter()));

      getLogger().debug1("new Commands:  " + normalizedPassword(curCommands));

      // Anpassen der Parameter f�r einen jump transfer per ftp
      // L�schen der Dateien erst nach erfolgreichen �bertragen
      arguments.put("remove_after_jump_transfer", sosString.parseToString(arguments.get("remove_files")));
      arguments.put("remove_files", "no");
      arguments.put("make_dirs", "yes");// erlaubt das Generierne einer Tempor�ren verzeichnis auf den lokalen Rechner
      arguments.put("jump_remote_dir", tempJumpRemoteDir);// Name des tempor�ren Verezcinis als remote_dir angeben

      if (!arguments.containsKey("jump_protocol"))
        arguments.put("jump_protocol", "sftp");

      // jump Parameter jetzt in ftp Parameter umbennen um die Dateien tempor�r zu �bertragen
      Properties prop = new Properties();
      java.util.Iterator keys2 = arguments.keySet().iterator();
      while (keys2.hasNext()) {
        String key = sosString.parseToString(keys2.next());
        if (key.startsWith("jump_")) {
          prop.put(key.substring(5), sosString.parseToString(arguments, key));
        }
      }
      arguments.putAll(prop);
    }
    catch (Exception e) {
      throw new Exception("Failed to jump to: " + e);
    }

  }

  /**
   * Alle Umgebungsvariable die mit sosftp_ anfangen werden ausgelesen.
   *
   * Umgebungsvaribalen werden in einem globalen Parametern gemerkt, um
   * Substitution von Environment-Variablen in Konfigurationsdateien vorzunehmen.
   *
   * @param logger
   * @return sos.util.Properties
   * @throws Exception
   */
  private static Properties getEnvVars(SOSLogger logger_) throws Exception {
    try {
      if (logger != null)
        logger.debug5("reading environment");

      Process p = null;
      Properties envVars = new Properties();
      Runtime r = Runtime.getRuntime();
      String OS = System.getProperty("os.name").toLowerCase();

      environment = new Properties();

      if (OS.indexOf("windows 9") > -1) {
        p = r.exec("command.com /c set");
      }
      else
        if ((OS.indexOf("nt") > -1) || (OS.indexOf("windows") > -1)) {
          p = r.exec("cmd.exe /c set");
        }
        else {
          p = r.exec("env");
        }

      BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
      String line;
      while ((line = br.readLine()) != null) {
        int idx = line.indexOf('=');
        if (idx > -1) {
          String key = line.substring(0, idx);
          String value = "";
          if (key.toLowerCase().startsWith("sosftp_")) {
            value = line.substring(idx + 1);
            envVars.setProperty(key.substring(7).toLowerCase(), value);
          }
          else
            if (key.toLowerCase().startsWith("current_pid") || key.toLowerCase().startsWith("ppid")) {
              value = line.substring(idx + 1);
              envVars.setProperty(key.toLowerCase(), value);

            }
            else
              if (key.toLowerCase().indexOf("scheduler_param_") > -1) {
                value = line.substring(idx + 1);
                // envVars.setProperty( key.toLowerCase(), value );
                schedulerParams.setProperty(key.toLowerCase().substring("scheduler_param_".length()), value);
                if (logger != null)
                  logger.debug5(".. environment [" + key + "]: " + value);
              }

          environment.put(key, line.substring(idx + 1));
        }
      }
      return envVars;
    }
    catch (Exception e) {
      if (logger != null)
        logger.warn("[ERROR] could not read environment, cause: " + e.getMessage());
      throw new Exception("error occurred reading environment: " + e.toString());
    }
  }

  /**
   * L�scht das Tempor�res Verzeichnis
   * @return boolean
   */
  private boolean removeTempDirectory() {

    try {
      getLogger().debug1("***********remove Temporary Directory*************");

      String inputFile = "";

      String[] split = sosString.parseToString(arguments, "input").split(";");
      for (int i = 0; i < split.length; i++) {
        inputFile = sosString.parseToString(split[i]);
        getLogger().debug5("remove: " + inputFile);
        if (inputFile.length() == 0) {
          getLogger().debug1("no directory/file has been specified for removal: " + inputFile);
          return false;
        }

        getLogger().debug1("..parameter [input=" + inputFile + "]");

        File tmpDir = new File(inputFile);
        if (!tmpDir.exists()) {
          getLogger().debug1("directory/file to be removed does not exist: " + tmpDir.getCanonicalPath());
          return false;
        }

        // Verzeichnis kann nicht gel�scht werden, wenn eine Datei unterhalb dieses Verzeichnis besteht
        File[] listOfFiles = tmpDir.listFiles();
        for (int j = 0; j < listOfFiles.length; j++) {
          if (listOfFiles.length > 0) {
            if (!listOfFiles[j].delete())
              getLogger().warn(listOfFiles[j].getCanonicalPath() + " could not be deleted");
            else
              getLogger().debug1(listOfFiles[j].getCanonicalPath() + " was successfully deleted");
          }
        }
        if (tmpDir.delete())
          getLogger().debug1(tmpDir.getCanonicalPath() + " was successfully deleted");
        else {
          getLogger().warn(tmpDir.getCanonicalPath() + " could not be deleted");
        }
      }

    }
    catch (Exception e) {
      try {
        getLogger().warn("error deleting temporary directory, cause: " + e.toString());
      }
      catch (Exception ex) {

      }
    }
    return true;
  }

  /**
   * Generiert ein Tempor�res Verzeichnis f�r ftp transfer auf der Jump Host
   * @return
   */
  private boolean makeTempDirectory() throws Exception {

    String output = "";
    try {
      getLogger().debug1("***********make Temporary Directory*************");
      if (sosString.parseToString(arguments, "root").length() > 0) {
        output = File.createTempFile("sos_ftp", null, new File(normalized(sosString.parseToString(arguments, "root")))).getCanonicalPath();
      }
      else {
        output = File.createTempFile("sos_ftp", null, new File(System.getProperty("java.io.tmpdir"))).getCanonicalPath();
      }
      tempJumpRemoteDir = output;
      // diese Logausgabe darf nicht ver�ndert werden. Wenn doch dann auch in execute-Methode anpassen. Der Log Level muss INFO sein
      getLogger().info("*******ftp transfer directory is:" + output + "******************");
      if (new File(output).getCanonicalFile().exists()) {
        // nur ein tempname wird gebraucht File.createTempFile erzeugt automatisch eine Datei, wir brauchen nur einen
        // eindeutigen Namen f�r einen Verzeichnis
        new File(output).getCanonicalFile().delete();
      }
      if (!new File(output).getCanonicalFile().mkdirs())
        throw new Exception("could not create temporary directory");
    }
    catch (Exception e) {

      getLogger().warn("error creating temporary directory, cause: " + e.toString());
      throw new Exception("error creating temporary directory, cause: " + e.toString());
    }
    return true;
  }

  protected String normalized(String str) {
    str = str.replaceAll(conRegExpBackslash, "/");
    return (str.endsWith("/") || str.endsWith("\\") ? str : str + "/");

  }

  /**
   * This program logs output to stdout or to a file that has been specified by the parameter log_filename.
   * A template can be used in order to organize the output that is created. The output is grouped into header, file list and footer.
   * This specifies a template file for header and footer output.
   * Templates can use internal variables and parameters as placeholders in the form %{placeholder}.
   * 
   * @param header
   * @return String
   * @throws Exception
   */
  public String getBanner(boolean header) throws Exception {
    String curBannerHeader = "";
    String curBannerFooter = "";
    String banner = "";
    try {

      if (header) {
        curBannerHeader = bannerHeader;

        if (sosString.parseToString(arguments, "banner_header").length() > 0) {
          String b = sosString.parseToString(arguments, "banner_header");
          File fBanner = new File(b);
          if (!fBanner.exists()) {
            getLogger().warn("[banner_header=" + b + "] does not exist. Using default banner");
          }
          else {
            curBannerHeader = sos.util.SOSFile.readFile(fBanner);
          }
        }

        Iterator it = arguments.keySet().iterator();
        while (it.hasNext()) {
          String key = sosString.parseToString(it.next());
          if (key.length() > 0) {
            if (key.equals("file_spec") && sosString.parseToString(arguments, "file_path").length() > 0)
              continue;

            int pos1 = -1;
            int pos2 = -1;
            boolean loop = true;
            while (loop) {
              pos1 = curBannerHeader.indexOf("%{" + key + "}");
              pos2 = pos1 + ("%{" + key + "}").length();
              if (pos1 > -1 && pos2 > pos1) {
                curBannerHeader = curBannerHeader.substring(0, pos1) + sosString.parseToString(arguments, key)
                    + curBannerHeader.substring(pos2);
              }

              pos1 = curBannerHeader.indexOf("%{" + key + "}", pos2);
              if (pos1 == -1)
                loop = false;
            }

          }
        }
        // alle Platzhalter, die keinen Wert haben l�schen
        curBannerHeader = clearBanner(curBannerHeader);
        banner = curBannerHeader;
      }
      else {

        curBannerFooter = bannerFooter;
        if (sosString.parseToString(arguments, "banner_footer").length() > 0) {
          String b = sosString.parseToString(arguments, "banner_footer");
          File fBanner = new File(b);
          if (!fBanner.exists()) {
            getLogger().warn("[banner_footer=" + b + "] does not exist. Using default banner");
          }
          else {
            curBannerFooter = sos.util.SOSFile.readFile(fBanner);
          }
        }

        @SuppressWarnings("rawtypes")
        Iterator it = arguments.keySet().iterator();
        while (it.hasNext()) {
          String key = sosString.parseToString(it.next());
          if (key.length() > 0) {
            if (key.equals("file_spec") && sosString.parseToString(arguments, "file_path").length() > 0)
              continue;
            boolean loop = true;

            loop = true;
            int pos3 = -1;
            int pos4 = -1;
            while (loop) {
              pos3 = curBannerFooter.indexOf("%{" + key + "}");
              pos4 = pos3 + ("%{" + key + "}").length();

              if (pos3 > -1 && pos4 > pos3)
                curBannerFooter = curBannerFooter.substring(0, pos3) + sosString.parseToString(arguments, key)
                    + curBannerFooter.substring(pos4);

              pos3 = curBannerFooter.indexOf("%{" + key + "}", pos4);
              if (pos3 == -1)
                loop = false;
            }
          }
        }

        // alle Platzhalter, die keinen Wert haben l�schen
        curBannerFooter = clearBanner(curBannerFooter);
        banner = curBannerFooter;
        // arguments.remove("for_banner");
      }
    }
    catch (Exception e) {
      throw new Exception("error occurred getting banner: " + e.getMessage());
    }
    return banner;
  }

  /**
   * L�schen von leeren Platzhalter
   * @param str
   * @return
   */
  private String clearBanner(String str) {
    boolean loop = true;
    while (loop) {
      int pos1 = str.indexOf("%{");
      int pos2 = str.indexOf("}", pos1) + "}".length();

      if (pos1 > -1 && pos2 > pos1) {
        int iSpace = pos2 - pos1;
        String space = "   ";
        while (iSpace != 0) {
          space = space + " ";
          iSpace--;
        }
        str = str.substring(0, pos1) + space + str.substring(pos2);
      }
      pos1 = str.indexOf("%{", pos2);
      if (pos1 == -1)
        loop = false;
    }
    return str;
  }

  /**
   * @return Returns the sshConnection.
   */
  protected Connection getSshConnection() {
    return sshConnection;
  }

  /**
   * @param sshConnection The sshConnection to set.
   */
  protected void setSshConnection(Connection sshConnection) {
    this.sshConnection = sshConnection;
  }

  /**
   * Install SOSFTP on a remote server
   *
   * @return boolean
   * @throws Exception
   */
  protected boolean install() throws Exception {
    return false;
  }

  /**
   * Initialisieren der sos.net.SOSFTP
   * @throws Exception
   */
  protected void initSOSFTP() throws Exception {
    try {

      try {
        sosftp = new SOSFTP(host, port);
      }
      catch (Exception e) {
        this.getLogger().debug("SOSFtp exception raised");
        // e.printStackTrace();
        throw e; // kb 2011-04-27 grrrrr
      }
      // sos.net.SOSFTP sosftp = new sos.net.SOSFTP(host, port);
      // sosftp.connect(host, port);
      ftpClient = sosftp;
      this.getLogger().debug("..ftp server reply [init] [host=" + host + "], [port=" + port + "]: " + ftpClient.getReplyString());

      if (account != null && account.length() > 0) {
        isLoggedIn = sosftp.login(user, SOSCommandline.getExternalPassword(password, logger), account);
        this.getLogger().debug("..ftp server reply [login] [user=" + user + "], [account=" + account + "]: " + ftpClient.getReplyString());
      }
      else {
        isLoggedIn = sosftp.login(user, SOSCommandline.getExternalPassword(password, logger));
        this.getLogger().debug("..ftp server reply [login] [user=" + user + "]: " + ftpClient.getReplyString());
      }

      if (!isLoggedIn || sosftp.getReplyCode() > ERROR_CODE) {
        throw new Exception("..ftp server reply [login failed] [user=" + user + "], [account=" + account + "]: " + ftpClient.getReplyString());
      }

      postLoginOperations();
    }
    catch (Exception e) {
      e.printStackTrace();
      throw new Exception("error in  " + sos.util.SOSClassUtil.getMethodName() + ", cause: " + e);
    }
  }

  /**
   * Performs some post-login operations, such trying to detect server support
   * for utf8.
   *
   */
  private void postLoginOperations() throws Exception {
    // synchronized (lock) {
    utf8Supported = false;
    restSupported = false;
    mlsdSupported = false;
    modezSupported = false;
    dataChannelEncrypted = false;

    if (flgCheckServerFeatures == true) { // JIRA SOSFTP-92
      String strCmd = "FEAT";
      sosftp.sendCommand(strCmd);
      this.getLogger().info("..ftp server reply [" + strCmd + "]: " + ftpClient.getReplyString());
    }
    // FTPReply r = sosftp.readFTPReply();
    // if (r.getCode() == 211) {
    // String[] lines = r.getMessages();
    // for (int i = 1; i < lines.length - 1; i++) {
    // String feat = lines[i].trim().toUpperCase();
    // // REST STREAM supported?
    // if ("REST STREAM".equalsIgnoreCase(feat)) {
    // restSupported = true;
    // continue;
    // }
    // // UTF8 supported?
    // if ("UTF8".equalsIgnoreCase(feat)) {
    // utf8Supported = true;
    // sosftp.changeCharset("UTF-8");
    // continue;
    // }
    // // MLSD supported?
    // if ("MLSD".equalsIgnoreCase(feat)) {
    // mlsdSupported = true;
    // continue;
    // }
    // // MODE Z supported?
    // if ("MODE Z".equalsIgnoreCase(feat) || feat.startsWith("MODE Z ")) {
    // modezSupported = true;
    // continue;
    // }
    // }
    // }
    // // Turn UTF 8 on (if supported).
    // if (utf8Supported) {
    // sosftp.sendFTPCommand("OPTS UTF8 ON");
    // sosftp.readFTPReply();
    // }
    // // Data channel security.
    // if (security == SECURITY_FTPS || security == SECURITY_FTPES) {
    // sosftp.sendFTPCommand("PBSZ 0");
    // sosftp.readFTPReply();
    // sosftp.sendFTPCommand("PROT P");
    // FTPReply reply = sosftp.readFTPReply();
    // if (reply.isSuccessCode()) {
    // dataChannelEncrypted = true;
    // }
    // }
    // }
  }

  /**
   * Initialisieren der sos.net.SOSSFTP
   * @throws Exception
   */
  protected void initSOSSFTP() throws Exception {

    try {
      SOSSFTP sftpClient = new SOSSFTP(host, port);

      ftpClient = sftpClient;
      sftpClient.setAuthenticationFilename(authenticationFilename);
      sftpClient.setAuthenticationMethod(authenticationMethod);
      sftpClient.setPassword(SOSCommandline.getExternalPassword(password, logger));
      sftpClient.setProxyHost(proxyHost);
      sftpClient.setProxyPort(proxyPort);
      sftpClient.setProxyPassword(SOSCommandline.getExternalPassword(proxyPassword, logger));
      sftpClient.setProxyUser(proxyUser);
      sftpClient.setUser(user);
      sftpClient.connect();
      this.getLogger().debug("..sftp server logged in [user=" + user + "], [host=" + host + "]");
    }
    catch (Exception e) {
      throw new Exception("..sftp server login failed [user=" + user + "], [host=" + host + "]: " + e);
    }
  }

  protected void initSOSFTPS() throws Exception {
    try {

      if (proxyHost != null && proxyPort != 0) {
        System.getProperties().setProperty("proxyHost", proxyHost);
        System.getProperties().setProperty("proxyPort", String.valueOf(proxyPort));
        System.getProperties().setProperty("proxySet", "true");
      }

      SOSFTPS sosftp = new SOSFTPS(host, port);
      ftpClient = sosftp;

      this.getLogger().debug("..ftps server reply [init] [host=" + host + "], [port=" + port + "]: " + ftpClient.getReplyString());

      isLoggedIn = sosftp.login(user, SOSCommandline.getExternalPassword(password, logger));
      this.getLogger().debug("..ftps server reply [login] [user=" + user + "]: " + ftpClient.getReplyString());

      if (!isLoggedIn || sosftp.getReplyCode() > ERROR_CODE) {
        throw new Exception("..ftps server reply [login failed] [user=" + user + "], [account=" + account + "]: " + ftpClient.getReplyString());
      }

    }
    catch (Exception e) {
      throw new Exception("..ftps server login failed [user=" + user + "], [host=" + host + "]: " + e);
    }
  }

  public Properties getArguments() {
    return arguments;
  }

  private BufferedWriter getHistory() {
    return history;
  }

  /**
   * History Eintrag schreiben
   * @param localFilename
   * @param remoteFilename
   * @throws Exception
   */
  @SuppressWarnings("unchecked")
  protected void writeHistory(String localFilename, String remoteFilename) throws Exception {
    String hist = "";
    String EMPTY = "";
    long guid = 0;
    String mandator = "";
    String transfer_timestamp = "";
    String pid = "";
    String ppid = "";
    String operation = "";
    String localhost = "";
    String localhost_ip = "";
    String local_user = "";
    String remote_host = "";
    String remote_host_ip = "";
    String remote_user = "";
    String protocol = "";
    String port = "";
    String local_dir = "";
    String remote_dir = "";
    String local_filename = "";
    String remote_filename = "";
    String fileSize = "";
    String md5 = "";
    String status = "";
    String last_error_message = "";
    String log_filename = "";

    // new HistoryFields 04.09.2009
    String jump_host = "";
    String jump_host_ip = "";
    String jump_port = "";
    String jump_protocol = "";
    String jump_user = "";

    try {
      if (!sosString.parseToString(arguments, "operation").equalsIgnoreCase("send")
          && !sosString.parseToString(arguments, "operation").equalsIgnoreCase("receive"))
        return;

      getLogger().debug9("local filename=" + localFilename + ", remote filename=" + remoteFilename);

      if (sosString.parseToBoolean(sosString.parseToString(arguments, "skip_transfer")))
        return;

      if (history == null && !sendSchedulerSignale)
        return;

      File localFile = null;

      if (sosString.parseToString(localFilename).length() > 0)
        localFile = new File(localFilename);

      guid = sos.util.SOSUniqueID.get(); // 4- GUID
      mandator = (sosString.parseToString(arguments, "mandator").length() > 0 ? sosString.parseToString(arguments, "mandator") : defaultMandator); // 0-
                                                                              // mandator:
                                                                              // default
                                                                              // SOS
      transfer_timestamp = sos.util.SOSDate.getCurrentTimeAsString(); // 1- timestamp: Zeitstempel im ISO-Format
      pid = (sosString.parseToString(arguments, "current_pid").length() > 0 ? sosString.parseToString(arguments, "current_pid") : "0"); // 2-
                                                                        // pid=
                                                                        // Environment
                                                                        // PID
                                                                        // |
                                                                        // 0
                                                                        // f�r
                                                                        // Windows
      ppid = (sosString.parseToString(arguments, "ppid").length() > 0 ? sosString.parseToString(arguments, "ppid") : "0"); // 3- ppid=
                                                                  // Environment
                                                                  // PPID
                                                                  // | 0
                                                                  // f�r
                                                                  // Windows
      operation = sosString.parseToString(arguments, "operation"); // 4- operation: send|receive
      localhost = sosString.parseToString(arguments, "localhost"); // 5- local host
      localhost_ip = sosString.parseToString(arguments, "local_host_ip"); // 5-1- local host IP adresse
      local_user = sosString.parseToString(System.getProperty("user.name")); // 6- local user
      if (jump) {
        remote_host = sosString.parseToString(originalParam, "host"); // 7- remote host
        if (remote_host.length() > 0)
          remote_host_ip = java.net.InetAddress.getByName(remote_host).getHostAddress();
        remote_user = sosString.parseToString(originalParam, "user"); // 8- remote host user
        protocol = sosString.parseToString(originalParam, "protocol"); // 9- protocol
      }
      else {
        remote_host = sosString.parseToString(arguments, "host"); // 7- remote host
        remote_host_ip = sosString.parseToString(arguments, "remote_host_ip"); // 7- remote host IP
        remote_user = sosString.parseToString(arguments, "user"); // 8- remote host user
        protocol = sosString.parseToString(arguments, "protocol"); // 9- protocol
      }

      port = sosString.parseToString(arguments, "port"); // 10- port

      // ab hier unterscheiden on der Fehler w�hrend dem Datei transfer oder vor dem datei transfer entstanden ist
      if (sosString.parseToString(arguments, "operation").equals("send")) {
        local_dir = (localFile != null && localFile.getParent() != null ? clearCRLF(localFile.getParent()) : clearCRLF(sosString.parseToString(
            arguments, "local_dir"))); // 11- local dir
      }
      else {
        local_dir = clearCRLF(sosString.parseToString(arguments, "local_dir")); // 11- local dir
      }
      if (sosString.parseToString(local_dir).length() == 0)
        local_dir = ".";
      if (jump) {
        remote_dir = clearCRLF(sosString.parseToString(originalParam, "remote_dir")); // 12- remote dir
      }
      else {
        remote_dir = clearCRLF(sosString.parseToString(arguments, "remote_dir")); // 12- remote dir
      }
      local_filename = localFile != null ? clearCRLF(localFile.getName()) : EMPTY; // 13- file name
      remote_filename = sosString.parseToString(remoteFilename).length() > 0 ? clearCRLF(new File(remoteFilename).getName()) : EMPTY; // 14-
                                                                      // file
                                                                      // name
      fileSize = sosString.parseToString(arguments, "file_size").length() > 0 ? sosString.parseToString(arguments, "file_size") : EMPTY;

      if (sosString.parseToString(localFilename).length() == 0 || sosString.parseToString(remoteFilename).length() == 0) {
        md5 = EMPTY; // MD5
      }
      else {
        File f4md5 = localFile.getName().equals(new File(remoteFilename).getName()) ? new File(remoteFilename) : (sosString.parseToString(arguments,
            "operation").equals("receive") ? new File(normalized(local_dir) + new File(remoteFilename).getName()) : new File(normalized(local_dir)
            + localFile.getName())); // falls ein replacing verwendet wurde

        if (f4md5.exists()) {
          getLogger().debug9("md5 for " + f4md5.getAbsolutePath());
          md5 = sos.util.SOSCrypt.MD5encrypt(f4md5); // MD5
        }
        else {
          md5 = EMPTY; // eventuell existiert die Datei nicht
        }
      }

      status = (sosString.parseToString(arguments, "status").length() == 0 ? "success" : sosString.parseToString(arguments, "status"));// -
                                                                        // status=success|error

      last_error_message = clearCRLF(((getLogger().getError() != null && getLogger().getError().length() > 0) ? getLogger().getError()
          : getLogger().getWarning())); // 15- last_error=|warn message
      last_error_message = normalizedPassword(sosString.parseToString(last_error_message));
      log_filename = sosString.parseToString(arguments, "log_filename");

      jump_host = sosString.parseToString(arguments, "jump_host");
      if (jump_host.length() > 0)
        jump_host_ip = java.net.InetAddress.getByName(host).getHostAddress();
      jump_port = sosString.parseToString(arguments, "jump_port");
      jump_protocol = sosString.parseToString(arguments, "jump_protocol");
      jump_user = sosString.parseToString(arguments, "jump_user");

      // TODO mit den Mappings im SOSFTPHistoryJob synchronisieren. Hier muss eine *gemeinsame* Klasse verwendet werden
      // am besten mit der OptionKlasse koppeln, da gleiche datentypen etc.

      Properties objSchedulerOrderParameterSet = new Properties();
      objSchedulerOrderParameterSet.put("guid", String.valueOf(guid)); // 1- GUID
      objSchedulerOrderParameterSet.put("mandator", mandator); // 2- mandator: default SOS
      objSchedulerOrderParameterSet.put("transfer_timestamp", transfer_timestamp); // 3- timestamp: Zeitstempel im ISO-Format
      objSchedulerOrderParameterSet.put("pid", pid); // 4- pid= Environment PID | 0 f�r Windows
      objSchedulerOrderParameterSet.put("ppid", ppid); // 5- ppid= Environment PPID | 0 f�r Windows
      objSchedulerOrderParameterSet.put("operation", operation); // 6- operation: send|receive
      objSchedulerOrderParameterSet.put("localhost", localhost); // 7- local host
      objSchedulerOrderParameterSet.put("localhost_ip", localhost_ip); // 8- local host IP adresse
      objSchedulerOrderParameterSet.put("local_user", local_user); // 9- local user
      objSchedulerOrderParameterSet.put("remote_host", remote_host); // 10- remote host
      objSchedulerOrderParameterSet.put("remote_host_ip", remote_host_ip); // 11- remote host IP
      objSchedulerOrderParameterSet.put("remote_user", remote_user); // 12- remote host user
      objSchedulerOrderParameterSet.put("protocol", protocol); // 13- protocol
      objSchedulerOrderParameterSet.put("port", port); // 14- port
      objSchedulerOrderParameterSet.put("local_dir", local_dir); // 15- local dir
      objSchedulerOrderParameterSet.put("remote_dir", remote_dir); // 16- remote dir
      objSchedulerOrderParameterSet.put("local_filename", local_filename); // 17- file name
      objSchedulerOrderParameterSet.put("remote_filename", remote_filename); // 18- file name
      objSchedulerOrderParameterSet.put("file_size", fileSize); // 19 - file name
      objSchedulerOrderParameterSet.put("md5", md5); // 20
      objSchedulerOrderParameterSet.put("status", status); // 21- status=success|error
      objSchedulerOrderParameterSet.put("last_error_message", last_error_message); // 22
      objSchedulerOrderParameterSet.put("log_filename", log_filename); // 23
      objSchedulerOrderParameterSet.put("jump_host", jump_host); // 24
      objSchedulerOrderParameterSet.put("jump_host_ip", jump_host_ip); // 25
      objSchedulerOrderParameterSet.put("jump_port", jump_port); // 26
      objSchedulerOrderParameterSet.put("jump_protocol", jump_protocol); // 27
      objSchedulerOrderParameterSet.put("jump_user", jump_user); // 28

      if (history != null) {
        String[] splitHistFields = historyFields.split(";");
        for (int i = 0; i < splitHistFields.length; i++) {
          String key = sosString.parseToString(splitHistFields[i]);
          String value = sosString.parseToString(objSchedulerOrderParameterSet, key).length() == 0 ? sosString.parseToString(arguments,
              "history_entry_".concat(key)) : sosString.parseToString(objSchedulerOrderParameterSet, key);
          hist = hist + (i == 0 ? "" : ";") + value; //
        }

        getLogger().debug9("history entry: " + hist);

        if (transActional) {
          if (transactionalHistoryFile == null)
            transactionalHistoryFile = new ArrayList();
          transactionalHistoryFile.add(hist);
        }
        else {
          history.write(hist);
          history.newLine();
        }
      }

      if (sendSchedulerSignale) {
        String schedulerMessages = "";
        if (sosString.parseToString(arguments, "scheduler_message").length() > 0) {
          schedulerMessages = sosString.parseToString(arguments, "scheduler_message");
          schedulerMessages = normalizedFields(schedulerMessages, objSchedulerOrderParameterSet, "%{", "}");
          schedulerMessages = normalizedFields(schedulerMessages, arguments, "%{", "}");
        }
        else {
          String strJobChainName = sosString.parseToString(arguments, "scheduler_job_chain");
          schedulerMessages = String.format("<add_order job_chain='%1$s'><params>", strJobChainName);

          for (final Entry element : objSchedulerOrderParameterSet.entrySet()) {
            final Map.Entry<String, String> mapItem = (Map.Entry<String, String>) element;
            String key = mapItem.getKey().toString();
            schedulerMessages += String.format("<param name='%1$s' value='%2$s'/>", key, mapItem.getValue());
          }
          schedulerMessages = schedulerMessages + "</params></add_order>";
        }

        if (transActional) {
          if (transactionalSchedulerRequestFile == null)
            transactionalSchedulerRequestFile = new ArrayList();
          transactionalSchedulerRequestFile.add(schedulerMessages);
        }
        else {
          sendSchedulerRequest(schedulerMessages);
          getLogger().debug9("sending Job Scheduler message: " + schedulerMessages);
        }
      }
    }
    catch (Exception e) {
      getLogger().warn("error occurred writing history entry, cause: " + e.getMessage());
    }
  }

  private String clearCRLF(String txt) {
    return txt.replaceAll("(\r\n|\r|\n|\n\r|;)", ",");
  }

  private void appendHistoryFile() throws Exception {

    int repeat = 3;
    int repeatIntervall = 1;
    try {

      if (sosString.parseToString(arguments, "history_repeat").length() > 0) {
        try {
          repeat = Integer.parseInt(sosString.parseToString(arguments, "history_repeat"));
        }
        catch (Exception e) {
          repeat = 3;
        }
      }
      if (sosString.parseToString(arguments, "history_repeat_interval").length() > 0) {
        try {
          repeatIntervall = Integer.parseInt(sosString.parseToString(arguments, "history_repeat_interval"));
        }
        catch (Exception e) {
          repeatIntervall = 1;
        }
      }

      boolean hasError = getLogger().hasErrors() || getLogger().hasWarnings();
      if (getHistory() != null) {
        for (int j = 0; transactionalHistoryFile != null && j < transactionalHistoryFile.size(); j++) {
          String hist = sosString.parseToString(transactionalHistoryFile.get(j));
          if (hasError) {
            hist = hist.replaceAll(";success;;", ";error;"
                + clearCRLF(((getLogger().getError() != null && getLogger().getError().length() > 0) ? getLogger().getError()
                    : getLogger().getWarning())) + ";");
          }
          history.write(hist);
          history.newLine();
          getLogger().debug9("history entry: " + hist);
        }
      }

    }
    catch (Exception e) {
      getLogger().warn("error occurred writing history, cause: " + e.getMessage());
    }
    finally {

      for (int i = repeat; i > 0; i--) {
        try {
          if (getHistory() != null) {
            getHistory().close();
            // schreibe diese in die globalen history Datei
            if (!existHistoryLockFile()) {
              createHistoryLockFile();
              sos.util.SOSFile.copyFile(getTempHistoryFile(), historyFile, true);
              removeHistoryLockFile();
            }
            if (!tempHistoryFile.delete())
              getLogger().info(tempHistoryFile.getAbsolutePath() + " could not delete");
          }

          break;
        }
        catch (Exception e) {
          if (i == 1)
            getLogger().warn("could not write in History File, cause: " + e.toString());
          Thread.sleep(repeatIntervall * 1000);
        }
      }
      if (tempHistoryFile != null && tempHistoryFile.exists())
        if (!tempHistoryFile.delete())
          getLogger().info(tempHistoryFile.getAbsolutePath() + " could not delete");
    }
  }

  private void sendTransactionalSchedulerRequestFile() throws Exception {
    if (transActional) {
      if (transactionalSchedulerRequestFile != null) {
        for (int i = 0; i < transactionalSchedulerRequestFile.size(); i++) {
          String msg = sosString.parseToString(transactionalSchedulerRequestFile.get(i));
          boolean hasError = getLogger().hasErrors() || getLogger().hasWarnings();
          if (hasError) {
            msg = msg.replaceAll("<param name='status' value='success'/>", "<param name='status' value='error'/>");
            msg = msg.replaceAll("<param name='last_error_message' value=''/>", "<param name='last_error_message' value='"
                + clearCRLF(((getLogger().getError() != null && getLogger().getError().length() > 0) ? getLogger().getError()
                    : getLogger().getWarning())) + "'/>");
            // sendSchedulerRequest(msg);
          }
          sendSchedulerRequest(msg);
        }
      }
    }
  }

  /**
   * sends a command to the scheduler
   *
   * @param command XML String containing the command
   * @throws java.lang.Exception
   */
  public void sendSchedulerRequest(String msg) throws Exception {

    String _host = "";
    int _port = 0;
    DatagramSocket udpSocket = null;
    try {

      _host = sosString.parseToString(arguments, "scheduler_host");
      if (sosString.parseToString(arguments, "scheduler_port").length() > 0)
        _port = Integer.parseInt(sosString.parseToString(arguments, "scheduler_port"));

      if (_host == null || _host.length() == 0)
        throw (new Exception("Job Scheduler host name missing."));

      if (_port == 0)
        throw (new Exception("Job Scheduler port missing."));

      udpSocket = new DatagramSocket();
      udpSocket.connect(InetAddress.getByName(_host), _port);

      // protocol=udp
      if (msg.indexOf("<?xml") == -1) {
        msg = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>" + msg + "\r\n";
      }

      getLogger().debug9("sending Job Scheduler message: " + msg);

      byte[] commandBytes = msg.getBytes();
      udpSocket.send(new DatagramPacket(commandBytes, commandBytes.length, InetAddress.getByName(_host), _port));
    }
    catch (Exception e) {
      getLogger().warn("could not send message to the Job Scheduler, cause " + e.toString());
    }
    finally {
      if (udpSocket != null)
        udpSocket.disconnect();

    }
  }

  /**
   * sends a command to the scheduler
   *
   * �berpr�ft ob alle Parameter correkt angegeben sind
   * @param command XML String containing the command
   * @throws java.lang.Exception
   */
  private void checkSchedulerRequest() throws Exception {
    String _command = "";
    String _host = "";
    int _port = 0;

    try {

      _host = sosString.parseToString(arguments, "scheduler_host");
      if (sosString.parseToString(arguments, "scheduler_port").length() > 0)
        _port = Integer.parseInt(sosString.parseToString(arguments, "scheduler_port"));

      _command = sosString.parseToString(arguments, "scheduler_message");

      // abbruchbedingung
      if (sosString.parseToString(_host).concat(sosString.parseToString(arguments, "scheduler_port")).concat(_command).length() == 0)
        return;

      if (_host == null || _host.length() == 0)
        throw (new RuntimeException("Job Scheduler host name missing."));

      if (_port == 0)
        throw (new RuntimeException("Job Scheduler port missing."));

      if (sosString.parseToString(arguments, "scheduler_job_chain").length() == 0)
        arguments.put("scheduler_job_chain", "scheduler_sosftp_history");

      sendSchedulerSignale = true;
    }
    catch (Exception e) {
      throw new RuntimeException("error in checkSchedulerRequestParameter(): " + e.toString(), e);
    }
  }

  /**
   * Alle Platzhalter in der Form %{parametername}  oder ${parametername}  oder %parametername% werden ersetzt mir dem Wert des Parameters,
   * falls dieser Parametername vorhanden sind.
   *
   *
   *
   * @param txt
   * @param prop
   * @return
   * @throws Exception
   */
  private static String normalizedFields(String txt, Properties prop, String startPrefix, String endPrefix) throws Exception {
    try {
      Iterator it = prop.keySet().iterator();
      while (it.hasNext()) {
        String key = sosString.parseToString(it.next());
        if (key.length() > 0) {
          int pos1 = -1;
          int pos2 = -1;
          boolean loop = true;
          while (loop) {

            pos1 = txt.indexOf(startPrefix + key + endPrefix);

            if (pos1 > -1 && txt.indexOf("\\" + startPrefix + key + endPrefix) > -1
                && txt.indexOf("\\" + startPrefix + key + endPrefix) == pos1 - 1) // ist quottiert?
              pos1 = -1;

            pos2 = pos1 + (startPrefix + key + endPrefix).length();
            if (pos1 > -1 && pos2 > pos1)
              txt = txt.substring(0, pos1) + sosString.parseToString(prop, key) + txt.substring(pos2);

            pos1 = txt.indexOf(startPrefix + key + endPrefix, pos2);

            if (pos1 == -1)
              loop = false;

          }
        }
      }
      return txt;
    }
    catch (Exception e) {
      throw new Exception("could not substitute parameters in: " + txt + ", cause: " + e.toString());
    }
  }

  private File getTempHistoryFile() {
    return tempHistoryFile;
  }

  /**
   * @return Returns the commandDelimiter.
   */
  protected String getCommandDelimiter() {
    return commandDelimiter;
  }

  private void readJumpSettings() throws Exception {

    this.getBaseParameters();
    String commandScript = "";
    String commandScriptFileName = "";

    try {

      if (sosString.parseToString(arguments.get("jump_command_delimiter")).length() > 0) {
        this.setCommandDelimiter(sosString.parseToString(arguments.get("jump_command_delimiter")));
        getLogger().debug1(".. parameter [jump_command_delimiter]: " + this.getCommandDelimiter());
      }
      else {
        this.setCommandDelimiter(DEFAULT_COMMAND_DELIMITER);
      }

      if (sosString.parseToString(arguments.get("jump_command_script")).length() > 0) {
        commandScript = sosString.parseToString(arguments.get("jump_command_script"));
        getLogger().debug1(".. parameter [jump_command_script]: " + commandScript);
      }

      if (sosString.parseToString(arguments.get("jump_command_script_file")).length() > 0) {
        commandScriptFileName = sosString.parseToString(arguments.get("jump_command_script_file"));
        getLogger().debug1(".. parameter [jump_command_script_file]: " + commandScriptFileName);
      }

      if (sosString.parseToString(arguments.get("jump_command")).length() > 0) {
        this.setCommands(sosString.parseToString(arguments.get("jump_command")).split(this.getCommandDelimiter()));
        getLogger().debug1(".. parameter [jump_command]: " + sosString.parseToString(arguments.get("jump_command")));
      }

      if (sosString.parseToString(arguments.get("jump_ignore_error")).length() > 0) {

        if (sosString.parseToBoolean(arguments.get("jump_ignore_error"))) {
          ignoreError = true;
        }
        else {
          ignoreError = false;
        }
        getLogger().debug1(".. parameter [jump_ignore_error]: " + ignoreError);
      }
      else {
        ignoreError = false;
      }

      if (sosString.parseToString(arguments.get("jump_ignore_signal")).length() > 0) {
        if (sosString.parseToBoolean(sosString.parseToString(arguments.get("jump_ignore_signal")))) {
          ignoreSignal = true;
        }
        else {
          ignoreSignal = false;
        }
        getLogger().debug1(".. parameter [jump_ignore_signal]: " + ignoreSignal);
      }
      else {
        ignoreSignal = false;
      }

      if (sosString.parseToString(arguments.get("jump_ignore_stderr")).length() > 0) {
        if (sosString.parseToBoolean(sosString.parseToString(arguments.get("jump_ignore_stderr")))) {
          ignoreStderr = true;
        }
        else {
          ignoreStderr = false;
        }
        getLogger().debug1(".. parameter [jump_ignore_stderr]: " + ignoreStderr);
      }
      else {
        ignoreStderr = false;
      }
    }
    catch (Exception e) {
      throw new Exception("error occurred processing parameters: " + e.getMessage());
    }
  }

  protected boolean remoteIsWindowsShell(boolean withConn) throws Exception {
    try {
      if (withConn) {
        if (getSshConnection() == null) {

          readJumpSettings();

          this.getBaseAuthentication();
        }
      }
      return remoteIsWindowsShell();

    }
    catch (Exception e) {
      throw new Exception("Failed to check if remote system has windows shell: " + e);

    }
    finally {
      if (withConn) {
        if (this.getSshConnection() != null)
          try {
            this.getSshConnection().close();
            this.setSshConnection(null);
          }
          catch (Exception ex) {
          } // gracefully ignore this error
      }
    }
  }

  /**
   * Authentication-Processing
   *
   */
  protected Connection getBaseAuthentication() throws Exception {

    try { // to connect and authenticate
      boolean isAuthenticated = false;
      this.setSshConnection(new Connection(this.host, this.port));

      if (proxyHost != null && this.proxyHost.length() > 0) {
        if (this.proxyUser != null && this.proxyUser.length() > 0) {
          this.getSshConnection().setProxyData(new HTTPProxyData(this.proxyHost, this.proxyPort));
        }
        else {
          this.getSshConnection().setProxyData(
              new HTTPProxyData(this.proxyHost, this.proxyPort, this.proxyUser, SOSCommandline.getExternalPassword(this.proxyPassword, logger)));
        }
      }

      this.getSshConnection().connect();

      if (this.authenticationMethod.equalsIgnoreCase("publickey")) {
        File authenticationFile = new File(authenticationFilename);
        if (!authenticationFile.exists())
          throw new Exception("authentication file does not exist: " + authenticationFile.getCanonicalPath());
        if (!authenticationFile.canRead())
          throw new Exception("authentication file not accessible: " + authenticationFile.getCanonicalPath());

        isAuthenticated = this.getSshConnection().authenticateWithPublicKey(this.user, authenticationFile,
            SOSCommandline.getExternalPassword(this.password, logger));
      }
      else
        if (this.authenticationMethod.equalsIgnoreCase("password")) {
          isAuthenticated = this.getSshConnection().authenticateWithPassword(this.user, SOSCommandline.getExternalPassword(this.password, logger));
        }

      if (!isAuthenticated)
        throw new Exception("authentication failed [jump_host=" + this.host + ", jump_port=" + this.port + ", jump_user:" + this.user
            + ", jump_ssh_auth_method=" + this.authenticationMethod + ", jump_ssh_auth_file=" + authenticationFilename);

      return this.getSshConnection();

    }
    catch (Exception e) {
      if (this.getSshConnection() != null)
        try {
          this.getSshConnection().close();
          this.setSshConnection(null);
        }
        catch (Exception ex) {
        } // gracefully ignore this error
      throw new Exception(e.getMessage());
    }
  }

  /**
   * Parameter-Processing
   *
   */
  protected void getBaseParameters() throws Exception {

    try {
      if (sosString.parseToString(arguments.get("jump_host")).length() > 0) {
        this.host = sosString.parseToString(arguments.get("jump_host"));
        getLogger().debug1(".. parameter [jump_host]: " + this.host);
      }
      else {
        throw new Exception("no host name or ip address was specified as parameter [jump_host]");
      }
      if (sosString.parseToString(arguments.get("jump_port")).length() <= 0) {
        arguments.put("jump_port", "22");
      }
      try {
        this.port = Integer.parseInt(sosString.parseToString(arguments.get("jump_port")));
        getLogger().debug1(".. parameter [jump_port]: " + this.port);
      }
      catch (Exception ex) {
        throw new Exception("illegal non-numeric value for parameter [jump_port]: " + sosString.parseToString(arguments.get("jump_port")));
      }

      if (sosString.parseToString(arguments.get("jump_user")).length() > 0) {
        this.user = (sosString.parseToString(arguments.get("jump_user")));
        getLogger().debug1(".. parameter [jump_user]: " + this.user);
      }
      else {
        throw new Exception("no user name was specified as parameter [jump_user]");
      }

      if (sosString.parseToString(arguments.get("jump_password")).length() > 0) {
        this.password = sosString.parseToString(arguments.get("jump_password"));
        getLogger().debug1(".. parameter [jump_password]: ********");
      }
      else {
        this.password = "";
      }

      if (sosString.parseToString(arguments.get("jump_proxy_host")).length() > 0) {
        proxyHost = sosString.parseToString(arguments.get("jump_proxy_host"));
        getLogger().debug1(".. parameter [jump_proxy_host]: " + this.proxyHost);
      }
      else {
        this.proxyHost = "";
      }

      if (sosString.parseToString(arguments.get("jump_proxy_port")).length() > 0) {
        try {
          this.proxyPort = (Integer.parseInt(sosString.parseToString(arguments.get("jump_proxy_port"))));
          getLogger().debug1(".. parameter [jump_proxy_port]: " + this.proxyPort);
        }
        catch (Exception ex) {
          throw new Exception("illegal non-numeric value for parameter [jump_proxy_port]: "
              + sosString.parseToString(arguments.get("jump_proxy_port")));
        }
      }
      else {
        this.proxyPort = 3128;
      }

      if (sosString.parseToString(arguments.get("jump_proxy_user")) != null && sosString.parseToString(arguments.get("jump_proxy_user")).length() > 0) {
        this.proxyUser = (sosString.parseToString(arguments.get("jump_proxy_user")));
        getLogger().debug1(".. parameter [jump_proxy_user]: " + this.proxyUser);
      }
      else {
        this.proxyUser = "";
      }

      if (sosString.parseToString(arguments.get("jump_proxy_password")).length() > 0) {
        this.proxyPassword = sosString.parseToString(arguments.get("jump_proxy_password"));
        getLogger().debug1(".. parameter [jump_proxy_password]: ********");
      }
      else {
        this.proxyPassword = "";
      }

      String authMeth = sosString.parseToString(arguments.get("jump_ssh_auth_method"));
      if (sosString.parseToString(arguments.get("jump_auth_method")).length() > 0)
        authMeth = sosString.parseToString(arguments.get("jump_auth_method"));
      else
        authMeth = sosString.parseToString(arguments.get("jump_ssh_auth_method"));
      if (authMeth.length() > 0) {
        if (authMeth.equalsIgnoreCase("publickey") || authMeth.equalsIgnoreCase("password")) {
          this.authenticationMethod = authMeth;
          getLogger().debug1(".. parameter [jump_ssh_auth_method]: " + this.authenticationMethod);
        }
        else {
          throw new Exception("invalid authentication method [publickey, password] specified: " + authMeth);
        }
      }
      else {
        this.authenticationMethod = "publickey";
      }

      String authFile = sosString.parseToString(arguments.get("jump_ssh_auth_file"));
      if (authFile.length() > 0) {
        authenticationFilename = authFile;
        getLogger().debug1(".. parameter [jump_ssh_auth_file]: " + authenticationFilename);
      }
      else {
        if (this.authenticationMethod.equalsIgnoreCase("publickey"))
          throw new Exception("no authentication filename was specified as parameter [jump_ssh_auth_file");
      }

    }
    catch (Exception e) {
      throw new Exception("error occurred processing parameters: " + e.getMessage());
    }
  }

  protected boolean remoteIsWindowsShell() {
    Session session = null;
    try {
      String checkShellCommand = "echo %ComSpec%";
      getLogger().debug9("Opening ssh session...");
      session = this.getSshConnection().openSession();
      getLogger().debug9("Executing command " + checkShellCommand);
      session.execCommand(checkShellCommand);

      getLogger().debug9("output to stdout for remote command: " + checkShellCommand);
      stdout = new StreamGobbler(session.getStdout());
      stderr = new StreamGobbler(session.getStderr());
      BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(stdout));
      String stdOut = "";
      while (true) {
        String line = stdoutReader.readLine();
        if (line == null)
          break;
        getLogger().debug9(line);
        stdOut += line;
      }
      getLogger().debug9("output to stderr for remote command: " + checkShellCommand);
      // Beide StreamGobbler m�ssen hintereinander instanziiert werden
      // InputStream stderr = new StreamGobbler(this.getSshSession().getStderr());
      BufferedReader stderrReader = new BufferedReader(new InputStreamReader(stderr));
      while (true) {
        String line = stderrReader.readLine();
        if (line == null)
          break;
        getLogger().debug1(line);
      }
      if (stdOut.indexOf("cmd.exe") > -1) {
        getLogger().debug3("Remote shell is Windows shell.");
        return true;
      }
    }
    catch (Exception e) {
      try {
        getLogger().warn("Failed to check if remote system is windows shell: " + e);
      }
      catch (Exception es) {
        System.out.println(" Failed to check if remote system is windows shell: " + e);
      }
    }
    finally {
      if (session != null)
        try {
          session.close();
        }
        catch (Exception e) {
          try {
            getLogger().warn("Failed to close session: " + e);
          }
          catch (Exception ea) {
            System.out.println(" Failed to close session: " + e);
          }
        }
    }
    return false;
  }

  /**
   * @param commandDelimiter The commandDelimiter to set.
   */
  protected void setCommandDelimiter(String commandDelimiter) {
    this.commandDelimiter = commandDelimiter;
  }

  /**
   * This thread consumes output from the remote server puts it into
   * fields of the main class
   */

  class RemoteConsumer extends Thread {

    private StringBuffer  sbuf;
    private boolean      writeCurrentline  = false;
    private InputStream    stream;
    boolean          end          = false;

    private RemoteConsumer(StringBuffer buffer, boolean writeCurr, InputStream str) {
      this.sbuf = buffer;
      this.writeCurrentline = true;
      this.stream = str;
    }

    private void addText(byte[] data, int len) {
      lasttime = System.currentTimeMillis();
      String outstring = new String(data).substring(0, len);
      sbuf.append(outstring);
      if (writeCurrentline) {
        int newlineIndex = outstring.indexOf(conNewLine);
        if (newlineIndex > -1) {
          String stringAfterNewline = outstring.substring(newlineIndex);
          currentLine = stringAfterNewline;
        }
        else
          currentLine += outstring;
      }
    }

    public void run() {
      byte[] buff = new byte[64];
      try {
        while (!end) {
          buff = new byte[8];
          int len = stream.read(buff);
          if (len == -1)
            return;
          addText(buff, len);
        }
      }
      catch (Exception e) {
      }
    }

    public synchronized void end() {
      end = true;
    }
  }

  protected void readSettings(boolean checkJumpArguments) throws Exception {
    try {

      // TODO wieso ist das auskommentiert ? kb 2010-05-18

      /*try {
        if(getSettingsFile() != null && getSettingsFile().length() > 0)
          this.setSettings(new SOSProfileSettings( this.getSettingsFile(), this.getSettingsSection(), this.getLogger()));         
      } catch (Exception e) {
        throw new Exception("error occurred retrieving settings: " + e.getMessage());
      }*/

      mergeSettings();

      if (checkJumpArguments)
        hasJumpArguments();

    }
    catch (Exception e) {
      throw new Exception("error in  " + sos.util.SOSClassUtil.getMethodName() + " , cause: " + e);
    }
  }

  public static String getVersion() {
    String version = JSVersionInfo.conVersionNumber;
    // String version = major + "." + minor + "." + bugFix;
    return version;
  }

  /**
   * Different file operations within one session
   * For different file sets multiple parameter sets should be used:
   *
   * a)      Use case:
   * -          3 files *.doc
   * -          2 files *.csv
   * -          For each file set a different replacing/replacement scheme should be applied
   *
   * Approach:
   *
   *   -          different file_spec paramters should be used and each file set should be assigned a set of different parameters
   *   -          changes to the initial parameters by a parameter set have local scope, i.e. a second parameter set makes use oft he initial parameters,
   *              and should not consider changes by a previous parameter set
   *             
   *              sosftp.sh �file_spec=[regex1]:[regex2] �transfer_mode=ascii:binary
   *              sosftp.sh �file_spec=[regex1] �file_spec2=[regex2]::[parameter_set2] �parameter_set2=�transfer_mode=ascii::remote_directory=/tmp�
   *             
   *              
   * @param arg
   * @return
   * @throws Exception
   */

  private static ArrayList getFileOperations(Properties arg) throws Exception {
    ArrayList list = new ArrayList();
    String key = "";
    String value = "";
    Iterator it = null;
    listOfSuccessTransfer = new ArrayList();
    listOfErrorTransfer = new ArrayList();

    try {

      arg.put("index", "0");
      list.add(arg.clone());
      arg.remove("index");

      it = arg.keySet().iterator();
      while (it.hasNext()) {
        key = sosString.parseToString(it.next());
        value = sosString.parseToString(arg, key);

        // unterschiedlich Parametrisierung
        if (key.startsWith("file_spec") && key.length() > "file_spec".length()) {// ein neues file_spec ist angegeben

          String[] split = value.split("::");
          Properties newArg = (Properties) arg.clone();
          newArg.put("file_spec", split[0]);
          noJumpParameter.add(key);// d�rfen dem jump host nicht �bergeben werden

          if (split.length > 1) {
            noJumpParameter.add(split[1]);// d�rfen dem jump host nicht �bergeben werden
            String newParameterSet = sosString.parseToString(arg, split[1]);
            String[] splitParams = newParameterSet.split("::");// Bsp.
                                      // �parameter_set2=�transfer_mode=ascii:remote_directory=/tmp�
            for (int i = 0; i < splitParams.length; i++) {
              String s = sosString.parseToString(splitParams[i]);
              if (s.length() > 0) {
                String[] splitParam = s.split("=");
                newArg.put(sosString.parseToString(splitParam[0]), splitParam.length == 1 ? "" : sosString.parseToString(splitParam[1]));
              }
            }
          }

          String index = key != null && key.length() > "file_spec".length() ? key.substring("file_spec".length()) : "";
          newArg.put("index", index);// hilpsparameter, wird sp�ter wieder gel�scht

          list.add(newArg);

        }
        else
          if (key.equalsIgnoreCase("transfer_success")) {// ein neues file_spec ist angegeben

            Properties newArg = (Properties) arg.clone();
            String newParameterSet = sosString.parseToString(arg.get(value));
            String[] splitParams = newParameterSet.split("::");// Bsp.
                                      // �parameter_set2=�transfer_mode=ascii:remote_directory=/tmp�
            for (int i = 0; i < splitParams.length; i++) {
              String s = sosString.parseToString(splitParams[i]);
              String[] splitParam = s.split("=");
              newArg.put(sosString.parseToString(splitParam[0]), splitParam.length == 1 ? "" : sosString.parseToString(splitParam[1]));
            }
            listOfSuccessTransfer.add(newArg);

          }
          else
            if (key.equalsIgnoreCase("transfer_error")) {// ein neues file_spec ist angegeben

              Properties newArg = (Properties) arg.clone();
              String newParameterSet = sosString.parseToString(arg.get(value));
              String[] splitParams = newParameterSet.split("::");// Bsp.
                                        // �parameter_set2=�transfer_mode=ascii:remote_directory=/tmp�
              for (int i = 0; i < splitParams.length; i++) {
                String s = sosString.parseToString(splitParams[i]);
                String[] splitParam = s.split("=");
                newArg.put(sosString.parseToString(splitParam[0]), splitParam.length == 1 ? "" : sosString.parseToString(splitParam[1]));
              }
              listOfErrorTransfer.add(newArg);
            }
      }
      list = prepareInstall(list);
    }
    catch (Exception e) {
      throw new Exception("error in  " + sos.util.SOSClassUtil.getMethodName() + " , cause: " + e);
    }

    list = sortListAtFileSpecNum(list);
    return list;
  }

  /**
   * Parameter list wird sortiert nach file_spec_[num]
   * @param list
   * @return list
   */
  private static ArrayList sortListAtFileSpecNum(ArrayList list) throws Exception {
    ArrayList sort = new ArrayList();
    try {
      // sortiert die Arrayliste nach index
      sort = sortArrayList(list, "index");

      // hilfsvariable index l�schen
      for (int i = 0; i < sort.size(); i++) {
        Properties p = (Properties) list.get(i);
        if (sosString.parseToString(p.get("index")).length() > 0) {
          p.remove("index");
        }
      }

    }
    catch (Exception e) {
      throw new Exception("error in  " + sos.util.SOSClassUtil.getMethodName() + " , cause: " + e);
    }
    return sort;
  }

  public static ArrayList sortArrayList(ArrayList list, String key) throws Exception {
    try {
      Properties h = null;
      Object[] o = null;
      int pos = 0;
      ArrayList newList = new ArrayList();
      try {
        o = new Object[list.size()];
        for (int i = 0; i < list.size(); i++) {
          h = (Properties) list.get(i);
          o[i] = h.get(key) + "_@_" + String.valueOf(i);
        }

        Arrays.sort(o);

        for (int i = 0; i < o.length; i++) {
          pos = Integer.parseInt(o[i].toString().substring(o[i].toString().indexOf("_@_") + 3));
          newList.add(list.get(pos));
        }

        list = newList;

      }
      catch (Exception e) {
        throw (e);
      }
      return list;
    }
    catch (Exception e) {
      throw new Exception("..error in " + SOSClassUtil.getMethodName() + " " + e);
    }
  }

  /**
   * Vorbereitung f�r operation=install. Es findet zwei installationen - entspricht zwei send Aufufe statt.
   *
   * 
   * @param list
   * @return
   * @throws Exception
   */
  private static ArrayList prepareInstall(ArrayList list) throws Exception {
    ArrayList newList = new ArrayList();
    for (int i = 0; i < list.size(); i++) {
      Properties p = (Properties) list.get(i);
      newList.add(p);
      if (p.containsKey("operation") && sosString.parseToString(p.get("operation")).equals("install")) {

        Properties newp = (Properties) p.clone();
        newp.put("operation", "install_doc");
        newList.add(newp);

      }
    }
    return newList;

  }

  /**
   * @return the writeBannerHeader
   */
  public boolean isWriteBannerHeader() {
    return writeBannerHeader;
  }

  /**
   * @param writeBannerHeader the writeBannerHeader to set
   */
  public void setWriteBannerHeader(boolean writeBannerHeader) {
    this.writeBannerHeader = writeBannerHeader;
  }

  private static String getUsage() {
    String usage = "Usage: sos.net.SOSFTPCommand -operation= -settings= -profile= -verbose=" + conNewLine
        + "        -operation   =[send|receive|execute|remove|install]   FTP operation" + conNewLine
        + "        -settings    =[file]                   Configuration file" + conNewLine
        + "        -profile     =[profile]                 Section/Profile for FTP settings" + conNewLine
        + "                                           in configuration file" + conNewLine
        + "        -verbose     =[1..9]                    Verbosity level" + conNewLine
        + "        -log_filename=[filename]               log file name    ";

    return usage;
  }

  private static boolean transfer(ArrayList extractArguments, String operation, Properties arg, boolean rc, boolean continueOnError) throws Exception {
    try {
      for (int i = 0; i < extractArguments.size(); i++) {
        arg = (Properties) extractArguments.get(i);
        if (i > 0) {
          operation = arg.getProperty("operation");
          sosConfiguration.setArguments(arg);

          sosConfiguration.checkConfigurationItems(REQUIRED_DEFAULT_PARAMETERS_FILENAME);

          if (sosString.parseToString(arg.get("current_pid")).length() == 0 && sosString.parseToString(System.getProperty("pid")).length() > 0)
            arg.put("pid", sosString.parseToString(System.getProperty("pid")));

          if (banner)
            logger.info("Transfer for file set no. " + i + " is being completed");
          else
            logger.debug1("All files have been transferred successfully. Transaction for file set no. " + i + " is being completed");

        }

        if (sosString.parseToBoolean(arg.get("testmode"))) {
          logger.info("Test mode is active, no transfers are effected");
          arg.put("skip_transfer", "yes");
          arg.put("remove_files", "no");
        }

        if (operation.equalsIgnoreCase("send")) {
          ftpCommand = new sos.net.sosftp.SOSFTPCommandSend(logger, arg);
          rc = ftpCommand.send();
        }
        else
          if (operation.equalsIgnoreCase("receive")) {
            ftpCommand = new sos.net.sosftp.SOSFTPCommandReceive(logger, arg);
            rc = ftpCommand.receive();
          }
          else
            if (operation.equalsIgnoreCase("execute")) {
              ftpCommand = new sos.net.sosftp.SOSFTPCommandSSH(logger, arg);
              rc = ftpCommand.execute();
            }
            else
              if (operation.equalsIgnoreCase("make_temp_directory")) {
                ftpCommand = new sos.net.sosftp.SOSFTPCommandSend(logger, arg);
                rc = ftpCommand.makeTempDirectory();
              }
              else
                if (operation.equalsIgnoreCase("remove_temp_directory")) {
                  ftpCommand = new sos.net.sosftp.SOSFTPCommandSend(logger, arg);
                  rc = ftpCommand.removeTempDirectory();
                }
                else
                  if (operation.equalsIgnoreCase("delete") || operation.equalsIgnoreCase("remove")) {
                    if (operation.equalsIgnoreCase("delete"))
                      arg.put("operation", "remove");// demn�chst wird nur mit remove gearbeitet
                    ftpCommand = new sos.net.sosftp.SOSFTPCommandReceive(logger, arg);
                    rc = ftpCommand.remove();
                  }
                  else
                    if (operation.equalsIgnoreCase("install")) {
                      ftpCommand = new sos.net.sosftp.SOSFTPCommandSend(logger, arg);
                      rc = ftpCommand.install();
                    }
                    else
                      if (operation.equalsIgnoreCase("install_doc")) {
                        ftpCommand = new sos.net.sosftp.SOSFTPCommandSend(logger, arg);
                        rc = ftpCommand.install();
                      }
                      else
                        if (operation.equalsIgnoreCase("delete_local_files")) {
                          // wird intern verwendet
                          ftpCommand = new sos.net.sosftp.SOSFTPCommandSend(logger, arg);
                          rc = ftpCommand.deleteLocalFiles();
                        }
                        else
                          if (operation.equalsIgnoreCase("rename_local_files")) {
                            // wird intern verwendet
                            ftpCommand = new sos.net.sosftp.SOSFTPCommandReceive(logger, arg);
                            rc = ftpCommand.renameAtomicSuffixTransferFiles();
                          }
                          else {
                            System.out.println(getUsage());
                            throw new Exception(
                                "[ERROR] no valid operation was specified, use send|receive|remove|execute|install: "
                                    + operation);
                          }
        if (logger.hasErrors() || logger.hasWarnings()) {
          ftpCommand.getArguments().put("status", "error");
        }
        else {
          ftpCommand.getArguments().put("status", "success");
        }
        if (sosString.parseToString(logger.getWarning()).length() > 0 || sosString.parseToString(logger.getError()).length() > 0) {
          ftpCommand.getArguments().put("last_error", logger.getWarning() + " " + logger.getError());
        }
        if (ftpCommand != null) {
          if (banner)
            logger.info(normalizedPassword(ftpCommand.getBanner(false)));
          else
            logger.debug(normalizedPassword(ftpCommand.getBanner(false)));
        }

        if ((logger.hasErrors() || logger.hasWarnings()) && !continueOnError) {
          // break;
          // throw new Exception();
          return false;
        }
      }

      return rc;
    }
    catch (Exception e) {
      e.printStackTrace();
      logger.warn("error in " + SOSClassUtil.getMethodName() + " cause: " + e.toString());
      return false;
    }
  }

  private static Properties extractArguments(String[] args) throws Exception {
    Properties arg = new Properties();
    try {

      String filename = "";
      // Argumente
      for (int i = 0; i < args.length; i++) {

        String[] split = args[i].split("=");

        String key = split[0].startsWith("-") ? split[0].substring(1) : split[0];
        if (split.length == 1 && !split[0].startsWith("-")) {
          if (key.trim().length() > 0)
            logger.debug1("file name specified as argument: " + key);
          filename = filename + key + ";";
        }
        else {
          arg.put(key.toLowerCase(), args[i].substring(args[i].indexOf("=") + 1));
        }
      }

      if (filename != null && filename.length() > 0) {
        filename = filename.replaceAll(conRegExpBackslash, "/");
        filename = filename.endsWith(";") ? filename.substring(0, filename.length() - 1) : filename;
        arg.put("file_path", filename);
      }

      return arg;
    }
    catch (Exception e) {
      logger.warn("[ERROR] could not process arguments, cause: " + e.getMessage());
      throw e;
    }

  }

  public static void createLoggerObject(String logFile, int logLevel) throws Exception {
    if (sosString.parseToString(logFile).length() > 0)
      logger = new SOSStandardLogger(logFile, logLevel);
    else
      logger = new SOSStandardLogger(logLevel);
  }

  private static boolean onlyVersion(Properties arg) throws Exception {

    if (arg.containsKey("version")) {
      if (!arg.containsKey("operation")) {
        logger.info("sosftp version \"" + getVersion() + "\"");
        return true;
      }
    }
    return false;
  }

  protected boolean deleteLocalFiles() throws Exception {

    ArrayList transActionalLocalFiles = new ArrayList();
    String error = "";
    if (arguments.containsKey("files"))
      transActionalLocalFiles = (ArrayList) arguments.get("files");

    for (int i = 0; i < transActionalLocalFiles.size(); i++) {
      File localRemFile = null;
      if (transActionalLocalFiles.get(i) instanceof File)
        localRemFile = (File) transActionalLocalFiles.get(i);
      else
        localRemFile = new File(sosString.parseToString(transActionalLocalFiles.get(i)));

      if (!localRemFile.delete()) {
        error = error + localRemFile.getAbsolutePath() + ";";
      }
      else {
        this.getLogger().debug1("removing file: " + localRemFile.getAbsolutePath());
      }
      if (error != null && error.length() > 0) {
        getLogger().warn("..error occurred, could not remove local file: " + error);
        return false;
      }

    }
    return true;
  }

  public boolean renameAtomicSuffixTransferFiles() throws Exception {

    try {
      ArrayList transActionalLocalFiles = new ArrayList();
      String atomicSuffix = sosString.parseToString(arguments.get("atomic_suffix"));

      if (arguments.containsKey("files"))
        transActionalLocalFiles = (ArrayList) arguments.get("files");

      for (int i = 0; i < transActionalLocalFiles.size(); i++) {
        String filename = sosString.parseToString(transActionalLocalFiles.get(i));
        if (filename.trim().length() > 0) {
          File f = new File(filename);
          File nf = new File(filename.substring(0, filename.lastIndexOf(atomicSuffix)));

          if (nf.exists()) {
            getLogger().debug9(nf.getCanonicalPath() + " exists and will be replaced");
            nf.delete();
          }
          getLogger().debug("..rename " + f.getCanonicalPath() + " to " + nf.getName());
          if (!f.renameTo(nf))
            throw new Exception("could not rename temporary file [" + f.getCanonicalPath() + "] to: " + nf.getAbsolutePath());

        }
      }

      return true;
    }
    catch (Exception e) {
      getLogger().warn("error in  " + sos.util.SOSClassUtil.getMethodName() + " , cause: " + e);
      return false;
    }
  }

  private static boolean doPostTransactionalOnSuccess() {

    try {
      boolean rc = true;
      banner = false;// es sollen keine banner mehr geschrieben werden
      if (listOfSuccessTransfer.size() > 0) {

        Properties p = (Properties) listOfSuccessTransfer.get(0);
        String operation = sosString.parseToString(p.get("operation"));
        rc = transfer(listOfSuccessTransfer, operation, p, true, false);
      }
      banner = true;
      if (!rc) {
        throw new Exception("All files have been transferred successfully, however, the transaction could not be completed");
      }
      return true;
    }
    catch (Exception e) {
      try {
        logger.warn("error in doPostTransactionalOnSuccess, cause: " + e.toString());
      }
      catch (Exception ex) {
      }
      doPostTransactionalOnError();
      return false;
    }
  }

  private static boolean doPostTransactionalOnError() {
    try {
      boolean rc = false;
      banner = false;// es sollen keine banner mehr geschrieben werden
      if (listOfErrorTransfer.size() > 0) {
        Properties p = (Properties) listOfErrorTransfer.get(0);
        String operation = sosString.parseToString(p.get("operation"));
        transfer(listOfErrorTransfer, operation, p, rc, true);
      }
    }
    catch (Exception e) {
      try {
        logger.warn("error in doPostTransactionalOnError, cause: " + e.toString());
      }
      catch (Exception ex) {
      }
    }
    finally {
      banner = true;
    }
    return false;
  }

  protected static String normalizedPassword(String str) {
    try {

      if (str == null || str.trim().length() == 0)
        return "";

      // alle m�glichen Passwortnamen, die gex't werden muss
      ArrayList namesOfPassword = sosConfiguration.getPasswordnames();
      if (!namesOfPassword.contains("password"))
        namesOfPassword.add("password");

      for (int i = 0; i < namesOfPassword.size(); i++) {
        String pw = sosString.parseToString(namesOfPassword.get(i));
        if (pw.trim().length() == 0)
          continue;

        int pos1 = str.indexOf(pw + "=");
        if (pos1 > -1) {
          int pos2 = str.indexOf(" ", pos1);
          if (pos2 == -1 || pos1 > pos2)
            pos2 = str.length();
          str = str.substring(0, pos1) + pw + "=***** " + str.substring(pos2);
        }
        pos1 = str.indexOf("-ssh_auth_file=\"filecontent:");
        ;
        if (pos1 > -1) {

          int pos2 = -1;

          if (pos1 == -1)
            return str;
          pos2 = str.indexOf("-----END DSA PRIVATE KEY-----", pos1) + "-----END DSA PRIVATE KEY-----".length() + 2;

          if (pos2 == -1 || pos1 > pos2)
            pos2 = str.length();
          str = str.substring(0, pos1) + "-ssh_auth_file=\"filecontent:*****" + str.substring(pos2);
        }
      }
      return str;
    }
    catch (Exception e) {

      return "";
    }
  }

  /**
   * Ermittelt die PID.
   * Der PID wird ermittelt, wenn historien Eintr�ge erw�nscht sind und
   * nicht im Testmodus ist.
   *
   * @param GETPIDSEXE
   * @param arg
   * @return
   * @throws Exception
   */
  public String getPids() throws Exception {
    String GETPIDSEXE = "";

    if (sosString.parseToBoolean(sosString.parseToString(arguments.get("testmode"))))
      return "";
    if (System.getProperty("os.name").toLowerCase().indexOf("wind") > -1) {
      if (GETPIDSEXE == null || GETPIDSEXE.length() == 0) {

        if (new File("getParentId.exe").exists()) {
          GETPIDSEXE = new File("getParentId.exe").getCanonicalPath();
        }
        else {
          getLogger().debug5("creating getParentId.exe ");

          // holt aus einer Bibliothek (jar File) die Datei und kopiert diese in das Verzeichnis
          java.net.URL url = ClassLoader.getSystemResource("getParentId.exe");
          getLogger().debug1("found url=" + url);
          InputStream in = getClass().getClassLoader().getSystemResourceAsStream("getParentId.exe");// aus Klassenpfad holen
          getLogger().debug9("get InputStream to create new getParentId.exe=" + in);
          if (in == null) {
            getLogger().debug9("try again to get InputStream to create new getParentId.exe=" + in);
            in = getClass().getClassLoader().getResourceAsStream("getParentId.exe");// aus der Bibliothel holen
            getLogger().debug9("InputStream is =" + in);
          }
          // /
          if (in == null) {
            // throw new Exception ("missing executable File getParentId.exe in Library sos.net.jar");
          }
          else {
            OutputStream out = null;
            byte[] buffer = new byte[1024];
            try {

              out = new FileOutputStream("getParentId.exe", false);
              while (true) {
                synchronized (buffer) {
                  int amountRead = in.read(buffer);
                  if (amountRead == -1) {
                    break;
                  }
                  out.write(buffer, 0, amountRead);
                }
              }
            }
            finally {
              if (in != null) {
                in.close();
              }
              if (out != null) {
                out.close();
              }
            }
            return getPids();
          }

        }
      }
    }
    String pid = getPID(GETPIDSEXE);

    if (pid != null && pid.length() > 0) {
      logger.debug1("current_pid is " + pid);
    }
    return pid;
  }

  /**
   *
   * Diese Methode liefert die aktuelle PID.
   *
   * Das Betriebssystem Windows brauch die Anwendung getpids.exe.
   * getpids.exe liefert die aktuelle PID.
   * Diese Anwendung kann von der Seite http://www.scheibli.com/projects/getpids/getpids-1.00.zip heruntergeladen werden.
   *
   * @param GETPIDEXE -> Anwendung
   * @return String -> liefert die PID
   * @throws IOException
   * TODO: sp�ter vielleicht daraus einen statischen Method in SOS UTIL
   */
  public String getPID(String GETPIDEXE) throws IOException {
    String pid = "";

    String cmd[];
    if (System.getProperty("os.name").toLowerCase().indexOf("wind") == -1) {
      cmd = new String[] { "/bin/sh", "-c", "echo $$ $PPID" };
    }
    else {
      if (GETPIDEXE == null || GETPIDEXE.length() == 0)
        throw new IOException("executables Files getpids.exe or getParentId.exe not found. Check Installation.");

      cmd = new String[] { GETPIDEXE };
    }
    if (cmd != null) {
      Process p = Runtime.getRuntime().exec(cmd);

      InputStream inputstream = p.getInputStream();
      InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
      BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
      String line;
      if ((line = bufferedreader.readLine()) != null) {

        StringTokenizer stok = new StringTokenizer(line);
        if (System.getProperty("os.name").toLowerCase().indexOf("wind") == -1) {
          stok.nextToken(); // this is pid of the process we spanned
        }
        pid = stok.nextToken();
      }

      if (pid != null)
        System.setProperty("pid", pid); // NOI18N

    }

    return pid;
  }

  private static String[] mergeSchedulerParamsAndArgumenst(String[] args) throws Exception {

    int index = -1;
    String filename = "";
    for (int i = 0; i < args.length; i++) {
      String arg = args[i];
      int pos0 = 1;
      int pos1 = arg.indexOf("=");
      if (pos1 == -1)
        pos1 = arg.length();

      if (!sosString.parseToString(arg).startsWith("-") && sosString.parseToString(arg).indexOf("=") == -1) {
        filename = filename.length() > 0 ? filename + ";" + arg : arg;
      }
      else {
        String key = arg.substring(pos0, pos1);
        String value = arg.length() == pos1 ? "" : arg.substring(pos1 + 1);
        schedulerParams.put(key, value);
      }
    }

    if (sosString.parseToString(filename).trim().length() > 0)
      schedulerParams.put("file_path", filename);

    String[] retVal = new String[schedulerParams.size()];
    Iterator it = schedulerParams.keySet().iterator();

    while (it.hasNext()) {
      Object key = it.next();
      Object val = schedulerParams.get(key);
      retVal[++index] = "-" + sosString.parseToString(key) + "=" + sosString.parseToString(val);
    }

    return retVal;
  }

  /**
   * Konvertiert ConfigurationsItem[] zu Properties.
   *
   * Ber�cksichtigen der include Parametern
   *
   *
   * @return
   * @throws Exception
   */
  private static Properties convertParameters() throws Exception {
    try {
      Properties arg_s = sosConfiguration.getParameterAsProperties();
      if (sosString.parseToString(arg_s.get("settings")).length() > 0 && sosString.parseToString(arg_s.get("include")).length() > 0) {
        sos.configuration.SOSConfiguration config_ = new sos.configuration.SOSConfiguration(sosString.parseToString(arg_s.get("settings")),
            sosString.parseToString(arg_s.get("include")), logger);
        sos.configuration.SOSConfigurationItem[] items = config_.checkConfigurationItems(REQUIRED_DEFAULT_PARAMETERS_FILENAME);
        arg_s.putAll(config_.getParameterAsProperties());
      }

      // L�schen der Argumente, weil dieser in sos.util.configuration.Configuration ausgelesen wurden
      arg_s.remove("settings");
      arg_s.remove("profile");
      arg_s.remove("include");
      arg_s = substituteEnvironment(arg_s);
      return arg_s;
    }
    catch (Exception e) {
      throw new Exception("error in " + sos.util.SOSClassUtil.getMethodName() + ": cause: " + e.toString());
    }
  }

  private static String checkOperation() throws Exception {
    try {
      String operation = sosConfiguration.getConfigurationItemByName("operation").getValue();

      if (sosString.parseToString(operation).length() == 0) {
        logger.warn(getUsage());
        throw new Exception("missing command line parameter: operation");
      }
      return operation;
    }
    catch (Exception e) {
      throw new Exception("error in " + sos.util.SOSClassUtil.getMethodName() + ": cause: " + e.toString());
    }
  }

  /**
   *
   * @return boolean
   */
  public boolean transfer() {

    boolean rc = false;
    String operation = "";

    listOfSuccessTransfer = new ArrayList();
    listOfErrorTransfer = new ArrayList();

    try {

      Properties env = getEnvVars(logger);// gleich am anfang, weil scheduler_params aus der Umgebungsvariable gelesen wird

      env.putAll(schedulerParams);

      operation = checkOperation();// operation value is given?
      Properties arg_s = new Properties();
      arg_s.putAll(env);
      arg_s.putAll(convertParameters()); // convert ConfigurationItem[] to Properties

      ArrayList extractArguments = getFileOperations(arg_s); // Different file operations within one session

      try {
        banner = true;
        rc = transfer(extractArguments, operation, arg_s, rc, false);

        if (rc) {
          rc = doPostTransactionalOnSuccess();
        }
        else {
          rc = doPostTransactionalOnError();
        }

      }
      catch (Exception e) {
        e.printStackTrace();
        banner = true;
        throw e;
      }
    }
    catch (Exception e) {

      try {
        if (ftpCommand != null) {
          if (banner)
            logger.info(ftpCommand.getBanner(false));
          else
            logger.debug(ftpCommand.getBanner(false));
        }
        else {
          System.out.println(e.toString());
        }
      }
      catch (Exception x) {
        System.out.println(e.toString());
      }
      System.exit(1);
    }
    finally {
      try {
        if (ftpCommand != null) {
          ftpCommand.appendHistoryFile();
          transactionalHistoryFile = null;
          ftpCommand.sendTransactionalSchedulerRequestFile();
        }
        logger.close();
      }
      catch (Exception e) {
        System.out.println(e.toString());

      }
    }
    return rc;
  }

  /**
   * Send/Receive files by FTP/SFTP and execute commands by SSH
   * @see documentation sosftp.xml
   */

  private static int getIntArg(Properties arg, String strKey, int pintDefault) {

    int intI = pintDefault;
    if (arg.containsKey(strKey)) {
      String strT = arg.getProperty(strKey);
      intI = Integer.valueOf(strT);
    }

    return intI;
  }

  private static String getStringArg(Properties arg, String strKey, String pstrDefault) {

    String strT = pstrDefault;
    if (arg.containsKey(strKey)) {
      strT = arg.getProperty(strKey);
    }

    return strT;
  }

  public static void main(String[] args) {

    boolean rc = false;
    int logLevel = 0;
    String logFile = "";
    String settingsFile = "";
    String settingsSection = "";
    String operation = "";

    listOfSuccessTransfer = new ArrayList();
    listOfErrorTransfer = new ArrayList();

    try {

      Properties env = getEnvVars(logger); // gleich am anfang, weil scheduler_params aus der Umgebungsvariable gelesen wird
      args = mergeSchedulerParamsAndArgumenst(args);
      Properties arg = extractArguments(args);
      arg.putAll(schedulerParams);

      SOSArguments arguments = null;
      try {
        arguments = new SOSArguments(args, true);
        operation = arguments.as_string("-operation=", "");
        settingsFile = arguments.as_string("-settings=", "");
        settingsSection = arguments.as_string("-profile=", "");
        logLevel = arguments.as_int("-verbose=", SOSLogger.INFO);
        logFile = arguments.as_string("-log_filename=", "");
      }
      catch (Exception e) {
        e.printStackTrace(System.err);
        System.err.println("[ERROR] could not init SOSArguments, cause: " + e.getMessage());
        throw e;
      }

      createLoggerObject(logFile, logLevel);

      if (onlyVersion(arg)) {
        rc = true;
        return;
      }

      try {
        sosConfiguration = new sos.configuration.SOSConfiguration(arg, settingsFile, settingsSection, logger);
        sos.configuration.SOSConfigurationItem[] items = sosConfiguration.checkConfigurationItems(REQUIRED_DEFAULT_PARAMETERS_FILENAME_NOREQUIRE);
      }
      catch (Exception e) {
        System.out.println("[ERROR] could not init Configuration, cause: " + e.getMessage());
        throw e;
      }

      operation = checkOperation(); // operation value is given?
      Properties arg_s = convertParameters(); // convert ConfigurationItem[] to Properties
      logLevel = getIntArg(arg_s, "verbose", (int) SOSLogger.INFO);
      logFile = getStringArg(arg_s, "log_filename", "");
      createLoggerObject(logFile, logLevel);

      ArrayList extractArguments = getFileOperations(arg_s); // Different file operations within one session

      try {
        banner = true;
        rc = transfer(extractArguments, operation, arg_s, rc, false);
        if (rc) {
          rc = doPostTransactionalOnSuccess();
        }
        else {
          rc = doPostTransactionalOnError();
        }
      }
      catch (Exception e) {
        banner = true;
        throw e;
      }
    }
    catch (Exception e) {

      try {
        if (ftpCommand != null) {
          if (banner)
            logger.info(ftpCommand.getBanner(false));
          else
            logger.debug(ftpCommand.getBanner(false));
        }
        else {
          System.out.println(e.toString());
        }
      }
      catch (Exception x) {
        System.out.println(e.toString());
      }
      System.exit(1);
    }
    finally {
      try {
        if (ftpCommand != null) {

          ftpCommand.appendHistoryFile();

          ftpCommand.sendTransactionalSchedulerRequestFile();
        }
        logger.close();
      }
      catch (Exception e) {
        System.out.println(e.toString());

      }
      System.exit((rc ? 0 : 1));
    }
  }

  /**
   * List of transfer Files
   *
   * @return the filelist
   */
  public Vector<String> getFilelist() throws Exception {
    return filelist;
  }

  /**
   * List of transfered Files
   *
   * @return the filelist
   */
  public Vector<File> getTransferredFilelist() throws Exception {
    if (transferFileList == null) {
      transferFileList = new Vector<File>();
    }
    return transferFileList;
  }

  /**
   * @return the exitStatus
   */
  public Integer getExitStatus() {
    if (exitStatus != null)
      return exitStatus;
    else
      return new Integer(0);
  }

  protected boolean getBooleanParam(final String pstrParamName, final String pstrDefaultvalue) throws Exception {
    String strResult = getParam(pstrParamName, pstrDefaultvalue);

    if (strResult.toString().equalsIgnoreCase("true") || strResult.toString().equalsIgnoreCase("yes") || strResult.equals("1")) {
      return true;
    }
    return false;
  }

  protected String getParam(final String pstrParamName, final String pstrDefaultvalue) throws Exception {

    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::getParam";
    String strRet = "";

    String strVal = "";
    try {
      strVal = sosString.parseToString(arguments.get(pstrParamName.toLowerCase()));
      if (strVal.length() <= 0) {
        String strNewParamName = pstrParamName.replaceAll("_", "");
        strVal = sosString.parseToString(arguments.get(strNewParamName.toLowerCase()));
      }
    }
    catch (Exception e) {
    }
    this.getLogger().debug(String.format(".. get Parameter '%1$s' with value '%2$s', default is '%3$s'", pstrParamName, strVal, pstrDefaultvalue));
    if (strVal.length() > 0) {
      strRet = strVal;
    }
    else {
      strRet = pstrDefaultvalue;
    }

    return strRet;
  } // private String getParam

  protected String doEncoding(final String pstrStringToEncode, final String pstrEncoding) throws Exception {

    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::doEncoding";

    // Zeichen Unicode
    // ------------------------------
    // �, � \u00c4, \u00e4
    // �, � \u00d6, \u00f6
    // �, � \u00dc, \u00fc
    // � \u00df

    final String conUTF8UmlU = "ü";
    final String conUTF8UmlBigA = "\u00c4"; // "�\\?";
    final String conUTF8UmlBigO = "\u00d6"; // "�\\?";
    final String conUTF8UmlBigU = "\u00dc"; // "�\\?";
    final String conUTF8UmlA = "ä";
    final String conUTF8UmlO = "ö";
    final String conUTF8UmlS = "\u00df";

    String strEncodedString = pstrStringToEncode;
    if (pstrEncoding.length() > 0) {
      byte[] iso88591Data = pstrStringToEncode.getBytes(Charset.forName(pstrEncoding));
      strEncodedString = new String(iso88591Data, Charset.forName(pstrEncoding));
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlU, "�");
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlBigA, "�");
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlBigU, "�");
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlBigO, "�");
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlA, "�");
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlO, "�");
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlS, "�");
      getLogger().debug(String.format("Encode String '%1$s' to/in '%2$s' using '%3$s'", pstrStringToEncode, strEncodedString, pstrEncoding));
    }
    return strEncodedString;
  } // private String doEncoding

  protected String doEncodeUmlaute(final String pstrStringToEncode, final String pstrEncoding) throws Exception {

    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::doEncodeUmlaute";

    // Zeichen Unicode
    // ------------------------------
    // �, � \u00c4, \u00e4
    // �, � \u00d6, \u00f6
    // �, � \u00dc, \u00fc
    // � \u00df

    final String conUTF8UmlU = "�";
    final String conUTF8UmlBigA = "\u00c4"; // "�\\?";
    final String conUTF8UmlBigO = "\u00d6"; // "�\\?";
    final String conUTF8UmlBigU = "\u00dc"; // "�\\?";
    final String conUTF8UmlA = "�";
    final String conUTF8UmlO = "�";
    final String conUTF8UmlS = "\u00df";

    String strEncodedString = pstrStringToEncode;
    if (pstrEncoding.length() > 0) {
      byte[] iso88591Data = pstrStringToEncode.getBytes(Charset.forName(pstrEncoding));
      strEncodedString = new String(iso88591Data, Charset.forName(pstrEncoding));
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlU, "ue");
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlBigA, "Ae");
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlBigU, "Ue");
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlBigO, "Oe");
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlA, "ae");
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlO, "oe");
      strEncodedString = strEncodedString.replaceAll(conUTF8UmlS, "sz");
      getLogger().debug(String.format("Encode String '%1$s' to/in '%2$s' using '%3$s'", pstrStringToEncode, strEncodedString, pstrEncoding));
    }
    return strEncodedString;
  } // private String doEncoding

  protected void retrieveCommonParameters() throws Exception {

    flgUsePathAndFileName4Matching = getBooleanParam(SOSFTPCommand.USE_PATH_AND_FILE_NAME_4_MATCHING, "false");
    flgCheckServerFeatures = getBooleanParam(SOSFTPCommand.CHECK_SERVER_FEATURES, "");
    strPreFtpCommands = getParam(PRE_FTP_COMMANDS, "");
    strControlEncoding = getParam(SOSFTPCommand.CONTROL_ENCODING, "");
    strFileNameEncoding = getParam(SOSFTPCommand.FILENAME_ENCODING, "");
    flgConvertUmlaute = getBooleanParam(SOSFTPCommand.CONVERT_UMLAUTE, "false");

  }

  public void setParam(final String pstrParamName, final String pstrParamValue) throws Exception {

    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::setParam";

    arguments.put(pstrParamName, pstrParamValue);
    logger.debug(String.format("set param '%1$s' to value '%2$s'", pstrParamName, pstrParamValue));

  } // private void setParam

  protected String stripRemoteDirName(final String pstrRootPath, final String pstrPathName) throws Exception {

    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::stripRemoteDirName";

    String strResult = pstrPathName;
    String strR = new File(pstrRootPath).getAbsolutePath();
    String strP = new File(pstrPathName).getAbsolutePath();
    if (strP.startsWith(strR) == true) {
      strResult = strP.substring(strR.length());
      if (strResult.contains(File.separator)) {
        if (strResult.startsWith(File.separator)) {
          strResult = strResult.substring(1);
        }
        if (strResult.contains(File.separator)) {
          strResult = "." + File.separator + strResult;
        }
      }
      // strResult = new File(strResult).getCanonicalPath();
      strResult = adjustSeparator(strResult);
    }
    return strResult;
  } // private String stripRemoteDirName

  protected String adjustSeparator(final String pstrPathName) {

    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::";

    String strRet = pstrPathName;
    String[] strA = pstrPathName.split("[/\\\\]");
    if (strA.length > 0) {
      strRet = "";
      for (String string : strA) {
        if (string.length() > 0) {
          strRet = strRet + string + File.separator;
        }
      }
      strRet = strRet.substring(0, strRet.length() - 1);
    }

    return strRet;
  } // private String adjustSeparator

}
TOP

Related Classes of sos.net.SOSFTPCommand$RemoteConsumer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.