#!/usr/bin/python
#
# Example Android logcat to wpa_supplicant wrapper for QR Code scans
# Copyright (c) 2017, Qualcomm Atheros, Inc.
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.

import os
import sys
import argparse
import logging
import qrcode

scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__))
sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy'))

import wpaspy

wpas_ctrl = '/var/run/wpa_supplicant'

def wpas_connect():
    ifaces = []
    if os.path.isdir(wpas_ctrl):
        try:
            ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
        except OSError as error:
            print("Could not find wpa_supplicant: ", error)
            return None

    if len(ifaces) < 1:
        print("No wpa_supplicant control interface found")
        return None

    for ctrl in ifaces:
        try:
            wpas = wpaspy.Ctrl(ctrl)
            return wpas
        except Exception as e:
            pass
    return None

def dpp_logcat():
    for line in iter(sys.stdin.readline, ''):
        if "ResultHandler: Launching intent: Intent" not in line:
            continue
        if "act=android.intent.action.VIEW" not in line:
            continue
        uri = None
        for val in line.split(' '):
            if val.startswith('dat='):
                uri = val.split('=', 1)[1]
                break
        if not uri:
            continue
        if not uri.startswith('DPP:'):
            continue
        print("Found DPP bootstrap info URI:")
        print(uri)
        wpas = wpas_connect()
        if not wpas:
            print("Could not connect to wpa_supplicant")
            print('')
            continue
        res = wpas.request("DPP_QR_CODE " + uri);
        try:
            id = int(res)
        except ValueError:
            print("QR Code URI rejected")
            continue
        print("QR Code URI accepted - ID=%d" % id)
        print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id))
        del wpas

def dpp_display(curve):
        wpas = wpas_connect()
        if not wpas:
            print("Could not connect to wpa_supplicant")
            return
        res = wpas.request("STATUS")
        addr = None
        for line in res.splitlines():
            if line.startswith("address="):
                addr = line.split('=')[1]
                break
        cmd = "DPP_BOOTSTRAP_GEN type=qrcode"
        cmd += " chan=81/1"
        if addr:
            cmd += " mac=" + addr.replace(':','')
        if curve:
            cmd += " curve=" + curve
        res = wpas.request(cmd)
        try:
            id = int(res)
        except ValueError:
            print("Failed to generate bootstrap info URI")
            return
        print("Bootstrap information - ID=%d" % id)
        print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id))
        uri = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % id)
        print(uri)
        print("ID=%d" % id)
        qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M,
                           border=3)
        qr.add_data(uri, optimize=5)
        qr.print_ascii(tty=True)
        print("ID=%d" % id)
        del wpas

def main():
    parser = argparse.ArgumentParser(description='Android logcat to wpa_supplicant integration for DPP QR Code operations')
    parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
                        action='store_const', dest='loglevel',
                        help='verbose debug output')
    parser.add_argument('--curve', '-c',
                        help='set a specific curve (P-256, P-384, P-521, BP-256R1, BP-384R1, BP-512R1) for key generation')
    parser.add_argument('command', choices=['logcat',
                                            'display'],
                        nargs='?')
    args = parser.parse_args()

    logging.basicConfig(level=args.loglevel)

    if args.command == "logcat":
        dpp_logcat()
    elif args.command == "display":
        dpp_display(args.curve)

if __name__ == '__main__':
    main()