Lines
63.21 %
Functions
66.67 %
use chrono::{Duration, TimeDelta};
use crate::proto::finger_protocol::{
FingerResponseStructuredUserEntry, FingerResponseUserSession, MailStatus,
};
pub fn classic_format_finger_response_structured_user_entry(
entry: &FingerResponseStructuredUserEntry,
) -> String {
let mut result = String::new();
result += &format!(
"Login: {:<16}\t\t\tName: {}\n",
entry.username, entry.full_name
);
"Directory: {:<24}\tShell: {}\n",
entry.home_dir.display(),
entry.shell.display()
if let Some(office) = &entry.office {
result += &format!("Office: {}\n", office);
}
if let Some(office_phone) = &entry.office_phone {
result += &format!("Office Phone: {}\n", office_phone);
if let Some(home_phone) = &entry.home_phone {
result += &format!("Home Phone: {}\n", home_phone);
if entry.never_logged_in {
result += "Never logged in.\n";
} else {
let max_tty_len = entry
.sessions
.iter()
.map(|s| s.tty.len())
.max()
.unwrap_or(0);
for session in &entry.sessions {
result += &format_session_for_finger(session, max_tty_len);
result += "\n";
if let Some(forward) = &entry.forward_status {
result += &format!("Mail forwarded to {}\n", forward);
if let Some(mail_status) = &entry.mail_status {
match mail_status {
MailStatus::NoMail => result += "No mail.\n",
MailStatus::NewMailReceived {
received_time,
unread_since,
} => {
"New mail received {}\nUnread since {}\n",
received_time.format("%a %b %e %H:%M (%Z)"),
unread_since.format("%a %b %e %H:%M (%Z)")
MailStatus::MailLastRead(last_read) => {
"Mail last read {}\n",
last_read.format("%a %b %e %H:%M (%Z)")
if let Some(pgp_key) = &entry.pgp_key {
result += &format!("PGP key:\n{}\n", pgp_key);
if let Some(project) = &entry.project {
result += &format!("Project:\n{}\n", project);
if let Some(plan) = &entry.plan {
result += &format!("Plan:\n{}\n", plan);
result += "No Plan.\n";
result.trim().to_string()
fn format_session_for_finger(session: &FingerResponseUserSession, max_tty_len: usize) -> String {
"On since {} on {} from {}",
session.login_time.format("%a %b %e %H:%M (%Z)"),
session.tty,
session.host.as_deref().unwrap_or("unknown")
if let Some(idle_time) = session.idle_time {
"\n{:width$}{} idle",
"",
format_idle_time_for_finger(idle_time),
width = max_tty_len - session.tty.len() + 3,
if !session.messages_on {
result += "\n (messages off)";
result
fn format_idle_time_for_finger(idle_time: TimeDelta) -> String {
debug_assert!(
idle_time.num_seconds() >= 0,
"Idle time should never be negative"
let days = idle_time.num_days();
let hours = (idle_time - Duration::days(days)).num_hours();
let minutes = (idle_time - Duration::days(days) - Duration::hours(hours)).num_minutes();
let seconds =
(idle_time - Duration::days(days) - Duration::hours(hours) - Duration::minutes(minutes))
.num_seconds();
if days > 0 {
result += &format!("{} day{} ", days, if days == 1 { "" } else { "s" });
if hours > 0 {
result += &format!("{} hour{} ", hours, if hours == 1 { "" } else { "s" });
if minutes > 0 && days == 0 {
result += &format!("{} minute{} ", minutes, if minutes == 1 { "" } else { "s" });
if seconds > 0 && days == 0 && hours == 0 {
result += &format!("{} second{} ", seconds, if seconds == 1 { "" } else { "s" });
#[cfg(test)]
mod tests {
use chrono::{TimeZone, Utc};
use indoc::indoc;
use crate::proto::finger_protocol::FingerResponseUserSession;
use super::*;
#[test]
fn test_format_session_for_finger() {
let values = [
(
FingerResponseUserSession {
tty: "pts/14".to_string(),
login_time: Utc.with_ymd_and_hms(2026, 5, 12, 15, 39, 0).unwrap(),
host: Some(":pts/21:S.5".to_string()),
idle_time: Some(Duration::days(3) + Duration::hours(18)),
messages_on: true,
},
indoc! {
"
On since Tue May 12 15:39 (UTC) on pts/14 from :pts/21:S.5
3 days 18 hours idle
.trim()
.to_string(),
),
tty: "pts/16".to_string(),
host: Some(":pts/21:S.6".to_string()),
idle_time: Some(Duration::hours(18) + Duration::minutes(47)),
On since Tue May 12 15:39 (UTC) on pts/16 from :pts/21:S.6
18 hours 47 minutes idle
tty: "pts/21".to_string(),
host: Some("212.102.29.193".to_string()),
idle_time: Some(Duration::minutes(24) + Duration::seconds(22)),
messages_on: false,
On since Tue May 12 15:39 (UTC) on pts/21 from 212.102.29.193
24 minutes 22 seconds idle
(messages off)
];
for (session, expected) in values {
assert_eq!(
format_session_for_finger(&session, "pts/10".len()),
expected
fn test_format_session_for_finger_long_tty_string() {
let session = FingerResponseUserSession {
tty: "pts/1".to_string(),
idle_time: Some(Duration::hours(1) + Duration::minutes(30)),
let expected = indoc! {
On since Tue May 12 15:39 (UTC) on pts/1 from :pts/21:S.5
1 hour 30 minutes idle
.to_string();
format_session_for_finger(&session, "pts/123".len()),