ntdsextract2 1.4.25

Display contents of Active Directory database files (ntds.dit)
use cursive_table_view::TableViewItem;
use libntdsextract2::{cache::RecordPointer, CDatabase};

use crate::walk::member_column::MemberColumn;

#[derive(Clone)]
pub struct MemberLine {
    account_name: String,
    distinguished_name: String,
}

impl MemberLine {
    pub fn try_from(pointer: &RecordPointer, database: &CDatabase<'_, '_>) -> Option<Self> {
        match database.entry(pointer.ds_record_id().into()) {
            Ok(Some(record)) => {
                let account_name = match record.att_sam_account_name_opt() {
                    Ok(Some(name)) => name,
                    Ok(None) => {
                        log::error!(
                            "Record {} has no samAccountName",
                            record.ds_record_id().unwrap()
                        );
                        return None;
                    }
                    Err(why) => {
                        log::error!(
                            "Error while reading samAccountName for {}: {why}",
                            record.ds_record_id().unwrap()
                        );
                        return None;
                    }
                };

                let distinguished_name = match database.data_table().object_tree().dn_of(pointer) {
                    Some(dn) => dn,
                    None => {
                        log::error!(
                            "Record {} has no distinguished name",
                            record.ds_record_id().unwrap()
                        );
                        return None;
                    }
                };

                Some(Self {
                    account_name,
                    distinguished_name,
                })
            }
            Ok(None) => panic!("illegal record pointer: {pointer:?}"),
            Err(why) => {
                log::error!("Error while reading a record: {why}");
                None
            }
        }
    }
}

impl TableViewItem<MemberColumn> for MemberLine {
    fn to_column(&self, column: MemberColumn) -> String {
        match column {
            MemberColumn::AccountName => self.account_name.clone(),
            MemberColumn::DistinguishedName => self.distinguished_name.clone(),
        }
    }

    fn cmp(&self, other: &Self, column: MemberColumn) -> std::cmp::Ordering
    where
        Self: Sized,
    {
        match column {
            MemberColumn::AccountName => self.account_name.cmp(&other.account_name),
            MemberColumn::DistinguishedName => self.distinguished_name.cmp(&other.distinguished_name),
        }
    }
}