Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions proto/ipp/getdocument.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// MFP - Multi-Function Printers and scanners toolkit
// IPP - Internet Printing Protocol implementation
//
// Copyright (C) 2024 and up by Yogesh Singla (yogeshsingla481@gmail.com)
// See LICENSE for license terms and conditions
//
// Request and Response for Get-Next-Document-Data operation

package ipp

import (
"github.com/OpenPrinting/go-mfp/util/optional"
"github.com/OpenPrinting/goipp"
)

// GetNextDocumentDataRequest is the Get-Next-Document-Data request.
//
// The Get-Next-Document-Data operation allows a Scan
// Client to retrieve the scan data from an existing Job object, enabling
// pull scanning. The target Job MUST be in the 'processing' or 'completed'
// state.
type GetNextDocumentDataRequest struct {
ObjectRawAttrs
RequestHeader

OperationGroup

PrinterURI optional.Val[string] `ipp:"printer-uri"`
JobID optional.Val[int] `ipp:"job-id"`
RequestingUserName optional.Val[string] `ipp:"requesting-user-name"`
RequestingUserURI optional.Val[string] `ipp:"requesting-user-uri"`
DocumentDataWait optional.Val[bool] `ipp:"document-data-wait"`
}

// GetNextDocumentDataResponse is the Get-Next-Document-Data response.
type GetNextDocumentDataResponse struct {
ObjectRawAttrs
ResponseHeader

OperationGroup

Compression optional.Val[KwCompression] `ipp:"compression"`
DocumentFormat optional.Val[string] `ipp:"document-format"`
DocumentDataGetInterval optional.Val[int] `ipp:"document-data-get-interval"`
LastDocument bool `ipp:"last-document"`

Document *DocumentStatus
}

type DocumentStatus struct {
ObjectRawAttrs
DocumentStatusGroup

DocumentNumber optional.Val[int] `ipp:"document-number"`
}

// DecodeDocumentStatusAttributes decodes [DocumentStatus] from
// [goipp.Attributes].
func DecodeDocumentStatusAttributes(attrs goipp.Attributes,
opt *DecoderOptions) (*DocumentStatus, error) {

doc := &DocumentStatus{}
dec := NewDecoder(opt)
defer dec.Free()

err := dec.Decode(doc, attrs)
if err != nil {
return nil, err
}
return doc, nil
}

// GetOp returns GetNextDocumentDataRequest IPP Operation code.
func (rq *GetNextDocumentDataRequest) GetOp() goipp.Op {
return goipp.OpGetNextDocumentData
}

// Encode encodes GetNextDocumentDataRequest into the goipp.Message.
func (rq *GetNextDocumentDataRequest) Encode() *goipp.Message {
enc := ippEncoder{}

groups := goipp.Groups{
{
Tag: goipp.TagOperationGroup,
Attrs: enc.Encode(rq),
},
}

return goipp.NewMessageWithGroups(
rq.Version, goipp.Code(rq.GetOp()),
rq.RequestID, groups,
)
}

// Decode decodes GetNextDocumentDataRequest from goipp.Message.
func (rq *GetNextDocumentDataRequest) Decode(
msg *goipp.Message, opt *DecoderOptions) error {

rq.Version = msg.Version
rq.RequestID = msg.RequestID

dec := NewDecoder(opt)
defer dec.Free()

err := dec.Decode(rq, msg.Operation)
if err != nil {
return err
}

return nil
}

// Encode encodes GetNextDocumentDataResponse into the goipp.Message.
func (rsp *GetNextDocumentDataResponse) Encode() *goipp.Message {
enc := ippEncoder{}

groups := goipp.Groups{
{
Tag: goipp.TagOperationGroup,
Attrs: enc.Encode(rsp),
},
}

if rsp.Document != nil {
groups = append(groups, goipp.Group{
Tag: goipp.TagDocumentGroup,
Attrs: enc.Encode(rsp.Document),
})
}

return goipp.NewMessageWithGroups(
rsp.Version, goipp.Code(rsp.Status),
rsp.RequestID, groups,
)
}

// Decode decodes GetNextDocumentDataResponse from goipp.Message.
func (rsp *GetNextDocumentDataResponse) Decode(
msg *goipp.Message, opt *DecoderOptions) error {

rsp.Version = msg.Version
rsp.RequestID = msg.RequestID
rsp.Status = goipp.Status(msg.Code)

dec := NewDecoder(opt)
defer dec.Free()

err := dec.Decode(rsp, msg.Operation)
if err != nil {
return err
}

rsp.Document, err = DecodeDocumentStatusAttributes(msg.Document, opt)
if err != nil {
return err
}

return nil
}
10 changes: 5 additions & 5 deletions proto/ipp/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
type Handler struct {
Op goipp.Op
callback func(context.Context, *goipp.Message, io.Reader) (
*goipp.Message, error)
*goipp.Message, io.ReadCloser, error)
}

