z39/types/
pdu.rs

1//! Z39.50 ASN.1 Primary Data Units (i.e. Messages) and Related Types
2//!
3//! See https://www.loc.gov/z3950/agency/asn1.html
4use crate::error::{LocalError, LocalResult};
5use crate::prefs::ImplementationPrefs;
6
7use rasn::ber::de::DecodeErrorKind;
8use rasn::prelude::*;
9use rasn::AsnType;
10
11#[derive(Debug, Clone, PartialEq, Default, AsnType, Decode, Encode)]
12#[rasn(tag(context, 20))]
13pub struct InitializeRequest {
14    #[rasn(tag(2))]
15    pub reference_id: Option<OctetString>,
16    #[rasn(tag(3))]
17    pub protocol_version: BitString,
18    #[rasn(tag(4))]
19    pub options: BitString,
20    #[rasn(tag(5))]
21    pub preferred_message_size: u32,
22    #[rasn(tag(6))]
23    pub exceptional_record_size: u32,
24    #[rasn(tag(110))]
25    pub implementation_id: Option<String>,
26    #[rasn(tag(111))]
27    pub implementation_name: Option<String>,
28    #[rasn(tag(112))]
29    pub implementation_version: Option<String>,
30}
31
32#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
33#[rasn(tag(context, 21))]
34pub struct InitializeResponse {
35    #[rasn(tag(2))]
36    pub reference_id: Option<OctetString>,
37    #[rasn(tag(3))]
38    pub protocol_version: BitString,
39    #[rasn(tag(4))]
40    pub options: BitString,
41    #[rasn(tag(5))]
42    pub preferred_message_size: u32,
43    #[rasn(tag(6))]
44    pub exceptional_record_size: u32,
45    #[rasn(tag(12))]
46    pub result: Option<bool>,
47    #[rasn(tag(110))]
48    pub implementation_id: Option<String>,
49    #[rasn(tag(111))]
50    pub implementation_name: Option<String>,
51    #[rasn(tag(112))]
52    pub implementation_version: Option<String>,
53}
54
55// InitializeResponse will always be a canned response.
56impl Default for InitializeResponse {
57    fn default() -> Self {
58        let settings = ImplementationPrefs::global();
59
60        // Translate the InitOptions values into the required BitString
61        let mut options = BitString::repeat(false, 16);
62        for (idx, val) in settings
63            .init_options
64            .as_positioned_values()
65            .iter()
66            .enumerate()
67        {
68            if *val {
69                options.set(idx, true);
70            }
71        }
72
73        InitializeResponse {
74            reference_id: None,
75            protocol_version: BitString::repeat(true, 3),
76            options,
77            result: Some(true),
78            preferred_message_size: settings.preferred_message_size,
79            exceptional_record_size: settings.exceptional_record_size,
80            implementation_id: settings.implementation_id.clone(),
81            implementation_name: settings.implementation_name.clone(),
82            implementation_version: settings.implementation_version.clone(),
83        }
84    }
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, AsnType, Decode, Encode)]
88#[rasn(enumerated)]
89pub enum KnownProximityUnit {
90    Character = 1,
91    Word,
92    Sentence,
93    Paragraph,
94    Section,
95    Chapter,
96    Document,
97    Element,
98    Subelement,
99    ElementType,
100    Byte,
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, AsnType, Decode, Encode)]
104#[rasn(enumerated)]
105pub enum RelationType {
106    LessThan = 1,
107    LessThanOrEqual,
108    Equal,
109    GreaterThanOrEqual,
110    GreaterThan,
111    NotEqual,
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, AsnType, Decode, Encode)]
115#[rasn(enumerated)]
116pub enum ResultSetStatus {
117    Empty = 1,
118    Interim,
119    Unchanged,
120    None,
121}
122
123#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
124#[rasn(choice)]
125pub enum ProximityUnitCode {
126    #[rasn(tag(0))]
127    Known(KnownProximityUnit),
128    #[rasn(tag(1))]
129    Private(u32),
130}
131
132#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
133pub struct ProximityOperator {
134    #[rasn(tag(1))]
135    pub exclusion: bool,
136    #[rasn(tag(2))]
137    pub distance: u32,
138    #[rasn(tag(3))]
139    pub ordered: bool,
140    #[rasn(tag(4))]
141    pub relation_type: RelationType,
142    #[rasn(tag(5))]
143    pub proximity_unit_code: ProximityUnitCode,
144}
145
146// NOTE a single-item enum Encodes/Decodes as expected, whereas a
147// 'struct DatabaseName(String)' does not.
148#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
149#[rasn(choice)]
150pub enum DatabaseName {
151    #[rasn(tag(105))]
152    Name(String),
153}
154
155#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
156#[rasn(choice)]
157pub enum ElementSetName {
158    #[rasn(tag(103))]
159    Name(String),
160}
161
162#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
163pub struct DatabaseSpecific {
164    pub db_name: DatabaseName,
165    pub esn: ElementSetName,
166}
167
168#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
169#[rasn(choice)]
170pub enum ElementSetNames {
171    #[rasn(tag(0))]
172    GenericElementSetName(String),
173    #[rasn(tag(1))]
174    DatabaseSpecific(Vec<DatabaseSpecific>),
175}
176
177#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
178#[rasn(choice)]
179pub enum StringOrNumeric {
180    #[rasn(tag(1))]
181    String(String),
182    #[rasn(tag(2))]
183    Numeric(u32),
184}
185
186#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
187pub struct ComplexAttributeValue {
188    #[rasn(tag(1))]
189    pub list: Vec<StringOrNumeric>,
190    #[rasn(tag(2))]
191    pub semantic_action: Option<Vec<u32>>,
192}
193
194#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
195#[rasn(choice)]
196pub enum AttributeValue {
197    #[rasn(tag(121))]
198    Numeric(u32),
199    #[rasn(tag(224))]
200    Complex(ComplexAttributeValue),
201}
202
203#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
204#[rasn(choice)]
205// #[rasn(tag(46))]
206// Uses tag 46 but that's best encoded in the containing struct, instead
207// of attached to the Operator struct, to make rasn happy.
208pub enum Operator {
209    #[rasn(tag(0))]
210    And,
211    #[rasn(tag(1))]
212    Or,
213    #[rasn(tag(2))]
214    AndNot,
215    #[rasn(tag(3))]
216    Prox(ProximityOperator),
217}
218
219#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
220pub struct Unit {
221    #[rasn(tag(1))]
222    pub unit_system: Option<String>,
223    #[rasn(tag(2))]
224    pub unit_type: Option<StringOrNumeric>,
225    #[rasn(tag(3))]
226    pub unit: Option<StringOrNumeric>,
227    #[rasn(tag(4))]
228    pub scale_factor: Option<u32>,
229}
230
231#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
232pub struct IntUnit {
233    #[rasn(tag(1))]
234    pub value: u32,
235    #[rasn(tag(2))]
236    pub unit_used: Unit,
237}
238
239#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
240#[rasn(choice)]
241pub enum Term {
242    #[rasn(tag(45))]
243    General(OctetString),
244    #[rasn(tag(215))]
245    Numeric(u32),
246    #[rasn(tag(216))]
247    CharacterString(String),
248    #[rasn(tag(217))]
249    Oid(ObjectIdentifier),
250    #[rasn(tag(218))]
251    DateTime(GeneralizedTime),
252    #[rasn(tag(219))]
253    External(Any),
254    #[rasn(tag(220))]
255    IntegerAndUnit(IntUnit),
256    #[rasn(tag(221))]
257    Null,
258}
259
260impl Term {
261    pub fn general_from_str(s: &str) -> Term {
262        Term::General(OctetString::copy_from_slice(s.as_bytes()))
263    }
264}
265
266#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
267pub struct AttributeElement {
268    #[rasn(tag(1))]
269    pub attribute_set: Option<ObjectIdentifier>,
270    #[rasn(tag(120))]
271    pub attribute_type: u32,
272    pub attribute_value: AttributeValue,
273}
274
275#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
276pub struct ResultSetPlusAttributes {
277    pub result_set: ObjectIdentifier,
278    #[rasn(tag(44))]
279    pub attributes: Vec<AttributeElement>,
280}
281
282#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
283pub struct AttributesPlusTerm {
284    #[rasn(tag(44))]
285    pub attributes: Vec<AttributeElement>,
286    pub term: Term,
287}
288
289#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
290#[rasn(choice)]
291pub enum Operand {
292    #[rasn(tag(102))]
293    AttrTerm(AttributesPlusTerm),
294    #[rasn(tag(31))]
295    ResultSet(String),
296    #[rasn(tag(214))]
297    ResultAttr(ResultSetPlusAttributes),
298}
299
300#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
301pub struct RpnOp {
302    pub rpn1: RpnStructure,
303    pub rpn2: RpnStructure,
304    #[rasn(tag(46))]
305    pub op: Operator,
306}
307
308#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
309#[rasn(choice)]
310pub enum RpnStructure {
311    #[rasn(tag(0))]
312    Op(Operand),
313    #[rasn(tag(1))]
314    RpnOp(Box<RpnOp>),
315}
316
317#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
318pub struct RpnQuery {
319    pub attribute_set: ObjectIdentifier,
320    pub rpn: RpnStructure,
321}
322
323#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
324#[rasn(choice)]
325pub enum Query {
326    #[rasn(tag(0))]
327    Type0(Any),
328    #[rasn(tag(1))]
329    Type1(RpnQuery),
330    #[rasn(tag(2))]
331    Type2(OctetString),
332    #[rasn(tag(100))]
333    Type100(OctetString),
334    #[rasn(tag(101))]
335    Type101(RpnQuery),
336    #[rasn(tag(102))]
337    Type102(OctetString),
338}
339
340#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
341#[rasn(choice)]
342pub enum Information {
343    #[rasn(tag(2))]
344    CharacterInfo(String),
345    #[rasn(tag(3))]
346    BinaryInfo(OctetString),
347    #[rasn(tag(4))]
348    ExternallyDefinedInfo(Any),
349    #[rasn(tag(5))]
350    Oid(ObjectIdentifier),
351}
352
353#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
354pub struct InfoCategory {
355    #[rasn(tag(1))]
356    pub category_type_id: Option<ObjectIdentifier>,
357    #[rasn(tag(2))]
358    pub category_value: Option<u32>,
359}
360
361#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
362#[rasn(tag(201))]
363pub struct OtherInformation {
364    #[rasn(tag(1))]
365    pub category: Option<InfoCategory>,
366    pub information: Information,
367}
368
369#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
370#[rasn(tag(context, 22))]
371pub struct SearchRequest {
372    #[rasn(tag(2))]
373    pub reference_id: Option<OctetString>,
374    #[rasn(tag(13))]
375    pub small_set_upper_bound: u32,
376    #[rasn(tag(14))]
377    pub large_set_lower_bound: u32,
378    #[rasn(tag(15))]
379    pub medium_set_present_number: u32,
380    #[rasn(tag(16))]
381    pub replace_indicator: bool,
382    #[rasn(tag(17))]
383    pub result_set_name: String,
384    #[rasn(tag(18))]
385    pub database_names: Vec<DatabaseName>,
386    #[rasn(tag(21))]
387    pub query: Query,
388    #[rasn(tag(100))]
389    pub small_set_element_names: Option<ElementSetNames>,
390    #[rasn(tag(101))]
391    pub medium_set_element_names: Option<ElementSetNames>,
392    #[rasn(tag(104))]
393    pub preferred_record_syntax: Option<ObjectIdentifier>,
394    #[rasn(tag(203))]
395    pub additional_search_info: Option<OtherInformation>,
396}
397
398#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
399#[rasn(choice)]
400pub enum AddInfo {
401    V2AddInfo(VisibleString),
402    V3AddInfo(GeneralString),
403}
404
405#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
406pub struct DefaultDiagFormat {
407    pub diagnostic_set_id: ObjectIdentifier,
408    pub condition: u32,
409    pub addinfo: AddInfo,
410}
411
412#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
413#[rasn(choice)]
414pub enum DiagRec {
415    DefaultFormat(DefaultDiagFormat),
416    ExternallyDefined(Any),
417}
418
419#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
420#[rasn(choice)]
421pub enum FragmentSyntax {
422    ExternallyTagged(Any),
423    NotExternallyTagged(OctetString),
424}
425
426#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
427#[rasn(choice)]
428pub enum Encoding {
429    #[rasn(tag(0))]
430    SingleAsn1Type(Any),
431    #[rasn(tag(1))]
432    OctetAligned(OctetString),
433    #[rasn(tag(2))]
434    Arbitrary(BitString),
435}
436
437#[derive(Debug, Clone, PartialEq, AsnType, Encode, Decode)]
438#[rasn(tag(universal, 8))]
439pub struct ExternalMessage {
440    pub direct_reference: Option<ObjectIdentifier>,
441    pub indirect_reference: Option<u32>,
442    pub data_value_descriptor: Option<String>,
443    pub encoding: Encoding,
444}
445
446impl ExternalMessage {
447    pub fn new(encoding: Encoding) -> Self {
448        Self {
449            direct_reference: None,
450            indirect_reference: None,
451            data_value_descriptor: None,
452            encoding,
453        }
454    }
455}
456
457// Wrapper around our ExternalMessage type, which seems to be
458// required to make rasn honor the struct-level UNIVERSAL tag on our
459// ExternalMessage.  Otherwise, it either ignores the tag or, if
460// `explicit` is used, it adds the tag and an unwanted SEQUENCE tag.
461// This gives us the EXTERNAL tag without the SEQUENCE, without having
462// to maually implement Encode/Decode.
463#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
464pub struct External(pub ExternalMessage);
465
466#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
467#[rasn(choice)]
468pub enum Record {
469    #[rasn(tag(1))]
470    RetrievalRecord(External),
471    #[rasn(tag(2))]
472    SurrogateDiagnostic(DiagRec),
473    #[rasn(tag(3))]
474    StartingFragment(FragmentSyntax),
475    #[rasn(tag(4))]
476    IntermediateFragment(FragmentSyntax),
477    #[rasn(tag(5))]
478    FinalFragment(FragmentSyntax),
479}
480
481#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
482pub struct NamePlusRecord {
483    #[rasn(tag(0))]
484    pub name: Option<DatabaseName>,
485    #[rasn(tag(1))]
486    pub record: Record,
487}
488
489impl NamePlusRecord {
490    pub fn new(record: Record) -> Self {
491        Self { name: None, record }
492    }
493}
494
495#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
496#[rasn(choice)]
497pub enum Records {
498    #[rasn(tag(28))]
499    ResponseRecords(Vec<NamePlusRecord>),
500    #[rasn(tag(130))]
501    NonSurrogateDiagnostic(DefaultDiagFormat),
502    #[rasn(tag(205))]
503    MultipleNonSurDiagnostics(Vec<DiagRec>),
504}
505
506#[derive(Debug, Clone, PartialEq, Default, AsnType, Decode, Encode)]
507#[rasn(tag(context, 23))]
508pub struct SearchResponse {
509    #[rasn(tag(2))]
510    pub reference_id: Option<OctetString>,
511    #[rasn(tag(23))]
512    pub result_count: u32,
513    #[rasn(tag(24))]
514    pub number_of_records_returned: u32,
515    #[rasn(tag(25))]
516    pub next_result_set_position: u32,
517    #[rasn(tag(22))]
518    pub search_status: bool,
519    #[rasn(tag(26))]
520    pub result_set_status: Option<ResultSetStatus>,
521    #[rasn(tag(27))]
522    pub present_status: Option<PresentStatus>,
523    pub records: Option<Records>,
524    #[rasn(tag(203))]
525    pub additional_search_info: Option<OtherInformation>,
526    pub other_info: Option<OtherInformation>,
527}
528
529#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
530pub struct Range {
531    #[rasn(tag(1))]
532    pub starting_position: u32,
533    #[rasn(tag(2))]
534    pub number_of_records: u32,
535}
536
537#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
538pub struct ElementSpec {
539    #[rasn(tag(1))]
540    pub element_set_name: String,
541    #[rasn(tag(2))]
542    pub external_espec: Option<Any>,
543}
544
545#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
546pub struct Specification {
547    #[rasn(tag(1))]
548    pub schema: Option<ObjectIdentifier>,
549    #[rasn(tag(2))]
550    pub element_spec: Option<ElementSpec>,
551}
552
553#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
554pub struct CompSpecDatabaseSpecific {
555    #[rasn(tag(1))]
556    pub db: DatabaseName,
557    #[rasn(tag(2))]
558    pub spec: Specification,
559}
560
561#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
562pub struct CompSpec {
563    #[rasn(tag(1))]
564    pub select_alternative_syntax: bool,
565    #[rasn(tag(2))]
566    pub generic: Option<Specification>,
567    #[rasn(tag(3))]
568    pub db_specific: Option<CompSpecDatabaseSpecific>,
569    #[rasn(tag(4))]
570    pub record_syntax: Option<Vec<ObjectIdentifier>>,
571}
572
573#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
574#[rasn(choice)]
575pub enum RecordComposition {
576    #[rasn(tag(19))]
577    Simple(ElementSetNames),
578    #[rasn(tag(209))]
579    Complex(CompSpec),
580}
581
582#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
583#[rasn(tag(context, 24))]
584pub struct PresentRequest {
585    #[rasn(tag(2))]
586    pub reference_id: Option<OctetString>,
587    #[rasn(tag(31))]
588    pub result_set_id: String,
589    #[rasn(tag(30))]
590    pub reset_set_start_point: u32,
591    #[rasn(tag(29))]
592    pub number_of_records_requested: u32,
593    #[rasn(tag(212))]
594    pub additional_ranges: Option<Vec<Range>>,
595    pub record_composition: Option<RecordComposition>,
596    #[rasn(tag(104))]
597    pub preferred_record_syntax: Option<ObjectIdentifier>,
598    #[rasn(tag(204))]
599    pub max_segment_count: Option<u32>,
600    #[rasn(tag(206))]
601    pub max_record_size: Option<u32>,
602    #[rasn(tag(207))]
603    pub max_segment_size: Option<u32>,
604    pub other_info: Option<OtherInformation>,
605}
606
607#[derive(Debug, Clone, Copy, PartialEq, AsnType, Decode, Encode)]
608#[rasn(enumerated)]
609pub enum PresentStatus {
610    Success = 0,
611    Partial1,
612    Partial2,
613    Partial3,
614    Partial4,
615    Failure,
616}
617
618#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
619#[rasn(tag(context, 25))]
620pub struct PresentResponse {
621    #[rasn(tag(2))]
622    pub reference_id: Option<OctetString>,
623    #[rasn(tag(24))]
624    pub number_of_records_returned: u32,
625    #[rasn(tag(25))]
626    pub next_result_set_position: u32,
627    #[rasn(tag(27))]
628    pub present_status: PresentStatus,
629    pub records: Option<Records>,
630    pub other_info: Option<OtherInformation>,
631}
632
633impl Default for PresentResponse {
634    fn default() -> Self {
635        PresentResponse {
636            reference_id: None,
637            number_of_records_returned: 0,
638            next_result_set_position: 0,
639            present_status: PresentStatus::Success,
640            records: None,
641            other_info: None,
642        }
643    }
644}
645
646#[derive(Debug, Clone, Copy, PartialEq, AsnType, Decode, Encode)]
647#[rasn(enumerated)]
648pub enum CloseReason {
649    Finished = 0,
650    Shutdown,
651    SystemProblem,
652    CostLimit,
653    Resources,
654    SecurityViolation,
655    ProtocolError,
656    LackOfActivity,
657    PeerAbort,
658    Unspecified,
659}
660
661#[derive(Debug, Clone, PartialEq, AsnType, Decode, Encode)]
662#[rasn(tag(context, 48))]
663pub struct Close {
664    #[rasn(tag(2))]
665    pub reference_id: Option<OctetString>,
666    #[rasn(tag(211))]
667    pub close_reason: CloseReason,
668    #[rasn(tag(3))]
669    pub diagnostic_information: Option<String>,
670    #[rasn(tag(4))]
671    pub resource_report_format: Option<ObjectIdentifier>,
672    #[rasn(tag(5))]
673    pub resource_report: Option<External>,
674    pub other_info: Option<OtherInformation>,
675}
676
677impl Default for Close {
678    fn default() -> Self {
679        Self {
680            reference_id: None,
681            close_reason: CloseReason::Finished,
682            diagnostic_information: None,
683            resource_report_format: None,
684            resource_report: None,
685            other_info: None,
686        }
687    }
688}
689
690#[derive(Debug, Clone, PartialEq)]
691pub enum MessagePayload {
692    InitializeRequest(InitializeRequest),
693    InitializeResponse(InitializeResponse),
694    SearchRequest(SearchRequest),
695    SearchResponse(SearchResponse),
696    PresentRequest(PresentRequest),
697    PresentResponse(PresentResponse),
698    Close(Close),
699}
700
701/// Models a single Z39.50 message whose payload is one of the known
702/// message types.
703#[derive(Debug, Clone, PartialEq)]
704pub struct Message {
705    pub payload: MessagePayload,
706}
707
708impl Message {
709    /// Parses a collection of bytes into a Message.
710    ///
711    /// Returns None if more bytes are needed to complete the message,
712    /// which can happen e.g. when reading bytes from a TcpStream.
713    pub fn from_bytes(bytes: &[u8]) -> LocalResult<Option<Self>> {
714        if bytes.is_empty() {
715            return Ok(None);
716        }
717
718        // Parse error handler.
719        // Return None if more bytes are needed, LocalError otherwise.
720        let handle_error = |e: rasn::error::DecodeError| match *e.kind {
721            DecodeErrorKind::Incomplete { needed: _ } => Ok(None),
722            _ => Err(LocalError::DecodeError(e)),
723        };
724
725        // The first byte of a Z39 ASN1 BER message is structed like so:
726        // [
727        //   10......   - context-specific tag class
728        //   ..1.....   - structured data
729        //   ...nnnnn   - PDU / message tag.
730        //  ]
731        //
732        //  The Initialize Request message, with tag 20, has a
733        //  first-byte value of 10110100 == 180 decimal, IOW 20 + 160.
734        //
735        //  However, if the last 5 bits of the first byte are all 1's,
736        //  the tag value is stored in the second byte (to accommodate
737        //  larger tag values, for 31 <= tag <= 127).
738        //
739        //  There are other rules for tags > 127, but they are not needed for Z39
740        let tag = if bytes[0] == 191 {
741            // bytes[0] == 10111111
742            bytes[1]
743        } else if bytes[0] >= 180 {
744            bytes[0] - 160
745        } else {
746            0
747        };
748
749        let payload = match tag {
750            20 => match rasn::ber::decode(bytes) {
751                Ok(m) => MessagePayload::InitializeRequest(m),
752                Err(e) => return handle_error(e),
753            },
754            21 => match rasn::ber::decode(bytes) {
755                Ok(m) => MessagePayload::InitializeResponse(m),
756                Err(e) => return handle_error(e),
757            },
758            22 => match rasn::ber::decode(bytes) {
759                Ok(m) => MessagePayload::SearchRequest(m),
760                Err(e) => return handle_error(e),
761            },
762            23 => match rasn::ber::decode(bytes) {
763                Ok(m) => MessagePayload::SearchResponse(m),
764                Err(e) => return handle_error(e),
765            },
766            24 => match rasn::ber::decode(bytes) {
767                Ok(m) => MessagePayload::PresentRequest(m),
768                Err(e) => return handle_error(e),
769            },
770            25 => match rasn::ber::decode(bytes) {
771                Ok(m) => MessagePayload::PresentResponse(m),
772                Err(e) => return handle_error(e),
773            },
774            48 => match rasn::ber::decode(bytes) {
775                Ok(m) => MessagePayload::Close(m),
776                Err(e) => return handle_error(e),
777            },
778            _ => {
779                return Err(LocalError::ProtocolError(format!(
780                    "Cannot process message with first byte: {}",
781                    bytes[0]
782                )))
783            }
784        };
785
786        Ok(Some(Message { payload }))
787    }
788
789    /// Create a new message from its payload
790    pub fn from_payload(payload: MessagePayload) -> Self {
791        Message { payload }
792    }
793
794    /// Translate a message into a collection of bytes suitable for dropping
795    /// onto the wire.
796    pub fn to_bytes(&self) -> LocalResult<Vec<u8>> {
797        let res = match &self.payload {
798            MessagePayload::InitializeRequest(m) => rasn::ber::encode(&m),
799            MessagePayload::InitializeResponse(m) => rasn::ber::encode(&m),
800            MessagePayload::SearchRequest(m) => rasn::ber::encode(&m),
801            MessagePayload::SearchResponse(m) => rasn::ber::encode(&m),
802            MessagePayload::PresentRequest(m) => rasn::ber::encode(&m),
803            MessagePayload::PresentResponse(m) => rasn::ber::encode(&m),
804            MessagePayload::Close(m) => rasn::ber::encode(&m),
805        };
806
807        res.map_err(LocalError::EncodeError)
808    }
809}