#!/usr/bin/env python3
# coding: utf8
# LAVA Controls Copyright 2020 LAVA Controls - Stephen Loeckle

import netifaces
import netaddr
import socket
import subprocess
import sys
import argparse
import urllib.request
import traceback
import logging
import inspect
from lavacontrolscorelib import checkmake, fetchpage, fetchhostname, netinfo, scansingle, sendlog
import lavacontrolsneclib as lcnec
import lavacontrolssamsunglib as lcsam
from time import sleep

def main():
    gotthefunc = inspect.stack()[0][3]
    logger = logging.getLogger('main')
    logger.setLevel(logging.DEBUG)
    sock = logging.handlers.SocketHandler('localhost', logging.handlers.DEFAULT_TCP_LOGGING_PORT)
    logger.addHandler(sock)
    consolelog = logging.StreamHandler(sys.stdout)
#    logger.addHandler(consolelog)
    msg = 'Log test'
    sendlog(gotthefunc, msg, 10)
    
    sysinfo = {}
    
    sysinfo['SYSTEM'] = {}
    sysinfo['WALL'] = {}
    sysinfo['SYSTEM']['SERIALPORT'] = None
    sysinfo['SYSTEM']['CONNECTION'] = 'ip'

    while True:
        try:
            sysinfo['SYSTEM']['MAC'], sysinfo['SYSTEM']['MYIP'], sysinfo['SYSTEM']['IFACE'] = netinfo(sysinfo)
        except:
            msg = ('Error in {0} calling netinfo! Halting!'.format(gotthefunc))
            sendlog(gotthefunc, msg, 40)
            err = traceback.format_exc()
            msg = ('Error Detail: {0}'.format(err))
            sendlog(gotthefunc, msg, 10)
        else:
            if sysinfo['SYSTEM']['MAC'] != 'ERROR' and sysinfo['SYSTEM']['MYIP'] != 'ERROR' and sysinfo['SYSTEM']['IFACE'] != 'ERROR':
                msg = ('CONFIG: Using MAC {} and IP {} and IFACE {} for operations.'.format(sysinfo['SYSTEM']['MAC'], sysinfo['SYSTEM']['MYIP'], sysinfo['SYSTEM']['IFACE']))
                sendlog(gotthefunc, msg, 10)
                break
            elif sysinfo['SYSTEM']['MAC'] == 'ERROR' or sysinfo['SYSTEM']['MYIP'] == 'ERROR' or sysinfo['SYSTEM']['IFACE'] == 'ERROR':
                pass
            else:
                msg = ('ERROR: Received MAC "{}" and IP "{}" and IFACE "{}" from netinfo. Retrying.'.format(sysinfo['SYSTEM']['MAC'], sysinfo['SYSTEM']['MYIP'], sysinfo['SYSTEM']['IFACE']))
                sendlog(gotthefunc, msg, 10)
        sleep(1)
    addrs = netifaces.ifaddresses(sysinfo['SYSTEM']['IFACE'])
    ipinfo = addrs[socket.AF_INET][0]
    address = ipinfo['addr']
    netmask = ipinfo['netmask']
    cidr = netaddr.IPNetwork('%s/%s' % (address, netmask))
    network = cidr.network
    broadcast = cidr.broadcast

    parser = argparse.ArgumentParser(description='Display Engine Discovery Tools')
    parser.add_argument('-amt', action='store_true', help='Search for Intel AMT Engines')
    parser.add_argument('-apc', action='store_true', help='Search for APC PDUs')
    parser.add_argument('-lb', action='store_true', help='Search for LAVA Boxes')
    parser.add_argument('-d', action='store_true', help='Search for Commercial Displays')
    args = parser.parse_args()
    if not any([args.amt, args.apc, args.lb, args.d]):
        parser.print_help()
        quit()
    if args.d:
        displaylistforpdcommsconfig = {}
        displaylistforlavacontrolsconfig = ''
        displaylistno = 1
        necport = 7142
        samport = 1515
        print('Scanning {} {} for Commercial Displays'.format(cidr.cidr,cidr.netmask))
        for ip in netaddr.IPNetwork(cidr):
            if ip != network and ip != broadcast:
                make = None
                displaymodel = None
                displayserial = None
                isnec = scansingle(ip,necport)
                issam = scansingle(ip,samport)
                if isnec or issam:
                    try:
                        displayid, make = checkmake(sysinfo, str(ip))
                    except:
                        err = traceback.format_exc()
                        msg = ('Error in {} Detail: {}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        print(msg)
                        sys.exit()
                    
                    sysinfo['D{}'.format(displayid)] = {}
                    sysinfo['D{}'.format(displayid)]['IP'] = str(ip)

                    if make == 'nec':
                        try:
                            dispconn = lcnec.DisplayInfo(sysinfo, displayid)
                        except:
                            err = traceback.format_exc()
                            msg = ('D{}: Error in {} Detail: {}'.format(displayid,gotthefunc,err))
                            print(msg)
                            pass
                    if make == 'sam':
                        try:
                            dispconn = lcsam.DisplayInfo(sysinfo, displayid)
                        except:
                            err = traceback.format_exc()
                            msg = ('D{}: Error in {} Detail: {}'.format(displayid,gotthefunc,err))
                            print(msg)
                            pass
                    try:
                        displaymodel = dispconn.getmodel()
                    except:
                        err = traceback.format_exc()
                        msg = ('D{}: Error in {} Detail: {}'.format(displayid,gotthefunc,err))
                        print(msg)
                        pass
                    try:
                        displayserial = dispconn.getserialnumber()
                    except:
                        err = traceback.format_exc()
                        msg = ('D{}: Error in {} Detail: {}'.format(displayid,gotthefunc,err))
                        print(msg)
                        pass
                    print('{}: *** Found {} Display: Model: {} ID: {} Serial: {} ***'.format(ip,make,displaymodel,displayid,displayserial))
                    displaylistforlavacontrolsconfig += ('IP%d=%s\n' % (displaylistno,ip))
                    displaylistforpdcommsconfig[displayid] = ip
                    displaylistno += 1
        print('\nFor LAVA Controls Config:')
        print(displaylistforlavacontrolsconfig)
        print('For PD Comms Config:')
        for x,y in displaylistforpdcommsconfig.items():
            print ('TYPE=1,PORT={},ID={}'.format(y,x))
    if args.apc:
        apclist = []
        apclistno = 1
        print('Scanning {} {} for APC Products'.format(cidr.cidr,cidr.netmask))
        for ip in netaddr.IPNetwork(cidr):
            if ip != network and ip != broadcast:
                port1 = scansingle(ip,80)
                port2 = scansingle(ip,23)
                if port1 and port2:
                    if 'apc' in fetchpage(ip):
                        print('{}: *** APC found ***' .format(ip))
                        apclist.append([apclistno,ip])
                        apclistno += 1
    if args.amt:
        amtlist = []
        amtlistno = 1
        print('Scanning {} {} for Intel AMT Engines'.format(cidr.cidr,cidr.netmask))
        for ip in netaddr.IPNetwork(cidr):
            if ip != network and ip != broadcast:
                port1 = scansingle(ip,22)
                port2 = scansingle(ip,16992)
                if port1 and port2:
                    print('{}: *** Intel AMT Engine found ***' .format(ip))
                    amtlistno += 1
    if args.lb:
        delist = []
        delistno = 1
        print('Scanning {} {} for LAVA Boxes'.format(cidr.cidr,cidr.netmask))
        for ip in netaddr.IPNetwork(cidr):
            if ip != network and ip != broadcast:
                port1 = scansingle(ip,4243)
                port2 = scansingle(ip,22)
                if port1 and port2:
                    hostname=fetchhostname(ip)
                    print('{0} {1}: *** LAVA Box found ***' .format(ip,hostname))
                    delist.append([delistno,ipi,hostname])
                    delistno += 1

if __name__ == '__main__':
   main()
