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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
//! `rust-gravatar` is a small Rust library that generates Gravatar image URLs
//! based on the
//! [official Gravatar specification](http://en.gravatar.com/site/implement/images/).
//!
//! Example
//! --------
//! ```ignore
//! extern crate gravatar;
//! use gravatar::{Gravatar, Rating};
//!
//! let mut g = Gravatar::new("email@example.com");
//! g.size = Some(150);
//! g.rating = Some(Rating::Pg);
//! assert_eq!(
//!     g.image_url(),
//!     "https://secure.gravatar.com/avatar/5658ffccee7f0ebfda2b226238b1eb6e\
//!      ?s=150&r=pg"
//! );
//! ```

extern crate crypto;
extern crate url;

use crypto::md5::Md5;
use crypto::digest::Digest;
use std::ascii::AsciiExt;
use url::Url;

/// The default image to display if the user's email does not have a Gravatar.
///
/// See http://en.gravatar.com/site/implement/images/#default-image.
#[derive(Clone,Debug)]
pub enum Default {
    /// The URL of an image file to display as the default.
    Url(String),

    /// Instead of loading an image, the Gravatar URL will return an
    /// HTTP 404 (File Not Found) response if the email is not found.
    Http404,

    /// A transparent PNG image.
    Blank,

    /// A simple, cartoon-style silhouetted outline of a person that does not
    /// vary by email hash.
    MysteryMan,

    /// A geometric pattern based on the email hash.
    Identicon,

    /// A "monster" with different colors, faces, etc. that are generated by the
    /// email hash.
    MonsterId,

    /// A face with different features and backgrounds, generated by the email
    /// hash.
    Wavatar,

    /// An 8-bit arcade-style pixelated face that is generated by the email
    /// hash.
    Retro
}

/// The maximum rating level for which Gravatar will show the user's image
/// instead of the specified default.
///
/// See http://en.gravatar.com/site/implement/images/#rating.
#[derive(Clone,Debug)]
pub enum Rating {
    /// Show "G"-rated images only.
    G,

    /// Show "PG"-rated images or lower only.
    Pg,

    /// Show "R"-rated images or lower only.
    R,

    /// Show all images, up to and including "X"-rated ones.
    X
}

/// Representation of a single Gravatar image URL.
#[derive(Clone,Debug)]
pub struct Gravatar {
    /// The email of the user whose Gravatar you are trying to get.
    pub email: String,

    /// The desired image size. If `None` is provided, then no size is passed to
    /// Gravatar, which will then use a default of 80px by 80px. Gravatar will
    /// only provide images between 1px and 2048px by size.
    ///
    /// For more information, see
    /// http://en.gravatar.com/site/implement/images/#size.
    ///
    /// **Default value:** `None`
    pub size: Option<u16>,

    /// The default image to use if the user does not have a Gravatar. If `None`
    /// is provided, then Gravatar returns a blue Gravatar logo. The default
    /// image can be either a URL or one of Gravatar's premade defaults.
    ///
    /// For more information, see
    /// http://en.gravatar.com/site/implement/images/#default-image.
    ///
    /// **Default value:** `None`
    pub default: Option<Default>,

    /// If force_default is set to true, then Gravatar will always return the
    /// specified default image, whether or not the user's email exists.
    ///
    /// For more information, see
    /// http://en.gravatar.com/site/implement/images/#force-default.
    ///
    /// **Default value:** `false`
    pub force_default: bool,

    /// The maximum rating level for which Gravatar will show the user's image.
    /// If `None` is provided, then Gravatar will only deliver "G"-rated images
    /// by default. If an image is at a higher rating level than the requested
    /// one, the default image is returned instead.
    ///
    /// For more information, see
    /// http://en.gravatar.com/site/implement/images/#rating.
    ///
    /// **Default value:** `None`
    pub rating: Option<Rating>,

    /// If true, Gravatar's secure URL (https://secure.gravatar.com/avatar/...)
    /// is used. Otherwise, the non-SSL website is used instead
    /// (http://www.gravatar.com/avatar/...).
    ///
    /// **Default value:** `true`
    pub ssl: bool
}

impl Gravatar {
    /// Creates a new Gravatar with the given email and default values for the
    /// other parameters.
    pub fn new(email: &str) -> Gravatar {
        Gravatar {
            email: email.to_string(),
            size: None,
            default: None,
            force_default: false,
            rating: None,
            ssl: true
        }
    }

    /// Returns the image URL of the user's Gravatar with all specified
    /// parameters.
    pub fn image_url(self: &Self) -> String {
        // Generate MD5 hash of email
        let hash = {
            let mut hasher = Md5::new();
            hasher.input_str(&self.email.trim().to_ascii_lowercase());
            hasher.result_str()
        };

        // Create base URL using the hash
        let mut url = Url::parse(&format!(
            "{}.gravatar.com/avatar/{}",
            match self.ssl {
                true => "https://secure",
                false => "http://www"
            },
            hash
        )).unwrap();

        match self.size {
            Some(ref s) => {
                url.query_pairs_mut().append_pair("s", &s.to_string());
            },
            None => {}
        }
        match self.default {
            Some(ref d) => {
                let val = match *d {
                    Default::Url(ref u) => u.as_ref(),
                    Default::Http404 => "404",
                    Default::MysteryMan => "mm",
                    Default::Identicon => "identicon",
                    Default::MonsterId => "monsterid",
                    Default::Wavatar => "wavatar",
                    Default::Retro => "retro",
                    Default::Blank => "blank",
                };
                url.query_pairs_mut().append_pair("d", val);
            },
            None => {}
        }
        match self.force_default {
            true => { url.query_pairs_mut().append_pair("f", "y"); },
            false => {}
        }
        match self.rating {
            Some(ref r) => {
                let val = match *r {
                    Rating::G => "g",
                    Rating::Pg => "pg",
                    Rating::R => "r",
                    Rating::X => "x"
                };
                url.query_pairs_mut().append_pair("r", val);
            },
            None => {}
        };

        url.into_string()
    }

}