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
use std::{collections::HashMap, fmt};

use super::*;

impl fmt::Display for Header {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Header::To(value) => write_simple_field("To", value, f),
            Header::From(value) => write_simple_field("From", value, f),
            Header::Contact(value) => write_simple_field("Contact", value, f),
            Header::ReplyTo(value) => write_simple_field("Reply-To", value, f),
            Header::CSeq(num, method) => write!(f, "CSeq: {} {}", num, method),
            Header::MaxForwards(num) => write!(f, "Max-Forwards: {}", num),
            Header::Expires(num) => write!(f, "Expires: {}", num),
            Header::Event(value) => write!(f, "Event: {}", value),
            Header::Accept(methods) => write_method_array_header("Accept", f, methods),
            Header::Allow(methods) => write_method_array_header("Allow", f, methods),
            Header::ContentEncoding(ty) => write_simple_field("Content-Encoding", ty, f),
            Header::ContentLength(len) => write_simple_field("Content-Length", len, f),
            Header::ContentType(ty) => write_simple_field("Content-Type", ty, f),
            Header::UserAgent(agent) => write_simple_field("User-Agent", agent, f),
            Header::CallId(call_id) => write_simple_field("Call-ID", call_id, f),
            Header::ContentLanguage(lang) => write_simple_field("Content-Language", lang, f),
            Header::AcceptLanguage(lang) => write_simple_field("Accept-Language", lang, f),
            Header::AcceptEncoding(ty) => write_simple_field("Accept-Encoding", ty, f),
            Header::AlertInfo(data) => write_simple_field("Alert-Info", data, f),
            Header::ErrorInfo(data) => write_simple_field("Error-Info", data, f),
            Header::AuthenticationInfo(data) => write_simple_field("Authentication-Info", data, f),
            Header::Authorization(data) => write_auth_header("Authorization", data, f),
            Header::CallInfo(data) => write_simple_field("Call-Info", data, f),
            Header::InReplyTo(data) => write_simple_field("In-Reply-To", data, f),
            Header::ContentDisposition(data) => write_simple_field("Content-Disposition", data, f),
            Header::Date(string) => write_simple_field("Date", string, f),
            Header::MinExpires(exp) => write_simple_field("Min-Expires", exp, f),
            Header::MimeVersion(exp) => write_simple_field("MIME-Version", exp, f),
            Header::Organization(org) => write_simple_field("Organization", org, f),
            Header::ProxyAuthenticate(data) => write_simple_field("Proxy-Authenticate", data, f),
            Header::ProxyAuthorization(data) => write_simple_field("Proxy-Authorization", data, f),
            Header::ProxyRequire(data) => write_simple_field("Proxy-Require", data, f),
            Header::Require(data) => write_simple_field("Require", data, f),
            Header::RetryAfter(data) => write_simple_field("Retry-After", data, f),
            Header::Route(data) => write_simple_field("Route", data, f),
            Header::Subject(data) => write_simple_field("Subject", data, f),
            Header::SubscriptionState(data) => write_simple_field("Subscription-State", data, f),
            Header::RecordRoute(data) => write_simple_field("Record-Route", data, f),
            Header::Server(data) => write_simple_field("Server", data, f),
            Header::Supported(data) => write_string_array_header("Supported", f, data),
            Header::Timestamp(data) => write_simple_field("Timestamp", data, f),
            Header::Unsupported(data) => write_simple_field("Unsupported", data, f),
            Header::Warning(data) => write_simple_field("Warning", data, f),
            Header::Via(data) => write!(f, "{}", data),
            Header::Priority(data) => write_simple_field("Priority", data, f),
            Header::WwwAuthenticate(data) => write_auth_header("WWW-Authenticate", data, f),
            Header::XFsSendingMessage(data) => write_simple_field("X-FS-Sending-Message", data, f),
            Header::Other(key, value) => write!(f, "{}: {}", key, value),
        }
    }
}

macro_rules! write_array_header {
    ($name:ident, $item:ident) => {
        fn $name(name: &str, f: &mut fmt::Formatter, v: &[$item]) -> fmt::Result {
            write!(f, "{}: ", name)?;
            for (index, item) in v.iter().enumerate() {
                if index == 0 {
                    write!(f, "{}", item)?;
                } else {
                    write!(f, ",{}", item)?;
                }
            }
            Ok(())
        }
    };
}

write_array_header!(write_method_array_header, Method);
write_array_header!(write_string_array_header, String);
fn write_simple_field<D: fmt::Display>(
    header: &str,
    data: D,
    f: &mut fmt::Formatter,
) -> fmt::Result {
    write!(f, "{}: {}", header, data)
}

fn write_auth_header<D: fmt::Display>(
    header: &str,
    data: D,
    f: &mut fmt::Formatter,
) -> fmt::Result {
    write!(f, "{}: {}", header, data)
}

/// Writes an optional parameter if it has any value, prepending it with ';'.
pub fn write_optional_param<V: fmt::Display>(
    param: &str,
    value: &Option<V>,
    f: &mut fmt::Formatter,
) -> fmt::Result {
    if let Some(value) = value {
        write!(f, ";{}={}", param, value)
    } else {
        Ok(())
    }
}

/// Writes generic parameters, adding ';' before each (including the first one)
pub fn write_generic_params(
    params: &HashMap<String, Option<String>>,
    f: &mut fmt::Formatter,
) -> fmt::Result {
    for (name, value) in params.iter() {
        write!(f, ";{}", name)?;
        if let Some(value) = value {
            write!(f, "={}", value)?;
        }
    }
    Ok(())
}