#!/usr/bin/python2
# coding: utf-8

# This file is part of BLEAH.
#
# Copyleft 2017 Simone Margaritelli
# evilsocket@protonmail.com
# http://www.evilsocket.net
#
# This file may be licensed under the terms of of the
# GNU General Public License Version 3 (the ``GPL'').
#
# Software distributed under the License is distributed
# on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
# express or implied. See the GPL for the specific language
# governing rights and limitations.
#
# You should have received a copy of the GPL along with this
# program. If not, go to http://www.gnu.org/licenses/gpl.html
# or write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import argparse
import sys
import re
import string
import binascii

from bluepy.btle import BTLEException

from bleah.swag import *
from bleah.scan import *

def check_args(args):
    if args.datafile is not None:
        try:
            with open( args.datafile, 'rb' ) as fd:
                args.data = fd.read()
        except:
            print("! Could not access %s for reading, please don't be this guy: https://github.com/evilsocket/bleah/issues/18" % args.datafile)
            quit()

    if args.uuid is not None and args.handle is not None:
        print("Both a UUID and Handle have been set, using handle.\n")
        args.uuid=""

    # check for hex string
    if args.data is not None and args.data.startswith('0x'):
        hexdata = args.data[2:]
        if all(c in string.hexdigits for c in hexdata):
            args.data = binascii.unhexlify(hexdata)

    if args.uuid is not None or args.handle is not None:
        if args.data is None:
            print("! Data parameter ( --data ) is required for write operations.\n")
            quit()

        if args.mac is None:
            print("! MAC parameter ( --mac ) is required for write operations.\n")
            quit()

    if args.mac is not None:
        args.mac = args.mac.lower()

    if args.uuid is not None and not re.match( r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', args.uuid, re.I ):
        print("! Invalid UUID value:", args.uuid, "\n")
        quit()

    if args.handle is not None:
        # convert it to an int
        try:
            args.handle=int(args.handle, 0)
        except ValueError:
            print("! Invalid handle:", args.handle, "\n")
            quit()

    if args.mtu is not None:
        try:
            args.mtu=int(args.mtu)
            # 23 byte are the default ATT_MTU size, according to the standard a maximum of 512 bytes are allowed
            if args.mtu < 23 or args.mtu > 512:
              raise ValueError
        except ValueError:
            print("! Invalid mtu:", args.mtu, "\n")
            quit()


def main():
    print_sexy_banner()

    parser = argparse.ArgumentParser()
    parser.add_argument('-i', '--hci', action='store', type=int, default=0, help='HCI device index.')
    parser.add_argument('-t', '--timeout', action='store', type=int, default=5, help='Scan delay, 0 for continuous scanning.')
    parser.add_argument('-s', '--sensitivity', action='store', type=int, default=-128, help='dBm threshold.')

    parser.add_argument('-b', '--mac', action='store', type=str, default=None, help='Filter by device address. Does not have the full mac. Also: separate several addresses by ","' )
    parser.add_argument('-f', '--force', action='store_true', help='Try to connect even if the device doesn\'t allow to.')

    parser.add_argument('-e', '--enumerate', action='store_true', help='Connect to available devices and perform services enumeration.')

    parser.add_argument('-u', '--uuid', action='store', type=str, default=None, help='Write data to this characteristic UUID (requires --mac and --data).' )
    parser.add_argument('-n', '--handle', action='store', type=str, default=None, help='Write data to this characteristic handle (requires --mac and --data).' )
    parser.add_argument('-d', '--data', action='store', type=str, default=None, help='Data to be written as a quoted string or as hex ( 0xdeadbeef... ).' )
    parser.add_argument('-r', '--datafile', action='store', type=str, default=None, help='Read data to be written from this file.' )
    parser.add_argument('-m', '--mtu', action='store', type=int, default=None, help='Set MTU.' )
    parser.add_argument('-j', '--json_log', action='store', type=str, default=None, help='Name of a json logfile' )
    parser.add_argument('-R', '--rescans', action='store', type=int, default=1, help='Number of rescans' )
    parser.add_argument('-N', '--nicknames', action='store', type=str, default=None, help='Json file containing nicknames for devices and services' )

    args = parser.parse_args(sys.argv[1:])

    check_args(args)

    bleah = Bleah(args)



if __name__ == "__main__":
    try:
        main()
    except BTLEException as be:
        print("\nBTLE Exception:\n%s\n" % red( str(be) ))

    except KeyboardInterrupt:
        print("\n@ Quitting.")
