Skip to content

Commit

Permalink
api: add mailto parse api (#4829)
Browse files Browse the repository at this point in the history
close #4620 

This PR introduces a new core API to parse mailto links into a uniform
data format. This could be used to unify the different implementations
on the current platforms.
To complete this PR we have to decide for which APIs we want to expose
this (now) internal API (c, python, json-rpc, etc.), and if we want such
an API at all as it doesn't have a corresponding UI-PR and is not
_really_ needed.
  • Loading branch information
Septias authored Oct 26, 2023
1 parent 25a78ac commit 7399a39
Showing 1 changed file with 89 additions and 1 deletion.
90 changes: 89 additions & 1 deletion src/tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use mailparse::headers::Headers;
use mailparse::MailHeaderMap;
use rand::{thread_rng, Rng};
use tokio::{fs, io};
use url::Url;

use crate::chat::{add_device_msg, add_device_msg_with_importance};
use crate::constants::{DC_ELLIPSIS, DC_OUTDATED_WARNING_DAYS};
Expand Down Expand Up @@ -481,7 +482,43 @@ pub(crate) fn time() -> i64 {
.as_secs() as i64
}

/// Very simple email address wrapper.
/// Struct containing all mailto information
#[derive(Debug, Default, Eq, PartialEq)]
pub struct MailTo {
pub to: Vec<EmailAddress>,
pub subject: Option<String>,
pub body: Option<String>,
}

/// Parse mailto urls
pub fn parse_mailto(mailto_url: &str) -> Option<MailTo> {
if let Ok(url) = Url::parse(mailto_url) {
if url.scheme() == "mailto" {
let mut mailto: MailTo = Default::default();
// Extract the email address
url.path().split(',').for_each(|email| {
if let Ok(email) = EmailAddress::new(email) {
mailto.to.push(email);
}
});

// Extract query parameters
for (key, value) in url.query_pairs() {
if key == "subject" {
mailto.subject = Some(value.to_string());
} else if key == "body" {
mailto.body = Some(value.to_string());
}
}
Some(mailto)
} else {
None
}
} else {
None
}
}

///
/// Represents an email address, right now just the `name@domain` portion.
///
Expand Down Expand Up @@ -1283,4 +1320,55 @@ DKIM Results: Passed=true, Works=true, Allow_Keychange=true";
assert_eq!(remove_subject_prefix("Fwd: Subject"), "Subject");
assert_eq!(remove_subject_prefix("Fw: Subject"), "Subject");
}

#[test]
fn test_parse_mailto() {
let mailto_url = "mailto:[email protected]";
let reps = parse_mailto(mailto_url);
assert_eq!(
Some(MailTo {
to: vec![EmailAddress {
local: "someone".to_string(),
domain: "example.com".to_string()
}],
subject: None,
body: None
}),
reps
);

let mailto_url = "mailto:[email protected]?subject=Hello%20World";
let reps = parse_mailto(mailto_url);
assert_eq!(
Some(MailTo {
to: vec![EmailAddress {
local: "someone".to_string(),
domain: "example.com".to_string()
}],
subject: Some("Hello World".to_string()),
body: None
}),
reps
);

let mailto_url = "mailto:[email protected],[email protected]?subject=Hello%20World&body=This%20is%20a%20test";
let reps = parse_mailto(mailto_url);
assert_eq!(
Some(MailTo {
to: vec![
EmailAddress {
local: "someone".to_string(),
domain: "example.com".to_string()
},
EmailAddress {
local: "someoneelse".to_string(),
domain: "example.com".to_string()
}
],
subject: Some("Hello World".to_string()),
body: Some("This is a test".to_string())
}),
reps
);
}
}

0 comments on commit 7399a39

Please sign in to comment.