use hashbrown::HashMap;
#[cfg(not(feature = "std"))]
use alloc::{string::{String, ToString}, format};
use serde::{Deserialize, Serialize, de::Error};
use serde_json::Value;
use crate::io::{TcpStreamImpl, TlsStreamImpl};
pub mod battery;
pub mod clipboard;
pub mod connectivity_report;
pub mod contacts;
pub mod digitizer;
pub mod identity;
pub mod lock;
pub mod mousepad;
pub mod mpris;
pub mod notification;
pub mod pair;
pub mod ping;
pub mod presenter;
pub mod runcommand;
pub mod sftp;
pub mod share;
pub mod sms;
pub mod system_volume;
pub mod telephony;
pub(super) fn deserialize_number_or_string<'de, D: serde::Deserializer<'de>>(
de: D,
) -> Result<u64, D::Error> {
match Value::deserialize(de)? {
Value::Number(n) => n
.as_u64()
.ok_or_else(|| Error::custom("JSON number cannot be converted to u64")),
Value::String(s) => s
.parse::<u64>()
.map_err(|e| Error::custom(format!("String cannot be parsed as u64: {e}"))),
_ => Err(Error::custom("unknown type, expected number or string")),
}
}
pub(super) fn deserialize_number_or_string_in_option<'de, D: serde::Deserializer<'de>>(
de: D,
) -> Result<Option<u64>, D::Error> {
match Value::deserialize(de)? {
Value::Number(n) => {
Ok(Some(n.as_u64().ok_or_else(|| {
Error::custom("JSON number cannot be converted to u64")
})?))
}
Value::String(s) => {
Ok(Some(s.parse::<u64>().map_err(|e| {
Error::custom(format!("String cannot be parsed as u64: {e}"))
})?))
}
_ => Err(Error::custom("unknown type, expected number or string")),
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type", content = "body")]
pub enum NetworkPacketBody {
#[serde(rename = "kdeconnect.identity")]
Identity(identity::IdentityPacket),
#[serde(rename = "kdeconnect.pair")]
Pair(pair::PairPacket),
#[serde(rename = "kdeconnect.battery")]
Battery(battery::BatteryPacket),
#[serde(rename = "kdeconnect.clipboard")]
Clipboard(clipboard::ClipboardPacket),
#[serde(rename = "kdeconnect.clipboard.connect")]
ClipboardConnect(clipboard::ClipboardConnectPacket),
#[serde(rename = "kdeconnect.connectivity_report")]
ConnectivityReport(connectivity_report::ConnectivityReportPacket),
#[serde(rename = "kdeconnect.contacts.request_all_uids_timestamps")]
ContactsRequestAllUidsTimestamps(()),
#[serde(rename = "kdeconnect.contacts.request_vcards_by_uid")]
ContactsRequestVcardByUid(contacts::ContactsRequestVcardsByUid),
#[serde(rename = "kdeconnect.contacts.response_uids_timestamps")]
ContactsResponseUidsTimestamps(contacts::ContactsResponseUidsTimestamp),
#[serde(rename = "kdeconnect.contacts.response_vcards")]
ContactsResponseVcards(contacts::ContactsResponseVcards),
#[serde(rename = "kdeconnect.digitizer.session")]
DigitizerSession(digitizer::DigitizerSessionPacket),
#[serde(rename = "kdeconnect.digitizer")]
Digitizer(digitizer::DigitizerPacket),
#[serde(rename = "kdeconnect.findmyphone.request")]
FindmyphoneRequest(()),
#[serde(rename = "kdeconnect.lock")]
Lock(lock::LockPacket),
#[serde(rename = "kdeconnect.lock.request")]
LockRequest(lock::LockRequestPacket),
#[serde(rename = "kdeconnect.mousepad.echo")]
MousepadEcho(mousepad::MousepadEchoPacket),
#[serde(rename = "kdeconnect.mousepad.keyboardstate")]
MousepadKeyboardState(mousepad::MousepadKeyboardStatePacket),
#[serde(rename = "kdeconnect.mousepad.request")]
MousepadRequest(mousepad::MousepadRequestPacket),
#[serde(rename = "kdeconnect.mpris")]
Mpris(mpris::MprisPacket),
#[serde(rename = "kdeconnect.mpris.request")]
MprisRequest(mpris::MprisRequestPacket),
#[serde(rename = "kdeconnect.notification")]
Notification(notification::NotificationPacket),
#[serde(rename = "kdeconnect.notification.action")]
NotificationAction(notification::NotificationActionPacket),
#[serde(rename = "kdeconnect.notification.reply")]
NotificationReply(notification::NotificationReplyPacket),
#[serde(rename = "kdeconnect.notification.request")]
NotificationRequest(notification::NotificationRequestPacket),
#[serde(rename = "kdeconnect.ping")]
Ping(ping::PingPacket),
#[serde(rename = "kdeconnect.presenter")]
Presenter(presenter::PresenterPacket),
#[serde(rename = "kdeconnect.runcommand")]
RunCommand(runcommand::RunCommandPacket),
#[serde(rename = "kdeconnect.runcommand.request")]
RunCommandRequest(runcommand::RunCommandRequestPacket),
#[serde(rename = "kdeconnect.sftp")]
Sftp(sftp::SftpPacket),
#[serde(rename = "kdeconnect.sftp.request")]
SftpRequest(sftp::SftpRequestPacket),
#[serde(rename = "kdeconnect.share.request")]
ShareRequest(share::ShareRequestPacket),
#[serde(rename = "kdeconnect.share.request.update")]
ShareRequestUpdate(share::ShareRequestUpdatePacket),
#[serde(rename = "kdeconnect.sms.attachment_file")]
SmsAttachmentFile(sms::SmsAttachmentFilePacket),
#[serde(rename = "kdeconnect.sms.messages")]
SmsMessages(sms::SmsMessagesPacket),
#[serde(rename = "kdeconnect.sms.request")]
SmsRequest(sms::SmsRequestPacket),
#[serde(rename = "kdeconnect.sms.request_attachment")]
SmsRequestAttachment(sms::SmsRequestAttachmentPacket),
#[serde(rename = "kdeconnect.sms.request_conversation")]
SmsRequestConversation(sms::SmsRequestConversationPacket),
#[serde(rename = "kdeconnect.sms.request_conversations")]
SmsRequestConversations(()),
#[serde(rename = "kdeconnect.systemvolume")]
SystemVolume(system_volume::SystemVolumePacket),
#[serde(rename = "kdeconnect.systemvolume.request")]
SystemVolumeRequest(system_volume::SystemVolumeRequestPacket),
#[serde(rename = "kdeconnect.telephony")]
Telephony(telephony::TelephonyPacket),
#[serde(rename = "kdeconnect.telephony.request_mute")]
TelephonyRequestMute(()),
#[serde(untagged)]
Other(Value),
}
impl NetworkPacketBody {
pub fn get_type(&self) -> NetworkPacketType {
match self {
NetworkPacketBody::Identity(_) => NetworkPacketType::Identity,
NetworkPacketBody::Pair(_) => NetworkPacketType::Pair,
NetworkPacketBody::Ping(_) => NetworkPacketType::Ping,
NetworkPacketBody::Battery(_) => NetworkPacketType::Battery,
NetworkPacketBody::Clipboard(_) => NetworkPacketType::Clipboard,
NetworkPacketBody::ClipboardConnect(_) => NetworkPacketType::ClipboardConnect,
NetworkPacketBody::ConnectivityReport(_) => NetworkPacketType::ConnectivityReport,
NetworkPacketBody::ContactsRequestAllUidsTimestamps(()) => {
NetworkPacketType::ContactsRequestAllUidsTimestamps
}
NetworkPacketBody::ContactsRequestVcardByUid(_) => {
NetworkPacketType::ContactsRequestVcardByUid
}
NetworkPacketBody::ContactsResponseUidsTimestamps(_) => {
NetworkPacketType::ContactsResponseUidsTimestamps
}
NetworkPacketBody::ContactsResponseVcards(_) => {
NetworkPacketType::ContactsResponseVcards
}
NetworkPacketBody::DigitizerSession(_) => NetworkPacketType::DigitizerSession,
NetworkPacketBody::Digitizer(_) => NetworkPacketType::Digitizer,
NetworkPacketBody::FindmyphoneRequest(()) => NetworkPacketType::FindmyphoneRequest,
NetworkPacketBody::Lock(_) => NetworkPacketType::Lock,
NetworkPacketBody::LockRequest(_) => NetworkPacketType::LockRequest,
NetworkPacketBody::MousepadEcho(_) => NetworkPacketType::MousepadEcho,
NetworkPacketBody::MousepadKeyboardState(_) => NetworkPacketType::MousepadKeyboardState,
NetworkPacketBody::MousepadRequest(_) => NetworkPacketType::MousepadRequest,
NetworkPacketBody::Mpris(_) => NetworkPacketType::Mpris,
NetworkPacketBody::MprisRequest(_) => NetworkPacketType::MprisRequest,
NetworkPacketBody::Notification(_) => NetworkPacketType::Notification,
NetworkPacketBody::NotificationAction(_) => NetworkPacketType::NotificationAction,
NetworkPacketBody::NotificationReply(_) => NetworkPacketType::NotificationReply,
NetworkPacketBody::NotificationRequest(_) => NetworkPacketType::NotificationRequest,
NetworkPacketBody::Presenter(_) => NetworkPacketType::Presenter,
NetworkPacketBody::RunCommand(_) => NetworkPacketType::RunCommand,
NetworkPacketBody::RunCommandRequest(_) => NetworkPacketType::RunCommandRequest,
NetworkPacketBody::Sftp(_) => NetworkPacketType::Sftp,
NetworkPacketBody::SftpRequest(_) => NetworkPacketType::SftpRequest,
NetworkPacketBody::ShareRequest(_) => NetworkPacketType::ShareRequest,
NetworkPacketBody::ShareRequestUpdate(_) => NetworkPacketType::ShareRequestUpdate,
NetworkPacketBody::SmsAttachmentFile(_) => NetworkPacketType::SmsAttachmentFile,
NetworkPacketBody::SmsMessages(_) => NetworkPacketType::SmsMessages,
NetworkPacketBody::SmsRequest(_) => NetworkPacketType::SmsRequest,
NetworkPacketBody::SmsRequestAttachment(_) => NetworkPacketType::SmsRequestAttachment,
NetworkPacketBody::SmsRequestConversation(_) => {
NetworkPacketType::SmsRequestConversation
}
NetworkPacketBody::SmsRequestConversations(()) => {
NetworkPacketType::SmsRequestConversations
}
NetworkPacketBody::SystemVolume(_) => NetworkPacketType::SystemVolume,
NetworkPacketBody::SystemVolumeRequest(_) => NetworkPacketType::SystemVolumeRequest,
NetworkPacketBody::Telephony(_) => NetworkPacketType::Telephony,
NetworkPacketBody::TelephonyRequestMute(()) => NetworkPacketType::TelephonyRequestMute,
NetworkPacketBody::Other(value) => NetworkPacketType::Other(
value
.get("type")
.unwrap_or(&Value::String("Unknown".into()))
.as_str()
.unwrap_or("Unknown")
.to_string(),
),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub enum NetworkPacketType {
#[serde(rename = "kdeconnect.identity")]
Identity,
#[serde(rename = "kdeconnect.pair")]
Pair,
#[serde(rename = "kdeconnect.battery")]
Battery,
#[serde(rename = "kdeconnect.clipboard")]
Clipboard,
#[serde(rename = "kdeconnect.clipboard.connect")]
ClipboardConnect,
#[serde(rename = "kdeconnect.connectivity_report")]
ConnectivityReport,
#[serde(rename = "kdeconnect.contacts.request_all_uids_timestamps")]
ContactsRequestAllUidsTimestamps,
#[serde(rename = "kdeconnect.contacts.request_vcards_by_uid")]
ContactsRequestVcardByUid,
#[serde(rename = "kdeconnect.contacts.response_uids_timestamps")]
ContactsResponseUidsTimestamps,
#[serde(rename = "kdeconnect.contacts.response_vcards")]
ContactsResponseVcards,
#[serde(rename = "kdeconnect.digitizer.session")]
DigitizerSession,
#[serde(rename = "kdeconnect.digitizer")]
Digitizer,
#[serde(rename = "kdeconnect.findmyphone.request")]
FindmyphoneRequest,
#[serde(rename = "kdeconnect.lock")]
Lock,
#[serde(rename = "kdeconnect.lock.request")]
LockRequest,
#[serde(rename = "kdeconnect.mousepad.echo")]
MousepadEcho,
#[serde(rename = "kdeconnect.mousepad.keyboardstate")]
MousepadKeyboardState,
#[serde(rename = "kdeconnect.mousepad.request")]
MousepadRequest,
#[serde(rename = "kdeconnect.mpris")]
Mpris,
#[serde(rename = "kdeconnect.mpris.request")]
MprisRequest,
#[serde(rename = "kdeconnect.notification")]
Notification,
#[serde(rename = "kdeconnect.notification.action")]
NotificationAction,
#[serde(rename = "kdeconnect.notification.reply")]
NotificationReply,
#[serde(rename = "kdeconnect.notification.request")]
NotificationRequest,
#[serde(rename = "kdeconnect.ping")]
Ping,
#[serde(rename = "kdeconnect.presenter")]
Presenter,
#[serde(rename = "kdeconnect.runcommand")]
RunCommand,
#[serde(rename = "kdeconnect.runcommand.request")]
RunCommandRequest,
#[serde(rename = "kdeconnect.sftp")]
Sftp,
#[serde(rename = "kdeconnect.sftp.request")]
SftpRequest,
#[serde(rename = "kdeconnect.share.request")]
ShareRequest,
#[serde(rename = "kdeconnect.share.request.update")]
ShareRequestUpdate,
#[serde(rename = "kdeconnect.sms.attachment_file")]
SmsAttachmentFile,
#[serde(rename = "kdeconnect.sms.messages")]
SmsMessages,
#[serde(rename = "kdeconnect.sms.request")]
SmsRequest,
#[serde(rename = "kdeconnect.sms.request_attachment")]
SmsRequestAttachment,
#[serde(rename = "kdeconnect.sms.request_conversation")]
SmsRequestConversation,
#[serde(rename = "kdeconnect.sms.request_conversations")]
SmsRequestConversations,
#[serde(rename = "kdeconnect.systemvolume")]
SystemVolume,
#[serde(rename = "kdeconnect.systemvolume.request")]
SystemVolumeRequest,
#[serde(rename = "kdeconnect.telephony")]
Telephony,
#[serde(rename = "kdeconnect.telephony.request_mute")]
TelephonyRequestMute,
#[serde(untagged)]
Other(String),
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct NetworkPacket {
#[serde(deserialize_with = "deserialize_number_or_string")]
id: u64,
#[serde(flatten)]
pub body: NetworkPacketBody,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub range: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub payload_transfer_info: Option<HashMap<String, Value>>,
}
impl NetworkPacket {
pub fn new(body: NetworkPacketBody) -> Self {
Self {
id: 0,
body,
range: None,
payload_transfer_info: None,
}
}
pub(crate) fn try_read_from(buf: &[u8]) -> Result<Self, serde_json::Error> {
serde_json::from_slice::<NetworkPacket>(buf)
}
pub(crate) async fn write_to_socket_unencrypted<T: TcpStreamImpl + Unpin>(self, socket: &mut T) {
let mut serialized_packet = serde_json::to_string(&self).unwrap();
serialized_packet.push('\n');
socket
.write_all(serialized_packet.as_bytes())
.await
.unwrap();
}
pub(crate) async fn write_to_socket<T: TlsStreamImpl + Unpin>(self, socket: &mut T) {
let mut serialized_packet = serde_json::to_string(&self).unwrap();
serialized_packet.push('\n');
socket
.write_all(serialized_packet.as_bytes())
.await
.unwrap();
}
}