#!/usr/bin/python3

# Information Security
# Certification Project #3

import socket
import common_ports
import re

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Testing
# target = "www.freecodecamp.org"
# target = socket.gethostbyname("www.freecodecamp.org")
# target = "hi"
# port_range = [75,85]

# Testing Function
# get_open_ports(target, port_range)


def get_open_ports(target, port_range, verbose=None):
    # Test if target is URL or IP address, if invalid give correct error message

    target_ip = None
    target_url = None
    try:
        ip_addr = socket.gethostbyname(target)
    except:
        if re.search('^[0-9]+', target):
            print('Target:', target, 'is an ip address')
            target_ip = True
            print('Error: Invalid IP address')
            exit()
        elif re.search('^[A-Za-z]+', target):
            print('Target:', target, 'is a url')
            target_url = True
            print('Error: Invalid hostname')
            exit()
        print('Error: Invalid hostname or IP address')
        exit()

    # Creates list of ports from starting and ending ports given
    ports_list = list()
    for port in port_range:
        while port <= port_range[1]:
            ports_list.append(port)
            port += 1

    # Connects (if url/ip is valid) and checks for open ports
    open_ports = []
    # for each port in list, connect
    for port in ports_list:
        print('Checking port:', port, 'for target:', target)
        # if port is open, add to open_ports
        try:
            s.connect_ex((target, port))  # == 0
            s.settimeout(5)
            open_ports.append[port]
            print('Port', port, 'is open')
            print('Open ports:', open_ports)

        # if it can't connect, display correct output
        except socket.error or socket.gaierror or socket.getaddrinfo:
            if target_ip:
                print('Error: Invalid IP address')
                exit()
            elif target_url:
                print('Error: Invalid hostname')
                exit()
        except:
            print('Port', port, 'is closed')
            continue
    print('\n* Finished scanning target *')
    if not open_ports:
        print('No open ports found on target', target)
    else:
        print('Open ports found:', open_ports, 'on', target)

    # Output
    print(f'\n* Scanning Target: {target} ({ip_addr}) *')
    print('- Scanning ports:', port_range[0], 'to', port_range[-1])

    # Verbose Output
    # ports = tuple()
    # service = dict()
    serv_d = common_ports.ports_and_services
    # for each port in open_ports
    svcs_dict = {port: serv_d[port] for port in open_ports}
    # svcs_list = [ v for k,v in svcs_dict.items() ]

    if verbose:
        print(f'\nOpen ports for {target} ({ip_addr})')
        print('PORT     SERVICE')
        # for port in open_ports:
        # print(f'{port}     {common_ports.ports_and_services[port]}')
        # print(f'{port}     {common_ports.ports_and_services(port)}')
        # for opts in service:
        for port, service in svcs_dict.items():
            print(str(port) + '     ' + str(service))
            # return print('{}     {}'.format(port, service))
        return

    elif not verbose:
        print('Open Ports:', open_ports)
    s.close()
    return
    return (open_ports)
    # return(target, port_range)
