More development.
More types. Fixed attribute groups in requests. Started on client. Saving data to file.
This commit is contained in:
77
main.go
77
main.go
@@ -1,77 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"ippserver/packages/ipp"
|
||||
"ippserver/packages/mdnsserver"
|
||||
"net/http"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
customFormatter := new(log.TextFormatter)
|
||||
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
|
||||
log.SetFormatter(customFormatter)
|
||||
customFormatter.FullTimestamp = true
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
func handle(w http.ResponseWriter, r *http.Request) {
|
||||
log.Infoln("handle")
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Unsupported method", http.StatusMethodNotAllowed)
|
||||
|
||||
}
|
||||
//body := make([]byte, r.ContentLength)
|
||||
//io.ReadFull(r.Body, body)
|
||||
//log.Infof("Body %x", body)
|
||||
|
||||
request := ipp.NewRequest()
|
||||
//rdata := make([]byte, r.ContentLength)
|
||||
//io.ReadFull(r.Body, rdata)
|
||||
//log.Printf("Data %x", rdata)
|
||||
//fmt.Printf("data % #0x", rdata)
|
||||
//buf := bytes.NewBuffer(rdata)
|
||||
request.UnMarshal(r.Body)
|
||||
fmt.Printf("Request: \n%v\n", request)
|
||||
response := ipp.NewResponse(ipp.SuccessfulOk, request.RequestId())
|
||||
var a ipp.Attribute
|
||||
a = ipp.NewCharSetValue("attributes-charset", "utf-8")
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewNaturalLanguage("attributes-natural-language", "en")
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewUriValue("printer-uri", "ipp://drpork:1234/ipp/print")
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewtextWithoutLanguage("printer-make-and-model", "ChroBro 001")
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewEnum("printer-state", int32(ipp.Idle))
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewKeyWord("ipp-versions-supported", "1.0", "1.1", "2.0")
|
||||
response.AddOperatonAttribute(a)
|
||||
response.AddOperatonAttribute(ipp.NewKeyWord("ipp-features-supported", "wfds-print-1.0"))
|
||||
response.AddOperatonAttribute(ipp.NewMimeMediaType("document-format-supported", "image/pwg-raster"))
|
||||
response.AddOperatonAttribute(ipp.NewKeyWord("media-supported", "iso_a4_210x297mm"))
|
||||
response.AddOperatonAttribute(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"))
|
||||
|
||||
fmt.Printf("Response:\n%v\n", response)
|
||||
data := response.Marshal()
|
||||
|
||||
log.Debugf("% x", data)
|
||||
w.Write(data)
|
||||
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type enum struct {
|
||||
@@ -27,8 +29,7 @@ func (e *enum) valueTag() tag {
|
||||
}
|
||||
|
||||
func (e *enum) unmarshal(byteStream io.Reader) {
|
||||
//e.name, e.value = unmarshalSingleValue(byteStream)
|
||||
|
||||
log.Warn("Unmarshal of enum is not implemented yet")
|
||||
}
|
||||
|
||||
func (e *enum) marshal() []byte {
|
||||
|
||||
@@ -55,33 +55,33 @@ const (
|
||||
)
|
||||
|
||||
// Operation-id, defined in rfc8011
|
||||
type operationId uint16
|
||||
type OperationId uint16
|
||||
|
||||
const (
|
||||
PrintJob operationId = 0x0002
|
||||
PrintURI operationId = 0x0003
|
||||
ValidateJob operationId = 0x0004
|
||||
CreateJob operationId = 0x0005
|
||||
SendDocument operationId = 0x0006
|
||||
SendURI operationId = 0x0007
|
||||
CancelJob operationId = 0x0008
|
||||
GetJobAttributes operationId = 0x0009
|
||||
GetJobs operationId = 0x000a
|
||||
GetPrinterAttributes operationId = 0x000b
|
||||
HoldJob operationId = 0x000c
|
||||
ReleaseJob operationId = 0x000d
|
||||
RestartJob operationId = 0x000e
|
||||
PausePrinter operationId = 0x0010
|
||||
ResumePrinter operationId = 0x0011
|
||||
PurgeJobs operationId = 0x0012
|
||||
PrintJob OperationId = 0x0002
|
||||
PrintURI OperationId = 0x0003
|
||||
ValidateJob OperationId = 0x0004
|
||||
CreateJob OperationId = 0x0005
|
||||
SendDocument OperationId = 0x0006
|
||||
SendURI OperationId = 0x0007
|
||||
CancelJob OperationId = 0x0008
|
||||
GetJobAttributes OperationId = 0x0009
|
||||
GetJobs OperationId = 0x000a
|
||||
GetPrinterAttributes OperationId = 0x000b
|
||||
HoldJob OperationId = 0x000c
|
||||
ReleaseJob OperationId = 0x000d
|
||||
RestartJob OperationId = 0x000e
|
||||
PausePrinter OperationId = 0x0010
|
||||
ResumePrinter OperationId = 0x0011
|
||||
PurgeJobs OperationId = 0x0012
|
||||
)
|
||||
|
||||
type printerState int32
|
||||
|
||||
const (
|
||||
Idle printerState = 3
|
||||
Preocessing printerState = 4
|
||||
Stopped printerState = 5
|
||||
Idle printerState = 3
|
||||
Processing printerState = 4
|
||||
Stopped printerState = 5
|
||||
)
|
||||
|
||||
type statusCode uint16
|
||||
@@ -101,17 +101,13 @@ func (v versionNumber) String() string {
|
||||
func unmarshalSingleValue(byteStream io.Reader) (string, string) {
|
||||
var length uint16
|
||||
binary.Read(byteStream, binary.BigEndian, &length)
|
||||
//log.Infof("Length %v", length)
|
||||
attributeName := make([]byte, length)
|
||||
if length > 0 {
|
||||
binary.Read(byteStream, binary.BigEndian, attributeName)
|
||||
//log.Infof("Valuename %v", string(attributeName))
|
||||
}
|
||||
binary.Read(byteStream, binary.BigEndian, &length)
|
||||
//log.Infof("Length %v", length)
|
||||
attributeValue := make([]byte, length)
|
||||
binary.Read(byteStream, binary.BigEndian, attributeValue)
|
||||
//log.Infof("Value %v", string(attributeValue))
|
||||
return string(attributeName), string(attributeValue)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,30 +2,30 @@ package ipp
|
||||
|
||||
import "io"
|
||||
|
||||
type nameWithoutLanguage struct {
|
||||
type NameWithoutLanguage struct {
|
||||
name string
|
||||
value string
|
||||
}
|
||||
|
||||
func NewNameWithoutLanguage(name, value string) *nameWithoutLanguage {
|
||||
c := new(nameWithoutLanguage)
|
||||
func NewNameWithoutLanguage(name, value string) *NameWithoutLanguage {
|
||||
c := new(NameWithoutLanguage)
|
||||
c.name = name
|
||||
c.value = value
|
||||
return c
|
||||
}
|
||||
|
||||
func (c nameWithoutLanguage) String() string {
|
||||
func (c NameWithoutLanguage) String() string {
|
||||
return c.name + ":" + c.value
|
||||
}
|
||||
func (c *nameWithoutLanguage) valueTag() tag {
|
||||
func (c *NameWithoutLanguage) valueTag() tag {
|
||||
return nameWithoutLanguageValueTag
|
||||
}
|
||||
|
||||
func (c *nameWithoutLanguage) unmarshal(byteStream io.Reader) {
|
||||
func (c *NameWithoutLanguage) unmarshal(byteStream io.Reader) {
|
||||
c.name, c.value = unmarshalSingleValue(byteStream)
|
||||
}
|
||||
|
||||
func (c *nameWithoutLanguage) marshal() []byte {
|
||||
func (c *NameWithoutLanguage) marshal() []byte {
|
||||
l := 5 + len(c.name) + len(c.value)
|
||||
b := make([]byte, l, l)
|
||||
b[0] = byte(nameWithoutLanguageValueTag)
|
||||
@@ -33,9 +33,13 @@ func (c *nameWithoutLanguage) marshal() []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
func (c *nameWithoutLanguage) size() int {
|
||||
func (c *NameWithoutLanguage) size() int {
|
||||
l := 1 + 4 // The attribute tag + 2 lengths
|
||||
l += len(c.name)
|
||||
l += len(c.value)
|
||||
return l
|
||||
}
|
||||
|
||||
func (n NameWithoutLanguage) Value() string {
|
||||
return n.value
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ var (
|
||||
_operationId_index_1 = [...]uint8{0, 12, 25, 34}
|
||||
)
|
||||
|
||||
func (i operationId) String() string {
|
||||
func (i OperationId) String() string {
|
||||
switch {
|
||||
case 2 <= i && i <= 14:
|
||||
i -= 2
|
||||
|
||||
@@ -9,7 +9,7 @@ func _() {
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[Idle-3]
|
||||
_ = x[Preocessing-4]
|
||||
_ = x[Processing-4]
|
||||
_ = x[Stopped-5]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ipp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -10,16 +11,25 @@ import (
|
||||
|
||||
type ippRequestHeader struct {
|
||||
versionNumber versionNumber
|
||||
operationId operationId
|
||||
operationId OperationId
|
||||
requestId uint32
|
||||
}
|
||||
|
||||
func (h *ippRequestHeader) marshal(byteStream io.Reader) {
|
||||
func (h *ippRequestHeader) unmarshal(byteStream io.Reader) {
|
||||
binary.Read(byteStream, binary.BigEndian, &h.versionNumber)
|
||||
binary.Read(byteStream, binary.BigEndian, &h.operationId)
|
||||
binary.Read(byteStream, binary.BigEndian, &h.requestId)
|
||||
}
|
||||
|
||||
func (h *ippRequestHeader) marshal() []byte {
|
||||
b := make([]byte, 0, 8)
|
||||
buf := bytes.NewBuffer(b)
|
||||
binary.Write(buf, binary.BigEndian, h.versionNumber)
|
||||
binary.Write(buf, binary.BigEndian, h.operationId)
|
||||
binary.Write(buf, binary.BigEndian, h.requestId)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func (h ippRequestHeader) String() string {
|
||||
return fmt.Sprintf("Version number: %v Operation Id: %v Request Id: %v", h.versionNumber, h.operationId, h.requestId)
|
||||
}
|
||||
@@ -41,8 +51,11 @@ type Request struct {
|
||||
header ippRequestHeader
|
||||
}
|
||||
|
||||
func NewRequest() *Request {
|
||||
func NewRequest(op OperationId, requestId uint32) *Request {
|
||||
r := new(Request)
|
||||
r.header.operationId = op
|
||||
r.header.requestId = requestId
|
||||
r.header.versionNumber = 0x0200
|
||||
r.operationAttributes = make(map[string]Attribute)
|
||||
r.jobAttributes = make(map[string]Attribute)
|
||||
r.printerAttributes = make(map[string]Attribute)
|
||||
@@ -67,7 +80,7 @@ func (r Request) String() string {
|
||||
}
|
||||
|
||||
func (r *Request) UnMarshal(body io.Reader) {
|
||||
r.header.marshal(body)
|
||||
r.header.unmarshal(body)
|
||||
log.Debugf("Header %v", r.header)
|
||||
var tag tag
|
||||
err := binary.Read(body, binary.BigEndian, &tag)
|
||||
@@ -75,95 +88,116 @@ func (r *Request) UnMarshal(body io.Reader) {
|
||||
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)
|
||||
}
|
||||
|
||||
if tag == operationAttributes {
|
||||
var lastAddValuer AddValuer
|
||||
nextoperationattr:
|
||||
for tag != endOfAttributes {
|
||||
|
||||
err = binary.Read(body, binary.BigEndian, &tag)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
log.Debugf("Value tag - %v", tag)
|
||||
switch tag {
|
||||
case endOfAttributes:
|
||||
err = binary.Read(body, binary.BigEndian, &tag)
|
||||
if err == io.EOF {
|
||||
// No more data
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
log.Debugf("got tag - %v", tag)
|
||||
err = binary.Read(body, binary.BigEndian, &tag)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
log.Debugf("got tag - %v", tag)
|
||||
|
||||
break nextoperationattr
|
||||
case charsetValueTag:
|
||||
c := NewCharSetValue("", "")
|
||||
c.unmarshal(body)
|
||||
r.operationAttributes[c.name] = c
|
||||
log.Debugf("%v %v", c.name, c.value)
|
||||
case uriValueTag:
|
||||
u := NewUriValue("", "")
|
||||
u.unmarshal(body)
|
||||
r.operationAttributes[u.name] = u
|
||||
log.Debugf("%v %v", u.name, u.value)
|
||||
case naturalLanguageValueTag:
|
||||
n := NewNaturalLanguage("", "")
|
||||
n.unmarshal(body)
|
||||
r.operationAttributes[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)
|
||||
r.operationAttributes[name] = k
|
||||
lastAddValuer = k
|
||||
}
|
||||
log.Debugf("%v : %v", name, value)
|
||||
case nameWithoutLanguageValueTag:
|
||||
n := NewNameWithoutLanguage("", "")
|
||||
n.unmarshal(body)
|
||||
r.operationAttributes[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)
|
||||
r.operationAttributes[name] = m
|
||||
lastAddValuer = m
|
||||
}
|
||||
case jobAttributes:
|
||||
log.Debug("Start job attributes")
|
||||
case resolutionValueTag:
|
||||
res := NewResolution()
|
||||
res.unmarshal(body)
|
||||
r.operationAttributes["resolution"] = res
|
||||
log.Debugf("Resolution %v", res)
|
||||
|
||||
default:
|
||||
log.Errorf("Unsupported tag %v", tag)
|
||||
|
||||
}
|
||||
var lastAddValuer AddValuer
|
||||
for {
|
||||
err = binary.Read(body, binary.BigEndian, &tag)
|
||||
if err != nil {
|
||||
log.Errorf("End of input before end of attributes tag (%v)", err.Error())
|
||||
}
|
||||
log.Debugf("Value tag - %v", tag)
|
||||
switch tag {
|
||||
case endOfAttributes:
|
||||
return
|
||||
case charsetValueTag:
|
||||
c := NewCharSetValue("", "")
|
||||
c.unmarshal(body)
|
||||
currentAttributeGroup[c.name] = c
|
||||
log.Debugf("%v %v", c.name, c.value)
|
||||
case uriValueTag:
|
||||
u := NewUriValue("", "")
|
||||
u.unmarshal(body)
|
||||
currentAttributeGroup[u.name] = u
|
||||
log.Debugf("%v %v", u.name, u.value)
|
||||
case naturalLanguageValueTag:
|
||||
n := NewNaturalLanguage("", "")
|
||||
n.unmarshal(body)
|
||||
currentAttributeGroup[n.name] = n
|
||||
log.Debugf("%v %v", n.name, n.value)
|
||||
case keyWordValueTag:
|
||||
name, value := unmarshalSingleValue(body)
|
||||
if name == "" {
|
||||
lastAddValuer.addValue(value)
|
||||
} else {
|
||||
k := NewKeyWord(name, value)
|
||||
currentAttributeGroup[name] = k
|
||||
lastAddValuer = k
|
||||
}
|
||||
log.Debugf("%v : %v", name, value)
|
||||
case nameWithoutLanguageValueTag:
|
||||
n := NewNameWithoutLanguage("", "")
|
||||
n.unmarshal(body)
|
||||
currentAttributeGroup[n.name] = n
|
||||
log.Debugf("%v %v", n.name, n.value)
|
||||
case mimeMediaTypeValueTag:
|
||||
name, value := unmarshalSingleValue(body)
|
||||
if name == "" {
|
||||
lastAddValuer.addValue(value)
|
||||
} else {
|
||||
m := NewMimeMediaType(name, value)
|
||||
currentAttributeGroup[name] = m
|
||||
lastAddValuer = m
|
||||
}
|
||||
log.Debugf("%v : %v", name, value)
|
||||
case jobAttributes:
|
||||
log.Debug("Start job attributes")
|
||||
currentAttributeGroup = r.jobAttributes
|
||||
case resolutionValueTag:
|
||||
res := NewResolution("", 0, 0)
|
||||
res.unmarshal(body)
|
||||
currentAttributeGroup[res.name] = res
|
||||
log.Debugf("Resolution %v", res)
|
||||
default:
|
||||
log.Errorf("Unsupported tag %v", tag)
|
||||
}
|
||||
log.Infof("Value tag %v", tag)
|
||||
} else {
|
||||
log.Error("unexpected tag")
|
||||
// TODO Return something sensible here
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) RequestId() uint32 {
|
||||
return r.header.requestId
|
||||
}
|
||||
|
||||
func (r *Request) Operation() OperationId {
|
||||
return r.header.operationId
|
||||
}
|
||||
|
||||
func (r *Request) GetAttribute(name string) Attribute {
|
||||
return r.operationAttributes[name]
|
||||
}
|
||||
|
||||
func (r *Request) Marshal() []byte {
|
||||
// //s = r.size
|
||||
var buf bytes.Buffer
|
||||
buf.Write(r.header.marshal())
|
||||
if len(r.operationAttributes) > 0 {
|
||||
buf.WriteByte(byte(operationAttributes))
|
||||
for _, e := range r.operationAttributes {
|
||||
buf.Write(e.marshal())
|
||||
}
|
||||
}
|
||||
if len(r.jobAttributes) > 0 {
|
||||
buf.WriteByte(byte(jobAttributes))
|
||||
for _, e := range r.jobAttributes {
|
||||
buf.Write(e.marshal())
|
||||
}
|
||||
}
|
||||
if len(r.printerAttributes) > 0 {
|
||||
buf.WriteByte(byte(printerAttributes))
|
||||
for _, e := range r.printerAttributes {
|
||||
buf.Write(e.marshal())
|
||||
}
|
||||
}
|
||||
buf.WriteByte(byte(endOfAttributes))
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ var testRequest = []byte{0x01, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x11,
|
||||
func TestUnmarshalRequestPrinterAttributes(T *testing.T) {
|
||||
buf := bytes.NewBuffer(testRequest)
|
||||
|
||||
req := NewRequest()
|
||||
req := NewRequest(GetPrinterAttributes, 17)
|
||||
|
||||
req.UnMarshal(buf)
|
||||
fmt.Print(req)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ipp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -13,8 +14,12 @@ type resolution struct {
|
||||
units int8
|
||||
}
|
||||
|
||||
func NewResolution() *resolution {
|
||||
func NewResolution(name string, xfres int32, fres int32) *resolution {
|
||||
r := new(resolution)
|
||||
r.name = name
|
||||
r.crossFeedResolution = xfres
|
||||
r.feedResolution = fres
|
||||
r.units = 3 // 3 seems to mean dpi (rfc3805)
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -36,11 +41,21 @@ func (r *resolution) unmarshal(byteStream io.Reader) {
|
||||
}
|
||||
|
||||
func (r resolution) String() string {
|
||||
return fmt.Sprintf("%v:%v:%v", r.crossFeedResolution, r.feedResolution, r.units)
|
||||
return fmt.Sprintf("%v:%v,%v,%v", r.name, r.crossFeedResolution, r.feedResolution, r.units)
|
||||
}
|
||||
|
||||
func (r *resolution) marshal() []byte {
|
||||
return []byte{}
|
||||
|
||||
b := make([]byte, 0, 14+len(r.name))
|
||||
buf := bytes.NewBuffer(b)
|
||||
buf.WriteByte(byte(resolutionValueTag))
|
||||
binary.Write(buf, binary.BigEndian, uint16(len(r.name)))
|
||||
buf.WriteString(r.name)
|
||||
binary.Write(buf, binary.BigEndian, uint16(9))
|
||||
binary.Write(buf, binary.BigEndian, int32(r.crossFeedResolution))
|
||||
binary.Write(buf, binary.BigEndian, int32(r.feedResolution))
|
||||
buf.WriteByte(byte(r.units))
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func (r *resolution) valueTag() tag {
|
||||
|
||||
@@ -25,10 +25,10 @@ func (h *ippResponseHeader) marshal() []byte {
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
header ippResponseHeader
|
||||
operationAttributes []Attribute
|
||||
jobAttributes []Attribute
|
||||
printerAttributes []Attribute
|
||||
header ippResponseHeader
|
||||
}
|
||||
|
||||
func NewResponse(code statusCode, requestId uint32) *Response {
|
||||
|
||||
@@ -3,9 +3,9 @@ package ipp
|
||||
import "encoding/binary"
|
||||
|
||||
type setOfStrings struct {
|
||||
vTag tag
|
||||
name string
|
||||
values []string
|
||||
vTag tag
|
||||
}
|
||||
|
||||
func NewSetOfStrings(name string, t tag, values []string) *setOfStrings {
|
||||
|
||||
8
server/handlegetjobs.go
Normal file
8
server/handlegetjobs.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package main
|
||||
|
||||
import "ippserver/packages/ipp"
|
||||
|
||||
func handleGetJobs(r *ipp.Request) *ipp.Response {
|
||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestId())
|
||||
return response
|
||||
}
|
||||
28
server/handlegetprinterattributes.go
Normal file
28
server/handlegetprinterattributes.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import "ippserver/packages/ipp"
|
||||
|
||||
func handleGetPrinterAttributes(r *ipp.Request) *ipp.Response {
|
||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestId())
|
||||
var a ipp.Attribute
|
||||
a = ipp.NewCharSetValue("attributes-charset", "utf-8")
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewNaturalLanguage("attributes-natural-language", "en")
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewUriValue("printer-uri", "ipp://drpork:1234/ipp/print")
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewtextWithoutLanguage("printer-make-and-model", "ChroBro 001")
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewEnum("printer-state", int32(ipp.Idle))
|
||||
response.AddOperatonAttribute(a)
|
||||
a = ipp.NewKeyWord("ipp-versions-supported", "1.0", "1.1", "2.0")
|
||||
response.AddOperatonAttribute(a)
|
||||
response.AddOperatonAttribute(ipp.NewKeyWord("ipp-features-supported", "wfds-print-1.0"))
|
||||
response.AddOperatonAttribute(ipp.NewMimeMediaType("document-format-supported", "image/pwg-raster"))
|
||||
response.AddOperatonAttribute(ipp.NewKeyWord("media-supported", "iso_a4_210x297mm"))
|
||||
response.AddOperatonAttribute(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.AddOperatonAttribute(ipp.NewResolution("printer-resolution-default", 600, 600))
|
||||
response.AddOperatonAttribute(ipp.NewBoolean("printer-is-accepting-jobs", true))
|
||||
return response
|
||||
}
|
||||
22
server/handleprintjob.go
Normal file
22
server/handleprintjob.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"ippserver/packages/ipp"
|
||||
"os"
|
||||
)
|
||||
|
||||
func handlePrintJob(r *ipp.Request, byteStream io.Reader) *ipp.Response {
|
||||
|
||||
a := r.GetAttribute("job-name")
|
||||
//a.(nameWithoutLanguage).Value
|
||||
f, err := os.Create(a.(*ipp.NameWithoutLanguage).Value())
|
||||
if err != nil {
|
||||
panic("fail")
|
||||
}
|
||||
defer f.Close()
|
||||
io.Copy(f, byteStream)
|
||||
response := ipp.NewResponse(ipp.SuccessfulOk, r.RequestId())
|
||||
|
||||
return response
|
||||
}
|
||||
69
server/main.go
Normal file
69
server/main.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ippserver/packages/ipp"
|
||||
"ippserver/packages/mdnsserver"
|
||||
"net/http"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
func handle(w http.ResponseWriter, r *http.Request) {
|
||||
log.Infoln("handle")
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Unsupported method", http.StatusMethodNotAllowed)
|
||||
|
||||
}
|
||||
log.Info(r.Header)
|
||||
//body := make([]byte, r.ContentLength)
|
||||
//io.ReadFull(r.Body, body)
|
||||
//log.Infof("Body %x", body)
|
||||
|
||||
request := ipp.NewRequest(0, 0)
|
||||
//rdata := make([]byte, r.ContentLength)
|
||||
//io.ReadFull(r.Body, rdata)
|
||||
//log.Printf("Data %x", rdata)
|
||||
//fmt.Printf("data % #0x", rdata)
|
||||
//buf := bytes.NewBuffer(rdata)
|
||||
request.UnMarshal(r.Body)
|
||||
log.Infof("Request: \n%v\n", request)
|
||||
var response *ipp.Response
|
||||
switch request.Operation() {
|
||||
case ipp.GetPrinterAttributes:
|
||||
response = handleGetPrinterAttributes(request)
|
||||
case ipp.PrintJob:
|
||||
response = handlePrintJob(request, r.Body)
|
||||
case ipp.GetJobs:
|
||||
response = handleGetJobs(request)
|
||||
default:
|
||||
response = ipp.NewResponse(ipp.ClientErrorBadRequest, request.RequestId())
|
||||
}
|
||||
|
||||
log.Infof("Response:\n%v\n", response)
|
||||
data := response.Marshal()
|
||||
|
||||
//log.Debugf("% x", data)
|
||||
w.Write(data)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user