/** * 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 * gyan000 */ using Json; public errordomain PacketError { MALFORMED } namespace MConnect { public class Packet : GLib.Object { public const int PROTOCOL_VERSION = 7; public const string IDENTITY = "kdeconnect.identity"; public const string PAIR = "kdeconnect.pair"; public const string ENCRYPTED = "kdeconnect.encrypted"; /** * Payload: * Wrapper for payload transfer information */ public struct Payload { public uint64 size; public uint port; } public string pkt_type { get; private set; default = ""; } public int64 id { get; private set; default = 0; } public Json.Object body { get; private set; default = null; } public Packet.Payload ? payload { get; set; default = null; } public Packet (string type, Json.Object body, int64 id = 0) { this.pkt_type = type; this.body = body; if (id == 0) { this.id = get_real_time () / 1000; } else { this.id = id; } } public static Packet ? new_from_data (string data) { Json.Parser jp = new Json.Parser (); try { jp.load_from_data (data, -1); // There should be an object at root node Json.Object root_obj = jp.get_root ().get_object (); if (root_obj == null) throw new PacketError.MALFORMED ("Missing root object"); // Object needs to have these fields string[] required_members = { "type", "id", "body" }; foreach (string m in required_members) { if (root_obj.has_member (m) == false) throw new PacketError.MALFORMED (@"Missing $m member"); } string type = root_obj.get_string_member ("type"); int64 id = root_obj.get_int_member ("id"); Json.Object body = root_obj.get_object_member ("body"); debug ("Packet type: %s", type); var pkt = new Packet (type, body, id); // ignore payload info for encrypted packets if (type != ENCRYPTED) { if (root_obj.has_member ("payloadSize") && root_obj.has_member ("payloadTransferInfo")) { var size = root_obj.get_int_member ("payloadSize"); var pti = root_obj.get_object_member ("payloadTransferInfo"); int64 port = 0; if (pti == null) { warning ("No payload transfer info?"); } else { port = (int) pti.get_int_member ("port"); } if (size != 0 && port != 0) { pkt.payload = { (uint64) size, (uint) port }; } } } return pkt; } catch (Error e) { message ("Failed to parse message: \'%s\', error: %s", data, e.message); } return null; } public static Packet new_pair (bool pair = true) { var builder = new Json.Builder (); builder.begin_object (); builder.set_member_name ("pair"); builder.add_boolean_value (pair); builder.end_object (); var data_obj = builder.get_root ().get_object (); return new Packet (PAIR, data_obj); } public static Packet new_identity (string name, string device_id, string[] in_interfaces, string[] out_interfaces, string device_type = "desktop") { var builder = new Json.Builder (); builder.begin_object (); builder.set_member_name ("deviceName"); builder.add_string_value (name); builder.set_member_name ("deviceId"); builder.add_string_value (device_id); builder.set_member_name ("deviceType"); builder.add_string_value (device_type); builder.set_member_name ("SupportedIncomingInterfaces"); builder.add_string_value (string.joinv (",", in_interfaces)); builder.set_member_name ("SupportedOutgoingInterfaces"); builder.add_string_value (string.joinv (",", out_interfaces)); builder.set_member_name ("protocolVersion"); builder.add_int_value (PROTOCOL_VERSION); builder.end_object (); Json.Object data_obj = builder.get_root ().get_object (); return new Packet (IDENTITY, data_obj); } public string to_string (bool pretty_format = false) { var gen = new Json.Generator (); var root = new Json.Node (Json.NodeType.OBJECT); var root_obj = new Json.Object (); root_obj.set_string_member ("type", pkt_type); root_obj.set_int_member ("id", id); root_obj.set_object_member ("body", body); if (this.payload != null) { root_obj.set_int_member ("payloadSize", (int64) this.payload.size); var pti = new Json.Object (); pti.set_int_member ("port", this.payload.port); root_obj.set_object_member ("payloadTransferInfo", pti); } root.set_object (root_obj); gen.set_root (root); gen.set_pretty (pretty_format); return gen.to_data (null);; } } }