Compare commits
6 Commits
5864035064
...
2-add-keyw
| Author | SHA1 | Date | |
|---|---|---|---|
| 77ef627fe2 | |||
| 8b5f69cb52 | |||
| 7ecbae27c2 | |||
| a1261c1b8f | |||
| c3c608b28a | |||
| 74c1ce257a |
123
client/main.go
123
client/main.go
@@ -1,123 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"ippserver/packages/ipp"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
const printerURI = "brn30055cb5e3ae.local:631/ipp/print"
|
|
||||||
|
|
||||||
//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.InfoLevel)
|
|
||||||
|
|
||||||
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(rb)
|
|
||||||
|
|
||||||
// fmt.Print("\n-------------\n")
|
|
||||||
// printFile("4-untitled")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func printFile(fname string) {
|
|
||||||
|
|
||||||
f, err := os.Open(fname)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to open file %v", fname)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// fileContents, err := ioutil.ReadAll(f)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Errorf("Failed to read file %v", fname)
|
|
||||||
// return
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
request := ipp.NewRequest(ipp.PrintJob, 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))
|
|
||||||
request.AddOperatonAttribute(ipp.NewNameWithoutLanguage("requesting-user-name", "chronos"))
|
|
||||||
request.AddOperatonAttribute(ipp.NewNameWithoutLanguage("job-name", "foobar"))
|
|
||||||
request.AddOperatonAttribute(ipp.NewMimeMediaType("document-format", "image/pwg-raster"))
|
|
||||||
|
|
||||||
//request.AddJobAttribute(ipp.NewNameWithoutLanguage("ColorModel", "Gray"))
|
|
||||||
//request.AddJobAttribute(ipp.NewNameWithoutLanguage("cupsPrintQuality", "Normal"))
|
|
||||||
//request.AddJobAttribute(ipp.NewNameWithoutLanguage("Duplex", "DuplexNoTumble"))
|
|
||||||
//request.AddJobAttribute(ipp.NewNameWithoutLanguage("job-originating-host-name", "localhost"))
|
|
||||||
//request.AddJobAttribute(ipp.NewURIValue("name string", value string)
|
|
||||||
request.AddJobAttribute(ipp.NewKeyWord("media", "iso_a4_210x297mm"))
|
|
||||||
//request.AddJobAttribute(ipp.NewKeyWord("multiple-document-handling", "separate-documents-collated-copies"))
|
|
||||||
request.AddJobAttribute(ipp.NewKeyWord("output-bin", "face-down"))
|
|
||||||
//request.AddJobAttribute(ipp.NewNameWithoutLanguage("PageSize", "A4"))
|
|
||||||
request.AddJobAttribute(ipp.NewKeyWord("print-color-mode", "monochrome"))
|
|
||||||
request.AddJobAttribute(ipp.NewSetOfResolution("printer-resolution", ipp.Resolution{CrossFeedResolution: 600, FeedResolution: 600, Unit: 3}))
|
|
||||||
request.AddJobAttribute(ipp.NewKeyWord("sides", "two-sided-long-edge"))
|
|
||||||
fmt.Print(request)
|
|
||||||
r := request.Marshal()
|
|
||||||
b := bytes.NewBuffer(r)
|
|
||||||
|
|
||||||
mr := io.MultiReader(b, f)
|
|
||||||
httpResponse, err := http.Post("http://"+"brn30055cb5e3ae.local:631/ipp/print", "application/ipp", mr)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Print(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Print("\n---response------\n")
|
|
||||||
log.Printf("HTTP status: %v %v", httpResponse.StatusCode, httpResponse.Status)
|
|
||||||
// resp, err := io.ReadAll(httpResponse.Body)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Error("could not read response")
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// fmt.Printf("% x", resp)
|
|
||||||
rb := ipp.NewResponse(0, 0)
|
|
||||||
rb.UnMarshal(httpResponse.Body)
|
|
||||||
fmt.Print(rb)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
requesting-user-name:chronos (nameWithoutLanguagageValueTag)
|
|
||||||
job-name:2 - Untitled (nameWithoutLanguagageValueTag)
|
|
||||||
document-format : image/pwg-raster (mimeMediaTypeValueTag)
|
|
||||||
document-format : application/octet-stream (mimeMediaTypeValueTag)
|
|
||||||
PrinterAttributes
|
|
||||||
JobAttributes
|
|
||||||
ColorModel:Gray (nameWithoutLanguagageValueTag)
|
|
||||||
cupsPrintQuality:Normal (nameWithoutLanguagageValueTag)
|
|
||||||
Duplex:DuplexNoTumble (nameWithoutLanguagageValueTag)
|
|
||||||
job-originating-host-name:localhost (nameWithoutLanguagageValueTag)
|
|
||||||
job-uuid:urn:uuid:67a09d25-5df8-3026-6e9c-b55f7afee4ca (uriValueTag)
|
|
||||||
media : iso_a4_210x297mm (keywordValueTag)
|
|
||||||
multiple-document-handling : separate-documents-collated-copies (keywordValueTag)
|
|
||||||
output-bin : face-down (keywordValueTag)
|
|
||||||
PageSize:A4 (nameWithoutLanguagageValueTag)
|
|
||||||
print-color-mode : monochrome (keywordValueTag)
|
|
||||||
printer-resolution:[{600 600 3}] (resolutionValueTag)
|
|
||||||
sides : two-sided-long-edge (keywordValueTag)
|
|
||||||
*/
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
package ipp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Boolean is the ipp attribute boolean
|
|
||||||
type Boolean struct {
|
|
||||||
name string
|
|
||||||
value bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBoolean creates a nre boolean attribute
|
|
||||||
func NewBoolean(name string, value bool) *Boolean {
|
|
||||||
b := new(Boolean)
|
|
||||||
b.name = name
|
|
||||||
b.value = value
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name gets tha name of the boolean attribute
|
|
||||||
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) {
|
|
||||||
name, data := unmarshalSingleAttribute(byteStream)
|
|
||||||
b.name = name
|
|
||||||
if data[0] == 0 {
|
|
||||||
b.value = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@@ -4,47 +4,42 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CharSetValue struct {
|
type charSetValue struct {
|
||||||
name string
|
name string
|
||||||
value string
|
value string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCharSetValue(name string, value string) *CharSetValue {
|
func NewCharSetValue(name string, value string) *charSetValue {
|
||||||
c := new(CharSetValue)
|
c := new(charSetValue)
|
||||||
c.name = name
|
c.name = name
|
||||||
c.value = value
|
c.value = value
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CharSetValue) Name() string {
|
func (c charSetValue) String() string {
|
||||||
return c.name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c CharSetValue) String() string {
|
|
||||||
return c.name + ":" + c.value
|
return c.name + ":" + c.value
|
||||||
}
|
}
|
||||||
|
func (c *charSetValue) valueTag() tag {
|
||||||
func (c *CharSetValue) valueTag() tag {
|
|
||||||
return charsetValueTag
|
return charsetValueTag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CharSetValue) unmarshal(byteStream io.Reader) {
|
func (c *charSetValue) unmarshal(byteStream io.Reader) {
|
||||||
c.name, c.value = unmarshalSingleValue(byteStream)
|
c.name, c.value = unmarshalSingleValue(byteStream)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CharSetValue) marshal() []byte {
|
func (c *charSetValue) marshal() []byte {
|
||||||
l := 5 + len(c.name) + len(c.value)
|
l := 5 + len(c.name) + len(c.value)
|
||||||
b := make([]byte, l)
|
b := make([]byte, l, l)
|
||||||
b[0] = byte(charsetValueTag)
|
b[0] = byte(charsetValueTag)
|
||||||
marshalNameValue(c.name, c.value, b[1:])
|
marshalNameValue(c.name, c.value, b[1:])
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CharSetValue) marshalInto([]byte) int {
|
func (c *charSetValue) marshalInto([]byte) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CharSetValue) size() int {
|
func (c *charSetValue) size() int {
|
||||||
l := 1 + 4 // The attribute tag + 2 lengths
|
l := 1 + 4 // The attribute tag + 2 lengths
|
||||||
l += len(c.name)
|
l += len(c.name)
|
||||||
l += len(c.value)
|
l += len(c.value)
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
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,41 +1,52 @@
|
|||||||
package ipp
|
package ipp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Enum struct {
|
type enum struct {
|
||||||
name string
|
name string
|
||||||
values []int32
|
value int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEnum(name string, values ...int32) *Enum {
|
func NewEnum(name string, value int32) *enum {
|
||||||
e := new(Enum)
|
e := new(enum)
|
||||||
e.name = name
|
e.name = name
|
||||||
e.values = values
|
e.value = value
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Enum) Name() string {
|
func (e enum) String() string {
|
||||||
return e.name
|
return e.name + ":" + fmt.Sprint(e.value)
|
||||||
}
|
}
|
||||||
|
func (e *enum) valueTag() tag {
|
||||||
func (e Enum) String() string {
|
|
||||||
return e.name + ":" + fmt.Sprint(e.values)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Enum) valueTag() tag {
|
|
||||||
return enumValueTag
|
return enumValueTag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Enum) size() int {
|
func (e *enum) unmarshal(byteStream io.Reader) {
|
||||||
return 9 + len(e.name)
|
log.Warn("Unmarshal of enum is not implemented yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Enum) addValue(v interface{}) {
|
func (e *enum) marshal() []byte {
|
||||||
e.values = append(e.values, v.(int32))
|
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) marshal() []byte {
|
func (e *enum) size() int {
|
||||||
return marshalInteger(enumValueTag, e.name, e.values)
|
l := 1 + 4 // The attribute tag + 2 lengths
|
||||||
|
l += len(e.name)
|
||||||
|
l += 4
|
||||||
|
return l
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
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) + 9*(len(values)-1)
|
|
||||||
b := make([]byte, 0, l)
|
|
||||||
buf := bytes.NewBuffer(b)
|
|
||||||
buf.WriteByte(byte(t))
|
|
||||||
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(t))
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
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")
|
|
||||||
}
|
|
||||||
@@ -1,37 +1,33 @@
|
|||||||
package ipp
|
package ipp
|
||||||
|
|
||||||
type KeyWord struct {
|
type keyWord struct {
|
||||||
sos *SetOfStrings
|
sos *setOfStrings
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewKeyWord(name string, values ...string) *KeyWord {
|
func NewKeyWord(name string, values ...string) *keyWord {
|
||||||
|
|
||||||
k := new(KeyWord)
|
k := new(keyWord)
|
||||||
k.sos = NewSetOfStrings(name, keyWordValueTag, values)
|
k.sos = NewSetOfStrings(name, keyWordValueTag, values)
|
||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KeyWord) Name() string {
|
func (k keyWord) String() string {
|
||||||
return k.sos.name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k KeyWord) String() string {
|
|
||||||
return k.sos.String()
|
return k.sos.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *KeyWord) size() int {
|
func (k *keyWord) size() int {
|
||||||
return k.sos.size()
|
return k.sos.size()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *KeyWord) valueTag() tag {
|
func (k *keyWord) valueTag() tag {
|
||||||
return k.sos.valueTag()
|
return k.sos.valueTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *KeyWord) marshal() []byte {
|
func (k *keyWord) marshal() []byte {
|
||||||
return k.sos.marshal()
|
return k.sos.marshal()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *KeyWord) addValue(v interface{}) {
|
func (k *keyWord) addValue(v string) {
|
||||||
k.sos.AddValue(v.(string))
|
k.sos.AddValue(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,15 @@
|
|||||||
//Package ipp provides functonality to handle ipp messages
|
|
||||||
//go:generate stringer -type jobState -type printerState
|
|
||||||
package ipp
|
package ipp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// References
|
// References
|
||||||
// https://tools.ietf.org/html/rfc8010
|
// https://tools.ietf.org/html/rfc8010
|
||||||
// https://tools.ietf.org/html/rfc8011
|
// https://tools.ietf.org/html/rfc8011
|
||||||
|
|
||||||
// ErrNilAttribute is returned when an attempt to use nil as a attribute
|
|
||||||
var ErrNilAttribute = errors.New("can not add use nil as attribute")
|
|
||||||
|
|
||||||
// Defined value tags
|
// Defined value tags
|
||||||
// from rfc8010
|
// from rfc8010
|
||||||
type tag uint8
|
type tag uint8
|
||||||
@@ -63,59 +54,41 @@ const (
|
|||||||
memberAttrNameValueTag tag = 0x4a
|
memberAttrNameValueTag tag = 0x4a
|
||||||
)
|
)
|
||||||
|
|
||||||
// OperationID is defined in rfc8011
|
// Operation-id, defined in rfc8011
|
||||||
type OperationID uint16
|
type OperationId uint16
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PrintJob OperationID = 0x0002
|
PrintJob OperationId = 0x0002
|
||||||
PrintURI OperationID = 0x0003
|
PrintURI OperationId = 0x0003
|
||||||
ValidateJob OperationID = 0x0004
|
ValidateJob OperationId = 0x0004
|
||||||
CreateJob OperationID = 0x0005
|
CreateJob OperationId = 0x0005
|
||||||
SendDocument OperationID = 0x0006
|
SendDocument OperationId = 0x0006
|
||||||
SendURI OperationID = 0x0007
|
SendURI OperationId = 0x0007
|
||||||
CancelJob OperationID = 0x0008
|
CancelJob OperationId = 0x0008
|
||||||
GetJobAttributes OperationID = 0x0009
|
GetJobAttributes OperationId = 0x0009
|
||||||
GetJobs OperationID = 0x000a
|
GetJobs OperationId = 0x000a
|
||||||
GetPrinterAttributes OperationID = 0x000b
|
GetPrinterAttributes OperationId = 0x000b
|
||||||
HoldJob OperationID = 0x000c
|
HoldJob OperationId = 0x000c
|
||||||
ReleaseJob OperationID = 0x000d
|
ReleaseJob OperationId = 0x000d
|
||||||
RestartJob OperationID = 0x000e
|
RestartJob OperationId = 0x000e
|
||||||
PausePrinter OperationID = 0x0010
|
PausePrinter OperationId = 0x0010
|
||||||
ResumePrinter OperationID = 0x0011
|
ResumePrinter OperationId = 0x0011
|
||||||
PurgeJobs OperationID = 0x0012
|
PurgeJobs OperationId = 0x0012
|
||||||
)
|
)
|
||||||
|
|
||||||
type printerState int32
|
type printerState int32
|
||||||
|
|
||||||
// printerstate defenitions
|
|
||||||
const (
|
const (
|
||||||
Idle printerState = 3
|
Idle printerState = 3
|
||||||
Processing printerState = 4
|
Processing printerState = 4
|
||||||
Stopped printerState = 5
|
Stopped printerState = 5
|
||||||
)
|
)
|
||||||
|
|
||||||
// jobstate defined in rfc8011 ch 5.3.7
|
|
||||||
type jobState uint16
|
|
||||||
|
|
||||||
const (
|
|
||||||
pending jobState = 3
|
|
||||||
pendingHeld jobState = 4
|
|
||||||
processing jobState = 5
|
|
||||||
processingStoppped jobState = 6
|
|
||||||
cancelled jobState = 7
|
|
||||||
aborted jobState = 8
|
|
||||||
completed jobState = 9
|
|
||||||
)
|
|
||||||
|
|
||||||
type statusCode uint16
|
type statusCode uint16
|
||||||
|
|
||||||
// status code defenitions
|
|
||||||
const (
|
const (
|
||||||
SuccessfulOk statusCode = 0x0000
|
SuccessfulOk statusCode = 0x0000
|
||||||
SuccessfulOkIgnoredOrSubstitutedAttributes statusCode = 0x0001
|
|
||||||
SuccessfulOkConflictingAttributes statusCode = 0x0002
|
|
||||||
ClientErrorBadRequest statusCode = 0x0400
|
ClientErrorBadRequest statusCode = 0x0400
|
||||||
ServerErrorServiceUnavailable statusCode = 0x0502
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type versionNumber uint16
|
type versionNumber uint16
|
||||||
@@ -125,19 +98,6 @@ func (v versionNumber) String() string {
|
|||||||
return fmt.Sprintf("%x.%x", vn&0xff00>>8, vn&0x00ff)
|
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) {
|
func unmarshalSingleValue(byteStream io.Reader) (string, string) {
|
||||||
var length uint16
|
var length uint16
|
||||||
binary.Read(byteStream, binary.BigEndian, &length)
|
binary.Read(byteStream, binary.BigEndian, &length)
|
||||||
@@ -161,188 +121,3 @@ func marshalNameValue(name, value string, b []byte) {
|
|||||||
p += 2
|
p += 2
|
||||||
copy(b[p:], []byte(value))
|
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
|
|
||||||
unsupported []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())
|
|
||||||
}
|
|
||||||
s = s + " Unsupported" + "\n"
|
|
||||||
for _, a := range a.unsupported {
|
|
||||||
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)
|
|
||||||
case unsupportedAttributes:
|
|
||||||
a.unsupported = append(a.unsupported, attr)
|
|
||||||
default:
|
|
||||||
log.Errorf("Unknown attribute group %v", 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 unsupportedValueTag:
|
|
||||||
attr := NewUnsupportedValue()
|
|
||||||
attr.unmarshal(bytestream)
|
|
||||||
a.addAttribute(currentAttributeGroup, attr)
|
|
||||||
|
|
||||||
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 unsupportedAttributes:
|
|
||||||
log.Debug("Start unsupported attributes")
|
|
||||||
currentAttributeGroup = unsupportedAttributes
|
|
||||||
case resolutionValueTag:
|
|
||||||
res := NewSetOfResolution("")
|
|
||||||
res.unmarshal(bytestream)
|
|
||||||
a.addAttribute(currentAttributeGroup, res)
|
|
||||||
log.Debugf("Resolution %v", res)
|
|
||||||
default:
|
|
||||||
log.Errorf("Unsupported tag %v (%x)", t, uint8(t))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,36 +1,32 @@
|
|||||||
package ipp
|
package ipp
|
||||||
|
|
||||||
type MimeMediaType struct {
|
type mimeMediaType struct {
|
||||||
sos *SetOfStrings
|
sos *setOfStrings
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMimeMediaType(name string, values ...string) *MimeMediaType {
|
func NewMimeMediaType(name string, values ...string) *mimeMediaType {
|
||||||
|
|
||||||
m := new(MimeMediaType)
|
m := new(mimeMediaType)
|
||||||
m.sos = NewSetOfStrings(name, mimeMediaTypeValueTag, values)
|
m.sos = NewSetOfStrings(name, mimeMediaTypeValueTag, values)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m MimeMediaType) Name() string {
|
func (m mimeMediaType) String() string {
|
||||||
return m.sos.name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m MimeMediaType) String() string {
|
|
||||||
return m.sos.String()
|
return m.sos.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MimeMediaType) size() int {
|
func (m *mimeMediaType) size() int {
|
||||||
return m.sos.size()
|
return m.sos.size()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MimeMediaType) valueTag() tag {
|
func (m *mimeMediaType) valueTag() tag {
|
||||||
return m.sos.valueTag()
|
return m.sos.valueTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MimeMediaType) marshal() []byte {
|
func (m *mimeMediaType) marshal() []byte {
|
||||||
return m.sos.marshal()
|
return m.sos.marshal()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MimeMediaType) addValue(v interface{}) {
|
func (m *mimeMediaType) addValue(v string) {
|
||||||
m.sos.AddValue(v.(string))
|
m.sos.AddValue(v)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,33 +14,29 @@ func NewNameWithoutLanguage(name, value string) *NameWithoutLanguage {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n NameWithoutLanguage) Name() string {
|
func (c NameWithoutLanguage) String() string {
|
||||||
return n.name
|
return c.name + ":" + c.value
|
||||||
}
|
}
|
||||||
|
func (c *NameWithoutLanguage) valueTag() tag {
|
||||||
func (n NameWithoutLanguage) String() string {
|
|
||||||
return n.name + ":" + n.value
|
|
||||||
}
|
|
||||||
func (n *NameWithoutLanguage) valueTag() tag {
|
|
||||||
return nameWithoutLanguageValueTag
|
return nameWithoutLanguageValueTag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NameWithoutLanguage) unmarshal(byteStream io.Reader) {
|
func (c *NameWithoutLanguage) unmarshal(byteStream io.Reader) {
|
||||||
n.name, n.value = unmarshalSingleValue(byteStream)
|
c.name, c.value = unmarshalSingleValue(byteStream)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NameWithoutLanguage) marshal() []byte {
|
func (c *NameWithoutLanguage) marshal() []byte {
|
||||||
l := 5 + len(n.name) + len(n.value)
|
l := 5 + len(c.name) + len(c.value)
|
||||||
b := make([]byte, l)
|
b := make([]byte, l, l)
|
||||||
b[0] = byte(nameWithoutLanguageValueTag)
|
b[0] = byte(nameWithoutLanguageValueTag)
|
||||||
marshalNameValue(n.name, n.value, b[1:])
|
marshalNameValue(c.name, c.value, b[1:])
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NameWithoutLanguage) size() int {
|
func (c *NameWithoutLanguage) size() int {
|
||||||
l := 1 + 4 // The attribute tag + 2 lengths
|
l := 1 + 4 // The attribute tag + 2 lengths
|
||||||
l += len(n.name)
|
l += len(c.name)
|
||||||
l += len(n.value)
|
l += len(c.value)
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,43 +4,38 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NaturalLanguage struct {
|
type naturalLanguage struct {
|
||||||
name string
|
name string
|
||||||
value string
|
value string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNaturalLanguage(name, value string) *NaturalLanguage {
|
func NewNaturalLanguage(name, value string) *naturalLanguage {
|
||||||
c := new(NaturalLanguage)
|
c := new(naturalLanguage)
|
||||||
c.name = name
|
c.name = name
|
||||||
c.value = value
|
c.value = value
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c NaturalLanguage) Name() string {
|
func (c naturalLanguage) String() string {
|
||||||
return c.name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c NaturalLanguage) String() string {
|
|
||||||
return c.name + ":" + c.value
|
return c.name + ":" + c.value
|
||||||
}
|
}
|
||||||
|
func (c *naturalLanguage) valueTag() tag {
|
||||||
func (c *NaturalLanguage) valueTag() tag {
|
|
||||||
return naturalLanguageValueTag
|
return naturalLanguageValueTag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *NaturalLanguage) unmarshal(byteStream io.Reader) {
|
func (c *naturalLanguage) unmarshal(byteStream io.Reader) {
|
||||||
c.name, c.value = unmarshalSingleValue(byteStream)
|
c.name, c.value = unmarshalSingleValue(byteStream)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *NaturalLanguage) marshal() []byte {
|
func (c *naturalLanguage) marshal() []byte {
|
||||||
l := 5 + len(c.name) + len(c.value)
|
l := 5 + len(c.name) + len(c.value)
|
||||||
b := make([]byte, l)
|
b := make([]byte, l, l)
|
||||||
b[0] = byte(naturalLanguageValueTag)
|
b[0] = byte(naturalLanguageValueTag)
|
||||||
marshalNameValue(c.name, c.value, b[1:])
|
marshalNameValue(c.name, c.value, b[1:])
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *NaturalLanguage) size() int {
|
func (c *naturalLanguage) size() int {
|
||||||
l := 1 + 4 // The attribute tag + 2 lengths
|
l := 1 + 4 // The attribute tag + 2 lengths
|
||||||
l += len(c.name)
|
l += len(c.name)
|
||||||
l += len(c.value)
|
l += len(c.value)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ var (
|
|||||||
_operationId_index_1 = [...]uint8{0, 12, 25, 34}
|
_operationId_index_1 = [...]uint8{0, 12, 25, 34}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (i OperationID) String() string {
|
func (i OperationId) String() string {
|
||||||
switch {
|
switch {
|
||||||
case 2 <= i && i <= 14:
|
case 2 <= i && i <= 14:
|
||||||
i -= 2
|
i -= 2
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Code generated by "stringer -type jobState -type printerState"; DO NOT EDIT.
|
// Code generated by "stringer -type printerState ."; DO NOT EDIT.
|
||||||
|
|
||||||
package ipp
|
package ipp
|
||||||
|
|
||||||
@@ -13,9 +13,9 @@ func _() {
|
|||||||
_ = x[Stopped-5]
|
_ = x[Stopped-5]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _printerState_name = "IdleProcessingStopped"
|
const _printerState_name = "IdlePreocessingStopped"
|
||||||
|
|
||||||
var _printerState_index = [...]uint8{0, 4, 14, 21}
|
var _printerState_index = [...]uint8{0, 4, 15, 22}
|
||||||
|
|
||||||
func (i printerState) String() string {
|
func (i printerState) String() string {
|
||||||
i -= 3
|
i -= 3
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
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,149 +1,203 @@
|
|||||||
package ipp
|
package ipp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ippMessageHeader struct {
|
type ippRequestHeader struct {
|
||||||
versionNumber versionNumber
|
versionNumber versionNumber
|
||||||
operationID OperationID
|
operationId OperationId
|
||||||
requestID uint32
|
requestId uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ippMessageHeader) unmarshal(byteStream io.Reader) {
|
func (h *ippRequestHeader) unmarshal(byteStream io.Reader) {
|
||||||
binary.Read(byteStream, binary.BigEndian, &h.versionNumber)
|
binary.Read(byteStream, binary.BigEndian, &h.versionNumber)
|
||||||
binary.Read(byteStream, binary.BigEndian, &h.operationID)
|
binary.Read(byteStream, binary.BigEndian, &h.operationId)
|
||||||
binary.Read(byteStream, binary.BigEndian, &h.requestID)
|
binary.Read(byteStream, binary.BigEndian, &h.requestId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ippMessageHeader) marshal() []byte {
|
func (h *ippRequestHeader) marshal() []byte {
|
||||||
b := make([]byte, 0, 8)
|
b := make([]byte, 0, 8)
|
||||||
buf := bytes.NewBuffer(b)
|
buf := bytes.NewBuffer(b)
|
||||||
binary.Write(buf, binary.BigEndian, h.versionNumber)
|
binary.Write(buf, binary.BigEndian, h.versionNumber)
|
||||||
binary.Write(buf, binary.BigEndian, h.operationID)
|
binary.Write(buf, binary.BigEndian, h.operationId)
|
||||||
binary.Write(buf, binary.BigEndian, h.requestID)
|
binary.Write(buf, binary.BigEndian, h.requestId)
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h ippMessageHeader) String() string {
|
func (h ippRequestHeader) String() string {
|
||||||
return fmt.Sprintf("Version number: %v Operation Id: %v Request Id: %v", h.versionNumber, h.operationID, h.requestID)
|
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 {
|
type AddValuer interface {
|
||||||
addValue(interface{})
|
addValue(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
a *Attributes
|
operationAttributes map[string]Attribute
|
||||||
header ippMessageHeader
|
jobAttributes map[string]Attribute
|
||||||
|
printerAttributes map[string]Attribute
|
||||||
|
header ippRequestHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRequest(op OperationID, requestID uint32) *Request {
|
func NewRequest(op OperationId, requestId uint32) *Request {
|
||||||
r := new(Request)
|
r := new(Request)
|
||||||
r.header.operationID = op
|
r.header.operationId = op
|
||||||
r.header.requestID = requestID
|
r.header.requestId = requestId
|
||||||
r.header.versionNumber = 0x0200
|
r.header.versionNumber = 0x0200
|
||||||
r.a = new(Attributes)
|
r.operationAttributes = make(map[string]Attribute)
|
||||||
|
r.jobAttributes = make(map[string]Attribute)
|
||||||
|
r.printerAttributes = make(map[string]Attribute)
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Request) String() string {
|
func (r Request) String() string {
|
||||||
return r.header.String() + "\n" + r.a.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) {
|
func (r *Request) UnMarshal(body io.Reader) {
|
||||||
buffbody := bufio.NewReader(body)
|
r.header.unmarshal(body)
|
||||||
r.header.unmarshal(buffbody)
|
log.Debugf("Header %v", r.header)
|
||||||
r.a = UnMarshalAttributes(buffbody)
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Request) RequestID() uint32 {
|
var lastAddValuer AddValuer
|
||||||
return r.header.requestID
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Operation returns the operation is of the request.
|
func (r *Request) RequestId() uint32 {
|
||||||
func (r *Request) Operation() OperationID {
|
return r.header.requestId
|
||||||
return r.header.operationID
|
}
|
||||||
|
|
||||||
|
func (r *Request) Operation() OperationId {
|
||||||
|
return r.header.operationId
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Request) GetAttribute(name string) Attribute {
|
func (r *Request) GetAttribute(name string) Attribute {
|
||||||
for _, a := range r.a.operation {
|
return r.operationAttributes[name]
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marshal converts the request object to a ipp request
|
|
||||||
func (r *Request) Marshal() []byte {
|
func (r *Request) Marshal() []byte {
|
||||||
|
// //s = r.size
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.Write(r.header.marshal())
|
buf.Write(r.header.marshal())
|
||||||
if len(r.a.operation) > 0 {
|
if len(r.operationAttributes) > 0 {
|
||||||
buf.WriteByte(byte(operationAttributes))
|
buf.WriteByte(byte(operationAttributes))
|
||||||
for _, e := range r.a.operation {
|
for _, e := range r.operationAttributes {
|
||||||
buf.Write(e.marshal())
|
buf.Write(e.marshal())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(r.a.job) > 0 {
|
if len(r.jobAttributes) > 0 {
|
||||||
buf.WriteByte(byte(jobAttributes))
|
buf.WriteByte(byte(jobAttributes))
|
||||||
for _, e := range r.a.job {
|
for _, e := range r.jobAttributes {
|
||||||
buf.Write(e.marshal())
|
buf.Write(e.marshal())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(r.a.printer) > 0 {
|
if len(r.printerAttributes) > 0 {
|
||||||
buf.WriteByte(byte(printerAttributes))
|
buf.WriteByte(byte(printerAttributes))
|
||||||
for _, e := range r.a.printer {
|
for _, e := range r.printerAttributes {
|
||||||
buf.Write(e.marshal())
|
buf.Write(e.marshal())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf.WriteByte(byte(endOfAttributes))
|
buf.WriteByte(byte(endOfAttributes))
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddPrinterAttribute adds a printer attribute to the request object
|
|
||||||
func (r *Request) AddPrinterAttribute(a Attribute) error {
|
|
||||||
if a != nil {
|
|
||||||
r.a.addAttribute(printerAttributes, a)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return ErrNilAttribute
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddOperatonAttribute adds a operation attribute to the request object
|
|
||||||
func (r *Request) AddOperatonAttribute(a Attribute) error {
|
|
||||||
if a != nil {
|
|
||||||
r.a.addAttribute(operationAttributes, a)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return ErrNilAttribute
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddJobAttribute adds a job attribute to the request object
|
|
||||||
func (r *Request) AddJobAttribute(a Attribute) error {
|
|
||||||
if a != nil {
|
|
||||||
r.a.addAttribute(jobAttributes, a)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return ErrNilAttribute
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -64,10 +64,10 @@ func TestUnmarshalRequestPrinterAttributes(T *testing.T) {
|
|||||||
req.UnMarshal(buf)
|
req.UnMarshal(buf)
|
||||||
fmt.Print(req)
|
fmt.Print(req)
|
||||||
assert.Equal(T, versionNumber(0x0101), req.header.versionNumber, "Wrong version number")
|
assert.Equal(T, versionNumber(0x0101), req.header.versionNumber, "Wrong version number")
|
||||||
assert.Equal(T, GetPrinterAttributes, req.header.operationID, "Wrong Operation")
|
assert.Equal(T, GetPrinterAttributes, req.header.operationId, "Wrong Operation")
|
||||||
assert.Equal(T, uint32(17), req.header.requestID, "Wrong request id")
|
assert.Equal(T, uint32(17), req.header.requestId, "Wrong request id")
|
||||||
assert.Len(T, req.a.operation, 4)
|
assert.Len(T, req.operationAttributes, 4)
|
||||||
v := req.GetAttribute("requested-attributes").(*KeyWord).sos.values
|
v := req.operationAttributes["requested-attributes"].(*keyWord).sos.values
|
||||||
assert.Len(T, v, 7)
|
assert.Len(T, v, 7)
|
||||||
assert.Contains(T, v, "printer-make-and-model")
|
assert.Contains(T, v, "printer-make-and-model")
|
||||||
assert.Contains(T, v, "ipp-versions-supported")
|
assert.Contains(T, v, "ipp-versions-supported")
|
||||||
|
|||||||
@@ -1,95 +1,63 @@
|
|||||||
package ipp
|
package ipp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Resolution represents a ipp resolution attribute
|
type resolution struct {
|
||||||
type Resolution struct {
|
|
||||||
CrossFeedResolution int32
|
|
||||||
FeedResolution int32
|
|
||||||
Unit int8 // 3 seems to mean dpi (rfc3805)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetOfResolutions represents a set ipp resolution attributes
|
|
||||||
type SetOfResolutions struct {
|
|
||||||
name string
|
name string
|
||||||
sor []Resolution
|
crossFeedResolution int32
|
||||||
|
feedResolution int32
|
||||||
|
units int8
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSetOfResolution creats a new set of ipp resolution attributes
|
func NewResolution(name string, xfres int32, fres int32) *resolution {
|
||||||
func NewSetOfResolution(name string, resSet ...Resolution) *SetOfResolutions {
|
r := new(resolution)
|
||||||
r := new(SetOfResolutions)
|
|
||||||
r.name = name
|
r.name = name
|
||||||
r.sor = resSet
|
r.crossFeedResolution = xfres
|
||||||
|
r.feedResolution = fres
|
||||||
|
r.units = 3 // 3 seems to mean dpi (rfc3805)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *SetOfResolutions) unmarshal(byteStream *bufio.Reader) {
|
func (r *resolution) unmarshal(byteStream io.Reader) {
|
||||||
var length uint16
|
var length uint16
|
||||||
var res Resolution
|
|
||||||
for {
|
|
||||||
binary.Read(byteStream, binary.BigEndian, &length)
|
binary.Read(byteStream, binary.BigEndian, &length)
|
||||||
attributeName := make([]byte, length)
|
attributeName := make([]byte, length)
|
||||||
if length > 0 {
|
if length > 0 {
|
||||||
binary.Read(byteStream, binary.BigEndian, attributeName)
|
binary.Read(byteStream, binary.BigEndian, attributeName)
|
||||||
r.name = string(attributeName)
|
|
||||||
}
|
}
|
||||||
|
r.name = string(attributeName)
|
||||||
binary.Read(byteStream, binary.BigEndian, &length)
|
binary.Read(byteStream, binary.BigEndian, &length)
|
||||||
if length != 9 {
|
if length != 9 {
|
||||||
panic("Wrong length in resolution")
|
panic("Wrong length in resolution")
|
||||||
}
|
}
|
||||||
binary.Read(byteStream, binary.BigEndian, &res.CrossFeedResolution)
|
binary.Read(byteStream, binary.BigEndian, &r.crossFeedResolution)
|
||||||
binary.Read(byteStream, binary.BigEndian, &res.FeedResolution)
|
binary.Read(byteStream, binary.BigEndian, &r.feedResolution)
|
||||||
binary.Read(byteStream, binary.BigEndian, &res.Unit)
|
binary.Read(byteStream, binary.BigEndian, &r.units)
|
||||||
r.sor = append(r.sor, res)
|
|
||||||
var t tag
|
|
||||||
err := binary.Read(byteStream, binary.BigEndian, &t)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err.Error())
|
|
||||||
}
|
|
||||||
if t != resolutionValueTag {
|
|
||||||
byteStream.UnreadByte()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns the name of the attribute
|
func (r resolution) String() string {
|
||||||
func (r SetOfResolutions) Name() string {
|
return fmt.Sprintf("%v:%v,%v,%v", r.name, r.crossFeedResolution, r.feedResolution, r.units)
|
||||||
return r.name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r SetOfResolutions) String() string {
|
func (r *resolution) marshal() []byte {
|
||||||
return fmt.Sprintf("%v:%v", r.name, r.sor)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *SetOfResolutions) marshal() []byte {
|
b := make([]byte, 0, 14+len(r.name))
|
||||||
|
|
||||||
b := make([]byte, 0, 14+len(r.name)+14*(len(r.sor)-1))
|
|
||||||
buf := bytes.NewBuffer(b)
|
buf := bytes.NewBuffer(b)
|
||||||
|
|
||||||
for i, res := range r.sor {
|
|
||||||
buf.WriteByte(byte(resolutionValueTag))
|
buf.WriteByte(byte(resolutionValueTag))
|
||||||
if i == 0 {
|
|
||||||
binary.Write(buf, binary.BigEndian, uint16(len(r.name)))
|
binary.Write(buf, binary.BigEndian, uint16(len(r.name)))
|
||||||
buf.WriteString(r.name)
|
buf.WriteString(r.name)
|
||||||
} else {
|
|
||||||
binary.Write(buf, binary.BigEndian, uint16(0))
|
|
||||||
}
|
|
||||||
binary.Write(buf, binary.BigEndian, uint16(9))
|
binary.Write(buf, binary.BigEndian, uint16(9))
|
||||||
binary.Write(buf, binary.BigEndian, int32(res.CrossFeedResolution))
|
binary.Write(buf, binary.BigEndian, int32(r.crossFeedResolution))
|
||||||
binary.Write(buf, binary.BigEndian, int32(res.FeedResolution))
|
binary.Write(buf, binary.BigEndian, int32(r.feedResolution))
|
||||||
buf.WriteByte(byte(res.Unit))
|
buf.WriteByte(byte(r.units))
|
||||||
}
|
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *SetOfResolutions) valueTag() tag {
|
func (r *resolution) valueTag() tag {
|
||||||
return resolutionValueTag
|
return resolutionValueTag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,144 +1,115 @@
|
|||||||
package ipp
|
package ipp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ippResponseHeader struct {
|
type ippResponseHeader struct {
|
||||||
versionNumber versionNumber
|
versionNumber versionNumber
|
||||||
statusCode statusCode
|
statusCode statusCode
|
||||||
requestID uint32
|
requestId uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h ippResponseHeader) String() string {
|
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 {
|
func (h *ippResponseHeader) marshal() []byte {
|
||||||
a := make([]byte, 8)
|
a := make([]byte, 8, 8)
|
||||||
binary.BigEndian.PutUint16(a[0:2], uint16(h.versionNumber))
|
binary.BigEndian.PutUint16(a[0:2], uint16(h.versionNumber))
|
||||||
binary.BigEndian.PutUint16(a[2:4], uint16(h.statusCode))
|
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
|
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 {
|
type Response struct {
|
||||||
a *Attributes
|
operationAttributes []Attribute
|
||||||
|
jobAttributes []Attribute
|
||||||
|
printerAttributes []Attribute
|
||||||
header ippResponseHeader
|
header ippResponseHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResponse creates a new ipp response object
|
func NewResponse(code statusCode, requestId uint32) *Response {
|
||||||
func NewResponse(code statusCode, requestID uint32) *Response {
|
|
||||||
r := new(Response)
|
r := new(Response)
|
||||||
r.a = new(Attributes)
|
|
||||||
r.header.versionNumber = 0x0101
|
r.header.versionNumber = 0x0101
|
||||||
r.header.requestID = requestID
|
r.header.requestId = requestId
|
||||||
r.header.statusCode = code
|
r.header.statusCode = code
|
||||||
|
r.operationAttributes = make([]Attribute, 0)
|
||||||
|
r.printerAttributes = make([]Attribute, 0)
|
||||||
|
r.jobAttributes = make([]Attribute, 0)
|
||||||
return r
|
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 {
|
func (r Response) String() string {
|
||||||
return r.header.String() + "\n" + r.a.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 Response) Header() ippResponseHeader {
|
|
||||||
return r.header
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal converts the response object to a wire formatted byte stream.
|
|
||||||
func (r *Response) Marshal() []byte {
|
func (r *Response) Marshal() []byte {
|
||||||
a := make([]byte, 0, 20)
|
a := make([]byte, 0, 20)
|
||||||
a = append(a, r.header.marshal()...)
|
a = append(a, r.header.marshal()...)
|
||||||
if len(r.a.operation) > 0 {
|
if len(r.operationAttributes) > 0 {
|
||||||
a = append(a, byte(operationAttributes))
|
a = append(a, byte(operationAttributes))
|
||||||
for _, e := range r.a.operation {
|
for _, e := range r.operationAttributes {
|
||||||
a = append(a, e.marshal()...)
|
a = append(a, e.marshal()...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(r.a.job) > 0 {
|
if len(r.jobAttributes) > 0 {
|
||||||
a = append(a, byte(jobAttributes))
|
a = append(a, byte(jobAttributes))
|
||||||
for _, e := range r.a.job {
|
for _, e := range r.jobAttributes {
|
||||||
a = append(a, e.marshal()...)
|
a = append(a, e.marshal()...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(r.a.printer) > 0 {
|
if len(r.printerAttributes) > 0 {
|
||||||
a = append(a, byte(printerAttributes))
|
a = append(a, byte(printerAttributes))
|
||||||
for _, e := range r.a.printer {
|
for _, e := range r.printerAttributes {
|
||||||
a = append(a, e.marshal()...)
|
a = append(a, e.marshal()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
a = append(a, byte(endOfAttributes))
|
a = append(a, byte(endOfAttributes))
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnMarshal unmarshals a ipp response into a response object
|
func (r *Response) AddPrinterAttribute(a Attribute) {
|
||||||
func (r *Response) UnMarshal(body io.Reader) {
|
r.printerAttributes = append(r.printerAttributes, a)
|
||||||
buffbody := bufio.NewReader(body)
|
|
||||||
r.header.unmarshal(buffbody)
|
|
||||||
r.a = UnMarshalAttributes(buffbody)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddPrinterAttribute adds a printer attribute to the response object
|
func (r *Response) AddOperatonAttribute(a Attribute) {
|
||||||
func (r *Response) AddPrinterAttribute(a Attribute) error {
|
r.operationAttributes = append(r.operationAttributes, a)
|
||||||
if a != nil {
|
|
||||||
r.a.addAttribute(printerAttributes, a)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return ErrNilAttribute
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOperatonAttribute adds a printer attribute to the response object
|
func (r *Response) AddJobAttribute(a Attribute) {
|
||||||
func (r *Response) AddOperatonAttribute(a Attribute) error {
|
r.jobAttributes = append(r.jobAttributes, a)
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ func TestMarshalResponseHeader(T *testing.T) {
|
|||||||
|
|
||||||
h.versionNumber = 0x0101
|
h.versionNumber = 0x0101
|
||||||
h.statusCode = SuccessfulOk
|
h.statusCode = SuccessfulOk
|
||||||
h.requestID = 0xdeadbeef
|
h.requestId = 0xdeadbeef
|
||||||
|
|
||||||
b := h.marshal()
|
b := h.marshal()
|
||||||
fmt.Printf("% x\n", b)
|
fmt.Printf("% x\n", b)
|
||||||
|
|||||||
@@ -2,31 +2,28 @@ package ipp
|
|||||||
|
|
||||||
import "encoding/binary"
|
import "encoding/binary"
|
||||||
|
|
||||||
// SetOfStrings is the strings attribute
|
type setOfStrings struct {
|
||||||
type SetOfStrings struct {
|
|
||||||
name string
|
name string
|
||||||
values []string
|
values []string
|
||||||
vTag tag
|
vTag tag
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSetOfStrings creates a new strings attribute
|
func NewSetOfStrings(name string, t tag, values []string) *setOfStrings {
|
||||||
func NewSetOfStrings(name string, t tag, values []string) *SetOfStrings {
|
s := new(setOfStrings)
|
||||||
s := new(SetOfStrings)
|
|
||||||
s.name = name
|
s.name = name
|
||||||
s.vTag = t
|
s.vTag = t
|
||||||
s.values = values //make([]string, 0)
|
s.values = values //make([]string, 0)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SetOfStrings) String() string {
|
func (s setOfStrings) String() string {
|
||||||
r := s.name + " :"
|
r := s.name + " :"
|
||||||
for _, v := range s.values {
|
for _, v := range s.values {
|
||||||
r = r + " " + v
|
r = r + " " + v
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
func (s *setOfStrings) valueTag() tag {
|
||||||
func (s *SetOfStrings) valueTag() tag {
|
|
||||||
return s.vTag
|
return s.vTag
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,15 +39,15 @@ func (s *SetOfStrings) valueTag() tag {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func (s *SetOfStrings) marshal() []byte {
|
func (s *setOfStrings) marshal() []byte {
|
||||||
l := 5 + len(s.name) + len(s.values[0])
|
l := 5 + len(s.name) + len(s.values[0])
|
||||||
for i := range s.values[1:] {
|
for i := range s.values[1:] {
|
||||||
l += 5 + len(s.values[i+1])
|
l += 5 + len(s.values[i+1])
|
||||||
}
|
}
|
||||||
res := make([]byte, l)
|
res := make([]byte, l, l)
|
||||||
p := 0
|
p := 0
|
||||||
res[p] = byte(s.vTag)
|
res[p] = byte(s.vTag)
|
||||||
p++
|
p += 1
|
||||||
binary.BigEndian.PutUint16(res[p:p+2], uint16(len(s.name)))
|
binary.BigEndian.PutUint16(res[p:p+2], uint16(len(s.name)))
|
||||||
p += 2
|
p += 2
|
||||||
copy(res[p:], []byte(s.name))
|
copy(res[p:], []byte(s.name))
|
||||||
@@ -61,7 +58,7 @@ func (s *SetOfStrings) marshal() []byte {
|
|||||||
p += len(s.values[0])
|
p += len(s.values[0])
|
||||||
for i := range s.values[1:] {
|
for i := range s.values[1:] {
|
||||||
res[p] = byte(s.vTag)
|
res[p] = byte(s.vTag)
|
||||||
p++
|
p += 1
|
||||||
binary.BigEndian.PutUint16(res[p:p+2], uint16(0))
|
binary.BigEndian.PutUint16(res[p:p+2], uint16(0))
|
||||||
p = p + 2
|
p = p + 2
|
||||||
binary.BigEndian.PutUint16(res[p:p+2], uint16(len(s.values[i+1])))
|
binary.BigEndian.PutUint16(res[p:p+2], uint16(len(s.values[i+1])))
|
||||||
@@ -73,12 +70,11 @@ func (s *SetOfStrings) marshal() []byte {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddValue adds a new sring to the set
|
func (s *setOfStrings) AddValue(v string) {
|
||||||
func (s *SetOfStrings) AddValue(v string) {
|
|
||||||
s.values = append(s.values, v)
|
s.values = append(s.values, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SetOfStrings) size() int {
|
func (s *setOfStrings) size() int {
|
||||||
l := 1 + 2 // The value tag (0x44) + name-length field (2 bytes)
|
l := 1 + 2 // The value tag (0x44) + name-length field (2 bytes)
|
||||||
l += len(s.name)
|
l += len(s.name)
|
||||||
l += 2 // value-length field (2 bytes)
|
l += 2 // value-length field (2 bytes)
|
||||||
|
|||||||
41
packages/ipp/textWithoutLanguage.go
Normal file
41
packages/ipp/textWithoutLanguage.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package ipp
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
type textWithoutLanguage struct {
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewtextWithoutLanguage(name, value string) *textWithoutLanguage {
|
||||||
|
c := new(textWithoutLanguage)
|
||||||
|
c.name = name
|
||||||
|
c.value = value
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c textWithoutLanguage) String() string {
|
||||||
|
return c.name + ":" + c.value
|
||||||
|
}
|
||||||
|
func (c *textWithoutLanguage) valueTag() tag {
|
||||||
|
return textWithoutLanguageValueTag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *textWithoutLanguage) unmarshal(byteStream io.Reader) {
|
||||||
|
c.name, c.value = unmarshalSingleValue(byteStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *textWithoutLanguage) marshal() []byte {
|
||||||
|
l := 5 + len(c.name) + len(c.value)
|
||||||
|
b := make([]byte, l, l)
|
||||||
|
b[0] = byte(textWithoutLanguageValueTag)
|
||||||
|
marshalNameValue(c.name, c.value, b[1:])
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *textWithoutLanguage) size() int {
|
||||||
|
l := 1 + 4 // The attribute tag + 2 lengths
|
||||||
|
l += len(c.name)
|
||||||
|
l += len(c.value)
|
||||||
|
return l
|
||||||
|
}
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package ipp
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
// TextWithoutLanguage is the TextWithoutLanguage attribute
|
|
||||||
type TextWithoutLanguage struct {
|
|
||||||
name string
|
|
||||||
value string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewtextWithoutLanguage creates a new textWithoutLanguage attribute
|
|
||||||
func NewtextWithoutLanguage(name, value string) *TextWithoutLanguage {
|
|
||||||
c := new(TextWithoutLanguage)
|
|
||||||
c.name = name
|
|
||||||
c.value = value
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns the name of the attribute
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TextWithoutLanguage) unmarshal(byteStream io.Reader) {
|
|
||||||
c.name, c.value = unmarshalSingleValue(byteStream)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TextWithoutLanguage) marshal() []byte {
|
|
||||||
l := 5 + len(c.name) + len(c.value)
|
|
||||||
b := make([]byte, l)
|
|
||||||
b[0] = byte(textWithoutLanguageValueTag)
|
|
||||||
marshalNameValue(c.name, c.value, b[1:])
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TextWithoutLanguage) size() int {
|
|
||||||
l := 1 + 4 // The attribute tag + 2 lengths
|
|
||||||
l += len(c.name)
|
|
||||||
l += len(c.value)
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package ipp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UnSupportedValue represents a ipp unsupported attributes attribute
|
|
||||||
type UnSupportedValue struct {
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewUnsupportedValue creates a new unsupported attributes attribute
|
|
||||||
func NewUnsupportedValue() *UnSupportedValue {
|
|
||||||
c := new(UnSupportedValue)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *UnSupportedValue) unmarshal(byteStream io.Reader) {
|
|
||||||
c.name, _ = unmarshalSingleValue(byteStream)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns the name of the attribute
|
|
||||||
func (c *UnSupportedValue) Name() string {
|
|
||||||
return c.name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *UnSupportedValue) marshal() (data []byte) {
|
|
||||||
log.Error("Unmarshal unsupported value is not implemented yet")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *UnSupportedValue) valueTag() tag {
|
|
||||||
return unsupportedValueTag
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c UnSupportedValue) String() string {
|
|
||||||
return c.name
|
|
||||||
}
|
|
||||||
@@ -4,49 +4,37 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// URIValue represents a ipp URI value attribute
|
type uriValue struct {
|
||||||
type URIValue struct {
|
|
||||||
name string
|
name string
|
||||||
value string
|
value string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewURIValue creates a new URIValue attribute
|
func NewUriValue(name, value string) *uriValue {
|
||||||
func NewURIValue(name, value string) *URIValue {
|
u := new(uriValue)
|
||||||
u := new(URIValue)
|
|
||||||
u.name = name
|
u.name = name
|
||||||
u.value = value
|
u.value = value
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns the name of the attribute
|
func (u uriValue) String() string {
|
||||||
func (u URIValue) Name() string {
|
|
||||||
return u.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the value of the attribute
|
|
||||||
func (u URIValue) Value() string {
|
|
||||||
return u.value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u URIValue) String() string {
|
|
||||||
return u.name + ":" + u.value
|
return u.name + ":" + u.value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *URIValue) valueTag() tag {
|
func (u *uriValue) valueTag() tag {
|
||||||
return uriValueTag
|
return uriValueTag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *URIValue) unmarshal(byteStream io.Reader) {
|
func (u *uriValue) unmarshal(byteStream io.Reader) {
|
||||||
u.name, u.value = unmarshalSingleValue(byteStream)
|
u.name, u.value = unmarshalSingleValue(byteStream)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *URIValue) marshal() []byte {
|
func (u *uriValue) marshal() []byte {
|
||||||
res := make([]byte, u.size())
|
res := make([]byte, u.size())
|
||||||
res[0] = byte(uriValueTag)
|
res[0] = byte(uriValueTag)
|
||||||
marshalNameValue(u.name, u.value, res[1:])
|
marshalNameValue(u.name, u.value, res[1:])
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
func (u *URIValue) size() int {
|
func (u *uriValue) size() int {
|
||||||
l := 1 + 4 // The attribute tag + 2 lengths
|
l := 1 + 4 // The attribute tag + 2 lengths
|
||||||
l += len(u.name)
|
l += len(u.name)
|
||||||
l += len(u.value)
|
l += len(u.value)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestMarshalUriValue(T *testing.T) {
|
func TestMarshalUriValue(T *testing.T) {
|
||||||
var u URIValue
|
var u uriValue
|
||||||
u.name = "foo"
|
u.name = "foo"
|
||||||
u.value = "bar"
|
u.value = "bar"
|
||||||
b := u.marshal()
|
b := u.marshal()
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ func Run(ctx context.Context) {
|
|||||||
log.Fatalf("EntryGroupNew() failed: %v", err)
|
log.Fatalf("EntryGroupNew() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//hostname, err := a.GetHostName()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("GetHostName() failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
fqdn, err := a.GetHostNameFqdn()
|
fqdn, err := a.GetHostNameFqdn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("GetHostNameFqdn() failed: %v", err)
|
log.Fatalf("GetHostNameFqdn() failed: %v", err)
|
||||||
@@ -31,11 +36,11 @@ func Run(ctx context.Context) {
|
|||||||
var txt [][]byte
|
var txt [][]byte
|
||||||
|
|
||||||
txt = append(txt, []byte("note=burken"))
|
txt = append(txt, []byte("note=burken"))
|
||||||
txt = append(txt, []byte("product=ChroBroPrint V1"))
|
txt = append(txt, []byte("product=coola-skrivaren"))
|
||||||
txt = append(txt, []byte("Color=T"))
|
txt = append(txt, []byte("Color=T"))
|
||||||
txt = append(txt, []byte("rp=ipp/print"))
|
txt = append(txt, []byte("rp=ipp/print"))
|
||||||
txt = append(txt, []byte("ty=ChroBroPrint"))
|
txt = append(txt, []byte("ty=ChroBro 001"))
|
||||||
err = eg.AddService(avahi.InterfaceUnspec, avahi.ProtoUnspec, 0, "ChroBroPrint", "_ipp._tcp", "local", fqdn, 1234, txt)
|
err = eg.AddService(avahi.InterfaceUnspec, avahi.ProtoUnspec, 0, "ChroBro 1000", "_ipp._tcp", "local", fqdn, 1234, txt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("AddService() failed: %v", err)
|
log.Fatalf("AddService() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "ippserver/packages/ipp"
|
|
||||||
|
|
||||||
func handleValidateJob(r *ipp.Request) *ipp.Response {
|
|
||||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestID())
|
|
||||||
response.AddOperatonAttribute(ipp.NewCharSetValue("attributes-charset", "utf-8"))
|
|
||||||
response.AddOperatonAttribute(ipp.NewNaturalLanguage("attributes-natural-language", "en"))
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"ippserver/packages/ipp"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func handleGetJobAttributes(r *ipp.Request, requestID uint32) (*ipp.Response, error) {
|
|
||||||
|
|
||||||
request := ipp.NewRequest(ipp.GetJobAttributes, requestID)
|
|
||||||
request.AddOperatonAttribute(ipp.NewCharSetValue("attributes-charset", "utf-8"))
|
|
||||||
request.AddOperatonAttribute(ipp.NewNaturalLanguage("attributes-natural-language", "en"))
|
|
||||||
request.AddOperatonAttribute(ipp.NewURIValue("printer-uri", "ipp://"+printerURI))
|
|
||||||
request.AddOperatonAttribute(r.GetAttribute("job-id"))
|
|
||||||
request.AddOperatonAttribute(r.GetAttribute("requesting-user-name"))
|
|
||||||
request.AddOperatonAttribute(r.GetAttribute("requested-attributes"))
|
|
||||||
|
|
||||||
log.Infof("Downstream request\n%v\n", request)
|
|
||||||
|
|
||||||
downStreamRequest := request.Marshal()
|
|
||||||
b := bytes.NewBuffer(downStreamRequest)
|
|
||||||
|
|
||||||
downStreamResponse, err := http.Post("http://"+"brn30055cb5e3ae.local:631/ipp/print", "application/ipp", b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rb := ipp.NewResponse(0, 0)
|
|
||||||
rb.UnMarshal(downStreamResponse.Body)
|
|
||||||
log.Infof("Downstream response\n%v\n", rb)
|
|
||||||
|
|
||||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestID())
|
|
||||||
response.AddOperatonAttribute(ipp.NewCharSetValue("attributes-charset", "utf-8"))
|
|
||||||
response.AddOperatonAttribute(ipp.NewNaturalLanguage("attributes-natural-language", "en"))
|
|
||||||
response.AddJobAttribute(rb.GetAttribute("job-id"))
|
|
||||||
response.AddJobAttribute(rb.GetAttribute("job-name"))
|
|
||||||
response.AddJobAttribute(rb.GetAttribute("job-originating-user-name"))
|
|
||||||
response.AddJobAttribute(rb.GetAttribute("job-state"))
|
|
||||||
response.AddJobAttribute(rb.GetAttribute("job-state-reasons"))
|
|
||||||
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"ippserver/packages/ipp"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func handleGetJobs(r *ipp.Request, requestID uint32) (*ipp.Response, error) {
|
|
||||||
|
|
||||||
request := ipp.NewRequest(ipp.GetJobs, requestID)
|
|
||||||
request.AddOperatonAttribute(ipp.NewCharSetValue("attributes-charset", "utf-8"))
|
|
||||||
request.AddOperatonAttribute(ipp.NewNaturalLanguage("attributes-natural-language", "en"))
|
|
||||||
request.AddOperatonAttribute(ipp.NewURIValue("printer-uri", "ipp://"+printerURI))
|
|
||||||
request.AddOperatonAttribute(r.GetAttribute("requesting-user-name"))
|
|
||||||
request.AddOperatonAttribute(r.GetAttribute("requested-attributes"))
|
|
||||||
|
|
||||||
log.Infof("Downstream request\n%v\n", request)
|
|
||||||
|
|
||||||
downStreamRequest := request.Marshal()
|
|
||||||
b := bytes.NewBuffer(downStreamRequest)
|
|
||||||
|
|
||||||
downStreamResponse, err := http.Post("http://"+"brn30055cb5e3ae.local:631/ipp/print", "application/ipp", b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
//log.Printf("response HTTP status: %v %v", downStreamResponse.StatusCode, downStreamResponse.Status)
|
|
||||||
rb := ipp.NewResponse(0, 0)
|
|
||||||
rb.UnMarshal(downStreamResponse.Body)
|
|
||||||
log.Infof("Downstream response\n%v\n", rb)
|
|
||||||
|
|
||||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestID())
|
|
||||||
response.AddOperatonAttribute(ipp.NewCharSetValue("attributes-charset", "utf-8"))
|
|
||||||
response.AddOperatonAttribute(ipp.NewNaturalLanguage("attributes-natural-language", "en"))
|
|
||||||
a := rb.GetAttribute("job-id")
|
|
||||||
response.AddJobAttribute(a)
|
|
||||||
response.AddJobAttribute(rb.GetAttribute("job-name"))
|
|
||||||
response.AddJobAttribute(rb.GetAttribute("job-originating-user-name"))
|
|
||||||
response.AddJobAttribute(rb.GetAttribute("job-state"))
|
|
||||||
response.AddJobAttribute(rb.GetAttribute("job-state-reasons"))
|
|
||||||
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "ippserver/packages/ipp"
|
|
||||||
|
|
||||||
func handleGetPrinterAttributes(r *ipp.Request) *ipp.Response {
|
|
||||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestID())
|
|
||||||
|
|
||||||
response.AddOperatonAttribute(ipp.NewCharSetValue("attributes-charset", "utf-8"))
|
|
||||||
response.AddOperatonAttribute(ipp.NewNaturalLanguage("attributes-natural-language", "en"))
|
|
||||||
|
|
||||||
response.AddPrinterAttribute(ipp.NewURIValue("printer-uri", "ipp://drpork:1234/ipp/print"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewtextWithoutLanguage("printer-make-and-model", "ChroBroPrint"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewEnum("printer-state", int32(ipp.Idle)))
|
|
||||||
response.AddPrinterAttribute(ipp.NewEnum("operations-supported", int32(ipp.PrintJob), int32(ipp.ValidateJob), int32(ipp.CancelJob), int32(ipp.GetJobAttributes), int32(ipp.GetJobs), int32(ipp.GetPrinterAttributes)))
|
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("printer-state-reasons", "none"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("ipp-versions-supported", "1.0", "1.1", "2.0"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("ipp-features-supported", "wfds-print-1.0"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewMimeMediaType("document-format-supported", "image/pwg-raster"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("media-supported", "iso_a4_210x297mm"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("media-default", "iso_a4_210x297mm"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("output-mode-supported", "color", "auto", "monochrome"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("output-mode-default", "color"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewBoolean("color-supported", true))
|
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("sides-supported", "one-sided", "two-sided-long-edge", "two-sided-short-edge"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("print-color-mode-supported", "auto", "color", "monochrome"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("job-creation-attributes-supported", "copies", "finishings", "ipp-attribute-fidelity",
|
|
||||||
"job-name", "media", "media-col", "orientation-requested", "output-bin", "output-mode", "print-quality", "printer-resolution",
|
|
||||||
"requesting-user-name", "sides", "print-color-mode"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewEnum("print-quality-supported", int32(4), int32(5))) //normal,high
|
|
||||||
res1 := ipp.Resolution{CrossFeedResolution: 600, FeedResolution: 600, Unit: 3}
|
|
||||||
res2 := ipp.Resolution{CrossFeedResolution: 2400, FeedResolution: 600, Unit: 3}
|
|
||||||
response.AddPrinterAttribute(ipp.NewSetOfResolution("printer-resolution-default", res1))
|
|
||||||
response.AddPrinterAttribute(ipp.NewSetOfResolution("printer-resolution-supported", res1, res2))
|
|
||||||
response.AddPrinterAttribute(ipp.NewBoolean("printer-is-accepting-jobs", true))
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io"
|
|
||||||
"ippserver/packages/ipp"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
const printerURI = "brn30055cb5e3ae.local:631/ipp/print"
|
|
||||||
|
|
||||||
func handlePrintJob(r *ipp.Request, byteStream io.Reader, requestID uint32) (*ipp.Response, error) {
|
|
||||||
|
|
||||||
// This request is what will be sent to the real printer
|
|
||||||
request := ipp.NewRequest(ipp.PrintJob, requestID)
|
|
||||||
request.AddOperatonAttribute(ipp.NewCharSetValue("attributes-charset", "utf-8"))
|
|
||||||
request.AddOperatonAttribute(ipp.NewNaturalLanguage("attributes-natural-language", "en"))
|
|
||||||
request.AddOperatonAttribute(ipp.NewURIValue("printer-uri", "ipp://"+printerURI))
|
|
||||||
request.AddOperatonAttribute(r.GetAttribute("requesting-user-name"))
|
|
||||||
request.AddOperatonAttribute(r.GetAttribute("job-name"))
|
|
||||||
request.AddOperatonAttribute(ipp.NewMimeMediaType("document-format", "image/pwg-raster"))
|
|
||||||
|
|
||||||
request.AddJobAttribute(r.GetAttribute("sides"))
|
|
||||||
request.AddJobAttribute(r.GetAttribute("media"))
|
|
||||||
request.AddJobAttribute(r.GetAttribute("print-color-mode"))
|
|
||||||
request.AddJobAttribute(r.GetAttribute("printer-resolution"))
|
|
||||||
request.AddJobAttribute(r.GetAttribute("output-bin"))
|
|
||||||
log.Infof("Downstream request\n%v\n", request)
|
|
||||||
|
|
||||||
downStreamRequest := request.Marshal()
|
|
||||||
b := bytes.NewBuffer(downStreamRequest)
|
|
||||||
|
|
||||||
mr := io.MultiReader(b, byteStream)
|
|
||||||
downStreamResponse, err := http.Post("http://"+"brn30055cb5e3ae.local:631/ipp/print", "application/ipp", mr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rb := ipp.NewResponse(0, 0)
|
|
||||||
rb.UnMarshal(downStreamResponse.Body)
|
|
||||||
log.Infof("Downstream response\n%v\n", rb)
|
|
||||||
|
|
||||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestID())
|
|
||||||
response.AddOperatonAttribute(ipp.NewCharSetValue("attributes-charset", "utf-8"))
|
|
||||||
response.AddOperatonAttribute(ipp.NewNaturalLanguage("attributes-natural-language", "en"))
|
|
||||||
jua := rb.GetAttribute("job-uri").(*ipp.URIValue)
|
|
||||||
if jua != nil {
|
|
||||||
u, err := url.Parse(jua.Value())
|
|
||||||
if err != nil {
|
|
||||||
log.Error("could not parse job-uri")
|
|
||||||
}
|
|
||||||
l := strings.Split(u.Path, "/")
|
|
||||||
j := l[len(l)-1]
|
|
||||||
|
|
||||||
joburi := r.GetAttribute("printer-uri").(*ipp.URIValue).Value() + "/" + j
|
|
||||||
response.AddJobAttribute(ipp.NewURIValue("job-uri", joburi))
|
|
||||||
}
|
|
||||||
response.AddJobAttribute(rb.GetAttribute("job-id"))
|
|
||||||
response.AddJobAttribute(rb.GetAttribute("job-state"))
|
|
||||||
response.AddJobAttribute(rb.GetAttribute("job-state-reasons"))
|
|
||||||
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"flag"
|
|
||||||
"ippserver/packages/ipp"
|
|
||||||
"ippserver/packages/mdnsserver"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
loglevel string
|
|
||||||
location string
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
flag.StringVar(&loglevel, "loglevel", "info", "The wanted loglevel error/info/debug")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
customFormatter := new(log.TextFormatter)
|
|
||||||
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
|
|
||||||
log.SetFormatter(customFormatter)
|
|
||||||
customFormatter.FullTimestamp = true
|
|
||||||
log.SetLevel(log.InfoLevel)
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
go mdnsserver.Run(ctx)
|
|
||||||
|
|
||||||
http.HandleFunc("/ipp/print", handle)
|
|
||||||
|
|
||||||
log.Info("http server started on :1234")
|
|
||||||
err := http.ListenAndServe(":1234", nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("ListenAndServe: " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var mut sync.Mutex
|
|
||||||
var requestID uint32
|
|
||||||
|
|
||||||
func handle(w http.ResponseWriter, r *http.Request) {
|
|
||||||
mut.Lock()
|
|
||||||
requestID++
|
|
||||||
mut.Unlock()
|
|
||||||
if r.Method != http.MethodPost {
|
|
||||||
http.Error(w, "Unsupported method", http.StatusMethodNotAllowed)
|
|
||||||
}
|
|
||||||
|
|
||||||
request := ipp.NewRequest(0, 0)
|
|
||||||
request.UnMarshal(r.Body)
|
|
||||||
log.Infof("Upstream Request: id: %v op: %v", request.RequestID(), request.Operation())
|
|
||||||
var response *ipp.Response
|
|
||||||
var err error
|
|
||||||
switch request.Operation() {
|
|
||||||
case ipp.GetPrinterAttributes:
|
|
||||||
response = handleGetPrinterAttributes(request)
|
|
||||||
case ipp.PrintJob:
|
|
||||||
response, err = handlePrintJob(request, r.Body, requestID)
|
|
||||||
case ipp.GetJobs:
|
|
||||||
response, err = handleGetJobs(request, requestID)
|
|
||||||
case ipp.ValidateJob:
|
|
||||||
response = handleValidateJob(request)
|
|
||||||
case ipp.GetJobAttributes:
|
|
||||||
response, err = handleGetJobAttributes(request, requestID)
|
|
||||||
default:
|
|
||||||
response = ipp.NewResponse(ipp.ClientErrorBadRequest, request.RequestID())
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to handle request: %v", err.Error())
|
|
||||||
response = ipp.NewResponse(ipp.ServerErrorServiceUnavailable, request.RequestID())
|
|
||||||
}
|
|
||||||
log.Infof("Upstream Response: %v", response.Header())
|
|
||||||
data := response.Marshal()
|
|
||||||
w.Write(data)
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "ippserver/packages/ipp"
|
|
||||||
|
|
||||||
func handleValidateJob(r *ipp.Request) *ipp.Response {
|
|
||||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestID())
|
|
||||||
response.AddOperatonAttribute(ipp.NewCharSetValue("attributes-charset", "utf-8"))
|
|
||||||
response.AddOperatonAttribute(ipp.NewNaturalLanguage("attributes-natural-language", "en"))
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,6 @@ package main
|
|||||||
import "ippserver/packages/ipp"
|
import "ippserver/packages/ipp"
|
||||||
|
|
||||||
func handleGetJobs(r *ipp.Request) *ipp.Response {
|
func handleGetJobs(r *ipp.Request) *ipp.Response {
|
||||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestID())
|
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestId())
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,34 +3,26 @@ package main
|
|||||||
import "ippserver/packages/ipp"
|
import "ippserver/packages/ipp"
|
||||||
|
|
||||||
func handleGetPrinterAttributes(r *ipp.Request) *ipp.Response {
|
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
|
||||||
response.AddOperatonAttribute(ipp.NewCharSetValue("attributes-charset", "utf-8"))
|
a = ipp.NewCharSetValue("attributes-charset", "utf-8")
|
||||||
response.AddOperatonAttribute(ipp.NewNaturalLanguage("attributes-natural-language", "en"))
|
response.AddOperatonAttribute(a)
|
||||||
|
a = ipp.NewNaturalLanguage("attributes-natural-language", "en")
|
||||||
response.AddPrinterAttribute(ipp.NewURIValue("printer-uri", "ipp://drpork:1234/ipp/print"))
|
response.AddOperatonAttribute(a)
|
||||||
response.AddPrinterAttribute(ipp.NewtextWithoutLanguage("printer-make-and-model", "ChroBroPrint"))
|
a = ipp.NewUriValue("printer-uri", "ipp://drpork:1234/ipp/print")
|
||||||
response.AddPrinterAttribute(ipp.NewEnum("printer-state", int32(ipp.Idle)))
|
response.AddOperatonAttribute(a)
|
||||||
response.AddPrinterAttribute(ipp.NewEnum("operations-supported", int32(ipp.PrintJob), int32(ipp.ValidateJob), int32(ipp.CancelJob), int32(ipp.GetJobAttributes), int32(ipp.GetJobs), int32(ipp.GetPrinterAttributes)))
|
a = ipp.NewtextWithoutLanguage("printer-make-and-model", "ChroBro 001")
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("printer-state-reasons", "none"))
|
response.AddOperatonAttribute(a)
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("ipp-versions-supported", "1.0", "1.1", "2.0"))
|
a = ipp.NewEnum("printer-state", int32(ipp.Idle))
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("ipp-features-supported", "wfds-print-1.0"))
|
response.AddOperatonAttribute(a)
|
||||||
response.AddPrinterAttribute(ipp.NewMimeMediaType("document-format-supported", "image/pwg-raster"))
|
a = ipp.NewKeyWord("ipp-versions-supported", "1.0", "1.1", "2.0")
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("media-supported", "iso_a4_210x297mm"))
|
response.AddOperatonAttribute(a)
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("media-default", "iso_a4_210x297mm"))
|
response.AddOperatonAttribute(ipp.NewKeyWord("ipp-features-supported", "wfds-print-1.0"))
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("output-mode-supported", "color", "auto", "monochrome"))
|
response.AddOperatonAttribute(ipp.NewMimeMediaType("document-format-supported", "image/pwg-raster"))
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("output-mode-default", "color"))
|
response.AddOperatonAttribute(ipp.NewKeyWord("media-supported", "iso_a4_210x297mm"))
|
||||||
response.AddPrinterAttribute(ipp.NewBoolean("color-supported", true))
|
response.AddOperatonAttribute(ipp.NewKeyWord("sides-supported", "one-sided", "two-sided-long-edge", "two-sided-short-edge"))
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("sides-supported", "one-sided", "two-sided-long-edge", "two-sided-short-edge"))
|
response.AddOperatonAttribute(ipp.NewKeyWord("print-color-mode-supported", "auto", "color", "monochrome"))
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("print-color-mode-supported", "auto", "color", "monochrome"))
|
response.AddOperatonAttribute(ipp.NewResolution("printer-resolution-default", 600, 600))
|
||||||
response.AddPrinterAttribute(ipp.NewKeyWord("job-creation-attributes-supported", "copies", "finishings", "ipp-attribute-fidelity",
|
response.AddOperatonAttribute(ipp.NewBoolean("printer-is-accepting-jobs", true))
|
||||||
"job-name", "media", "media-col", "orientation-requested", "output-bin", "output-mode", "print-quality", "printer-resolution",
|
|
||||||
"requesting-user-name", "sides", "print-color-mode"))
|
|
||||||
response.AddPrinterAttribute(ipp.NewEnum("print-quality-supported", int32(4), int32(5))) //normal,high
|
|
||||||
res1 := ipp.Resolution{CrossFeedResolution: 600, FeedResolution: 600, Unit: 3}
|
|
||||||
res2 := ipp.Resolution{CrossFeedResolution: 2400, FeedResolution: 600, Unit: 3}
|
|
||||||
response.AddPrinterAttribute(ipp.NewSetOfResolution("printer-resolution-default", res1))
|
|
||||||
response.AddPrinterAttribute(ipp.NewSetOfResolution("printer-resolution-supported", res1, res2))
|
|
||||||
response.AddPrinterAttribute(ipp.NewBoolean("printer-is-accepting-jobs", true))
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,7 @@ func handlePrintJob(r *ipp.Request, byteStream io.Reader) *ipp.Response {
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
io.Copy(f, byteStream)
|
io.Copy(f, byteStream)
|
||||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestID())
|
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestId())
|
||||||
response.AddOperatonAttribute(ipp.NewCharSetValue("attributes-charset", "utf-8"))
|
|
||||||
response.AddOperatonAttribute(ipp.NewNaturalLanguage("attributes-natural-language", "en"))
|
|
||||||
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handle(w http.ResponseWriter, r *http.Request) {
|
func handle(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Infoln("handle")
|
||||||
if r.Method != http.MethodPost {
|
if r.Method != http.MethodPost {
|
||||||
http.Error(w, "Unsupported method", http.StatusMethodNotAllowed)
|
http.Error(w, "Unsupported method", http.StatusMethodNotAllowed)
|
||||||
|
|
||||||
@@ -55,10 +56,8 @@ func handle(w http.ResponseWriter, r *http.Request) {
|
|||||||
response = handlePrintJob(request, r.Body)
|
response = handlePrintJob(request, r.Body)
|
||||||
case ipp.GetJobs:
|
case ipp.GetJobs:
|
||||||
response = handleGetJobs(request)
|
response = handleGetJobs(request)
|
||||||
case ipp.ValidateJob:
|
|
||||||
response = handleValidateJob(request)
|
|
||||||
default:
|
default:
|
||||||
response = ipp.NewResponse(ipp.ClientErrorBadRequest, request.RequestID())
|
response = ipp.NewResponse(ipp.ClientErrorBadRequest, request.RequestId())
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Response:\n%v\n", response)
|
log.Infof("Response:\n%v\n", response)
|
||||||
|
|||||||
Reference in New Issue
Block a user