|
|
- /* 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>
- */
-
- /**
- * General device wrapper.
- */
- class Device : Object {
-
- public signal void paired(bool pair);
- public signal void connected();
- public signal void disconnected();
- public signal void message(Packet pkt);
-
- 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 bool is_paired { get; private set; default = false; }
-
- // set to true if pair request was sent
- private bool _pair_in_progress = false;
-
- private DeviceChannel _channel = null;
-
- private Device() {
-
- }
-
- /**
- * Constructs a new Device wrapper based on identity packet.
- *
- * @param pkt identity packet
- * @param host source host that the packet came from
- */
- public Device.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");
-
- debug("added new device: %s", this.to_string());
- }
-
- ~Device() {
-
- }
-
- /**
- * Generates a unique string for this device
- */
- public string to_unique_string() {
- return this.to_string().replace(" ", "-");
- }
-
- public string to_string() {
- return "%s-%s-%s-%u".printf(this.device_id, this.device_name,
- this.device_type, this.protocol_version);
- }
-
- private async void greet() {
- string[] interfaces = {"kdeconnect.notification",
- "kdeconnect.battery",
- "kdeconnect.ping"};
- yield _channel.send(Packet.new_identity("test-laptop",
- "dadada",
- interfaces, interfaces));
- this.pair_if_needed();
- }
-
- /**
- * pair: sent pair request
- *
- * Internally changes pair requests state tracking.
- *
- * @param expect_response se to true if expecting a response
- */
- public async void pair(bool expect_response = true) {
- if (this.host != null) {
- debug("start pairing");
-
- var core = Core.instance();
- string pubkey = core.crypt.get_public_key_pem();
- debug("public key: %s", pubkey);
-
- if (expect_response == true)
- _pair_in_progress = true;
- yield _channel.send(Packet.new_pair(pubkey));
- }
- }
-
- public void pair_if_needed() {
- if (is_paired == false && _pair_in_progress == false)
- this.pair();
- }
-
- public void activate() {
- assert(_channel == null);
-
- var core = Core.instance();
- _channel = new DeviceChannel(this.host, this.tcp_port,
- core.crypt);
- _channel.connected.connect((c) => {
- this.greet();
- });
- _channel.disconnected.connect((c) => {
- this.handle_disconnect();
- });
- _channel.packet_received.connect((c, pkt) => {
- this.packet_received(pkt);
- });
- _channel.open();
- debug("open finished");
- }
-
- public void deactivate() {
- if (_channel == null)
- _channel.close();
- _channel = null;
- }
-
- /**
- * activate_from_device:
- *
- * Try to activate using a newly discovered device. If device is
- * already active, compare the host address to see if it
- * changed. If so, close the current connection and activate with
- * new address.
- *
- * @param dev device
- */
- public void activate_from_device(Device dev) {
- if (host == null) {
- activate();
- } else if (dev.host.to_string() != host.to_string()) {
- // same host, assuming no activation needed
- deactivate();
- activate();
- } else {
- debug("device %s already active", dev.to_string());
- }
- }
-
- private void packet_received(Packet pkt) {
- debug("got packet");
- if (pkt.pkt_type == Packet.PAIR) {
- // pairing
- handle_pair_packet(pkt);
- }
- }
-
- private void handle_pair_packet(Packet pkt) {
- assert(pkt.pkt_type == Packet.PAIR);
-
- bool pair = pkt.body.get_boolean_member("pair");
- if (_pair_in_progress == true) {
- // response to host initiated pairing
- if (pair == true) {
- debug("device is paired, pairing complete");
- this.is_paired = true;
- } else {
- critical("pairing rejected by device");
- this.is_paired = false;
- }
- // pair completed
- _pair_in_progress = false;
- } else {
- debug("unsolicited pair change from device");
- if (pair == false) {
- // unpair from device
- this.is_paired = false;
- } else {
- // pair request from device
- this.pair(false);
- }
- }
-
- // emit signal
- paired(is_paired);
- }
-
- private void handle_disconnect() {
- // channel got disconnected
- debug("channel disconnected");
- }
- }
|