#!/usr/bin/python3 -BbbEIsSttW all
# -*- coding: utf-8 -*-

"""This tool allows to connect to a remote control socket, send
requests and retrieve the responses. To allow remote use of this
tool, e.g. via SSH forwarding, the remote control address can
be set on the command line, no configuration is read.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
"""

__authors__ = ["Markus Wurzenberger", "Max Landauer", "Wolfgang Hotwagner",
               "Ernst Leierzopf", "Roman Fiedler", "Georg Hoeld"]
__contact__ = "aecid@ait.ac.at"
__copyright__ = "Copyright 2020, AIT Austrian Institute of Technology GmbH"
__credits__ = ["Florian Skopik"]
__date__ = "2020/06/19"
__deprecated__ = False
__email__ = "aecid@ait.ac.at"
__license__ = "GPLv3"
__maintainer__ = "Markus Wurzenberger"
__status__ = "Production"
__version__ = "2.0.1"

import sys
# Get rid of the default sys path immediately. Otherwise Python
# also attempts to load the following imports from e.g. directory
# where this binary resides.
sys.path = sys.path[1:]+['/usr/lib/logdata-anomaly-miner']

import json
import os
import socket
import traceback

from aminer.AnalysisChild import AnalysisChildRemoteControlHandler

remoteControlSocketName = None
remoteControlData = None
argPos = 1
commandList = []
stringResponseFlag = False
while argPos < len(sys.argv):
  paramName = sys.argv[argPos]
  argPos += 1

  if paramName == '--ControlSocket':
    if remoteControlSocketName != None:
      print('%s: %s parameter given twice' % (sys.argv[0], paramName))
      sys.exit(1)
    remoteControlSocketName = sys.argv[argPos]
    argPos += 1
    continue
  if paramName == '--Data':
    remoteControlData = json.loads(sys.argv[argPos])
    argPos += 1
    continue
  if paramName == '--Exec':
    commandList.append((sys.argv[argPos].encode(), remoteControlData))
    argPos += 1
    continue
  if paramName == '--ExecFile':
    if not os.path.exists(sys.argv[argPos]):
      print('File %s does not exit' % sys.argv[argPos])
      sys.exit(1)
    execData = None
    with open(sys.argv[argPos], 'rb') as execFile:
      execData = execFile.read()
    commandList.append((execData, remoteControlData))
    argPos += 1
    continue
  if paramName == '--Help':
    if len(sys.argv) != 2:
      print('Ignoring all other arguments with --Help')
    print("""Usage: %s [arguments]
  --ControlSocket [socketpath]: when given, use nonstandard control socket.
  --Data [data]: provide this json serialized data within execution
    environment as 'remoteControlData' (see man page).
  --Exec [command]: add command to the execution list, can be
    used more than once.
  --ExecFile [file]: add commands from file to the execution list
    in same way as if content would have been used with "--Exec".
  --Help: this output
  --StringResponse: if set, print the response just as string
    instead of passing it to repr.

  For further information read the man pages running 'man AMinerRemoteControl'.""" % sys.argv[0])
    sys.exit(0)
  if paramName == '--StringResponse':
    stringResponseFlag = True
    continue

  print('Unknown parameter "%s", use --Help for overview' % paramName)
  sys.exit(1)

if remoteControlSocketName is None:
  remoteControlSocketName = '/var/run/aminer-remote.socket'

if not commandList:
  print('No commands given, use --Exec [cmd]')
  sys.exit(1)

remoteControlSocket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
  remoteControlSocket.connect(remoteControlSocketName)
except socket.error as connectException:
  print('Failed to connect to socket %s, AMiner ' \
      'might not be running or remote control is disabled in ' \
      'configuration: %s' % (remoteControlSocketName, str(connectException)))
  sys.exit(1)
remoteControlSocket.setblocking(1)

controlHandler = AnalysisChildRemoteControlHandler(remoteControlSocket)

for remoteControlCode, remoteControlData in commandList:
  controlHandler.put_execute_request(remoteControlCode, remoteControlData)
# Send data until we are ready for receiving.
  while not controlHandler.may_receive():
    controlHandler.do_send()
  while not controlHandler.may_get():
    controlHandler.do_receive()
  requestData = controlHandler.do_get()
  requestType = requestData[4:8]
  if requestType == b'RRRR':
    try:
      remoteData = json.loads(requestData[8:])
      if remoteData[0] != None:
        print('Remote execution exception:\n%s' % remoteData[0])
      if stringResponseFlag:
        print('Remote execution response: %s' % str(remoteData[1]))
      else:
        print('Remote execution response: %s' % repr(remoteData[1]))
    except:
      print('Failed to process response %s' % repr(requestData))
      traceback.print_exc()
  else:
    raise Exception('Invalid request type %s' % repr(requestType))

remoteControlSocket.close()
