diff --git a/packages/ipp/messages.go b/packages/ipp/messages.go index da6c279..5033df9 100644 --- a/packages/ipp/messages.go +++ b/packages/ipp/messages.go @@ -4,8 +4,6 @@ import ( "encoding/binary" "fmt" "io" - - log "github.com/sirupsen/logrus" ) // References @@ -92,137 +90,6 @@ func (v versionNumber) String() string { return fmt.Sprintf("%x.%x", vn&0xff00>>8, vn&0x00ff) } -type ippRequestHeader struct { - versionNumber versionNumber - operationId operationId - requestId uint32 -} - -func (h *ippRequestHeader) marshal(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) 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 - unmarshal(io.Reader) - marshal() []byte - size() int -} - -type Request struct { - header ippRequestHeader - operationAttributes map[string]Attribute - jobAttributes map[string]Attribute - printerAttributes map[string]Attribute -} - -func NewRequest() *Request { - r := new(Request) - 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()) - } - return s -} - -// log.Info(r.Header) -// log.Info(r.ContentLength) - -//body := make([]byte, r.ContentLength) -//body.Read(body) - -func (r *Request) UnMarshal(body io.Reader) { - r.header.marshal(body) - log.Infof("Header %v", r.header) - var tag tag - err := binary.Read(body, binary.BigEndian, &tag) - if err != nil { - log.Error(err.Error()) - } - log.Infof("got tag - %v", tag) - - if tag == operationAttributes { - nextoperationattr: - for tag != endOfAttributes { - var lastKeyword *keyWord - err = binary.Read(body, binary.BigEndian, &tag) - if err != nil { - log.Error(err.Error()) - } - log.Infof("Value tag - %v", tag) - switch tag { - case endOfAttributes: - err = binary.Read(body, binary.BigEndian, &tag) - if err == io.EOF { - // No more data - return - } - if err != nil { - log.Error(err.Error()) - } - log.Infof("got tag - %v", tag) - err = binary.Read(body, binary.BigEndian, &tag) - if err != nil { - log.Error(err.Error()) - } - log.Infof("got tag - %v", tag) - - break nextoperationattr - case charsetValueTag: - c := NewCharSetValue("", "") - c.unmarshal(body) - r.operationAttributes[c.name] = c - log.Infof("%v %v", c.name, c.value) - case uriValueTag: - u := newUriValue("", "") - u.unmarshal(body) - r.operationAttributes[u.name] = u - log.Infof("%v %v", u.name, u.value) - case naturalLanguagageValueTag: - n := newNaturalLanguagage("", "") - n.unmarshal(body) - r.operationAttributes[n.name] = n - log.Infof("%v %v", n.name, n.value) - case keyWordValueTag: - k := newKeyWord() - k.unmarshal(body) - r.operationAttributes[k.name] = k - if k.name == "" { - lastKeyword.addValue(k.values[0]) - } else { - lastKeyword = k - } - default: - log.Errorf("Unsupported tag %v", tag) - - } - } - log.Infof("Value tag %v", tag) - } else { - log.Error("unexpected tag") - // TODO Return something sensible here - - } -} - -func (r *Request) RequestId() uint32 { - return r.header.requestId -} - func unmarshalSingleValue(byteStream io.Reader) (string, string) { var length uint16 binary.Read(byteStream, binary.BigEndian, &length) diff --git a/packages/ipp/request.go b/packages/ipp/request.go new file mode 100644 index 0000000..a4d014d --- /dev/null +++ b/packages/ipp/request.go @@ -0,0 +1,137 @@ +package ipp + +import ( + "encoding/binary" + "fmt" + "io" + + log "github.com/sirupsen/logrus" +) + +type ippRequestHeader struct { + versionNumber versionNumber + operationId operationId + requestId uint32 +} + +func (h *ippRequestHeader) marshal(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) 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 + //unmarshal(io.Reader) + marshal() []byte + size() int +} + +type Request struct { + header ippRequestHeader + operationAttributes map[string]Attribute + jobAttributes map[string]Attribute + printerAttributes map[string]Attribute +} + +func NewRequest() *Request { + r := new(Request) + 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()) + } + return s +} + +func (r *Request) UnMarshal(body io.Reader) { + r.header.marshal(body) + log.Infof("Header %v", r.header) + var tag tag + err := binary.Read(body, binary.BigEndian, &tag) + if err != nil { + log.Error(err.Error()) + } + log.Infof("got tag - %v", tag) + + if tag == operationAttributes { + var lastKeyword *keyWord + nextoperationattr: + for tag != endOfAttributes { + + err = binary.Read(body, binary.BigEndian, &tag) + if err != nil { + log.Error(err.Error()) + } + log.Infof("Value tag - %v", tag) + switch tag { + case endOfAttributes: + err = binary.Read(body, binary.BigEndian, &tag) + if err == io.EOF { + // No more data + return + } + if err != nil { + log.Error(err.Error()) + } + log.Infof("got tag - %v", tag) + err = binary.Read(body, binary.BigEndian, &tag) + if err != nil { + log.Error(err.Error()) + } + log.Infof("got tag - %v", tag) + + break nextoperationattr + case charsetValueTag: + c := NewCharSetValue("", "") + c.unmarshal(body) + r.operationAttributes[c.name] = c + log.Infof("%v %v", c.name, c.value) + case uriValueTag: + u := newUriValue("", "") + u.unmarshal(body) + r.operationAttributes[u.name] = u + log.Infof("%v %v", u.name, u.value) + case naturalLanguagageValueTag: + n := newNaturalLanguagage("", "") + n.unmarshal(body) + r.operationAttributes[n.name] = n + log.Infof("%v %v", n.name, n.value) + case keyWordValueTag: + name, value := unmarshalSingleValue(body) + if name == "" { + lastKeyword.addValue(value) + } else { + k := newKeyWord() + k.name = name + k.addValue(value) + r.operationAttributes[k.name] = k + lastKeyword = k + } + default: + log.Errorf("Unsupported tag %v", tag) + + } + } + log.Infof("Value tag %v", tag) + } else { + log.Error("unexpected tag") + // TODO Return something sensible here + + } +} + +func (r *Request) RequestId() uint32 { + return r.header.requestId +} diff --git a/packages/ipp/request_test.go b/packages/ipp/request_test.go new file mode 100644 index 0000000..7dfafdc --- /dev/null +++ b/packages/ipp/request_test.go @@ -0,0 +1,79 @@ +package ipp + +import ( + "bytes" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +var testRequest = []byte{0x01, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x11, + 0x01, + 0x47, + 0x00, 0x12, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, + 0x00, 0x05, + 0x75, 0x74, 0x66, 0x2d, 0x38, + 0x48, + 0x00, 0x1b, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2d, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x61, 0x6c, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, + 0x00, 0x05, + 0x65, 0x6e, 0x2d, 0x75, 0x73, + 0x45, // uriValueTag + 0x00, 0x0b, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x75, 0x72, 0x69, + 0x00, 0x20, + 0x69, 0x70, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x32, 0x3a, 0x31, 0x32, 0x33, 0x34, 0x2f, 0x69, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x44, // keywordValueTag + 0x00, 0x14, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x2d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, + 0x00, 0x16, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x6d, 0x61, 0x6b, 0x65, 0x2d, 0x61, 0x6e, 0x64, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x6c, + 0x44, // keywordValueTag + 0x00, 0x00, + 0x00, 0x16, + 0x69, 0x70, 0x70, 0x2d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x44, // keywordValueTag + 0x00, 0x00, + 0x00, 0x16, + 0x69, 0x70, 0x70, 0x2d, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x44, // keywordValueTag + 0x00, 0x00, + 0x00, 0x19, + 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x44, + 0x00, 0x00, + 0x00, 0x0d, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x44, + 0x00, 0x00, + 0x00, 0x15, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2d, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x73, + 0x44, + 0x00, 0x00, + 0x00, 0x15, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x03} + +func TestUnmarshalRequestPrinterAttributes(T *testing.T) { + buf := bytes.NewBuffer(testRequest) + + req := NewRequest() + + req.UnMarshal(buf) + fmt.Print(req) + assert.Equal(T, versionNumber(0x0101), req.header.versionNumber, "Wrong version number") + assert.Equal(T, GetPrinterAttributes, req.header.operationId, "Wrong Operation") + assert.Equal(T, uint32(17), req.header.requestId, "Wrong request id") + assert.Len(T, req.operationAttributes, 4) + v := req.operationAttributes["requested-attributes"].(*keyWord).values + assert.Len(T, v, 7) + assert.Contains(T, v, "printer-make-and-model") + assert.Contains(T, v, "ipp-versions-supported") + assert.Contains(T, v, "ipp-features-supported") + assert.Contains(T, v, "document-format-supported") + assert.Contains(T, v, "printer-state-reasons") + assert.Contains(T, v, "printer-state-message") + assert.Contains(T, v, "printer-state") +}