package ipp import ( "bytes" "encoding/binary" "fmt" "io" log "github.com/sirupsen/logrus" ) type ippRequestHeader struct { versionNumber versionNumber operationId OperationId requestId uint32 } func (h *ippRequestHeader) unmarshal(byteStream io.Reader) { binary.Read(byteStream, binary.BigEndian, &h.versionNumber) binary.Read(byteStream, binary.BigEndian, &h.operationId) binary.Read(byteStream, binary.BigEndian, &h.requestId) } func (h *ippRequestHeader) marshal() []byte { b := make([]byte, 0, 8) buf := bytes.NewBuffer(b) binary.Write(buf, binary.BigEndian, h.versionNumber) binary.Write(buf, binary.BigEndian, h.operationId) binary.Write(buf, binary.BigEndian, h.requestId) return buf.Bytes() } func (h ippRequestHeader) String() string { return fmt.Sprintf("Version number: %v Operation Id: %v Request Id: %v", h.versionNumber, h.operationId, h.requestId) } type Attribute interface { valueTag() tag marshal() []byte //size() int } type AddValuer interface { addValue(string) } type Request struct { operationAttributes map[string]Attribute jobAttributes map[string]Attribute printerAttributes map[string]Attribute header ippRequestHeader } func NewRequest(op OperationId, requestId uint32) *Request { r := new(Request) r.header.operationId = op r.header.requestId = requestId r.header.versionNumber = 0x0200 r.operationAttributes = make(map[string]Attribute) r.jobAttributes = make(map[string]Attribute) r.printerAttributes = make(map[string]Attribute) return r } func (r Request) String() string { s := r.header.String() + "\n" + " OperationAttributes" + "\n" for _, a := range r.operationAttributes { s = s + fmt.Sprintf(" %v (%v)\n", a, a.valueTag()) } s = s + " PrinterAttributes" + "\n" for _, a := range r.printerAttributes { s = s + fmt.Sprintf(" %v (%v)\n", a, a.valueTag()) } s = s + " JobAttributes" + "\n" for _, a := range r.jobAttributes { s = s + fmt.Sprintf(" %v (%v)\n", a, a.valueTag()) } return s } func (r *Request) UnMarshal(body io.Reader) { r.header.unmarshal(body) log.Debugf("Header %v", r.header) var tag tag err := binary.Read(body, binary.BigEndian, &tag) if err != nil { log.Error(err.Error()) } log.Debugf("got tag - %v", tag) var currentAttributeGroup map[string]Attribute switch tag { case operationAttributes: currentAttributeGroup = r.operationAttributes case jobAttributes: currentAttributeGroup = r.jobAttributes case printerAttributes: currentAttributeGroup = r.printerAttributes default: log.Errorf("Unknown tag %v", tag) } var lastAddValuer AddValuer for { err = binary.Read(body, binary.BigEndian, &tag) if err != nil { log.Errorf("End of input before end of attributes tag (%v)", err.Error()) } log.Debugf("Value tag - %v", tag) switch tag { case endOfAttributes: return case charsetValueTag: c := NewCharSetValue("", "") c.unmarshal(body) currentAttributeGroup[c.name] = c log.Debugf("%v %v", c.name, c.value) case uriValueTag: u := NewUriValue("", "") u.unmarshal(body) currentAttributeGroup[u.name] = u log.Debugf("%v %v", u.name, u.value) case naturalLanguageValueTag: n := NewNaturalLanguage("", "") n.unmarshal(body) currentAttributeGroup[n.name] = n log.Debugf("%v %v", n.name, n.value) case keyWordValueTag: name, value := unmarshalSingleValue(body) if name == "" { lastAddValuer.addValue(value) } else { k := NewKeyWord(name, value) currentAttributeGroup[name] = k lastAddValuer = k } log.Debugf("%v : %v", name, value) case nameWithoutLanguageValueTag: n := NewNameWithoutLanguage("", "") n.unmarshal(body) currentAttributeGroup[n.name] = n log.Debugf("%v %v", n.name, n.value) case mimeMediaTypeValueTag: name, value := unmarshalSingleValue(body) if name == "" { lastAddValuer.addValue(value) } else { m := NewMimeMediaType(name, value) currentAttributeGroup[name] = m lastAddValuer = m } log.Debugf("%v : %v", name, value) case jobAttributes: log.Debug("Start job attributes") currentAttributeGroup = r.jobAttributes case resolutionValueTag: res := NewResolution("", 0, 0) res.unmarshal(body) currentAttributeGroup[res.name] = res log.Debugf("Resolution %v", res) default: log.Errorf("Unsupported tag %v", tag) } } } func (r *Request) RequestId() uint32 { return r.header.requestId } func (r *Request) Operation() OperationId { return r.header.operationId } func (r *Request) GetAttribute(name string) Attribute { return r.operationAttributes[name] } func (r *Request) Marshal() []byte { // //s = r.size var buf bytes.Buffer buf.Write(r.header.marshal()) if len(r.operationAttributes) > 0 { buf.WriteByte(byte(operationAttributes)) for _, e := range r.operationAttributes { buf.Write(e.marshal()) } } if len(r.jobAttributes) > 0 { buf.WriteByte(byte(jobAttributes)) for _, e := range r.jobAttributes { buf.Write(e.marshal()) } } if len(r.printerAttributes) > 0 { buf.WriteByte(byte(printerAttributes)) for _, e := range r.printerAttributes { buf.Write(e.marshal()) } } buf.WriteByte(byte(endOfAttributes)) return buf.Bytes() }