1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use crate::contact_platform::ContactPlatform;

#[cfg(feature = "read_write")]
use crate::read_write::error::FromComponentError;
#[cfg(feature = "read_write")]
use crate::read_write::component::Component;

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct ContactInformation {
    // The pid, used for representing this
    pub pid: String,

    /// The Preference Value. In this implementation 0 represents that it is
    /// neutral, not either way.
    pub pref: u8,

    /// The Value (for example johndoe@example.com)
    pub value: String,

    /// The platform which this is on
    pub platform: ContactPlatform,

    /// The type
    pub typ: Option<Type>,
}

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(
    feature = "diesel-derive-enum",
    derive(DbEnum),
    DieselType = "Contack_contact_information_type",
    db_rename = "Contack_contact_information_type"
)]
pub enum Type {
    Work,
    Home,
}

impl ContactInformation {
    /// Creates a new Contact Information
    #[must_use]
    pub fn new(string: String, platform: ContactPlatform) -> Self {
        Self {
            pref: 0,
            value: string,
            pid: format!("{}", rand::random::<u64>() % 100),
            platform,
            typ: None,
        }
    }
}

#[cfg(feature = "read_write")]
impl From<ContactInformation> for Component {
    fn from(ci: ContactInformation) -> Self {
        Self {
            // No group
            group: None,

            // Name of platform
            name: match ci.platform {
                ContactPlatform::Email => "EMAIL",
                ContactPlatform::Tel => "TEL",
                ContactPlatform::Discord => "X-DISCORD",
                ContactPlatform::Matrix => "X-MATRIX",
                ContactPlatform::Skype => "X-SKYPE",
                ContactPlatform::Aim => "X-AIM",
                ContactPlatform::Jabber => "X-JABBER",
                ContactPlatform::Icq => "X-ICQ",
                ContactPlatform::Groupwise => "X-GROUPWISE",
                ContactPlatform::Gadugadu => "X-GADUGADU",
                ContactPlatform::Unknown => "IMPP",
            }
            .to_string(),

            // Parameters
            parameters: {
                // HashMap
                let mut hashmap = std::collections::HashMap::new();

                // Append the preference value.
                if ci.pref != 0 {
                    hashmap.insert("PREF".to_string(), ci.pref.to_string());
                }

                // Append the type
                if let Some(typ) = ci.typ {
                    hashmap.insert(
                        "TYPE".to_string(),
                        match typ {
                            Type::Home => "home",
                            Type::Work => "work",
                        }
                        .to_string(),
                    );
                }

                // And the pid
                hashmap.insert("PID".to_string(), ci.pid.to_string());

                hashmap
            },

            values: vec![vec![ci.value]],
        }
    }
}

#[cfg(feature = "read_write")]
impl std::convert::TryFrom<Component> for ContactInformation {
    type Error = Box<dyn std::error::Error>;

    fn try_from(mut comp: Component) -> Result<Self, Self::Error> {
        Ok(Self {
            pid: comp
                .parameters
                .remove("PID")
                .unwrap_or(format!("{}", rand::random::<u64>() % 100)),
            pref: comp
                .parameters
                .remove("PREF")
                .map_or(Ok(0), |x| x.parse())?,
            value: comp
                .values
                .pop()
                .map(|mut x| x.pop())
                .unwrap_or_default()
                .ok_or(FromComponentError::NotEnoughValues)?,
            platform: match comp.name.as_str() {
                "EMAIL" => ContactPlatform::Email,
                "TEL" => ContactPlatform::Tel,
                "X-DISCORD" => ContactPlatform::Discord,
                "X-MATRIX" => ContactPlatform::Matrix,
                "X-SKYPE" => ContactPlatform::Skype,
                "X-AIM" => ContactPlatform::Aim,
                "X-JABBER" => ContactPlatform::Jabber,
                "X-ICQ" => ContactPlatform::Icq,
                "X-GROUPWISE" => ContactPlatform::Groupwise,
                "X-GADUGADU" => ContactPlatform::Gadugadu,
                _ => ContactPlatform::Unknown,
            },
            typ: comp
                .parameters
                .remove("TYPE")
                .map(|x| {
                    match x.to_lowercase().split(',').next().unwrap_or_default()
                    {
                        "home" => Some(Type::Home),
                        "work" => Some(Type::Work),
                        // Its not fair to throw an error since technically other
                        // values may be used.
                        _ => None,
                    }
                })
                .unwrap_or_default(),
        })
    }
}