File indexing completed on 2024-12-22 04:41:42
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Albert Vaca Cintora <albertvaka@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 package org.kde.kdeconnect; 0008 0009 import org.apache.commons.io.IOUtils; 0010 import org.json.JSONArray; 0011 import org.json.JSONException; 0012 import org.json.JSONObject; 0013 0014 import java.io.ByteArrayInputStream; 0015 import java.io.IOException; 0016 import java.io.InputStream; 0017 import java.net.Socket; 0018 import java.util.ArrayList; 0019 import java.util.HashSet; 0020 import java.util.List; 0021 import java.util.Set; 0022 0023 public class NetworkPacket { 0024 0025 public final static String PACKET_TYPE_IDENTITY = "kdeconnect.identity"; 0026 public final static String PACKET_TYPE_PAIR = "kdeconnect.pair"; 0027 0028 public final static int PACKET_REPLACEID_MOUSEMOVE = 0; 0029 public final static int PACKET_REPLACEID_PRESENTERPOINTER = 1; 0030 0031 public static Set<String> protocolPacketTypes = new HashSet<String>() {{ 0032 add(PACKET_TYPE_IDENTITY); 0033 add(PACKET_TYPE_PAIR); 0034 }}; 0035 0036 private long mId; 0037 String mType; 0038 private JSONObject mBody; 0039 private Payload mPayload; 0040 private JSONObject mPayloadTransferInfo; 0041 private volatile boolean canceled; 0042 0043 private NetworkPacket() { 0044 0045 } 0046 0047 public NetworkPacket(String type) { 0048 mId = System.currentTimeMillis(); 0049 mType = type; 0050 mBody = new JSONObject(); 0051 mPayload = null; 0052 mPayloadTransferInfo = new JSONObject(); 0053 } 0054 0055 public boolean isCanceled() { return canceled; } 0056 public void cancel() { canceled = true; } 0057 0058 public String getType() { 0059 return mType; 0060 } 0061 0062 public long getId() { 0063 return mId; 0064 } 0065 0066 //Most commons getters and setters defined for convenience 0067 public String getString(String key) { 0068 return mBody.optString(key, ""); 0069 } 0070 0071 public String getString(String key, String defaultValue) { 0072 return mBody.optString(key, defaultValue); 0073 } 0074 0075 public void set(String key, String value) { 0076 if (value == null) return; 0077 try { 0078 mBody.put(key, value); 0079 } catch (Exception ignored) { 0080 } 0081 } 0082 0083 public int getInt(String key) { 0084 return mBody.optInt(key, -1); 0085 } 0086 0087 public int getInt(String key, int defaultValue) { 0088 return mBody.optInt(key, defaultValue); 0089 } 0090 0091 public void set(String key, int value) { 0092 try { 0093 mBody.put(key, value); 0094 } catch (Exception ignored) { 0095 } 0096 } 0097 0098 public long getLong(String key) { 0099 return mBody.optLong(key, -1); 0100 } 0101 0102 public long getLong(String key, long defaultValue) { 0103 return mBody.optLong(key, defaultValue); 0104 } 0105 0106 public void set(String key, long value) { 0107 try { 0108 mBody.put(key, value); 0109 } catch (Exception ignored) { 0110 } 0111 } 0112 0113 public boolean getBoolean(String key) { 0114 return mBody.optBoolean(key, false); 0115 } 0116 0117 public boolean getBoolean(String key, boolean defaultValue) { 0118 return mBody.optBoolean(key, defaultValue); 0119 } 0120 0121 public void set(String key, boolean value) { 0122 try { 0123 mBody.put(key, value); 0124 } catch (Exception ignored) { 0125 } 0126 } 0127 0128 public double getDouble(String key) { 0129 return mBody.optDouble(key, Double.NaN); 0130 } 0131 0132 public double getDouble(String key, double defaultValue) { 0133 return mBody.optDouble(key, defaultValue); 0134 } 0135 0136 public void set(String key, double value) { 0137 try { 0138 mBody.put(key, value); 0139 } catch (Exception ignored) { 0140 } 0141 } 0142 0143 public JSONArray getJSONArray(String key) { 0144 return mBody.optJSONArray(key); 0145 } 0146 0147 public void set(String key, JSONArray value) { 0148 try { 0149 mBody.put(key, value); 0150 } catch (Exception ignored) { 0151 } 0152 } 0153 0154 public JSONObject getJSONObject(String key) { 0155 return mBody.optJSONObject(key); 0156 } 0157 0158 public void set(String key, JSONObject value) { 0159 try { 0160 mBody.put(key, value); 0161 } catch (JSONException ignored) { 0162 } 0163 } 0164 0165 public Set<String> getStringSet(String key) { 0166 JSONArray jsonArray = mBody.optJSONArray(key); 0167 if (jsonArray == null) return null; 0168 Set<String> list = new HashSet<>(); 0169 int length = jsonArray.length(); 0170 for (int i = 0; i < length; i++) { 0171 try { 0172 String str = jsonArray.getString(i); 0173 list.add(str); 0174 } catch (Exception ignored) { 0175 } 0176 } 0177 return list; 0178 } 0179 0180 public Set<String> getStringSet(String key, Set<String> defaultValue) { 0181 if (mBody.has(key)) return getStringSet(key); 0182 else return defaultValue; 0183 } 0184 0185 public void set(String key, Set<String> value) { 0186 try { 0187 JSONArray jsonArray = new JSONArray(); 0188 for (String str : value) { 0189 jsonArray.put(str); 0190 } 0191 mBody.put(key, jsonArray); 0192 } catch (Exception ignored) { 0193 } 0194 } 0195 0196 public List<String> getStringList(String key) { 0197 JSONArray jsonArray = mBody.optJSONArray(key); 0198 if (jsonArray == null) return null; 0199 List<String> list = new ArrayList<>(); 0200 int length = jsonArray.length(); 0201 for (int i = 0; i < length; i++) { 0202 try { 0203 String str = jsonArray.getString(i); 0204 list.add(str); 0205 } catch (Exception ignored) { 0206 } 0207 } 0208 return list; 0209 } 0210 0211 public List<String> getStringList(String key, List<String> defaultValue) { 0212 if (mBody.has(key)) return getStringList(key); 0213 else return defaultValue; 0214 } 0215 0216 public void set(String key, List<String> value) { 0217 try { 0218 JSONArray jsonArray = new JSONArray(); 0219 for (String str : value) { 0220 jsonArray.put(str); 0221 } 0222 mBody.put(key, jsonArray); 0223 } catch (Exception ignored) { 0224 } 0225 } 0226 0227 public boolean has(String key) { 0228 return mBody.has(key); 0229 } 0230 0231 public String serialize() throws JSONException { 0232 JSONObject jo = new JSONObject(); 0233 jo.put("id", mId); 0234 jo.put("type", mType); 0235 jo.put("body", mBody); 0236 if (hasPayload()) { 0237 jo.put("payloadSize", mPayload.payloadSize); 0238 jo.put("payloadTransferInfo", mPayloadTransferInfo); 0239 } 0240 //QJSon does not escape slashes, but Java JSONObject does. Converting to QJson format. 0241 return jo.toString().replace("\\/", "/") + "\n"; 0242 } 0243 0244 static public NetworkPacket unserialize(String s) throws JSONException { 0245 0246 NetworkPacket np = new NetworkPacket(); 0247 JSONObject jo = new JSONObject(s); 0248 np.mId = jo.getLong("id"); 0249 np.mType = jo.getString("type"); 0250 np.mBody = jo.getJSONObject("body"); 0251 if (jo.has("payloadSize")) { 0252 np.mPayloadTransferInfo = jo.getJSONObject("payloadTransferInfo"); 0253 np.mPayload = new Payload(jo.getLong("payloadSize")); 0254 } else { 0255 np.mPayloadTransferInfo = new JSONObject(); 0256 np.mPayload = new Payload(0); 0257 } 0258 return np; 0259 } 0260 0261 public void setPayload(Payload payload) { mPayload = payload; } 0262 0263 public Payload getPayload() { 0264 return mPayload; 0265 } 0266 0267 public long getPayloadSize() { 0268 return mPayload == null ? 0 : mPayload.payloadSize; 0269 } 0270 0271 public boolean hasPayload() { 0272 return (mPayload != null && mPayload.payloadSize != 0); 0273 } 0274 0275 public boolean hasPayloadTransferInfo() { 0276 return (mPayloadTransferInfo.length() > 0); 0277 } 0278 0279 public JSONObject getPayloadTransferInfo() { 0280 return mPayloadTransferInfo; 0281 } 0282 0283 public void setPayloadTransferInfo(JSONObject payloadTransferInfo) { 0284 mPayloadTransferInfo = payloadTransferInfo; 0285 } 0286 0287 public static class Payload { 0288 private final InputStream inputStream; 0289 private final Socket inputSocket; 0290 private final long payloadSize; 0291 0292 public Payload(long payloadSize) { 0293 this((InputStream)null, payloadSize); 0294 } 0295 0296 public Payload(byte[] data) { 0297 this(new ByteArrayInputStream(data), data.length); 0298 } 0299 0300 /** 0301 * <b>NOTE: Do not use this to set an SSLSockets InputStream as the payload, use Payload(Socket, long) instead because of this <a href="https://issuetracker.google.com/issues/37018094">bug</a></b> 0302 */ 0303 public Payload(InputStream inputStream, long payloadSize) { 0304 this.inputSocket = null; 0305 this.inputStream = inputStream; 0306 this.payloadSize = payloadSize; 0307 } 0308 0309 public Payload(Socket inputSocket, long payloadSize) throws IOException { 0310 this.inputSocket = inputSocket; 0311 this.inputStream = inputSocket.getInputStream(); 0312 this.payloadSize = payloadSize; 0313 } 0314 0315 /** 0316 * <b>NOTE: Do not close the InputStream directly call Payload.close() instead, this is because of this <a href="https://issuetracker.google.com/issues/37018094">bug</a></b> 0317 */ 0318 public InputStream getInputStream() { return inputStream; } 0319 long getPayloadSize() { return payloadSize; } 0320 0321 public void close() { 0322 //TODO: If socket only close socket if that also closes the streams that is 0323 try { 0324 IOUtils.close(inputStream); 0325 } catch(IOException ignored) {} 0326 0327 try { 0328 IOUtils.close(inputSocket); 0329 } catch (IOException ignored) {} 0330 } 0331 } 0332 }