mirror of
https://github.com/chatmail/core.git
synced 2026-04-28 10:56:29 +03:00
Merge pull request #3492 from deltachat/adb/qr-mailto-draft
Detect draft from QR with mailto data
This commit is contained in:
78
src/qr.rs
78
src/qr.rs
@@ -61,6 +61,7 @@ pub enum Qr {
|
||||
},
|
||||
Addr {
|
||||
contact_id: ContactId,
|
||||
draft: Option<String>,
|
||||
},
|
||||
Url {
|
||||
url: String,
|
||||
@@ -451,15 +452,52 @@ pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<()> {
|
||||
async fn decode_mailto(context: &Context, qr: &str) -> Result<Qr> {
|
||||
let payload = &qr[MAILTO_SCHEME.len()..];
|
||||
|
||||
let addr = if let Some(query_index) = payload.find('?') {
|
||||
&payload[..query_index]
|
||||
let (addr, query) = if let Some(query_index) = payload.find('?') {
|
||||
(&payload[..query_index], &payload[query_index + 1..])
|
||||
} else {
|
||||
payload
|
||||
(payload, "")
|
||||
};
|
||||
|
||||
let param: BTreeMap<&str, &str> = query
|
||||
.split('&')
|
||||
.filter_map(|s| {
|
||||
if let [key, value] = s.splitn(2, '=').collect::<Vec<_>>()[..] {
|
||||
Some((key, value))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let subject = if let Some(subject) = param.get("subject") {
|
||||
subject.to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
let draft = if let Some(body) = param.get("body") {
|
||||
if subject.is_empty() {
|
||||
body.to_string()
|
||||
} else {
|
||||
subject + "\n" + body
|
||||
}
|
||||
} else {
|
||||
subject
|
||||
};
|
||||
let draft = draft.replace('+', "%20"); // sometimes spaces are encoded as `+`
|
||||
let draft = match percent_decode_str(&draft).decode_utf8() {
|
||||
Ok(decoded_draft) => decoded_draft.to_string(),
|
||||
Err(_err) => draft,
|
||||
};
|
||||
|
||||
let addr = normalize_address(addr)?;
|
||||
let name = "".to_string();
|
||||
Qr::from_address(context, name, addr).await
|
||||
Qr::from_address(
|
||||
context,
|
||||
name,
|
||||
addr,
|
||||
if draft.is_empty() { None } else { Some(draft) },
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Extract address for the smtp scheme.
|
||||
@@ -477,7 +515,7 @@ async fn decode_smtp(context: &Context, qr: &str) -> Result<Qr> {
|
||||
|
||||
let addr = normalize_address(addr)?;
|
||||
let name = "".to_string();
|
||||
Qr::from_address(context, name, addr).await
|
||||
Qr::from_address(context, name, addr, None).await
|
||||
}
|
||||
|
||||
/// Extract address for the matmsg scheme.
|
||||
@@ -502,7 +540,7 @@ async fn decode_matmsg(context: &Context, qr: &str) -> Result<Qr> {
|
||||
|
||||
let addr = normalize_address(addr)?;
|
||||
let name = "".to_string();
|
||||
Qr::from_address(context, name, addr).await
|
||||
Qr::from_address(context, name, addr, None).await
|
||||
}
|
||||
|
||||
static VCARD_NAME_RE: Lazy<regex::Regex> =
|
||||
@@ -531,14 +569,19 @@ async fn decode_vcard(context: &Context, qr: &str) -> Result<Qr> {
|
||||
bail!("Bad e-mail address");
|
||||
};
|
||||
|
||||
Qr::from_address(context, name, addr).await
|
||||
Qr::from_address(context, name, addr, None).await
|
||||
}
|
||||
|
||||
impl Qr {
|
||||
pub async fn from_address(context: &Context, name: String, addr: String) -> Result<Self> {
|
||||
pub async fn from_address(
|
||||
context: &Context,
|
||||
name: String,
|
||||
addr: String,
|
||||
draft: Option<String>,
|
||||
) -> Result<Self> {
|
||||
let (contact_id, _) =
|
||||
Contact::add_or_lookup(context, &name, &addr, Origin::UnhandledQrScan).await?;
|
||||
Ok(Qr::Addr { contact_id })
|
||||
Ok(Qr::Addr { contact_id, draft })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,12 +662,13 @@ mod tests {
|
||||
"BEGIN:VCARD\nVERSION:3.0\nN:Last;First\nEMAIL;TYPE=INTERNET:stress@test.local\nEND:VCARD"
|
||||
).await?;
|
||||
|
||||
if let Qr::Addr { contact_id } = qr {
|
||||
if let Qr::Addr { contact_id, draft } = qr {
|
||||
let contact = Contact::get_by_id(&ctx.ctx, contact_id).await?;
|
||||
assert_eq!(contact.get_addr(), "stress@test.local");
|
||||
assert_eq!(contact.get_name(), "First Last");
|
||||
assert_eq!(contact.get_authname(), "");
|
||||
assert_eq!(contact.get_display_name(), "First Last");
|
||||
assert!(draft.is_none());
|
||||
} else {
|
||||
bail!("Wrong QR code type");
|
||||
}
|
||||
@@ -642,9 +686,10 @@ mod tests {
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Qr::Addr { contact_id } = qr {
|
||||
if let Qr::Addr { contact_id, draft } = qr {
|
||||
let contact = Contact::get_by_id(&ctx.ctx, contact_id).await?;
|
||||
assert_eq!(contact.get_addr(), "stress@test.local");
|
||||
assert!(draft.is_none());
|
||||
} else {
|
||||
bail!("Wrong QR code type");
|
||||
}
|
||||
@@ -658,20 +703,22 @@ mod tests {
|
||||
|
||||
let qr = check_qr(
|
||||
&ctx.ctx,
|
||||
"mailto:stress@test.local?subject=hello&body=world",
|
||||
"mailto:stress@test.local?subject=hello&body=beautiful+world",
|
||||
)
|
||||
.await?;
|
||||
if let Qr::Addr { contact_id } = qr {
|
||||
if let Qr::Addr { contact_id, draft } = qr {
|
||||
let contact = Contact::get_by_id(&ctx.ctx, contact_id).await?;
|
||||
assert_eq!(contact.get_addr(), "stress@test.local");
|
||||
assert_eq!(draft.unwrap(), "hello\nbeautiful world");
|
||||
} else {
|
||||
bail!("Wrong QR code type");
|
||||
}
|
||||
|
||||
let res = check_qr(&ctx.ctx, "mailto:no-questionmark@example.org").await?;
|
||||
if let Qr::Addr { contact_id } = res {
|
||||
if let Qr::Addr { contact_id, draft } = res {
|
||||
let contact = Contact::get_by_id(&ctx.ctx, contact_id).await?;
|
||||
assert_eq!(contact.get_addr(), "no-questionmark@example.org");
|
||||
assert!(draft.is_none());
|
||||
} else {
|
||||
bail!("Wrong QR code type");
|
||||
}
|
||||
@@ -686,11 +733,12 @@ mod tests {
|
||||
async fn test_decode_smtp() -> Result<()> {
|
||||
let ctx = TestContext::new().await;
|
||||
|
||||
if let Qr::Addr { contact_id } =
|
||||
if let Qr::Addr { contact_id, draft } =
|
||||
check_qr(&ctx.ctx, "SMTP:stress@test.local:subjecthello:bodyworld").await?
|
||||
{
|
||||
let contact = Contact::get_by_id(&ctx.ctx, contact_id).await?;
|
||||
assert_eq!(contact.get_addr(), "stress@test.local");
|
||||
assert!(draft.is_none());
|
||||
} else {
|
||||
bail!("Wrong QR code type");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user