use crate::{DesktopEnv, Platform};
use std::{
ptr,
char,
convert::TryInto,
os::raw::{c_int, c_ulong, c_char, c_uchar},
};
#[allow(unused)]
#[repr(C)]
enum ExtendedNameFormat {
Unknown, FullyQualifiedDN, SamCompatible, Display, UniqueId, Canonical, UserPrincipal, CanonicalEx, ServicePrincipal, DnsDomain, GivenName, Surname, }
#[allow(unused)]
#[repr(C)]
enum ComputerNameFormat {
NetBIOS, DnsHostname, DnsDomain, DnsFullyQualified, PhysicalNetBIOS, PhysicalDnsHostname, PhysicalDnsDomain, PhysicalDnsFullyQualified, Max,
}
#[link(name = "secur32")]
extern "system" {
fn GetLastError() -> c_ulong;
fn GetUserNameExW(a: ExtendedNameFormat, b: *mut c_char, c: *mut c_ulong) -> c_uchar;
fn GetUserNameW(a: *mut c_char, b: *mut c_ulong) -> c_int;
fn GetComputerNameExW(
a: ComputerNameFormat,
b: *mut c_char,
c: *mut c_ulong,
) -> c_int;
}
pub fn username() -> String {
let mut size = 0;
let fail = unsafe {
GetUserNameW(ptr::null_mut(), &mut size) == 0
};
debug_assert_eq!(fail, true);
let mut name: Vec<u16> = Vec::with_capacity(size.try_into().unwrap());
let orig_size = size;
let fail = unsafe {
GetUserNameW(name.as_mut_ptr().cast(), &mut size) == 0
};
if fail {
panic!("Failed to get username: {}, report at https://github.com/libcala/whoami/issues",
unsafe { GetLastError() });
}
debug_assert_eq!(orig_size, size);
unsafe {
name.set_len(size.try_into().unwrap());
}
debug_assert_eq!(name.pop(), Some(0u16));
char::decode_utf16(name)
.map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
.collect()
}
#[inline(always)]
pub fn realname() -> String {
let mut size = 0;
let fail = unsafe {
GetUserNameExW(ExtendedNameFormat::Display, ptr::null_mut(), &mut size) == 0
};
debug_assert_eq!(fail, true);
match unsafe { GetLastError() } {
0x00EA => { }
0x054B => {
return "Unknown".to_string()
}
0x0534 => {
return username();
}
u => {
eprintln!("Unknown error code: {}, report at https://github.com/libcala/whoami/issues", u);
unreachable!();
}
}
let mut name: Vec<u16> = Vec::with_capacity(size.try_into().unwrap());
let orig_size = size;
let fail = unsafe {
GetUserNameExW(ExtendedNameFormat::Display, name.as_mut_ptr().cast(), &mut size) == 0
};
if fail {
panic!("Failed to get username: {}, report at https://github.com/libcala/whoami/issues",
unsafe { GetLastError() });
}
debug_assert_eq!(orig_size, size);
unsafe {
name.set_len(size.try_into().unwrap());
}
char::decode_utf16(name)
.map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
.collect()
}
#[inline(always)]
pub fn computer() -> String {
let mut size = 0;
let fail = unsafe {
GetComputerNameExW(
ComputerNameFormat::DnsHostname, ptr::null_mut(), &mut size) == 0
};
debug_assert_eq!(fail, true);
let mut name: Vec<u16> = Vec::with_capacity(size.try_into().unwrap());
let fail = unsafe {
GetComputerNameExW(
ComputerNameFormat::DnsHostname, name.as_mut_ptr().cast(), &mut size) == 0
};
if fail {
panic!("Failed to get computer name: {}, report at https://github.com/libcala/whoami/issues",
unsafe { GetLastError() });
}
unsafe {
name.set_len(size.try_into().unwrap());
}
char::decode_utf16(name)
.map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
.collect()
}
pub fn hostname() -> String {
let mut size = 0;
let fail = unsafe {
GetComputerNameExW(
ComputerNameFormat::NetBIOS, ptr::null_mut(), &mut size) == 0
};
debug_assert_eq!(fail, true);
let mut name: Vec<u16> = Vec::with_capacity(size.try_into().unwrap());
let fail = unsafe {
GetComputerNameExW(
ComputerNameFormat::NetBIOS, name.as_mut_ptr().cast(), &mut size) == 0
};
if fail {
panic!("Failed to get computer name: {}, report at https://github.com/libcala/whoami/issues",
unsafe { GetLastError() });
}
unsafe {
name.set_len(size.try_into().unwrap());
}
char::decode_utf16(name)
.map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER).to_lowercase())
.flatten()
.collect()
}
pub fn os() -> Option<String> {
extern "system" {
fn GetVersion() -> usize;
}
let bits = unsafe { GetVersion() } as u32;
let mut out = "Windows ".to_string();
let major: u8 = (bits & 0b00000000_00000000_00000000_11111111) as u8;
let minor: u8 = ((bits & 0b00000000_00000000_11111111_00000000) >> 8) as u8;
let build: u16 =
((bits & 0b11111111_11111111_00000000_00000000) >> 16) as u16;
match major {
5 => out.push_str("XP"),
6 => match minor {
0 => out.push_str("Vista"),
1 => out.push_str("7"),
2 => match build {
9200 => out.push_str("10"),
_ => out.push_str("8"),
},
_ => out.push_str("8"),
},
_ => out.push_str("Unknown"),
}
Some(out)
}
#[inline(always)]
pub const fn env() -> DesktopEnv {
DesktopEnv::Windows
}
#[inline(always)]
pub const fn platform() -> Platform {
Platform::Windows
}