#!/usr/bin/python3

import sys
import dbus
import dbus.mainloop.glib
from gi.repository import GLib
import fnmatch

if len(sys.argv) not in [1, 2]:
    print("Usage: %s [<name_mask>]" % (sys.argv[0],))
    sys.exit(1)

name_mask = None
if len(sys.argv) >= 2:
    name_mask = sys.argv[1]

DEVICE_IF = 'net.connman.iwd.p2p.Device'
PEER_IF = 'net.connman.iwd.p2p.Peer'
WSC_IF = 'net.connman.iwd.SimpleConfiguration'

dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object('net.connman.iwd', '/'),
                                        'org.freedesktop.DBus.ObjectManager')
objects = manager.GetManagedObjects()

p2p_path = None
peers = {}
connecting = False
mainloop = None

for path in objects:
    if DEVICE_IF in objects[path] and p2p_path is None:
        p2p_path = path

if p2p_path is None:
    print('No P2P interfaces')
    sys.exit(-1)

values = objects[p2p_path][DEVICE_IF]
properties = dbus.Interface(bus.get_object('net.connman.iwd', p2p_path),
                                           'org.freedesktop.DBus.Properties')
p2p = dbus.Interface(bus.get_object('net.connman.iwd', p2p_path), DEVICE_IF)

def list_peers():
    global peers

    print('We have the following P2P peers')
    for path in peers:
        result = peers[path]

        print('   ' + result['Name'] + ' at ' + path)

def connect(path):
    global connecting, peers, mainloop

    list_peers()

    peer = dbus.Interface(bus.get_object('net.connman.iwd', path), PEER_IF)
    peer_wsc = dbus.Interface(bus.get_object('net.connman.iwd', path), WSC_IF)
    peer_props = peers[path]

    print('Connecting to ' + peer_props['Name'])
    connecting = True
    try:
        peer_wsc.PushButton(timeout=120)
        print('New connection')
    except Exception as e:
        connecting = False
        print('Connection error: ' + repr(e))

    if mainloop:
        mainloop.quit()
    else:
        sys.exit(0)

def properties_changed(interface, changed, invalidated, path):
    global peers

    path = str(path)
    if interface != PEER_IF or path not in peers:
        return

    peers[path].update(changed)
    for k in invalidated:
        del peers[path][k]

def interfaces_added(path, interfaces):
    global connecting, peers

    if PEER_IF not in interfaces:
        return

    path = str(path)
    peers[path] = interfaces[PEER_IF]
    print('Added peer ' + str(peers[path]['Name']))

    if connecting or name_mask is None or not fnmatch.fnmatch(peers[path]['Name'], name_mask):
        return

    connect(path)

def interfaces_removed(path, interfaces):
    global peers

    if PEER_IF not in interfaces:
        return

    print('Removed peer ' + str(peers[path]['Name']))
    del peers[path]

if not values['Enabled']:
    properties.Set(DEVICE_IF, 'Enabled', True)

if not values['AvailableConnections']:
    # See if we have peers we can disconnect or where we can cancel an ongoing
    # connection that may be in the 120s GO Negotiation timeout for example.
    # Should we have a Connecting property on the WSC interface so we can know
    # whether a connection is in progress?
    for path in objects:
        if PEER_IF not in objects[path]:
            continue
        peer_values = objects[path][PEER_IF]
        print('Trying to disconnect from peer ' + str(peer_values['Name']))
        peer = dbus.Interface(bus.get_object('net.connman.iwd', path), PEER_IF)
        try:
            peer.Disconnect()
        except:
            pass

for path in objects:
    if PEER_IF in objects[path]:
        interfaces_added(path, objects[path])

p2p.RequestDiscovery()

bus.add_signal_receiver(properties_changed,
                        bus_name="net.connman.iwd",
                        dbus_interface="org.freedesktop.DBus.Properties",
                        signal_name="PropertiesChanged",
                        path_keyword="path")

bus.add_signal_receiver(interfaces_added,
                        bus_name="net.connman.iwd",
                        dbus_interface="org.freedesktop.DBus.ObjectManager",
                        signal_name="InterfacesAdded")

bus.add_signal_receiver(interfaces_removed,
                        bus_name="net.connman.iwd",
                        dbus_interface="org.freedesktop.DBus.ObjectManager",
                        signal_name="InterfacesRemoved")

mainloop = GLib.MainLoop()
mainloop.run()
