Compare commits
7 Commits
2-add-keyw
...
add-collec
| Author | SHA1 | Date | |
|---|---|---|---|
| 48aa81238d | |||
| 0805cec129 | |||
| f449b535db | |||
| 1eff8711d3 | |||
| e0a0c88d95 | |||
| 53aaaf5521 | |||
| 04a4b4157f |
39
client/main.go
Normal file
39
client/main.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"ippserver/packages/ipp"
|
||||
"net/http"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
//application/ipp
|
||||
// brn30055cb5e3ae.local:631/ipp/print
|
||||
func main() {
|
||||
|
||||
customFormatter := new(log.TextFormatter)
|
||||
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
|
||||
log.SetFormatter(customFormatter)
|
||||
customFormatter.FullTimestamp = true
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
const printerUri = "brn30055cb5e3ae.local:631/ipp/print"
|
||||
|
||||
request := ipp.NewRequest(ipp.GetPrinterAttributes, 10)
|
||||
request.AddOperatonAttribute(ipp.NewCharSetValue("attributes-charset", "utf-8"))
|
||||
request.AddOperatonAttribute(ipp.NewNaturalLanguage("attributes-natural-language", "en"))
|
||||
request.AddOperatonAttribute(ipp.NewURIValue("printer-uri", "ipp://"+printerUri))
|
||||
r := request.Marshal()
|
||||
b := bytes.NewBuffer(r)
|
||||
httpResponse, err := http.Post("http://"+"brn30055cb5e3ae.local:631/ipp/print", "application/ipp", b)
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
return
|
||||
}
|
||||
rb := ipp.NewResponse(0, 0)
|
||||
rb.UnMarshal(httpResponse.Body)
|
||||
fmt.Print(r)
|
||||
|
||||
}
|
||||
59
packages/ipp/boolean.go
Normal file
59
packages/ipp/boolean.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package ipp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type boolean struct {
|
||||
name string
|
||||
value bool
|
||||
}
|
||||
|
||||
func NewBoolean(name string, value bool) *boolean {
|
||||
b := new(boolean)
|
||||
b.name = name
|
||||
b.value = value
|
||||
return b
|
||||
}
|
||||
|
||||
func (b boolean) Name() string {
|
||||
return b.name
|
||||
}
|
||||
|
||||
func (b boolean) String() string {
|
||||
return b.name + ":" + fmt.Sprint(b.value)
|
||||
}
|
||||
|
||||
func (b *boolean) valueTag() tag {
|
||||
return booleanValueTag
|
||||
}
|
||||
|
||||
func (b *boolean) unmarshal(byteStream io.Reader) {
|
||||
log.Warn("Unmarshal of boolean is not implemented yet")
|
||||
}
|
||||
|
||||
func (b *boolean) marshal() []byte {
|
||||
l := 5 + len(b.name)
|
||||
ba := make([]byte, 0, l)
|
||||
buf := bytes.NewBuffer(ba)
|
||||
buf.WriteByte(byte(booleanValueTag))
|
||||
binary.Write(buf, binary.BigEndian, uint16(len(b.name)))
|
||||
buf.WriteString(b.name)
|
||||
binary.Write(buf, binary.BigEndian, uint16(1))
|
||||
if b.value {
|
||||
buf.WriteByte(byte(1))
|
||||
} else {
|
||||
buf.WriteByte(byte(0))
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func (b *boolean) size() int {
|
||||
l := 5 + len(b.name)
|
||||
return l
|
||||
}
|
||||
@@ -16,9 +16,14 @@ func NewCharSetValue(name string, value string) *charSetValue {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c charSetValue) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
func (c charSetValue) String() string {
|
||||
return c.name + ":" + c.value
|
||||
}
|
||||
|
||||
func (c *charSetValue) valueTag() tag {
|
||||
return charsetValueTag
|
||||
}
|
||||
@@ -29,7 +34,7 @@ func (c *charSetValue) unmarshal(byteStream io.Reader) {
|
||||
|
||||
func (c *charSetValue) marshal() []byte {
|
||||
l := 5 + len(c.name) + len(c.value)
|
||||
b := make([]byte, l, l)
|
||||
b := make([]byte, l)
|
||||
b[0] = byte(charsetValueTag)
|
||||
marshalNameValue(c.name, c.value, b[1:])
|
||||
return b
|
||||
|
||||
74
packages/ipp/collection.go
Normal file
74
packages/ipp/collection.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package ipp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Currently the collection data is just consumed and dropped from the bytestream
|
||||
func consumeCollection(byteStream *bufio.Reader) {
|
||||
// RFC8010 Section 3.1.6
|
||||
var length uint16
|
||||
|
||||
binary.Read(byteStream, binary.BigEndian, &length)
|
||||
collectionName := make([]byte, length)
|
||||
if length > 0 {
|
||||
binary.Read(byteStream, binary.BigEndian, collectionName)
|
||||
}
|
||||
log.Info("collection name " + string(collectionName))
|
||||
err := binary.Read(byteStream, binary.BigEndian, &length) //Always zero ??
|
||||
if err != nil {
|
||||
log.Fatal("error ", err.Error())
|
||||
}
|
||||
if length != 0 {
|
||||
log.Fatal("Should be zero")
|
||||
}
|
||||
// Member attributes
|
||||
done:
|
||||
for {
|
||||
var t tag
|
||||
binary.Read(byteStream, binary.BigEndian, &t)
|
||||
log.Debug("Collection tag ", t)
|
||||
switch t {
|
||||
case endCollectionValueTag:
|
||||
binary.Read(byteStream, binary.BigEndian, &length)
|
||||
if length != 0 {
|
||||
log.Fatal("Should be zero")
|
||||
}
|
||||
binary.Read(byteStream, binary.BigEndian, &length)
|
||||
if length != 0 {
|
||||
log.Fatal("Should be zero")
|
||||
}
|
||||
case memberAttrNameValueTag:
|
||||
// RFC8010 Section 3.7.1
|
||||
binary.Read(byteStream, binary.BigEndian, &length) //Always zero ??
|
||||
if length != 0 {
|
||||
log.Fatal("Should be zero")
|
||||
}
|
||||
binary.Read(byteStream, binary.BigEndian, &length) // Value length
|
||||
memberName := make([]byte, length)
|
||||
binary.Read(byteStream, binary.BigEndian, memberName)
|
||||
log.Debugf("Member name: %v", string(memberName))
|
||||
var memberValueTag tag
|
||||
binary.Read(byteStream, binary.BigEndian, &memberValueTag)
|
||||
log.Debug("Member value tag: ", memberValueTag)
|
||||
binary.Read(byteStream, binary.BigEndian, &length) //Always zero ??
|
||||
if length != 0 {
|
||||
log.Fatal("Should be zero")
|
||||
}
|
||||
var memberValueLength uint16
|
||||
binary.Read(byteStream, binary.BigEndian, &memberValueLength)
|
||||
memberValue := make([]byte, memberValueLength)
|
||||
binary.Read(byteStream, binary.BigEndian, memberValue)
|
||||
log.Debugf("Member Value: % x", memberValue)
|
||||
default:
|
||||
// Next tag is one that can not be handled in the collection
|
||||
// Put it back in the byte stream and return to main loop
|
||||
byteStream.UnreadByte()
|
||||
break done
|
||||
}
|
||||
}
|
||||
log.Debug("Collection done")
|
||||
}
|
||||
@@ -1,52 +1,41 @@
|
||||
package ipp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type enum struct {
|
||||
name string
|
||||
value int32
|
||||
name string
|
||||
values []int32
|
||||
}
|
||||
|
||||
func NewEnum(name string, value int32) *enum {
|
||||
func NewEnum(name string, values ...int32) *enum {
|
||||
e := new(enum)
|
||||
e.name = name
|
||||
e.value = value
|
||||
e.values = values
|
||||
return e
|
||||
}
|
||||
|
||||
func (e enum) String() string {
|
||||
return e.name + ":" + fmt.Sprint(e.value)
|
||||
func (e enum) Name() string {
|
||||
return e.name
|
||||
}
|
||||
|
||||
func (e enum) String() string {
|
||||
return e.name + ":" + fmt.Sprint(e.values)
|
||||
}
|
||||
|
||||
func (e *enum) valueTag() tag {
|
||||
return enumValueTag
|
||||
}
|
||||
|
||||
func (e *enum) unmarshal(byteStream io.Reader) {
|
||||
log.Warn("Unmarshal of enum is not implemented yet")
|
||||
func (e *enum) size() int {
|
||||
return 9 + len(e.name)
|
||||
}
|
||||
|
||||
func (e *enum) addValue(v interface{}) {
|
||||
e.values = append(e.values, v.(int32))
|
||||
}
|
||||
|
||||
func (e *enum) marshal() []byte {
|
||||
l := 3 + len(e.name) + 6
|
||||
b := make([]byte, 0, l)
|
||||
buf := bytes.NewBuffer(b)
|
||||
buf.WriteByte(byte(enumValueTag))
|
||||
binary.Write(buf, binary.BigEndian, uint16(len(e.name)))
|
||||
buf.WriteString(e.name)
|
||||
binary.Write(buf, binary.BigEndian, uint16(4))
|
||||
binary.Write(buf, binary.BigEndian, e.value)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func (e *enum) size() int {
|
||||
l := 1 + 4 // The attribute tag + 2 lengths
|
||||
l += len(e.name)
|
||||
l += 4
|
||||
return l
|
||||
return marshalInteger(enumValueTag, e.name, e.values)
|
||||
}
|
||||
|
||||
67
packages/ipp/integer.go
Normal file
67
packages/ipp/integer.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package ipp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type integer struct {
|
||||
name string
|
||||
values []int32
|
||||
}
|
||||
|
||||
func NewInteger(name string, values ...int32) *integer {
|
||||
e := new(integer)
|
||||
e.name = name
|
||||
e.values = values
|
||||
return e
|
||||
}
|
||||
|
||||
func (i integer) Name() string {
|
||||
return i.name
|
||||
}
|
||||
|
||||
func (i integer) String() string {
|
||||
return i.name + ":" + fmt.Sprint(i.values)
|
||||
}
|
||||
|
||||
func (i *integer) valueTag() tag {
|
||||
return integerValueTag
|
||||
}
|
||||
|
||||
func (i *integer) size() int {
|
||||
return 9 + len(i.name) // The attribute tag + 2 lengths
|
||||
}
|
||||
|
||||
func (i *integer) addValue(v interface{}) {
|
||||
i.values = append(i.values, v.(int32))
|
||||
}
|
||||
|
||||
func (i *integer) marshal() []byte {
|
||||
return marshalInteger(integerValueTag, i.name, i.values)
|
||||
}
|
||||
|
||||
func marshalInteger(t tag, name string, values []int32) []byte {
|
||||
l := 9 + len(name)
|
||||
b := make([]byte, 0, l)
|
||||
buf := bytes.NewBuffer(b)
|
||||
buf.WriteByte(byte(integerValueTag))
|
||||
binary.Write(buf, binary.BigEndian, uint16(len(name)))
|
||||
buf.WriteString(name)
|
||||
binary.Write(buf, binary.BigEndian, uint16(4))
|
||||
binary.Write(buf, binary.BigEndian, values[0])
|
||||
for _, v := range values[1:] {
|
||||
buf.WriteByte(byte(integerValueTag))
|
||||
binary.Write(buf, binary.BigEndian, uint16(0))
|
||||
binary.Write(buf, binary.BigEndian, uint16(4))
|
||||
binary.Write(buf, binary.BigEndian, v)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func unmarshalSingleInteger(byteStream io.Reader) (string, int32) {
|
||||
name, data := unmarshalSingleAttribute(byteStream)
|
||||
return name, int32(binary.BigEndian.Uint32(data))
|
||||
}
|
||||
38
packages/ipp/integer_test.go
Normal file
38
packages/ipp/integer_test.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package ipp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUnMarshalSinglePositiveInteger(T *testing.T) {
|
||||
testdata := []byte{
|
||||
0x00, 0x04,
|
||||
0x66, 0x6c, 0x6f, 0x70, //flop
|
||||
0x00, 0x04,
|
||||
0x00, 0x0, 0x0, 0x4,
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(testdata)
|
||||
|
||||
n, v := unmarshalSingleInteger(buf)
|
||||
assert.Equal(T, "flop", n, "Should be equal")
|
||||
assert.Equal(T, int32(4), v, "Should be equal")
|
||||
}
|
||||
|
||||
func TestUnMarshalSingleNegativeInteger(T *testing.T) {
|
||||
testdata := []byte{
|
||||
0x00, 0x04,
|
||||
0x66, 0x6c, 0x6f, 0x70, //flop
|
||||
0x00, 0x04,
|
||||
0xff, 0xff, 0xff, 0xfc,
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(testdata)
|
||||
|
||||
n, v := unmarshalSingleInteger(buf)
|
||||
assert.Equal(T, "flop", n, "Should be equal")
|
||||
assert.Equal(T, int32(-4), v, "Should be equal")
|
||||
}
|
||||
@@ -11,6 +11,10 @@ func NewKeyWord(name string, values ...string) *keyWord {
|
||||
return k
|
||||
}
|
||||
|
||||
func (k keyWord) Name() string {
|
||||
return k.sos.name
|
||||
}
|
||||
|
||||
func (k keyWord) String() string {
|
||||
return k.sos.String()
|
||||
}
|
||||
@@ -27,7 +31,7 @@ func (k *keyWord) marshal() []byte {
|
||||
return k.sos.marshal()
|
||||
}
|
||||
|
||||
func (k *keyWord) addValue(v string) {
|
||||
k.sos.AddValue(v)
|
||||
func (k *keyWord) addValue(v interface{}) {
|
||||
k.sos.AddValue(v.(string))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
//Package ipp provides functonality to handle ipp messages
|
||||
package ipp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// References
|
||||
@@ -54,30 +58,31 @@ const (
|
||||
memberAttrNameValueTag tag = 0x4a
|
||||
)
|
||||
|
||||
// Operation-id, defined in rfc8011
|
||||
type OperationId uint16
|
||||
// OperationID is defined in rfc8011
|
||||
type OperationID uint16
|
||||
|
||||
const (
|
||||
PrintJob OperationId = 0x0002
|
||||
PrintURI OperationId = 0x0003
|
||||
ValidateJob OperationId = 0x0004
|
||||
CreateJob OperationId = 0x0005
|
||||
SendDocument OperationId = 0x0006
|
||||
SendURI OperationId = 0x0007
|
||||
CancelJob OperationId = 0x0008
|
||||
GetJobAttributes OperationId = 0x0009
|
||||
GetJobs OperationId = 0x000a
|
||||
GetPrinterAttributes OperationId = 0x000b
|
||||
HoldJob OperationId = 0x000c
|
||||
ReleaseJob OperationId = 0x000d
|
||||
RestartJob OperationId = 0x000e
|
||||
PausePrinter OperationId = 0x0010
|
||||
ResumePrinter OperationId = 0x0011
|
||||
PurgeJobs OperationId = 0x0012
|
||||
PrintJob OperationID = 0x0002
|
||||
PrintURI OperationID = 0x0003
|
||||
ValidateJob OperationID = 0x0004
|
||||
CreateJob OperationID = 0x0005
|
||||
SendDocument OperationID = 0x0006
|
||||
SendURI OperationID = 0x0007
|
||||
CancelJob OperationID = 0x0008
|
||||
GetJobAttributes OperationID = 0x0009
|
||||
GetJobs OperationID = 0x000a
|
||||
GetPrinterAttributes OperationID = 0x000b
|
||||
HoldJob OperationID = 0x000c
|
||||
ReleaseJob OperationID = 0x000d
|
||||
RestartJob OperationID = 0x000e
|
||||
PausePrinter OperationID = 0x0010
|
||||
ResumePrinter OperationID = 0x0011
|
||||
PurgeJobs OperationID = 0x0012
|
||||
)
|
||||
|
||||
type printerState int32
|
||||
|
||||
// printerstate defenitions
|
||||
const (
|
||||
Idle printerState = 3
|
||||
Processing printerState = 4
|
||||
@@ -86,6 +91,7 @@ const (
|
||||
|
||||
type statusCode uint16
|
||||
|
||||
// status code defenitions
|
||||
const (
|
||||
SuccessfulOk statusCode = 0x0000
|
||||
ClientErrorBadRequest statusCode = 0x0400
|
||||
@@ -98,6 +104,19 @@ func (v versionNumber) String() string {
|
||||
return fmt.Sprintf("%x.%x", vn&0xff00>>8, vn&0x00ff)
|
||||
}
|
||||
|
||||
func unmarshalSingleAttribute(byteStream io.Reader) (string, []byte) {
|
||||
var length uint16
|
||||
binary.Read(byteStream, binary.BigEndian, &length)
|
||||
attributeName := make([]byte, length)
|
||||
if length > 0 {
|
||||
binary.Read(byteStream, binary.BigEndian, attributeName)
|
||||
}
|
||||
binary.Read(byteStream, binary.BigEndian, &length)
|
||||
attributeValue := make([]byte, length)
|
||||
binary.Read(byteStream, binary.BigEndian, attributeValue)
|
||||
return string(attributeName), attributeValue
|
||||
}
|
||||
|
||||
func unmarshalSingleValue(byteStream io.Reader) (string, string) {
|
||||
var length uint16
|
||||
binary.Read(byteStream, binary.BigEndian, &length)
|
||||
@@ -121,3 +140,172 @@ func marshalNameValue(name, value string, b []byte) {
|
||||
p += 2
|
||||
copy(b[p:], []byte(value))
|
||||
}
|
||||
|
||||
type Attribute interface {
|
||||
Name() string
|
||||
valueTag() tag
|
||||
marshal() []byte
|
||||
//size() int
|
||||
}
|
||||
|
||||
type attributes struct {
|
||||
operation []Attribute
|
||||
printer []Attribute
|
||||
job []Attribute
|
||||
}
|
||||
|
||||
func (a *attributes) String() string {
|
||||
s := " OperationAttributes" + "\n"
|
||||
for _, a := range a.operation {
|
||||
s = s + fmt.Sprintf(" %v (%v)\n", a, a.valueTag())
|
||||
}
|
||||
s = s + " PrinterAttributes" + "\n"
|
||||
for _, a := range a.printer {
|
||||
s = s + fmt.Sprintf(" %v (%v)\n", a, a.valueTag())
|
||||
}
|
||||
s = s + " JobAttributes" + "\n"
|
||||
for _, a := range a.job {
|
||||
s = s + fmt.Sprintf(" %v (%v)\n", a, a.valueTag())
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (a *attributes) addAttribute(group tag, attr Attribute) {
|
||||
switch group {
|
||||
case operationAttributes:
|
||||
a.operation = append(a.operation, attr)
|
||||
case jobAttributes:
|
||||
a.job = append(a.job, attr)
|
||||
case printerAttributes:
|
||||
a.printer = append(a.printer, attr)
|
||||
default:
|
||||
log.Error("Unknown attribute group")
|
||||
}
|
||||
}
|
||||
|
||||
func UnMarshalAttributes(bytestream *bufio.Reader) *attributes {
|
||||
a := new(attributes)
|
||||
|
||||
var t tag
|
||||
err := binary.Read(bytestream, binary.BigEndian, &t)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
log.Debugf("got tag - %v", t)
|
||||
if t != operationAttributes && t != jobAttributes && t != printerAttributes {
|
||||
log.Errorf("Unknown attribute group tag %v", t)
|
||||
return nil
|
||||
}
|
||||
currentAttributeGroup := t
|
||||
|
||||
var lastAddValuer AddValuer
|
||||
for {
|
||||
err = binary.Read(bytestream, binary.BigEndian, &t)
|
||||
if err != nil {
|
||||
log.Fatal("End of input before end of attributes tag (%v)", err.Error())
|
||||
}
|
||||
log.Debugf("Value tag - %v", t)
|
||||
switch t {
|
||||
case endOfAttributes:
|
||||
return a
|
||||
case charsetValueTag:
|
||||
c := NewCharSetValue("", "")
|
||||
c.unmarshal(bytestream)
|
||||
a.addAttribute(currentAttributeGroup, c)
|
||||
log.Debugf("%v %v", c.name, c.value)
|
||||
case booleanValueTag:
|
||||
na := NewBoolean("", false)
|
||||
na.unmarshal(bytestream)
|
||||
a.addAttribute(currentAttributeGroup, na)
|
||||
case uriValueTag:
|
||||
u := NewURIValue("", "")
|
||||
u.unmarshal(bytestream)
|
||||
a.addAttribute(currentAttributeGroup, u)
|
||||
log.Debugf("%v %v", u.name, u.value)
|
||||
case naturalLanguageValueTag:
|
||||
n := NewNaturalLanguage("", "")
|
||||
n.unmarshal(bytestream)
|
||||
a.addAttribute(currentAttributeGroup, n)
|
||||
log.Debugf("%v %v", n.name, n.value)
|
||||
case keyWordValueTag:
|
||||
name, value := unmarshalSingleValue(bytestream)
|
||||
if name == "" {
|
||||
lastAddValuer.addValue(value)
|
||||
} else {
|
||||
k := NewKeyWord(name, value)
|
||||
a.addAttribute(currentAttributeGroup, k)
|
||||
lastAddValuer = k
|
||||
}
|
||||
log.Debugf("%v : %v", name, value)
|
||||
case nameWithoutLanguageValueTag:
|
||||
n := NewNameWithoutLanguage("", "")
|
||||
n.unmarshal(bytestream)
|
||||
a.addAttribute(currentAttributeGroup, n)
|
||||
log.Debugf("%v %v", n.name, n.value)
|
||||
case textWithoutLanguageValueTag:
|
||||
attr := NewtextWithoutLanguage("", "")
|
||||
attr.unmarshal(bytestream)
|
||||
a.addAttribute(currentAttributeGroup, attr)
|
||||
log.Debugf("%v %v", attr.name, attr.value)
|
||||
case mimeMediaTypeValueTag:
|
||||
name, value := unmarshalSingleValue(bytestream)
|
||||
if name == "" {
|
||||
lastAddValuer.addValue(value)
|
||||
} else {
|
||||
m := NewMimeMediaType(name, value)
|
||||
a.addAttribute(currentAttributeGroup, m)
|
||||
lastAddValuer = m
|
||||
}
|
||||
log.Debugf("%v : %v", name, value)
|
||||
case integerValueTag:
|
||||
name, value := unmarshalSingleInteger(bytestream)
|
||||
if name == "" {
|
||||
lastAddValuer.addValue(value)
|
||||
} else {
|
||||
i := NewInteger(name, value)
|
||||
a.addAttribute(currentAttributeGroup, i)
|
||||
lastAddValuer = i
|
||||
}
|
||||
log.Debugf("%v : %v", name, value)
|
||||
case rangeOfIntegerValueTag:
|
||||
name, value := unmarshalSingleRangeOfInteger(bytestream)
|
||||
if name == "" {
|
||||
lastAddValuer.addValue(value)
|
||||
} else {
|
||||
r := NewRangeOfInteger(name, value)
|
||||
a.addAttribute(currentAttributeGroup, r)
|
||||
lastAddValuer = r
|
||||
}
|
||||
log.Debugf("%v : %v", name, value)
|
||||
case enumValueTag:
|
||||
name, value := unmarshalSingleInteger(bytestream)
|
||||
if name == "" {
|
||||
lastAddValuer.addValue(value)
|
||||
} else {
|
||||
e := NewEnum(name, value)
|
||||
a.addAttribute(currentAttributeGroup, e)
|
||||
lastAddValuer = e
|
||||
}
|
||||
log.Debugf("%v : %v", name, value)
|
||||
case begCollectionValueTag:
|
||||
// For now just consume the collection
|
||||
consumeCollection(bytestream)
|
||||
case jobAttributes:
|
||||
log.Debug("Start job attributes")
|
||||
currentAttributeGroup = jobAttributes
|
||||
case printerAttributes:
|
||||
log.Debug("Start printer attributes")
|
||||
currentAttributeGroup = printerAttributes
|
||||
case operationAttributes:
|
||||
log.Debug("Start operation attributes")
|
||||
currentAttributeGroup = operationAttributes
|
||||
case resolutionValueTag:
|
||||
res := NewResolution("", 0, 0)
|
||||
res.unmarshal(bytestream)
|
||||
a.addAttribute(currentAttributeGroup, res)
|
||||
log.Debugf("Resolution %v", res)
|
||||
default:
|
||||
log.Errorf("Unsupported tag %v (%x)", t, uint8(t))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ func NewMimeMediaType(name string, values ...string) *mimeMediaType {
|
||||
return m
|
||||
}
|
||||
|
||||
func (m mimeMediaType) Name() string {
|
||||
return m.sos.name
|
||||
}
|
||||
|
||||
func (m mimeMediaType) String() string {
|
||||
return m.sos.String()
|
||||
}
|
||||
@@ -27,6 +31,6 @@ func (m *mimeMediaType) marshal() []byte {
|
||||
return m.sos.marshal()
|
||||
}
|
||||
|
||||
func (m *mimeMediaType) addValue(v string) {
|
||||
m.sos.AddValue(v)
|
||||
func (m *mimeMediaType) addValue(v interface{}) {
|
||||
m.sos.AddValue(v.(string))
|
||||
}
|
||||
|
||||
@@ -14,29 +14,33 @@ func NewNameWithoutLanguage(name, value string) *NameWithoutLanguage {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c NameWithoutLanguage) String() string {
|
||||
return c.name + ":" + c.value
|
||||
func (n NameWithoutLanguage) Name() string {
|
||||
return n.name
|
||||
}
|
||||
func (c *NameWithoutLanguage) valueTag() tag {
|
||||
|
||||
func (n NameWithoutLanguage) String() string {
|
||||
return n.name + ":" + n.value
|
||||
}
|
||||
func (n *NameWithoutLanguage) valueTag() tag {
|
||||
return nameWithoutLanguageValueTag
|
||||
}
|
||||
|
||||
func (c *NameWithoutLanguage) unmarshal(byteStream io.Reader) {
|
||||
c.name, c.value = unmarshalSingleValue(byteStream)
|
||||
func (n *NameWithoutLanguage) unmarshal(byteStream io.Reader) {
|
||||
n.name, n.value = unmarshalSingleValue(byteStream)
|
||||
}
|
||||
|
||||
func (c *NameWithoutLanguage) marshal() []byte {
|
||||
l := 5 + len(c.name) + len(c.value)
|
||||
b := make([]byte, l, l)
|
||||
func (n *NameWithoutLanguage) marshal() []byte {
|
||||
l := 5 + len(n.name) + len(n.value)
|
||||
b := make([]byte, l)
|
||||
b[0] = byte(nameWithoutLanguageValueTag)
|
||||
marshalNameValue(c.name, c.value, b[1:])
|
||||
marshalNameValue(n.name, n.value, b[1:])
|
||||
return b
|
||||
}
|
||||
|
||||
func (c *NameWithoutLanguage) size() int {
|
||||
func (n *NameWithoutLanguage) size() int {
|
||||
l := 1 + 4 // The attribute tag + 2 lengths
|
||||
l += len(c.name)
|
||||
l += len(c.value)
|
||||
l += len(n.name)
|
||||
l += len(n.value)
|
||||
return l
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,14 @@ func NewNaturalLanguage(name, value string) *naturalLanguage {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c naturalLanguage) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
func (c naturalLanguage) String() string {
|
||||
return c.name + ":" + c.value
|
||||
}
|
||||
|
||||
func (c *naturalLanguage) valueTag() tag {
|
||||
return naturalLanguageValueTag
|
||||
}
|
||||
@@ -29,7 +34,7 @@ func (c *naturalLanguage) unmarshal(byteStream io.Reader) {
|
||||
|
||||
func (c *naturalLanguage) marshal() []byte {
|
||||
l := 5 + len(c.name) + len(c.value)
|
||||
b := make([]byte, l, l)
|
||||
b := make([]byte, l)
|
||||
b[0] = byte(naturalLanguageValueTag)
|
||||
marshalNameValue(c.name, c.value, b[1:])
|
||||
return b
|
||||
|
||||
@@ -36,7 +36,7 @@ var (
|
||||
_operationId_index_1 = [...]uint8{0, 12, 25, 34}
|
||||
)
|
||||
|
||||
func (i OperationId) String() string {
|
||||
func (i OperationID) String() string {
|
||||
switch {
|
||||
case 2 <= i && i <= 14:
|
||||
i -= 2
|
||||
|
||||
55
packages/ipp/rangeofinteger.go
Normal file
55
packages/ipp/rangeofinteger.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package ipp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type IRange struct {
|
||||
lower int32
|
||||
upper int32
|
||||
}
|
||||
|
||||
type rangeOfInteger struct {
|
||||
name string
|
||||
values []IRange
|
||||
}
|
||||
|
||||
func NewRangeOfInteger(name string, values ...IRange) *rangeOfInteger {
|
||||
r := new(rangeOfInteger)
|
||||
r.name = name
|
||||
r.values = values
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *rangeOfInteger) Name() string {
|
||||
return r.name
|
||||
}
|
||||
|
||||
func (r rangeOfInteger) String() string {
|
||||
return r.name + ":" + fmt.Sprint(r.values)
|
||||
}
|
||||
|
||||
func (r *rangeOfInteger) valueTag() tag {
|
||||
return rangeOfIntegerValueTag
|
||||
}
|
||||
|
||||
func (r *rangeOfInteger) marshal() []byte {
|
||||
log.Error("marshal rangeOfInteger is not implemented yet")
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
func (r *rangeOfInteger) addValue(v interface{}) {
|
||||
r.values = append(r.values, v.(IRange))
|
||||
}
|
||||
|
||||
func unmarshalSingleRangeOfInteger(byteStream io.Reader) (string, IRange) {
|
||||
name, data := unmarshalSingleAttribute(byteStream)
|
||||
var r IRange
|
||||
r.lower = int32(binary.BigEndian.Uint32(data[0:4]))
|
||||
r.upper = int32(binary.BigEndian.Uint32(data[4:8]))
|
||||
return name, r
|
||||
}
|
||||
24
packages/ipp/rangeofinteger_test.go
Normal file
24
packages/ipp/rangeofinteger_test.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package ipp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUnMarshalSingleRange(T *testing.T) {
|
||||
testdata := []byte{
|
||||
0x00, 0x04,
|
||||
0x66, 0x6c, 0x6f, 0x70, //flop
|
||||
0x00, 0x08,
|
||||
0x00, 0x0, 0x0, 0x4, 0x00, 0x0, 0x0, 0x5,
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(testdata)
|
||||
|
||||
n, v := unmarshalSingleRangeOfInteger(buf)
|
||||
assert.Equal(T, "flop", n, "Should be equal")
|
||||
assert.Equal(T, int32(4), v.lower, "Should be equal")
|
||||
assert.Equal(T, int32(5), v.upper, "Should be equal")
|
||||
}
|
||||
@@ -1,203 +1,118 @@
|
||||
package ipp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type ippRequestHeader struct {
|
||||
type ippMessageHeader struct {
|
||||
versionNumber versionNumber
|
||||
operationId OperationId
|
||||
requestId uint32
|
||||
operationID OperationID
|
||||
requestID uint32
|
||||
}
|
||||
|
||||
func (h *ippRequestHeader) unmarshal(byteStream io.Reader) {
|
||||
func (h *ippMessageHeader) 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)
|
||||
binary.Read(byteStream, binary.BigEndian, &h.operationID)
|
||||
binary.Read(byteStream, binary.BigEndian, &h.requestID)
|
||||
}
|
||||
|
||||
func (h *ippRequestHeader) marshal() []byte {
|
||||
func (h *ippMessageHeader) 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)
|
||||
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
|
||||
func (h ippMessageHeader) String() string {
|
||||
return fmt.Sprintf("Version number: %v Operation Id: %v Request Id: %v", h.versionNumber, h.operationID, h.requestID)
|
||||
}
|
||||
|
||||
type AddValuer interface {
|
||||
addValue(string)
|
||||
addValue(interface{})
|
||||
}
|
||||
|
||||
type Request struct {
|
||||
operationAttributes map[string]Attribute
|
||||
jobAttributes map[string]Attribute
|
||||
printerAttributes map[string]Attribute
|
||||
header ippRequestHeader
|
||||
a *attributes
|
||||
header ippMessageHeader
|
||||
}
|
||||
|
||||
func NewRequest(op OperationId, requestId uint32) *Request {
|
||||
func NewRequest(op OperationID, requestID uint32) *Request {
|
||||
r := new(Request)
|
||||
r.header.operationId = op
|
||||
r.header.requestId = requestId
|
||||
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)
|
||||
|
||||
r.a = new(attributes)
|
||||
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
|
||||
return r.header.String() + "\n" + r.a.String()
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
buffbody := bufio.NewReader(body)
|
||||
r.header.unmarshal(buffbody)
|
||||
//log.Printf("Header %v", r.header)
|
||||
r.a = UnMarshalAttributes(buffbody)
|
||||
}
|
||||
|
||||
func (r *Request) RequestId() uint32 {
|
||||
return r.header.requestId
|
||||
func (r *Request) RequestID() uint32 {
|
||||
return r.header.requestID
|
||||
}
|
||||
|
||||
func (r *Request) Operation() OperationId {
|
||||
return r.header.operationId
|
||||
func (r *Request) Operation() OperationID {
|
||||
return r.header.operationID
|
||||
}
|
||||
|
||||
func (r *Request) GetAttribute(name string) Attribute {
|
||||
return r.operationAttributes[name]
|
||||
for _, a := range r.a.operation {
|
||||
if a.Name() == name {
|
||||
return a
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Request) Marshal() []byte {
|
||||
// //s = r.size
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.Write(r.header.marshal())
|
||||
if len(r.operationAttributes) > 0 {
|
||||
if len(r.a.operation) > 0 {
|
||||
buf.WriteByte(byte(operationAttributes))
|
||||
for _, e := range r.operationAttributes {
|
||||
for _, e := range r.a.operation {
|
||||
buf.Write(e.marshal())
|
||||
}
|
||||
}
|
||||
if len(r.jobAttributes) > 0 {
|
||||
if len(r.a.job) > 0 {
|
||||
buf.WriteByte(byte(jobAttributes))
|
||||
for _, e := range r.jobAttributes {
|
||||
for _, e := range r.a.job {
|
||||
buf.Write(e.marshal())
|
||||
}
|
||||
}
|
||||
if len(r.printerAttributes) > 0 {
|
||||
if len(r.a.printer) > 0 {
|
||||
buf.WriteByte(byte(printerAttributes))
|
||||
for _, e := range r.printerAttributes {
|
||||
for _, e := range r.a.printer {
|
||||
buf.Write(e.marshal())
|
||||
}
|
||||
}
|
||||
buf.WriteByte(byte(endOfAttributes))
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func (r *Request) AddPrinterAttribute(a Attribute) {
|
||||
r.a.addAttribute(printerAttributes, a)
|
||||
}
|
||||
|
||||
func (r *Request) AddOperatonAttribute(a Attribute) {
|
||||
r.a.addAttribute(operationAttributes, a)
|
||||
}
|
||||
|
||||
func (r *Request) AddJobAttribute(a Attribute) {
|
||||
r.a.addAttribute(jobAttributes, a)
|
||||
}
|
||||
|
||||
@@ -64,10 +64,10 @@ func TestUnmarshalRequestPrinterAttributes(T *testing.T) {
|
||||
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).sos.values
|
||||
assert.Equal(T, GetPrinterAttributes, req.header.operationID, "Wrong Operation")
|
||||
assert.Equal(T, uint32(17), req.header.requestID, "Wrong request id")
|
||||
assert.Len(T, req.a.operation, 4)
|
||||
v := req.GetAttribute("requested-attributes").(*keyWord).sos.values
|
||||
assert.Len(T, v, 7)
|
||||
assert.Contains(T, v, "printer-make-and-model")
|
||||
assert.Contains(T, v, "ipp-versions-supported")
|
||||
|
||||
@@ -40,6 +40,10 @@ func (r *resolution) unmarshal(byteStream io.Reader) {
|
||||
binary.Read(byteStream, binary.BigEndian, &r.units)
|
||||
}
|
||||
|
||||
func (r resolution) Name() string {
|
||||
return r.name
|
||||
}
|
||||
|
||||
func (r resolution) String() string {
|
||||
return fmt.Sprintf("%v:%v,%v,%v", r.name, r.crossFeedResolution, r.feedResolution, r.units)
|
||||
}
|
||||
|
||||
@@ -1,115 +1,95 @@
|
||||
package ipp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type ippResponseHeader struct {
|
||||
versionNumber versionNumber
|
||||
statusCode statusCode
|
||||
requestId uint32
|
||||
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)
|
||||
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, 8)
|
||||
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)
|
||||
binary.BigEndian.PutUint32(a[4:8], h.requestID)
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
operationAttributes []Attribute
|
||||
jobAttributes []Attribute
|
||||
printerAttributes []Attribute
|
||||
header ippResponseHeader
|
||||
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)
|
||||
}
|
||||
|
||||
func NewResponse(code statusCode, requestId uint32) *Response {
|
||||
type Response struct {
|
||||
a *attributes
|
||||
header ippResponseHeader
|
||||
}
|
||||
|
||||
func NewResponse(code statusCode, requestID uint32) *Response {
|
||||
r := new(Response)
|
||||
r.a = new(attributes)
|
||||
r.header.versionNumber = 0x0101
|
||||
r.header.requestId = requestId
|
||||
r.header.requestID = requestID
|
||||
r.header.statusCode = code
|
||||
r.operationAttributes = make([]Attribute, 0)
|
||||
r.printerAttributes = make([]Attribute, 0)
|
||||
r.jobAttributes = make([]Attribute, 0)
|
||||
return r
|
||||
}
|
||||
|
||||
// func (r *Response) length() int {
|
||||
// l := 8 + 1
|
||||
// if len(r.jobAttributes) > 0 {
|
||||
// l += 1 //
|
||||
// for _, e := range r.jobAttributes {
|
||||
// l += e.length()
|
||||
// }
|
||||
// }
|
||||
// for _, e := range r.operationAttributes {
|
||||
// l += e.length()
|
||||
// }
|
||||
// for _, e := range r.printerAttributes {
|
||||
// l += e.length()
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
func (r Response) 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
|
||||
return r.header.String() + "\n" + r.a.String()
|
||||
}
|
||||
|
||||
func (r *Response) Marshal() []byte {
|
||||
a := make([]byte, 0, 20)
|
||||
a = append(a, r.header.marshal()...)
|
||||
if len(r.operationAttributes) > 0 {
|
||||
if len(r.a.operation) > 0 {
|
||||
a = append(a, byte(operationAttributes))
|
||||
for _, e := range r.operationAttributes {
|
||||
for _, e := range r.a.operation {
|
||||
a = append(a, e.marshal()...)
|
||||
}
|
||||
}
|
||||
if len(r.jobAttributes) > 0 {
|
||||
if len(r.a.job) > 0 {
|
||||
a = append(a, byte(jobAttributes))
|
||||
for _, e := range r.jobAttributes {
|
||||
for _, e := range r.a.job {
|
||||
a = append(a, e.marshal()...)
|
||||
}
|
||||
}
|
||||
if len(r.printerAttributes) > 0 {
|
||||
if len(r.a.printer) > 0 {
|
||||
a = append(a, byte(printerAttributes))
|
||||
for _, e := range r.printerAttributes {
|
||||
for _, e := range r.a.printer {
|
||||
a = append(a, e.marshal()...)
|
||||
}
|
||||
|
||||
}
|
||||
a = append(a, byte(endOfAttributes))
|
||||
return a
|
||||
}
|
||||
|
||||
func (r *Response) UnMarshal(body io.Reader) {
|
||||
buffbody := bufio.NewReader(body)
|
||||
r.header.unmarshal(buffbody)
|
||||
//log.Printf("Header %v", r.header)
|
||||
r.a = UnMarshalAttributes(buffbody)
|
||||
}
|
||||
|
||||
func (r *Response) AddPrinterAttribute(a Attribute) {
|
||||
r.printerAttributes = append(r.printerAttributes, a)
|
||||
r.a.addAttribute(printerAttributes, a)
|
||||
}
|
||||
|
||||
func (r *Response) AddOperatonAttribute(a Attribute) {
|
||||
r.operationAttributes = append(r.operationAttributes, a)
|
||||
r.a.addAttribute(operationAttributes, a)
|
||||
}
|
||||
|
||||
func (r *Response) AddJobAttribute(a Attribute) {
|
||||
r.jobAttributes = append(r.jobAttributes, a)
|
||||
r.a.addAttribute(jobAttributes, a)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ func TestMarshalResponseHeader(T *testing.T) {
|
||||
|
||||
h.versionNumber = 0x0101
|
||||
h.statusCode = SuccessfulOk
|
||||
h.requestId = 0xdeadbeef
|
||||
h.requestID = 0xdeadbeef
|
||||
|
||||
b := h.marshal()
|
||||
fmt.Printf("% x\n", b)
|
||||
|
||||
@@ -44,7 +44,7 @@ func (s *setOfStrings) marshal() []byte {
|
||||
for i := range s.values[1:] {
|
||||
l += 5 + len(s.values[i+1])
|
||||
}
|
||||
res := make([]byte, l, l)
|
||||
res := make([]byte, l)
|
||||
p := 0
|
||||
res[p] = byte(s.vTag)
|
||||
p += 1
|
||||
|
||||
@@ -14,9 +14,14 @@ func NewtextWithoutLanguage(name, value string) *textWithoutLanguage {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c textWithoutLanguage) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
func (c textWithoutLanguage) String() string {
|
||||
return c.name + ":" + c.value
|
||||
}
|
||||
|
||||
func (c *textWithoutLanguage) valueTag() tag {
|
||||
return textWithoutLanguageValueTag
|
||||
}
|
||||
@@ -27,7 +32,7 @@ func (c *textWithoutLanguage) unmarshal(byteStream io.Reader) {
|
||||
|
||||
func (c *textWithoutLanguage) marshal() []byte {
|
||||
l := 5 + len(c.name) + len(c.value)
|
||||
b := make([]byte, l, l)
|
||||
b := make([]byte, l)
|
||||
b[0] = byte(textWithoutLanguageValueTag)
|
||||
marshalNameValue(c.name, c.value, b[1:])
|
||||
return b
|
||||
@@ -9,13 +9,17 @@ type uriValue struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func NewUriValue(name, value string) *uriValue {
|
||||
func NewURIValue(name, value string) *uriValue {
|
||||
u := new(uriValue)
|
||||
u.name = name
|
||||
u.value = value
|
||||
return u
|
||||
}
|
||||
|
||||
func (u uriValue) Name() string {
|
||||
return u.name
|
||||
}
|
||||
|
||||
func (u uriValue) String() string {
|
||||
return u.name + ":" + u.value
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@ package main
|
||||
import "ippserver/packages/ipp"
|
||||
|
||||
func handleGetJobs(r *ipp.Request) *ipp.Response {
|
||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestId())
|
||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestID())
|
||||
return response
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@ package main
|
||||
import "ippserver/packages/ipp"
|
||||
|
||||
func handleGetPrinterAttributes(r *ipp.Request) *ipp.Response {
|
||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestId())
|
||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestID())
|
||||
var a ipp.Attribute
|
||||
a = ipp.NewCharSetValue("attributes-charset", "utf-8")
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewNaturalLanguage("attributes-natural-language", "en")
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewUriValue("printer-uri", "ipp://drpork:1234/ipp/print")
|
||||
a = ipp.NewURIValue("printer-uri", "ipp://drpork:1234/ipp/print")
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewtextWithoutLanguage("printer-make-and-model", "ChroBro 001")
|
||||
response.AddOperatonAttribute(a)
|
||||
|
||||
@@ -16,7 +16,7 @@ func handlePrintJob(r *ipp.Request, byteStream io.Reader) *ipp.Response {
|
||||
}
|
||||
defer f.Close()
|
||||
io.Copy(f, byteStream)
|
||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestId())
|
||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestID())
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func handle(w http.ResponseWriter, r *http.Request) {
|
||||
case ipp.GetJobs:
|
||||
response = handleGetJobs(request)
|
||||
default:
|
||||
response = ipp.NewResponse(ipp.ClientErrorBadRequest, request.RequestId())
|
||||
response = ipp.NewResponse(ipp.ClientErrorBadRequest, request.RequestID())
|
||||
}
|
||||
|
||||
log.Infof("Response:\n%v\n", response)
|
||||
|
||||
Reference in New Issue
Block a user