use super::{RawPacket, UsbmuxdConnection, errors::UsbmuxdError};
use crate::IdeviceError;
#[derive(Debug, Clone)]
pub enum UsbmuxdServerRequest {
ListDevices,
Listen,
ReadBuid,
ReadPairRecord {
pair_record_id: String,
},
SavePairRecord {
pair_record_id: Option<String>,
device_id: Option<u64>,
pair_record_data: Vec<u8>,
},
Connect {
device_id: u64,
port: u16,
},
}
impl UsbmuxdServerRequest {
pub fn decode(packet: &RawPacket) -> Result<Self, IdeviceError> {
let plist = &packet.plist;
let message_type = match plist.get("MessageType") {
Some(plist::Value::String(s)) => s.as_str(),
Some(_) => return Err(UsbmuxdError::UnexpectedFieldType("MessageType").into()),
None => return Err(UsbmuxdError::MissingField("MessageType").into()),
};
Ok(match message_type {
"ListDevices" => Self::ListDevices,
"Listen" => Self::Listen,
"ReadBUID" => Self::ReadBuid,
"ReadPairRecord" => Self::ReadPairRecord {
pair_record_id: get_string(plist, "PairRecordID")?,
},
"SavePairRecord" => {
let pair_record_data = match plist.get("PairRecordData") {
Some(plist::Value::Data(d)) => d.clone(),
Some(_) => {
return Err(UsbmuxdError::UnexpectedFieldType("PairRecordData").into());
}
None => return Err(UsbmuxdError::MissingField("PairRecordData").into()),
};
let pair_record_id = match plist.get("PairRecordID") {
Some(plist::Value::String(s)) => Some(s.clone()),
_ => None,
};
let device_id = match plist.get("DeviceID") {
Some(plist::Value::Integer(i)) => i.as_unsigned(),
_ => None,
};
Self::SavePairRecord {
pair_record_id,
device_id,
pair_record_data,
}
}
"Connect" => Self::Connect {
device_id: get_unsigned(plist, "DeviceID")?,
port: get_port(plist)?,
},
other => return Err(UsbmuxdError::UnknownMessageType(other.to_string()).into()),
})
}
}
#[derive(Debug, Clone)]
pub enum UsbmuxdServerResponse {
Result(u32),
DeviceList(Vec<plist::Value>),
PairRecord(Vec<u8>),
Buid(String),
Attached(plist::Dictionary),
Detached(u64),
}
impl UsbmuxdServerResponse {
pub fn into_dictionary(self) -> plist::Dictionary {
match self {
Self::Result(number) => crate::plist!(dict {
"MessageType": "Result",
"Number": number,
}),
Self::DeviceList(devices) => crate::plist!(dict {
"DeviceList": devices,
}),
Self::PairRecord(data) => crate::plist!(dict {
"PairRecordData": plist::Value::Data(data),
}),
Self::Buid(buid) => crate::plist!(dict {
"BUID": buid,
}),
Self::Attached(payload) => payload,
Self::Detached(device_id) => crate::plist!(dict {
"MessageType": "Detached",
"DeviceID": device_id,
}),
}
}
pub fn into_packet(self, tag: u32) -> RawPacket {
RawPacket::new(
self.into_dictionary(),
UsbmuxdConnection::XML_PLIST_VERSION,
UsbmuxdConnection::PLIST_MESSAGE_TYPE,
tag,
)
}
}
fn get_string(plist: &plist::Dictionary, key: &'static str) -> Result<String, UsbmuxdError> {
match plist.get(key) {
Some(plist::Value::String(s)) => Ok(s.clone()),
Some(_) => Err(UsbmuxdError::UnexpectedFieldType(key)),
None => Err(UsbmuxdError::MissingField(key)),
}
}
fn get_unsigned(plist: &plist::Dictionary, key: &'static str) -> Result<u64, UsbmuxdError> {
match plist.get(key) {
Some(plist::Value::Integer(i)) => i
.as_unsigned()
.ok_or(UsbmuxdError::UnexpectedFieldType(key)),
Some(_) => Err(UsbmuxdError::UnexpectedFieldType(key)),
None => Err(UsbmuxdError::MissingField(key)),
}
}
fn get_port(plist: &plist::Dictionary) -> Result<u16, UsbmuxdError> {
let raw = match plist.get("PortNumber") {
Some(plist::Value::Integer(i)) => {
if let Some(u) = i.as_unsigned() {
u as u16
} else if let Some(s) = i.as_signed() {
s as u16
} else {
return Err(UsbmuxdError::UnexpectedFieldType("PortNumber"));
}
}
Some(_) => return Err(UsbmuxdError::UnexpectedFieldType("PortNumber")),
None => return Err(UsbmuxdError::MissingField("PortNumber")),
};
Ok(raw.to_be())
}