@ -0,0 +1,7 @@ | |||
((c-mode . ((c-file-style . "linux") | |||
(indent-tabs-mode . t) | |||
(show-trailing-whitespace . t) | |||
(c-basic-offset . 4) | |||
(tab-width . 4) | |||
)) | |||
) |
@ -1,22 +1,11 @@ | |||
# default 12.04 is ancient, use trusty instead | |||
dist: trusty | |||
# pretend we're building C | |||
language: c | |||
compiler: | |||
- gcc | |||
services: | |||
- docker | |||
env: | |||
- VALAC=valac-0.32 | |||
before_install: | |||
- sudo add-apt-repository -y ppa:vala-team/ppa | |||
- sudo apt-get update -qq | |||
- sudo apt-get install -qq ${VALAC} valac | |||
- sudo apt-get install -qq libgirepository1.0-dev | |||
- sudo apt-get install -qq gir1.2-gee-0.8 libgee-0.8-dev | |||
- sudo apt-get install -qq gir1.2-json-1.0 libjson-glib-dev | |||
- sudo apt-get install -qq gir1.2-notify-0.7 libnotify-dev | |||
- sudo apt-get install -qq gir1.2-atspi-2.0 libatspi2.0-dev | |||
- sudo apt-get install -qq gir1.2-gtk-3.0 libgtk-3-dev | |||
before_script: | |||
- autoreconf -if | |||
matrix: | |||
- DISTRO=fedora | |||
- DISTRO=archlinux | |||
- DISTRO=opensuse | |||
script: | |||
- ./configure && make V=1 | |||
- ./extra/travis-build "${DISTRO}" |
@ -0,0 +1,6 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<service> | |||
<short>mconnect</short> | |||
<description>mconnect service configuration</description> | |||
<port port="1714" protocol="udp"/> | |||
</service> |
@ -0,0 +1,142 @@ | |||
#!/bin/bash -xe | |||
# | |||
# This program is free software; you can redistribute it and/or modify | |||
# it under the terms of the GNU General Public License version 2 as | |||
# published by the Free Software Foundation. | |||
# | |||
# This program is distributed in the hope that it will be useful, | |||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
# GNU General Public License for more details. | |||
# | |||
# You should have received a copy of the GNU General Public License along | |||
# with this program; if not, write to the Free Software Foundation, Inc., | |||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
# | |||
# AUTHORS | |||
# Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
# Travis build script. The script reexecs itself inside the container (setting | |||
# IN_CONTAINER=1). The proceeds to install build dependencies and runs through | |||
# the whole build process. Source tree is bind-mounted at /mnt and the container | |||
# has its workdir set to /mnt | |||
# | |||
# NOTE: it is assumed that the script is run while at the top of source tree | |||
# (i.e. $PWD is your checked out tree, this crucial for properly mounting the | |||
# source code into the container). | |||
deps_fedora() { | |||
dnf install --best -y --refresh \ | |||
automake \ | |||
autoconf \ | |||
libtool \ | |||
pkgconfig \ | |||
gcc \ | |||
vala \ | |||
gobject-introspection-devel \ | |||
json-glib-devel \ | |||
libgee-devel \ | |||
openssl-devel \ | |||
libnotify-devel \ | |||
at-spi2-core-devel \ | |||
gtk3-devel | |||
} | |||
deps_opensuse() { | |||
zypper install -y \ | |||
make \ | |||
automake \ | |||
autoconf \ | |||
libtool \ | |||
pkgconfig \ | |||
gcc \ | |||
vala \ | |||
gobject-introspection-devel \ | |||
json-glib-devel \ | |||
libgee-devel \ | |||
openssl-devel \ | |||
libnotify-devel \ | |||
at-spi2-core-devel \ | |||
gtk3-devel | |||
} | |||
deps_archlinux() { | |||
pacman -Syu --noconfirm \ | |||
base-devel \ | |||
autoconf \ | |||
automake \ | |||
libtool \ | |||
pkg-config \ | |||
gcc \ | |||
vala \ | |||
glib2 \ | |||
gobject-introspection \ | |||
json-glib \ | |||
libgee \ | |||
openssl \ | |||
libnotify \ | |||
at-spi2-core \ | |||
gtk3 | |||
} | |||
install_deps() { | |||
case "$1" in | |||
fedora) | |||
deps_fedora | |||
;; | |||
opensuse) | |||
deps_opensuse | |||
;; | |||
archlinux) | |||
deps_archlinux | |||
;; | |||
*) | |||
echo "unsupported distro $1" | |||
exit 1 | |||
esac | |||
} | |||
build() { | |||
autoreconf -if | |||
# TODO: out of source builds | |||
./configure | |||
make | |||
make install | |||
} | |||
build_in_container() { | |||
install_deps $1 | |||
build | |||
} | |||
spin_container() { | |||
case "$1" in | |||
fedora) | |||
DOCKER_IMG=fedora | |||
;; | |||
archlinux) | |||
DOCKER_IMG=base/archlinux | |||
;; | |||
opensuse) | |||
DOCKER_IMG=opensuse:tumbleweed | |||
;; | |||
*) | |||
echo "unsupported distro $1" | |||
exit 1 | |||
esac | |||
# run a container, mount sources at /mnt, st | |||
docker run --rm \ | |||
-v $PWD:/mnt \ | |||
-w /mnt \ | |||
-e IN_CONTAINER=1 \ | |||
$DOCKER_IMG \ | |||
/mnt/extra/travis-build "$@" | |||
} | |||
if [ "$IN_CONTAINER" = "1" ]; then | |||
build_in_container "$@" | |||
else | |||
spin_container "$@" | |||
fi |
@ -0,0 +1,4 @@ | |||
set environment G_MESSAGES_DEBUG = all | |||
set environment G_DEBUG = fatal-criticals | |||
file @bindir@/mconnect | |||
run |
@ -0,0 +1,107 @@ | |||
/* ex:ts=4:sw=4:sts=4:et */ | |||
/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ | |||
/** | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
* AUTHORS | |||
* Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
*/ | |||
namespace Mconn { | |||
public class Application : GLib.Application { | |||
private Core core = null; | |||
private static bool log_debug = false; | |||
private static bool log_debug_verbose = false; | |||
private const GLib.OptionEntry[] options = { | |||
{"debug", 'd', 0, OptionArg.NONE, ref log_debug, | |||
"Show debug output", null}, | |||
{"verbose-debug", 0, 0, OptionArg.NONE, ref log_debug_verbose, | |||
"Show verbose debug output", null}, | |||
{null} | |||
}; | |||
private Discovery discovery = null; | |||
private DeviceManager manager = null; | |||
private DeviceManagerDBusProxy bus_manager = null; | |||
public Application() { | |||
Object(application_id: "org.mconnect"); | |||
add_main_option_entries(options); | |||
discovery = new Discovery(); | |||
manager = new DeviceManager(); | |||
} | |||
protected override void startup() { | |||
debug("startup"); | |||
base.startup(); | |||
if (log_debug == true) | |||
Environment.set_variable("G_MESSAGES_DEBUG", "all", false); | |||
if (log_debug_verbose == true) | |||
enable_vdebug(); | |||
core = Core.instance(); | |||
if (core == null) | |||
error("cannot initialize core"); | |||
if (core.config.is_debug_on() == true) | |||
Environment.set_variable("G_MESSAGES_DEBUG", "all", false); | |||
Notify.init("mconnect"); | |||
discovery.device_found.connect((disc, discdev) => { | |||
manager.handle_discovered_device(discdev); | |||
}); | |||
try { | |||
discovery.listen(); | |||
} catch (Error e) { | |||
message("failed to setup device listener: %s", e.message); | |||
} | |||
} | |||
protected override void activate() { | |||
debug("activate"); | |||
// reload devices from cache | |||
manager.load_cache(); | |||
hold(); | |||
} | |||
public override bool dbus_register(DBusConnection conn, | |||
string object_path) throws Error { | |||
this.bus_manager = new DeviceManagerDBusProxy.with_manager(conn, | |||
this.manager); | |||
this.bus_manager.publish(); | |||
base.dbus_register(conn, object_path); | |||
debug("dbus register, path %s", object_path); | |||
return true; | |||
} | |||
public override void dbus_unregister(DBusConnection conn, | |||
string object_path) { | |||
base.dbus_unregister(conn, object_path); | |||
debug("dbus unregister, path %s", object_path); | |||
} | |||
} | |||
} |
@ -0,0 +1,89 @@ | |||
/* ex:ts=4:sw=4:sts=4:et */ | |||
/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ | |||
/** | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
* AUTHORS | |||
* Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
*/ | |||
[DBus (name = "org.mconnect.Device.Battery")] | |||
class BatteryHandlerProxy : Object, PacketHandlerInterfaceProxy { | |||
private Device device = null; | |||
private BatteryHandler battery_handler = null; | |||
private uint register_id = 0; | |||
private ulong notify_id = 0; | |||
private DBusPropertyNotifier prop_notifier = null; | |||
public uint level { get; private set; default = 0; } | |||
public bool charging { get; private set; default = false; } | |||
public BatteryHandlerProxy.for_device_handler(Device dev, | |||
PacketHandlerInterface iface) { | |||
this.device = dev; | |||
this.battery_handler = (BatteryHandler) iface; | |||
this.battery_handler.battery.connect(this.battery_change); | |||
} | |||
private void battery_change(Device dev, uint level, bool charging) { | |||
if (this.device != dev) | |||
return; | |||
this.level = level; | |||
this.charging = charging; | |||
} | |||
[DBus (visible = false)] | |||
public void bus_register(DBusConnection conn, string path) throws IOError { | |||
if (this.register_id == 0) | |||
this.register_id = conn.register_object(path, this); | |||
this.prop_notifier = new DBusPropertyNotifier(conn, | |||
"org.mconnect.Device.Battery", | |||
path); | |||
this.notify.connect(this.send_property_change); | |||
} | |||
[DBus (visible = false)] | |||
public void bus_unregister(DBusConnection conn) throws IOError { | |||
if (this.register_id != 0) | |||
conn.unregister_object(this.register_id); | |||
this.register_id = 0; | |||
this.notify.disconnect(this.send_property_change); | |||
this.notify_id = 0; | |||
} | |||
private void send_property_change(ParamSpec p) { | |||
assert(this.prop_notifier != null); | |||
Variant v = null; | |||
if (p.name == "level") { | |||
v = this.level; | |||
} | |||
if (p.name == "charging") { | |||
v = this.charging; | |||
} | |||
if (v == null) | |||
return; | |||
this.prop_notifier.queue_property_change(p.name, v); | |||
} | |||
} |
@ -0,0 +1,244 @@ | |||
/* ex:ts=4:sw=4:sts=4:et */ | |||
/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ | |||
/** | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
* AUTHORS | |||
* Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
*/ | |||
using Gee; | |||
/** | |||
* General device wrapper. | |||
*/ | |||
[DBus (name = "org.mconnect.Device")] | |||
class DeviceDBusProxy : Object { | |||
public string id { | |||
get { return device.device_id; } | |||
private set {} | |||
default = ""; | |||
} | |||
public string name { | |||
get { return device.device_name; } | |||
private set {} | |||
default = ""; | |||
} | |||
public string device_type { | |||
get { return device.device_type; } | |||
private set {} | |||
default = ""; | |||
} | |||
public uint protocol_version { | |||
get { return device.protocol_version; } | |||
private set {} | |||
default = 5; | |||
} | |||
public string address { get; private set; default = ""; } | |||
public bool is_paired { | |||
get { return device.is_paired; } | |||
private set {} | |||
default = false; | |||
} | |||
public bool allowed { | |||
get { return device.allowed; } | |||
private set {} | |||
default = false; | |||
} | |||
public bool is_active { | |||
get { return device.is_active; } | |||
private set {} | |||
default = false; | |||
} | |||
public bool is_connected { get; private set; default = false; } | |||
public string[] incoming_capabilities { | |||
get; | |||
private set; | |||
} | |||
public string[] outgoing_capabilities { | |||
get; | |||
private set; | |||
} | |||
private HashMap<string,PacketHandlerInterfaceProxy> handlers; | |||
private uint register_id = 0; | |||
private DBusPropertyNotifier prop_notifier = null; | |||
[DBus (visible = false)] | |||
public ObjectPath object_path = null; | |||
[DBus (visible = false)] | |||
public Device device {get; private set; default = null; } | |||
public DeviceDBusProxy.for_device_with_path(Device device, ObjectPath path) { | |||
this.device = device; | |||
this.object_path = path; | |||
this.handlers = new HashMap<string, PacketHandlerInterfaceProxy>(); | |||
this.update_address(); | |||
this.update_capabilities(); | |||
this.device.notify.connect(this.param_changed); | |||
this.device.connected.connect(() => { | |||
this.is_connected = true; | |||
}); | |||
this.device.disconnected.connect(() => { | |||
this.is_connected = false; | |||
}); | |||
this.notify.connect(this.update_properties); | |||
} | |||
private void update_capabilities() { | |||
string[] caps = {}; | |||
foreach (var cap in device.incoming_capabilities) { | |||
caps += cap; | |||
} | |||
this.incoming_capabilities = caps; | |||
caps = {}; | |||
foreach (var cap in device.outgoing_capabilities) { | |||
caps += cap; | |||
} | |||
this.outgoing_capabilities = caps; | |||
} | |||
private void update_address() { | |||
this.address = "%s:%u".printf(device.host.to_string(), | |||
device.tcp_port); | |||
} | |||
private void update_properties(ParamSpec param) { | |||
debug("param %s changed", param.name); | |||
string name = param.name; | |||
Variant v = null; | |||
switch (param.name) { | |||
case "address": | |||
v = this.address; | |||
break; | |||
case "id": | |||
v = this.id; | |||
break; | |||
case "name": | |||
v = this.name; | |||
break; | |||
case "device-type": | |||
name = "DeviceType"; | |||
v = this.device_type; | |||
break; | |||
case "potocol-version": | |||
name = "ProtocolVersion"; | |||
v = this.protocol_version; | |||
break; | |||
case "is-paired": | |||
name = "IsPaired"; | |||
v = this.is_paired; | |||
break; | |||
case "allowed": | |||
v = this.allowed; | |||
break; | |||
case "is-active": | |||
name = "IsActive"; | |||
v = this.is_active; | |||
break; | |||
case "is-connected": | |||
name = "IsConnected"; | |||
v = this.is_connected; | |||
break; | |||
} | |||
if (v == null) | |||
return; | |||
this.prop_notifier.queue_property_change(name, v); | |||
} | |||
private void param_changed(ParamSpec param) { | |||
debug("parameter %s changed", param.name); | |||
switch (param.name) { | |||
case "host": | |||
case "tcp-port": | |||
this.update_address(); | |||
break; | |||
case "allowed": | |||
this.allowed = device.allowed; | |||
break; | |||
case "is-active": | |||
this.is_active = device.is_active; | |||
break; | |||
case "is-paired": | |||
this.is_paired = device.is_paired; | |||
break; | |||
case "incoming-capabilities": | |||
case "outgoing-capabilities": | |||
this.update_capabilities(); | |||
break; | |||
} | |||
} | |||
[DBus (visible = false)] | |||
public bool has_handler(string cap) { | |||
return this.handlers.has_key(cap); | |||
} | |||
[DBus (visible = false)] | |||
public void bus_register(DBusConnection conn) { | |||
try { | |||
this.register_id = conn.register_object(this.object_path, this); | |||
this.prop_notifier = new DBusPropertyNotifier(conn, | |||
"org.mconnect.Device", | |||
this.object_path); | |||
} catch (IOError err) { | |||
warning("failed to register DBus object for device %s under path %s", | |||
this.device.to_string(), this.object_path.to_string()); | |||
} | |||
} | |||
[DBus (visible = false)] | |||
public void bus_unregister(DBusConnection conn) { | |||
if (this.register_id != 0) { | |||
conn.unregister_object(this.register_id); | |||
} | |||
this.register_id = 0; | |||
this.prop_notifier = null; | |||
} | |||
[DBus (visible = false)] | |||
public void bus_register_handler(DBusConnection conn, | |||
string cap, | |||
PacketHandlerInterfaceProxy handler) { | |||
handler.bus_register(conn, this.object_path); | |||
this.handlers.@set(cap, handler); | |||
} | |||
[DBus (visible = false)] | |||
public void bus_unregister_handler(DBusConnection conn, | |||
string cap) { | |||
PacketHandlerInterfaceProxy handler; | |||
this.handlers.@unset(cap, out handler); | |||
if (handler != null) { | |||
handler.bus_unregister(conn); | |||
} | |||
} | |||
} |
@ -0,0 +1,170 @@ | |||
/* ex:ts=4:sw=4:sts=4:et */ | |||
/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ | |||
/** | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
* AUTHORS | |||
* Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
*/ | |||
using Gee; | |||
[DBus (name = "org.mconnect.DeviceManager")] | |||
class DeviceManagerDBusProxy : Object | |||
{ | |||
private DeviceManager manager; | |||
public signal void device_added(string path); | |||
public signal void device_removed(string path); | |||
private const string DBUS_PATH = "/org/mconnect/manager"; | |||
private DBusConnection bus = null; | |||
private HashMap<string, DeviceDBusProxy> devices; | |||
private int device_idx = 0; | |||
public DeviceManagerDBusProxy.with_manager(DBusConnection bus, | |||
DeviceManager manager) { | |||
this.manager = manager; | |||
this.bus = bus; | |||
this.devices = new HashMap<string, DeviceDBusProxy>(); | |||
manager.found_new_device.connect((d) => { | |||
this.add_device(d); | |||
}); | |||
manager.device_capability_added.connect(this.add_device_capability); | |||
} | |||
[DBus (visible = false)] | |||
public void publish() throws IOError { | |||
assert(this.bus != null); | |||
this.bus.register_object(DBUS_PATH, this); | |||
} | |||
/** | |||
* allow_device: | |||
* @path: device object path | |||
* | |||
* Allow given device | |||
*/ | |||
public void allow_device(string path) { | |||
debug("allow device %s", path); | |||
var dev_proxy = this.devices.@get(path); | |||
if (dev_proxy == null) { | |||
warning("no device under path %s", path); | |||
return; | |||
} | |||
this.manager.allow_device(dev_proxy.device); | |||
} | |||
/** | |||
* disallow_device: | |||
* @path: device object path | |||
* | |||
* Disallow given device | |||
*/ | |||
public void disallow_device(string path) { | |||
debug("disallow device %s", path); | |||
var dev_proxy = this.devices.@get(path); | |||
if (dev_proxy == null) { | |||
warning("no device under path %s", path); | |||
return; | |||
} | |||
this.manager.disallow_device(dev_proxy.device); | |||
} | |||
/** | |||
* list_devices: | |||
* | |||
* Returns a list of DBus paths of all known devices | |||
*/ | |||
public ObjectPath[] list_devices() { | |||
ObjectPath[] devices = {}; | |||
foreach (var path in this.devices.keys) { | |||
devices += new ObjectPath(path); | |||
} | |||
return devices; | |||
} | |||
private void add_device(Device dev) { | |||
var path = make_device_path(); | |||
var device_proxy = new DeviceDBusProxy.for_device_with_path(dev, | |||
new ObjectPath(path)); | |||
this.devices.@set(path, device_proxy); | |||
info("register device %s under path %s", | |||
dev.to_string(), path); | |||
device_proxy.bus_register(this.bus); | |||
device_added(path); | |||
} | |||
private DeviceDBusProxy? find_proxy_for_device(Device dev) { | |||
DeviceDBusProxy dp = null; | |||
foreach (var entry in this.devices.entries) { | |||
if (entry.value.device == dev) { | |||
dp = entry.value; | |||
break; | |||
} | |||
} | |||
return dp; | |||
} | |||
private void add_device_capability(Device dev, | |||
string capability, | |||
PacketHandlerInterface iface) { | |||
DeviceDBusProxy dp = find_proxy_for_device(dev); | |||
if (dp == null) { | |||
warning("no bus proxy for device %s", dev.to_string()); | |||
return; | |||
} | |||
if (dp.has_handler(capability)) { | |||
return; | |||
} | |||
info("add capability handler %s for device at path %s", | |||
capability, dp.object_path.to_string()); | |||
var h = PacketHandlersProxy.new_device_capability_handler(dev, | |||
capability, | |||
iface); | |||
if (h != null) { | |||
h.bus_register(this.bus, dp.object_path); | |||
} | |||
} | |||
/** | |||
* make_device_path: | |||
* | |||
* return device path string that can be used as ObjectPath | |||
*/ | |||
private string make_device_path() { | |||
var path = "/org/mconnect/device/%d".printf(this.device_idx); | |||
// bump device index | |||
this.device_idx++; | |||
return path; | |||
} | |||
} |
@ -0,0 +1,82 @@ | |||
/* ex:ts=4:sw=4:sts=4:et */ | |||
/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ | |||
/** | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
* AUTHORS | |||
* Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
*/ | |||
/** | |||
* Newly discovered device wrapper. | |||
*/ | |||
class DiscoveredDevice : Object { | |||
public string device_id { get; private set; default = ""; } | |||
public string device_name { get; private set; default = ""; } | |||
public string device_type { get; private set; default = ""; } | |||
public uint protocol_version {get; private set; default = 5; } | |||
public uint tcp_port {get; private set; default = 1714; } | |||
public InetAddress host { get; private set; default = null; } | |||
public string[] outgoing_capabilities { get; private set; default = null; } | |||
public string[] incoming_capabilities { get; private set; default = null; } | |||
/** | |||
* Constructs DiscoveredDevice based on identity packet. | |||
* | |||
* @param pkt identity packet | |||
* @param host source host that the packet came from | |||
*/ | |||
public DiscoveredDevice.from_identity(Packet pkt, InetAddress host) { | |||
debug("got packet: %s", pkt.to_string()); | |||
var body = pkt.body; | |||
this.host = host; | |||
this.device_name = body.get_string_member("deviceName"); | |||
this.device_id = body.get_string_member("deviceId"); | |||
this.device_type = body.get_string_member("deviceType"); | |||
this.protocol_version = (int) body.get_int_member("protocolVersion"); | |||
this.tcp_port = (uint) body.get_int_member("tcpPort"); | |||
var incoming = body.get_array_member("incomingCapabilities"); | |||
var outgoing = body.get_array_member("outgoingCapabilities"); | |||
this.outgoing_capabilities = new string[outgoing.get_length()]; | |||
this.incoming_capabilities = new string[incoming.get_length()]; | |||
incoming.foreach_element((a, i, n) => { | |||
this.incoming_capabilities[i] = n.get_string(); | |||
}); | |||
outgoing.foreach_element((a, i, n) => { | |||
this.outgoing_capabilities[i] = n.get_string(); | |||
}); | |||
debug("discovered new device: %s", this.to_string()); | |||
} | |||
public string to_string() { | |||
return "discovered-%s-%s-%s-%u".printf(this.device_id, | |||
this.device_name, | |||
this.device_type, | |||
this.protocol_version); | |||
} | |||
public string to_unique_string() { | |||
return make_unique_device_string(this.device_id, | |||
this.device_name, | |||
this.device_type, | |||
this.protocol_version); | |||
} | |||
} |
@ -0,0 +1,27 @@ | |||
/* ex:ts=4:sw=4:sts=4:et */ | |||
/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ | |||
/** | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
* AUTHORS | |||
* Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
*/ | |||
/** | |||
* PacketHandlerInterfaceProxy: interface of DBus exported packet handler | |||
*/ | |||
interface PacketHandlerInterfaceProxy : Object { | |||
public abstract void bus_register(DBusConnection conn, string path) throws IOError; | |||
public abstract void bus_unregister(DBusConnection conn) throws IOError; | |||
} |
@ -0,0 +1,44 @@ | |||
/* ex:ts=4:sw=4:sts=4:et */ | |||
/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ | |||
/** | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
* AUTHORS | |||
* Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
*/ | |||
class PacketHandlersProxy : Object { | |||
public static PacketHandlerInterfaceProxy? new_device_capability_handler( | |||
Device dev, | |||
string cap, | |||
PacketHandlerInterface iface) { | |||
switch (iface.get_pkt_type()) { | |||
case BatteryHandler.BATTERY: { | |||
return new BatteryHandlerProxy.for_device_handler(dev, iface); | |||
break; | |||
} | |||
case PingHandler.PING: { | |||
return new PingHandlerProxy.for_device_handler(dev, iface); | |||
break; | |||
} | |||
default: | |||
warning("cannot register bus handler for %s", | |||
iface.get_pkt_type()); | |||
break; | |||
} | |||
return null; | |||
} | |||
} |
@ -0,0 +1,52 @@ | |||
/* ex:ts=4:sw=4:sts=4:et */ | |||
/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ | |||
/** | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
* AUTHORS | |||
* Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
*/ | |||
[DBus (name = "org.mconnect.Device.Ping")] | |||
class PingHandlerProxy : Object, PacketHandlerInterfaceProxy { | |||
private Device device = null; | |||
private PingHandler ping_handler = null; | |||
public PingHandlerProxy.for_device_handler(Device dev, | |||
PacketHandlerInterface iface) { | |||
this.device = dev; | |||
this.ping_handler = (PingHandler) iface; | |||
this.ping_handler.ping.connect(this.ping_cb); | |||
} | |||
[DBus (visible = false)] | |||
public void bus_register(DBusConnection conn, string path) throws IOError { | |||
conn.register_object(path, this); | |||
} | |||
[DBus (visible = false)] | |||
public void bus_unregister(DBusConnection conn) throws IOError { | |||
//conn.unregister_object(this); | |||
} | |||
private void ping_cb(Device dev) { | |||
if (this.device != dev) | |||
return; | |||
ping(); | |||
} | |||
public signal void ping(); | |||
} |
@ -0,0 +1,57 @@ | |||
/* ex:ts=4:sw=4:sts=4:et */ | |||
/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ | |||
/** | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
* AUTHORS | |||
* Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
*/ | |||
class PingHandler : Object, PacketHandlerInterface { | |||
public const string PING = "kdeconnect.ping"; | |||
public string get_pkt_type() { | |||
return PING; | |||
} | |||
private PingHandler() { | |||
} | |||
public static PingHandler instance() { | |||
return new PingHandler(); | |||
} | |||
public void use_device(Device dev) { | |||
debug("use device %s for ping", dev.to_string()); | |||
dev.message.connect(this.message); | |||
} | |||
public void release_device(Device dev) { | |||
debug("release device %s", dev.to_string()); | |||
dev.message.disconnect(this.message); | |||
} | |||
public void message(Device dev, Packet pkt) { | |||
if (pkt.pkt_type != PING) { | |||
return; | |||
} | |||
GLib.message("ping from device %s", dev.to_string()); | |||
ping(dev); | |||
} | |||
public signal void ping(Device dev); | |||
} |
@ -0,0 +1,101 @@ | |||
/** | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
* AUTHORS | |||
* Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
*/ | |||
/** | |||
* DBusPropertyNotifier: | |||
* | |||
* Helper class for pushing out | |||
* org.freedesktop.DBus.Properties.PropertiesChanged signals. | |||
*/ | |||
class DBusPropertyNotifier : Object { | |||
private DBusConnection conn = null; | |||
private string iface = ""; | |||
private string path = ""; | |||
private VariantBuilder builder = null; | |||
private uint timeout_src = 0; | |||
public const uint TIMEOUT = 300; | |||
public DBusPropertyNotifier(DBusConnection conn, | |||
string iface, | |||
string path) { | |||
this.conn = conn; | |||
this.iface = iface; | |||
this.path = path; | |||
} | |||
/** | |||
* queue_property_change: | |||
* | |||
* @name: property name (will be automatically capitalized if needed) | |||
* @val: Variant holding property value | |||
* | |||
* This method will queue up property notifications for sending. By default | |||
* it waits @TIMEOUT ms before sending the actual signal. | |||
*/ | |||
public void queue_property_change(string name, Variant val) { | |||
if (this.builder == null) { | |||
this.builder = new VariantBuilder(VariantType.ARRAY); | |||
} | |||
string nm = name; | |||
if (name.get_char(0).islower()) { | |||
nm = name.get_char(0).toupper().to_string() + name.substring(1); | |||
} | |||
this.builder.add("{sv}", nm, val); | |||
if (this.timeout_src == 0) { | |||
this.timeout_src = Timeout.add(300, | |||
this.send_property_change); | |||
} | |||
} | |||
/** | |||
* send_property_change: | |||
* | |||
* Send out actual PropertiesChanged signals | |||
*/ | |||
private bool send_property_change() { | |||
this.timeout_src = 0; | |||
if (this.builder == null) | |||
return false;; | |||
try { | |||
var invalid_builder = new VariantBuilder(new VariantType ("as")); | |||
this.conn.emit_signal(null, | |||
this.path, | |||
"org.freedesktop.DBus.Properties", | |||
"PropertiesChanged", | |||
new Variant ("(sa{sv}as)", | |||
this.iface, | |||
builder, | |||
invalid_builder) | |||
); | |||
} catch (Error e) { | |||
warning("%s\n", e.message); | |||
} | |||
this.builder = null; | |||
return false; | |||
} | |||
} |
@ -0,0 +1,85 @@ | |||
/* ex:ts=4:sw=4:sts=4:et */ | |||
/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ | |||
/** | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
* AUTHORS | |||
* Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
*/ | |||
/** | |||
* @array_list_to_list: | |||
* @al: Gee.ArrayList<T> | |||
* | |||
* Convert Gee.ArrayList<T> to T[] | |||
*/ | |||
T[] array_list_to_list<T>(Gee.ArrayList<T> al) { | |||
T[] out_list = new T[al.size]; | |||
int i = 0; | |||
foreach(var v in al) { | |||
out_list[i] = v; | |||
i++; | |||
} | |||
return out_list; | |||
} | |||
namespace DebugLog{ | |||
public bool Verbose = false; | |||
} | |||
void enable_vdebug() { | |||
DebugLog.Verbose = true; | |||
} | |||
/** | |||
* vdebug: | |||
* @format: format string | |||
* | |||
* Same as debug() but looks at verbose debug flag | |||
*/ | |||
void vdebug(string format, ...) { | |||
if (DebugLog.Verbose == true) { | |||
var l = va_list(); | |||
logv(null, LogLevelFlags.LEVEL_DEBUG, format, l); | |||
} | |||
} | |||
/** | |||
* make_unique_device_string: | |||
* @id: device ID | |||
* @name: device name | |||
* @type: device type | |||
* @pv: protocol version | |||
* | |||
* Generate device string that can be used as map index | |||
*/ | |||
string make_unique_device_string(string id, string name, | |||
string type, uint pv) { | |||
return make_device_string(id, name, type, pv).replace(" ", "-"); | |||
} | |||
/** | |||
* make_device_string: | |||
* @id: device ID | |||
* @name: device name | |||
* @type: device type | |||
* @pv: protocol version | |||
* | |||
* Generate device string | |||
*/ | |||
string make_device_string(string id, string name, | |||
string type, uint pv) { | |||
return "%s-%s-%s-%u".printf(id, name, type, pv); | |||
} |
@ -0,0 +1,335 @@ | |||
/* ex:ts=4:sw=4:sts=4:et */ | |||
/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ | |||
/** | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
* AUTHORS | |||
* Maciek Borzecki <maciek.borzecki (at] gmail.com> | |||
*/ | |||
namespace Mconnect { | |||
[DBus (name = "org.mconnect.DeviceManager")] | |||
public interface DeviceManagerIface : Object { | |||
public const string OBJECT_PATH = "/org/mconnect/manager"; | |||
public abstract ObjectPath[] ListDevices() throws IOError; | |||
public abstract void AllowDevice(string path) throws IOError; | |||
} | |||
[DBus (name = "org.mconnect.Device")] | |||
public interface DeviceIface : Object { | |||
public abstract string id { owned get;} | |||
public abstract string name { owned get;} | |||
public abstract string device_type { owned get;} | |||
public abstract uint protocol_version { owned get;} | |||
public abstract string address { owned get;} | |||
public abstract bool is_paired { owned get;} | |||
public abstract bool allowed { owned get;} | |||
public abstract bool is_active { owned get;} | |||
public abstract bool is_connected { owned get;} | |||
public abstract string[] outgoing_capabilities { owned get;} | |||
public abstract string[] incoming_capabilities { owned get;} | |||
} | |||
public class Client { | |||
private static bool log_debug = false; | |||
private static bool verbose = false; | |||
// some hints for valac about the array holding remaining args | |||
[CCode (array_length = false, array_null_terminated = true)] | |||
private static string[] remaining; | |||
private BusType bus_type = BusType.SESSION; | |||
private const OptionEntry[] options = { | |||
{"debug", 'd', 0, OptionArg.NONE, ref log_debug, | |||
"Show debug output", null}, | |||
{"verbose", 'v', 0, OptionArg.NONE, ref verbose, | |||
"Be verbose", null}, | |||
// there's no Vala const for G_OPTION_REMAINING (which is a #define | |||
// for "") | |||
{"", 0, 0, OptionArg.STRING_ARRAY, ref remaining, null, | |||
"[COMMAND ..]"}, | |||
{null} | |||
}; | |||
/** | |||
* Command: | |||
* | |||
* command line 'command' wrapper | |||
*/ | |||
private struct Command { | |||
string command; // textual command, ex. list, show, etc. | |||
int arg_count; // number of required parameters, not including | |||
// command | |||
unowned CommandFunc clbk; // callback | |||
Command(string command, int arg_count, CommandFunc clbk) { | |||
this.command = command; | |||
this.arg_count = arg_count; | |||
this.clbk = clbk; | |||
} | |||
} | |||
// command callback | |||
private delegate int CommandFunc(string[] args); | |||
public static int main(string[] args) | |||
{ | |||
try { | |||
var opt_context = new OptionContext(); | |||
opt_context.set_description( | |||
"""Available commands: | |||
list-devices List devices | |||
allow-device <path> Allow device | |||
show-device <path> Show device details | |||
""" | |||
); | |||
opt_context.set_help_enabled(true); | |||
opt_context.add_main_entries(options, null); | |||
opt_context.parse(ref args); | |||
} catch (OptionError e) { | |||
stdout.printf("error: %s\n", e.message); | |||
stdout.printf("Run '%s --help' to see a full " + | |||
"list of available command line options.\n", | |||
args[0]); | |||
return 1; | |||
} | |||
if (log_debug == true) | |||
Environment.set_variable("G_MESSAGES_DEBUG", "all", false); | |||
var cl = new Client(); | |||
Command[] commands = { | |||
Command("list-devices", 0, cl.cmd_list_devices), | |||
Command("allow-device", 1, cl.cmd_allow_device), | |||
Command("show-device", 1, cl.cmd_show_device), | |||
}; | |||
handle_command(remaining, commands); | |||
return 0; | |||
} | |||
/** | |||
* handle_command: | |||
* @args: remaining command line arguments | |||
* @commands: supported commands array | |||
* | |||
* @return exit status of command or -1 on error | |||
*/ | |||
private static int handle_command(string[] args, Command[] commands) { | |||
// extract command and it's arguments if any | |||
string command = "list-devices"; | |||
if (args.length > 0) | |||
command = remaining[0]; | |||
debug("command is: %s", command); | |||
string[] command_args = {}; | |||
if (args.length > 1) | |||
command_args = args[1:args.length]; | |||
foreach (var cmden in commands) { | |||
if (cmden.command == command) { | |||
debug("found match for %s, args expect: %zd, have: %zd", | |||
command, cmden.arg_count, command_args.length); | |||
if (command_args.length != cmden.arg_count) { | |||
stderr.printf("Incorrect number of arguments " + | |||
"for command %s, see --help\n", | |||
command); | |||
return -1; | |||
} | |||
debug("running callback"); | |||
return cmden.clbk(command_args); | |||
} | |||
} | |||
stderr.printf("Incorrect command, see --help\n"); | |||
return -1; | |||
} | |||
private int cmd_list_devices(string[] args) { | |||
return checked_dbus_call(() => { | |||
var manager = get_manager(); | |||
debug("list devices"); | |||
var devs = manager.ListDevices(); | |||
print_paths(devs, "Devices", | |||
(path) => { | |||
try { | |||
var dp = get_device(path); | |||
return "%s - %s".printf(dp.id, dp.name); | |||
} catch (IOError e) { | |||
warning("error occurred: %s", e.message); | |||
return "(error)"; | |||
} | |||
}); | |||
return 0; | |||
}); | |||
} | |||
private int cmd_allow_device(string[] args) { | |||
return checked_dbus_call(() => { | |||
var dp = args[0]; | |||
var manager = get_manager(); | |||
debug("allow device device %s", dp); | |||
manager.AllowDevice(new ObjectPath(dp)); | |||
return 0; | |||
}); | |||
} | |||
private void print_sorted_caps(string[] caps, string format) { | |||
qsort_with_data<string>(caps, sizeof(string), | |||
(a, b) => GLib.strcmp(a, b)); | |||
foreach (var cap in caps) { | |||
stdout.printf(format, cap); | |||
} | |||
} | |||
private int cmd_show_device(string[] args) { | |||
return checked_dbus_call(() => { | |||
var dp = get_device(new ObjectPath(args[0])); | |||
stdout.printf("Device\n" + | |||
" Name: %s\n" + | |||
" ID: %s\n" + | |||
" Address: %s\n" + | |||
" Type: %s\n" + | |||
" Allowed: %s\n" + | |||
" Paired: %s\n" + | |||
" Active: %s\n" + | |||
" Connected: %s\n", | |||
dp.name, | |||
dp.id, | |||
dp.address, | |||
dp.device_type, | |||
dp.allowed.to_string(), | |||
dp.is_paired.to_string(), | |||
dp.is_active.to_string(), | |||
dp.is_connected.to_string()); | |||
if (verbose) { | |||
stdout.printf(" Capabilities (out):\n"); | |||
print_sorted_caps(dp.outgoing_capabilities, " %s\n"); | |||
stdout.printf(" Capabilities (in):\n"); | |||
print_sorted_caps(dp.incoming_capabilities, " %s\n"); | |||
} | |||
return 0; | |||
}); | |||
} | |||
private delegate int CheckDBusCallFunc() throws Error; | |||
/** | |||
* checked_dbus_call: | |||
* @clbk: function to wrap | |||
* | |||
* Catch any DBus errors and return appropriate status | |||
*/ | |||
private static int checked_dbus_call(CheckDBusCallFunc clbk) { | |||
try { | |||
return clbk(); | |||
} catch (IOError e) { | |||
warning("communication returned an error: %s", e.message); | |||
return -1; | |||
} catch (DBusError e) { | |||
warning("communication with service failed: %s", e.message); | |||
} catch (Error e) { | |||
warning("error: %s", e.message); | |||
} | |||
return 0; | |||
} | |||
/** | |||
* get_mconnect_obj_proxy: | |||
* @path: DBus object path | |||
* | |||
* Obtain an interface to a DBus object avaialble at | |||
* Mconnect service under @path. | |||
* | |||
* @return null or interface | |||
*/ | |||
private T? get_mconnect_obj_proxy<T>(ObjectPath path) throws IOError { | |||
T proxy_out = null; | |||
try { | |||
proxy_out = Bus.get_proxy_sync(bus_type, | |||
"org.mconnect", | |||
path); | |||
} catch (IOError e) { | |||
warning("failed to obtain proxy to mconnect service: %s", | |||
e.message); | |||
throw e; | |||
} | |||
return proxy_out; | |||
} | |||
/** | |||
* get_manager: | |||
* | |||
* Obtain DBus interface to Device Manager | |||
* | |||
* @return interface or null | |||
*/ | |||
private DeviceManagerIface? get_manager() throws IOError { | |||
return get_mconnect_obj_proxy( | |||
new ObjectPath(DeviceManagerIface.OBJECT_PATH)); | |||
} | |||
/** | |||
* get_device: | |||
* @path device object path | |||
* | |||
* Obtain DBus interface to Device | |||
* | |||
* @return interface or null | |||
*/ | |||
private DeviceIface? get_device(ObjectPath path) throws IOError { | |||
return get_mconnect_obj_proxy(path); | |||
} | |||
/** | |||
* print_paths: | |||
* @objs: object paths | |||
* @header: header for printing, | |||
* @desc_clbk: callback for producing a meaningful description | |||
* | |||
* Print a list of object paths, possibly adding a description | |||
*/ | |||
private static void print_paths(ObjectPath[] objs, string header, | |||
GetDescFunc desc_clbk) { | |||
if (objs.length == 0) | |||
stdout.printf("No objects were found\n"); | |||
else { | |||
stdout.printf(header + ":\n"); | |||
foreach (var o in objs) { | |||
string desc = null; | |||
if (desc_clbk != null) { | |||
debug("calling description callback for obj: %s", | |||
o.to_string()); | |||
desc = desc_clbk(o); | |||
} | |||
stdout.printf(" %s", o.to_string()); | |||
if (desc != null) | |||
stdout.printf(" %s", desc); | |||
stdout.printf("\n"); | |||
} | |||
} | |||
} | |||
private delegate string GetDescFunc(ObjectPath obj_path); | |||
} | |||
} |