2-add-keyword-support (#6)

More development.

More types.
Fixed attribute groups in requests.
Started on client.
Saving data to file.

More types. Printing from chromeos works a little bit.

More types.

Spelling corrections.

WIP: Fix keyword handling

Move request to a separate file and add test.

Co-authored-by: Henrik Sölver <henrik.solver@gmail.com>
Reviewed-on: #6
Co-Authored-By: henrik <henrik.solver@gmail.com>
Co-Committed-By: henrik <henrik.solver@gmail.com>
This commit was merged in pull request #6.
This commit is contained in:
2020-12-27 09:16:32 +01:00
parent 34c4385491
commit 04a4b4157f
23 changed files with 881 additions and 257 deletions

View File

@@ -4,8 +4,6 @@ import (
"encoding/binary"
"fmt"
"io"
log "github.com/sirupsen/logrus"
)
// References
@@ -45,37 +43,45 @@ const (
endCollectionValueTag tag = 0x37
// Character string values
textWithoutLanguagageValueTag tag = 0x41
nameWithoutLanguagageValueTag tag = 0x42
keyWordValueTag tag = 0x44
uriValueTag tag = 0x45
uriSchemeValueTag tag = 0x46
charsetValueTag tag = 0x47
naturalLanguagageValueTag tag = 0x48
mimeMediaTypeValueTag tag = 0x49
memberAttrNameValueTag tag = 0x4a
textWithoutLanguageValueTag tag = 0x41
nameWithoutLanguageValueTag tag = 0x42
keyWordValueTag tag = 0x44
uriValueTag tag = 0x45
uriSchemeValueTag tag = 0x46
charsetValueTag tag = 0x47
naturalLanguageValueTag tag = 0x48
mimeMediaTypeValueTag tag = 0x49
memberAttrNameValueTag tag = 0x4a
)
// Operation-id, defined in rfc8011
type operationId uint16
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
const (
Idle printerState = 3
Processing printerState = 4
Stopped printerState = 5
)
type statusCode uint16
@@ -92,151 +98,16 @@ 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)
//log.Infof("Length %v", length)
attributeName := make([]byte, length)
if length > 0 {
binary.Read(byteStream, binary.BigEndian, attributeName)
//log.Infof("Valuename %v", string(attributeName))
}
binary.Read(byteStream, binary.BigEndian, &length)
//log.Infof("Length %v", length)
attributeValue := make([]byte, length)
binary.Read(byteStream, binary.BigEndian, attributeValue)
//log.Infof("Value %v", string(attributeValue))
return string(attributeName), string(attributeValue)
}