Skip to main content

tailtalk_packets/afp/
types.rs

1/// AFP Error Codes. For AppleTalk implementations these result codes are passed via the
2/// ASP CmdResult field (i.e the 4 user bytes of an ATP packet)
3#[derive(Debug, Clone, PartialEq, Eq)]
4#[repr(i16)]
5pub enum AfpError {
6    /// Packet could not be parsed as it was of insufficient size
7    InvalidSize = -1,
8    /// End of File reached
9    EoFErr = -39,
10    /// Unknown or unsupported AFP version
11    BadVersNum = -1072,
12    /// Unknown or unsupported UAM
13    BadUam = -1073,
14    /// User does not have the correct access rights
15    AccessDenied = -5000,
16    /// A request to operate on a directory that is not empty
17    DirNotEmpty = -5007,
18    /// Bitmap is invalid
19    BitmapErr = -5006,
20    /// A request to operate on a file that is currently in use
21    FileBusy = -5010,
22    /// Item not found
23    ItemNotFound = -5012,
24    /// General lock error
25    LockErr = -5013,
26    /// Object (file or directory) already exists
27    ObjectExists = -5017,
28    /// Object (file or directory) not found
29    ObjectNotFound = -5018,
30    /// AFP command block size is zero or invalid
31    ParamError = -5019,
32    /// Attempt to unlock a byte range that is not locked
33    RangeNotLocked = -5020,
34    /// Attempt to lock a byte range that overlaps with an existing lock
35    RangeOverlap = -5021,
36    /// Object is the wrong type (e.g. file vs directory)
37    ObjectTypeErr = -5025,
38    /// Miscellaneous error
39    MiscErr = -10000,
40}
41
42#[repr(u16)]
43pub enum VolumeSignature {
44    /// Indicates no directories, only files, i.e MFS. Only supported in old AFP versions.
45    Flat = 1,
46    /// Indicates directory IDs do not change. Should be the default.
47    FixedDirectoryID = 2,
48    /// Indicates directory IDs can change. No need to implement this one.
49    VariableDirectoryID = 3,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq)]
53pub enum AfpVersion {
54    Version1,
55    Version1_1,
56    Version2,
57    Version2_1,
58}
59
60impl TryFrom<&str> for AfpVersion {
61    type Error = AfpError;
62    fn try_from(value: &str) -> Result<Self, Self::Error> {
63        match value {
64            "AFPVersion 1.0" => Ok(AfpVersion::Version1),
65            "AFPVersion 1.1" => Ok(AfpVersion::Version1_1),
66            "AFPVersion 2.0" => Ok(AfpVersion::Version2),
67            "AFPVersion 2.1" => Ok(AfpVersion::Version2_1),
68            _ => Err(AfpError::BadVersNum),
69        }
70    }
71}
72
73impl AfpVersion {
74    pub fn as_str(&self) -> &'static str {
75        match self {
76            AfpVersion::Version1 => "AFPVersion 1.0",
77            AfpVersion::Version1_1 => "AFPVersion 1.1",
78            AfpVersion::Version2 => "AFPVersion 2.0",
79            AfpVersion::Version2_1 => "AFPVersion 2.1",
80        }
81    }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
85pub enum AfpUam {
86    NoUserAuthent,
87    CleartxtPasswrd,
88    RandnumExchange,
89    TwoWayRandnumExchange,
90}
91
92impl TryFrom<&str> for AfpUam {
93    type Error = AfpError;
94    fn try_from(value: &str) -> Result<Self, Self::Error> {
95        // Inside AppleTalk shows these with capitalised values, but
96        // the actual values are case insensitive.
97        let value_lower = value.to_lowercase();
98        match value_lower.as_str() {
99            "no user authent" => Ok(AfpUam::NoUserAuthent),
100            "cleartxt passwrd" => Ok(AfpUam::CleartxtPasswrd),
101            "randnum exchange" => Ok(AfpUam::RandnumExchange),
102            "2-way randnum exchange" => Ok(AfpUam::TwoWayRandnumExchange),
103            _ => Err(AfpError::BadUam),
104        }
105    }
106}
107
108impl AfpUam {
109    pub fn as_str(&self) -> &'static str {
110        match self {
111            AfpUam::NoUserAuthent => "No User Authent",
112            AfpUam::CleartxtPasswrd => "Cleartxt Passwrd",
113            AfpUam::RandnumExchange => "Randnum Exchange",
114            AfpUam::TwoWayRandnumExchange => "2-Way Randnum Exchange",
115        }
116    }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120pub enum ForkType {
121    Data,
122    Resource,
123}
124
125impl From<u8> for ForkType {
126    fn from(value: u8) -> Self {
127        match value {
128            0 => Self::Data,
129            0b10000000 => Self::Resource,
130            _ => panic!("Invalid fork type"),
131        }
132    }
133}
134
135impl From<ForkType> for u8 {
136    fn from(val: ForkType) -> Self {
137        match val {
138            ForkType::Data => 0,
139            ForkType::Resource => 0b10000000,
140        }
141    }
142}
143
144#[derive(Debug, Clone, Copy, PartialEq, Eq)]
145pub enum PathType {
146    ShortName = 1,
147    LongName = 2,
148}
149
150impl From<u8> for PathType {
151    fn from(value: u8) -> Self {
152        match value {
153            2 => Self::LongName,
154            _ => Self::ShortName,
155        }
156    }
157}
158
159#[derive(Debug)]
160pub enum CreateFlag {
161    Soft,
162    Hard,
163}
164
165impl From<u8> for CreateFlag {
166    fn from(value: u8) -> Self {
167        match value {
168            0b10000000 => Self::Hard,
169            _ => Self::Soft,
170        }
171    }
172}
173
174impl From<CreateFlag> for u8 {
175    fn from(val: CreateFlag) -> Self {
176        match val {
177            CreateFlag::Hard => 0b10000000,
178            CreateFlag::Soft => 0,
179        }
180    }
181}
182
183pub enum FileType {
184    Directory,
185    File,
186}
187
188impl From<u8> for FileType {
189    fn from(value: u8) -> Self {
190        match value {
191            0b10000000 => Self::Directory,
192            _ => Self::File,
193        }
194    }
195}
196
197impl From<FileType> for u8 {
198    fn from(val: FileType) -> Self {
199        match val {
200            FileType::Directory => 0b10000000,
201            FileType::File => 0,
202        }
203    }
204}