You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

110 lines
2.7 KiB

  1. use acme_common::error::Error;
  2. use std::fmt;
  3. use std::str::FromStr;
  4. fn clean_mailto(value: &str) -> Result<String, Error> {
  5. // TODO: implement a simple RFC 6068 parser
  6. // - no "hfields"
  7. // - max one "addr-spec" in the "to" component
  8. Ok(value.to_string())
  9. }
  10. // TODO: implement other URI shemes
  11. // https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
  12. // https://en.wikipedia.org/wiki/List_of_URI_schemes
  13. // Exemples:
  14. // - P1: tel, sms
  15. // - P2: geo, maps
  16. // - P3: irc, irc6, ircs, xmpp
  17. // - P4: sip, sips
  18. #[derive(Clone, Debug, PartialEq)]
  19. pub enum ContactType {
  20. Mailto,
  21. }
  22. impl ContactType {
  23. pub fn clean_value(&self, value: &str) -> Result<String, Error> {
  24. match self {
  25. ContactType::Mailto => clean_mailto(value),
  26. }
  27. }
  28. }
  29. impl FromStr for ContactType {
  30. type Err = Error;
  31. fn from_str(s: &str) -> Result<Self, Error> {
  32. match s.to_lowercase().as_str() {
  33. "mailto" => Ok(ContactType::Mailto),
  34. _ => Err(format!("{}: unknown contact type.", s).into()),
  35. }
  36. }
  37. }
  38. impl fmt::Display for ContactType {
  39. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  40. let s = match self {
  41. ContactType::Mailto => "mailto",
  42. };
  43. write!(f, "{}", s)
  44. }
  45. }
  46. #[derive(Clone, Debug, PartialEq)]
  47. pub struct AccountContact {
  48. pub contact_type: ContactType,
  49. pub value: String,
  50. }
  51. impl AccountContact {
  52. pub fn new(contact_type: &str, value: &str) -> Result<Self, Error> {
  53. let contact_type: ContactType = contact_type.parse()?;
  54. let value = contact_type.clean_value(value)?;
  55. Ok(AccountContact {
  56. contact_type,
  57. value,
  58. })
  59. }
  60. }
  61. impl fmt::Display for AccountContact {
  62. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  63. write!(f, "{}:{}", self.contact_type, self.value)
  64. }
  65. }
  66. #[cfg(test)]
  67. mod tests {
  68. use super::*;
  69. #[test]
  70. fn test_account_contact_eq() {
  71. let c1 = AccountContact::new("mailto", "derp.derpson@example.com").unwrap();
  72. let c2 = AccountContact::new("mailto", "derp.derpson@example.com").unwrap();
  73. let c3 = AccountContact::new("mailto", "derp@example.com").unwrap();
  74. assert_eq!(c1, c2);
  75. assert_eq!(c2, c1);
  76. assert_ne!(c1, c3);
  77. assert_ne!(c2, c3);
  78. }
  79. #[test]
  80. fn test_account_contact_in_vec() {
  81. let contacts = vec![
  82. AccountContact::new("mailto", "derp.derpson@example.com").unwrap(),
  83. AccountContact::new("mailto", "derp@example.com").unwrap(),
  84. ];
  85. let c = AccountContact::new("mailto", "derp@example.com").unwrap();
  86. assert!(contacts.contains(&c));
  87. }
  88. #[test]
  89. fn test_account_contact_not_in_vec() {
  90. let contacts = vec![
  91. AccountContact::new("mailto", "derp.derpson@example.com").unwrap(),
  92. AccountContact::new("mailto", "derp@example.com").unwrap(),
  93. ];
  94. let c = AccountContact::new("mailto", "derpina@example.com").unwrap();
  95. assert!(!contacts.contains(&c));
  96. }
  97. }