// NewHandler creates a new IPP handler from the function that
Expand All @@ -34,19 +34,19 @@ func NewHandler[RQT any,
RQ interface {
*RQT
Request
}](f func(ctx context.Context, rq RQ) (*goipp.Message, error)) *Handler {
}](f func(ctx context.Context, rq RQ) (*goipp.Message, io.ReadCloser, error)) *Handler {

callback := func(ctx context.Context,
rqMsg *goipp.Message, body io.Reader) (

*goipp.Message, error) {
*goipp.Message, io.ReadCloser, error) {

rq := RQ(new(RQT))
rq.Header().setBody(body)

err := rq.Decode(rqMsg, nil)
if err != nil {
return nil, err
return nil, nil, err
}

return f(ctx, rq)
Expand All @@ -60,6 +60,6 @@ func NewHandler[RQT any,

// handle handles the received request.
func (h *Handler) handle(ctx context.Context, rq *goipp.Message, body io.Reader) (
*goipp.Message, error) {
*goipp.Message, io.ReadCloser, error) {
return h.callback(ctx, rq, body)
}
26 changes: 13 additions & 13 deletions proto/ipp/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,27 +79,27 @@ func (printer *Printer) ServeHTTP(w http.ResponseWriter, rq *http.Request) {
// handleGetPrinterAttributes handles Get-Printer-Attributes request.
func (printer *Printer) handleGetPrinterAttributes(
ctx context.Context,
rq *GetPrinterAttributesRequest) (*goipp.Message, error) {
rq *GetPrinterAttributesRequest) (*goipp.Message, io.ReadCloser, error) {

return rq.Apply(printer.attrs, printer.options.UseRawPrinterAttributes), nil
return rq.Apply(printer.attrs, printer.options.UseRawPrinterAttributes), nil, nil
}

// handleValidateJob handles Validate-Job request.
func (printer *Printer) handleValidateJob(
ctx context.Context,
rq *ValidateJobRequest) (*goipp.Message, error) {
rq *ValidateJobRequest) (*goipp.Message, io.ReadCloser, error) {

rsp := ValidateJobResponse{
ResponseHeader: rq.ResponseHeader(goipp.StatusOk),
}

return rsp.Encode(), nil
return rsp.Encode(), nil, nil
}

// handleCreateJob handles Create-Job request.
func (printer *Printer) handleCreateJob(
ctx context.Context,
rq *CreateJobRequest) (*goipp.Message, error) {
rq *CreateJobRequest) (*goipp.Message, io.ReadCloser, error) {

// Create new job
j := newJob(&rq.JobCreateOperation, rq.Job)
Expand All @@ -119,13 +119,13 @@ func (printer *Printer) handleCreateJob(
},
}

return rsp.Encode(), nil
return rsp.Encode(), nil, nil
}

// handleCreateJob handles Send-Document request.
func (printer *Printer) handleSendDocument(
ctx context.Context,
rq *SendDocumentRequest) (*goipp.Message, error) {
rq *SendDocumentRequest) (*goipp.Message, io.ReadCloser, error) {

// Lookup the job
var j *job
Expand All @@ -137,7 +137,7 @@ func (printer *Printer) handleSendDocument(
err := NewErrIPPFromRequest(rq,
goipp.StatusErrorNotFound,
"job not found (job-id=%d)", *rq.JobID)
return nil, err
return nil, nil, err
}

case rq.JobURI != nil:
Expand All @@ -146,14 +146,14 @@ func (printer *Printer) handleSendDocument(
err := NewErrIPPFromRequest(rq,
goipp.StatusErrorNotFound,
"job not found (job-uri=%q)", *rq.JobURI)
return nil, err
return nil, nil, err
}

default:
err := NewErrIPPFromRequest(rq,
goipp.StatusErrorBadRequest,
"missed job-id and job-uri attributes")
return nil, err
return nil, nil, err
}

j.Lock()
Expand All @@ -164,14 +164,14 @@ func (printer *Printer) handleSendDocument(
err := NewErrIPPFromRequest(rq,
goipp.StatusErrorNotPossible,
"job is not in pending-held state")
return nil, err
return nil, nil, err
}

if j.SendDocumentActive {
err := NewErrIPPFromRequest(rq,
goipp.StatusErrorNotPossible,
"Send-Document already in progress")
return nil, err
return nil, nil, err
}

// Consume the document body
Expand Down Expand Up @@ -231,5 +231,5 @@ func (printer *Printer) handleSendDocument(
},
}

return rsp.Encode(), nil
return rsp.Encode(), nil, nil
}
Loading