package ipp import ( "bufio" "encoding/binary" "fmt" "io" ) type ippResponseHeader struct { versionNumber versionNumber statusCode statusCode requestID uint32 } func (h ippResponseHeader) String() string { return fmt.Sprintf("Version number: %v Status code: %v Request Id: %v", h.versionNumber, h.statusCode, h.requestID) } func (h *ippResponseHeader) marshal() []byte { a := make([]byte, 8) binary.BigEndian.PutUint16(a[0:2], uint16(h.versionNumber)) binary.BigEndian.PutUint16(a[2:4], uint16(h.statusCode)) binary.BigEndian.PutUint32(a[4:8], h.requestID) return a } func (h *ippResponseHeader) unmarshal(byteStream io.Reader) { binary.Read(byteStream, binary.BigEndian, &h.versionNumber) binary.Read(byteStream, binary.BigEndian, &h.statusCode) binary.Read(byteStream, binary.BigEndian, &h.requestID) } // Response represens a ipp response object type Response struct { a *Attributes header ippResponseHeader } // NewResponse creates a new ipp response object func NewResponse(code statusCode, requestID uint32) *Response { r := new(Response) r.a = new(Attributes) r.header.versionNumber = 0x0101 r.header.requestID = requestID r.header.statusCode = code return r } func (r Response) String() string { return r.header.String() + "\n" + r.a.String() } func (r Response) Header() ippResponseHeader { return r.header } // Marshal converts the response object to a wire formatted byte stream. func (r *Response) Marshal() []byte { a := make([]byte, 0, 20) a = append(a, r.header.marshal()...) if len(r.a.operation) > 0 { a = append(a, byte(operationAttributes)) for _, e := range r.a.operation { a = append(a, e.marshal()...) } } if len(r.a.job) > 0 { a = append(a, byte(jobAttributes)) for _, e := range r.a.job { a = append(a, e.marshal()...) } } if len(r.a.printer) > 0 { a = append(a, byte(printerAttributes)) for _, e := range r.a.printer { a = append(a, e.marshal()...) } } a = append(a, byte(endOfAttributes)) return a } // UnMarshal unmarshals a ipp response into a response object func (r *Response) UnMarshal(body io.Reader) { buffbody := bufio.NewReader(body) r.header.unmarshal(buffbody) r.a = UnMarshalAttributes(buffbody) } // AddPrinterAttribute adds a printer attribute to the response object func (r *Response) AddPrinterAttribute(a Attribute) error { if a != nil { r.a.addAttribute(printerAttributes, a) return nil } return ErrNilAttribute } // AddOperatonAttribute adds a printer attribute to the response object func (r *Response) AddOperatonAttribute(a Attribute) error { if a != nil { r.a.addAttribute(operationAttributes, a) return nil } return ErrNilAttribute } // AddJobAttribute adds a printer attribute to the response object func (r *Response) AddJobAttribute(a Attribute) error { if a != nil { r.a.addAttribute(jobAttributes, a) return nil } return ErrNilAttribute } // GetAttribute retreives a attribute by name from the response object // returns nil a atribute with the provided name can be found. func (r *Response) GetAttribute(name string) Attribute { for _, a := range r.a.operation { if a.Name() == name { return a } } for _, a := range r.a.job { if a.Name() == name { return a } } for _, a := range r.a.printer { if a.Name() == name { return a } } for _, a := range r.a.unsupported { if a.Name() == name { return a } } return nil }