2019-03-10 17:43:47 +00:00
package ipp
import (
2019-03-15 15:20:02 +00:00
"errors"
2019-03-10 17:43:47 +00:00
"fmt"
"io"
"os"
"path"
)
2020-03-27 23:27:56 +00:00
// Document wraps an io.Reader with more information, needed for encoding
2019-03-15 15:20:02 +00:00
type Document struct {
Document io . Reader
Size int
Name string
MimeType string
}
2020-03-27 23:27:56 +00:00
// IPPClient implements a generic ipp client
2019-03-10 17:43:47 +00:00
type IPPClient struct {
username string
2021-02-26 08:40:29 +00:00
adapter Adapter
2019-03-10 17:43:47 +00:00
}
2021-02-26 08:40:29 +00:00
// NewIPPClient creates a new generic ipp client (used HttpAdapter internally)
2019-03-10 17:43:47 +00:00
func NewIPPClient ( host string , port int , username , password string , useTLS bool ) * IPPClient {
2021-02-26 08:40:29 +00:00
adapter := NewHttpAdapter ( host , port , username , password , useTLS )
2019-03-10 17:43:47 +00:00
2021-02-26 08:40:29 +00:00
return & IPPClient {
username : username ,
adapter : adapter ,
2019-03-15 15:20:02 +00:00
}
2021-02-26 08:40:29 +00:00
}
2019-03-15 15:20:02 +00:00
2021-02-26 08:40:29 +00:00
// NewIPPClientWithAdapter creates a new generic ipp client with given Adapter
func NewIPPClientWithAdapter ( username string , adapter Adapter ) * IPPClient {
return & IPPClient {
username : username ,
adapter : adapter ,
2019-03-15 15:20:02 +00:00
}
2021-02-26 08:40:29 +00:00
}
2019-03-15 15:20:02 +00:00
2021-02-26 08:40:29 +00:00
func ( c * IPPClient ) getHttpUri ( namespace string , object interface { } ) string {
return c . adapter . GetHttpUri ( namespace , object )
2019-03-15 15:20:02 +00:00
}
func ( c * IPPClient ) getPrinterUri ( printer string ) string {
return fmt . Sprintf ( "ipp://localhost/printers/%s" , printer )
}
func ( c * IPPClient ) getJobUri ( jobID int ) string {
return fmt . Sprintf ( "ipp://localhost/jobs/%d" , jobID )
2019-03-10 17:43:47 +00:00
}
2019-03-15 15:20:02 +00:00
func ( c * IPPClient ) getClassUri ( printer string ) string {
return fmt . Sprintf ( "ipp://localhost/classes/%s" , printer )
}
2020-03-27 23:27:56 +00:00
// SendRequest sends a request to a remote uri end returns the response
2019-12-26 15:46:08 +00:00
func ( c * IPPClient ) SendRequest ( url string , req * Request , additionalResponseData io . Writer ) ( * Response , error ) {
2021-02-26 08:40:29 +00:00
return c . adapter . SendRequest ( url , req , additionalResponseData )
2019-03-10 17:43:47 +00:00
}
2020-03-27 23:27:56 +00:00
// PrintDocuments prints one or more documents using a Create-Job operation followed by one or more Send-Document operation(s). custom job settings can be specified via the jobAttributes parameter
2019-06-08 22:03:50 +00:00
func ( c * IPPClient ) PrintDocuments ( docs [ ] Document , printer string , jobAttributes map [ string ] interface { } ) ( int , error ) {
2019-03-15 15:20:02 +00:00
printerURI := c . getPrinterUri ( printer )
2019-03-10 17:43:47 +00:00
req := NewRequest ( OperationCreateJob , 1 )
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributePrinterURI ] = printerURI
req . OperationAttributes [ AttributeRequestingUserName ] = c . username
2019-06-08 22:03:50 +00:00
// set defaults for some attributes, may get overwritten
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeJobName ] = docs [ 0 ] . Name
req . OperationAttributes [ AttributeCopies ] = 1
req . OperationAttributes [ AttributeJobPriority ] = DefaultJobPriority
2019-06-08 22:03:50 +00:00
for key , value := range jobAttributes {
req . JobAttributes [ key ] = value
}
2019-03-10 17:43:47 +00:00
2019-12-26 15:46:08 +00:00
resp , err := c . SendRequest ( c . getHttpUri ( "printers" , printer ) , req , nil )
2019-03-10 17:43:47 +00:00
if err != nil {
return - 1 , err
}
2020-03-05 15:31:05 +00:00
if len ( resp . JobAttributes ) == 0 {
2019-03-15 15:20:02 +00:00
return 0 , errors . New ( "server doesn't returned a job id" )
}
2020-03-09 09:36:29 +00:00
jobID := resp . JobAttributes [ 0 ] [ AttributeJobID ] [ 0 ] . Value . ( int )
2019-03-10 17:43:47 +00:00
2019-03-15 15:20:02 +00:00
documentCount := len ( docs ) - 1
for docID , doc := range docs {
req = NewRequest ( OperationSendDocument , 2 )
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributePrinterURI ] = printerURI
req . OperationAttributes [ AttributeRequestingUserName ] = c . username
req . OperationAttributes [ AttributeJobID ] = jobID
req . OperationAttributes [ AttributeDocumentName ] = doc . Name
req . OperationAttributes [ AttributeDocumentFormat ] = doc . MimeType
req . OperationAttributes [ AttributeLastDocument ] = docID == documentCount
2019-03-15 15:20:02 +00:00
req . File = doc . Document
req . FileSize = doc . Size
2019-12-26 15:46:08 +00:00
_ , err = c . SendRequest ( c . getHttpUri ( "printers" , printer ) , req , nil )
2019-03-15 15:20:02 +00:00
if err != nil {
return - 1 , err
}
2019-03-10 17:43:47 +00:00
}
return jobID , nil
2019-03-13 21:54:08 +00:00
}
2020-03-27 23:27:56 +00:00
// PrintJob prints a document using a Print-Job operation. custom job settings can be specified via the jobAttributes parameter
2019-05-30 00:51:10 +00:00
func ( c * IPPClient ) PrintJob ( doc Document , printer string , jobAttributes map [ string ] interface { } ) ( int , error ) {
printerURI := c . getPrinterUri ( printer )
req := NewRequest ( OperationPrintJob , 1 )
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributePrinterURI ] = printerURI
req . OperationAttributes [ AttributeRequestingUserName ] = c . username
req . OperationAttributes [ AttributeJobName ] = doc . Name
req . OperationAttributes [ AttributeDocumentFormat ] = doc . MimeType
2019-06-08 22:03:50 +00:00
// set defaults for some attributes, may get overwritten
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeCopies ] = 1
req . OperationAttributes [ AttributeJobPriority ] = DefaultJobPriority
2019-05-30 00:51:10 +00:00
for key , value := range jobAttributes {
req . JobAttributes [ key ] = value
}
req . File = doc . Document
req . FileSize = doc . Size
2019-12-26 15:46:08 +00:00
resp , err := c . SendRequest ( c . getHttpUri ( "printers" , printer ) , req , nil )
2019-05-30 00:51:10 +00:00
if err != nil {
return - 1 , err
}
2020-03-05 15:31:05 +00:00
if len ( resp . JobAttributes ) == 0 {
2019-05-30 00:51:10 +00:00
return 0 , errors . New ( "server doesn't returned a job id" )
}
2020-03-09 09:36:29 +00:00
jobID := resp . JobAttributes [ 0 ] [ AttributeJobID ] [ 0 ] . Value . ( int )
2019-05-30 00:51:10 +00:00
return jobID , nil
}
2020-03-27 23:27:56 +00:00
// PrintFile prints a local file on the file system. custom job settings can be specified via the jobAttributes parameter
2019-06-08 22:03:50 +00:00
func ( c * IPPClient ) PrintFile ( filePath , printer string , jobAttributes map [ string ] interface { } ) ( int , error ) {
2019-03-13 21:54:08 +00:00
fileStats , err := os . Stat ( filePath )
if os . IsNotExist ( err ) {
return - 1 , err
}
2019-03-15 15:20:02 +00:00
fileName := path . Base ( filePath )
2019-03-13 21:54:08 +00:00
document , err := os . Open ( filePath )
if err != nil {
return 0 , err
}
defer document . Close ( )
2020-03-09 09:36:29 +00:00
jobAttributes [ AttributeJobName ] = fileName
2019-06-08 22:03:50 +00:00
return c . PrintDocuments ( [ ] Document {
2019-03-15 15:20:02 +00:00
{
Document : document ,
Name : fileName ,
Size : int ( fileStats . Size ( ) ) ,
MimeType : MimeTypeOctetStream ,
} ,
2019-06-08 22:03:50 +00:00
} , printer , jobAttributes )
2019-03-15 15:20:02 +00:00
}
2020-03-27 23:27:56 +00:00
// GetPrinterAttributes returns the requested attributes for the specified printer, if attributes is nil the default attributes will be used
2019-03-15 15:20:02 +00:00
func ( c * IPPClient ) GetPrinterAttributes ( printer string , attributes [ ] string ) ( Attributes , error ) {
req := NewRequest ( OperationGetPrinterAttributes , 1 )
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributePrinterURI ] = c . getPrinterUri ( printer )
req . OperationAttributes [ AttributeRequestingUserName ] = c . username
2019-03-15 15:20:02 +00:00
if attributes == nil {
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeRequestedAttributes ] = DefaultPrinterAttributes
2019-03-15 15:20:02 +00:00
} else {
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeRequestedAttributes ] = attributes
2019-03-15 15:20:02 +00:00
}
2019-12-26 15:46:08 +00:00
resp , err := c . SendRequest ( c . getHttpUri ( "printers" , printer ) , req , nil )
2019-03-15 15:20:02 +00:00
if err != nil {
return nil , err
}
2020-03-05 15:31:05 +00:00
if len ( resp . PrinterAttributes ) == 0 {
2019-03-15 15:20:02 +00:00
return nil , errors . New ( "server doesn't return any printer attributes" )
}
2020-03-05 15:31:05 +00:00
return resp . PrinterAttributes [ 0 ] , nil
2019-03-15 15:20:02 +00:00
}
2020-03-27 23:27:56 +00:00
// ResumePrinter resumes a printer
2019-03-15 15:20:02 +00:00
func ( c * IPPClient ) ResumePrinter ( printer string ) error {
req := NewRequest ( OperationResumePrinter , 1 )
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributePrinterURI ] = c . getPrinterUri ( printer )
2019-03-15 15:20:02 +00:00
2019-12-26 15:46:08 +00:00
_ , err := c . SendRequest ( c . getHttpUri ( "admin" , "" ) , req , nil )
2019-03-15 15:20:02 +00:00
return err
}
2020-03-27 23:27:56 +00:00
// PausePrinter pauses a printer
2019-03-15 15:20:02 +00:00
func ( c * IPPClient ) PausePrinter ( printer string ) error {
req := NewRequest ( OperationPausePrinter , 1 )
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributePrinterURI ] = c . getPrinterUri ( printer )
2019-03-15 15:20:02 +00:00
2019-12-26 15:46:08 +00:00
_ , err := c . SendRequest ( c . getHttpUri ( "admin" , "" ) , req , nil )
2019-03-15 15:20:02 +00:00
return err
}
2020-03-27 23:27:56 +00:00
// GetJobAttributes returns the requested attributes for the specified job, if attributes is nil the default job will be used
2019-03-15 15:20:02 +00:00
func ( c * IPPClient ) GetJobAttributes ( jobID int , attributes [ ] string ) ( Attributes , error ) {
req := NewRequest ( OperationGetJobAttributes , 1 )
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeJobURI ] = c . getJobUri ( jobID )
2019-03-15 15:20:02 +00:00
if attributes == nil {
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeRequestedAttributes ] = DefaultJobAttributes
2019-03-15 15:20:02 +00:00
} else {
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeRequestedAttributes ] = attributes
2019-03-15 15:20:02 +00:00
}
2019-12-26 15:46:08 +00:00
resp , err := c . SendRequest ( c . getHttpUri ( "jobs" , jobID ) , req , nil )
2019-03-15 15:20:02 +00:00
if err != nil {
return nil , err
}
2020-03-05 15:31:05 +00:00
if len ( resp . PrinterAttributes ) == 0 {
2019-03-15 15:20:02 +00:00
return nil , errors . New ( "server doesn't return any job attributes" )
}
2020-03-05 15:31:05 +00:00
return resp . PrinterAttributes [ 0 ] , nil
2019-03-15 15:20:02 +00:00
}
2020-03-27 23:27:56 +00:00
// GetJobs returns jobs from a printer or class
2020-03-09 11:47:23 +00:00
func ( c * IPPClient ) GetJobs ( printer , class string , whichJobs string , myJobs bool , firstJobId , limit int , attributes [ ] string ) ( map [ int ] Attributes , error ) {
2019-03-15 15:20:02 +00:00
req := NewRequest ( OperationGetJobs , 1 )
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeWhichJobs ] = string ( whichJobs )
req . OperationAttributes [ AttributeMyJobs ] = myJobs
2019-03-15 15:20:02 +00:00
2019-12-26 15:46:08 +00:00
if printer != "" {
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributePrinterURI ] = c . getPrinterUri ( printer )
2019-12-26 15:46:08 +00:00
} else if class != "" {
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributePrinterURI ] = c . getClassUri ( printer )
2019-12-26 15:46:08 +00:00
} else {
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributePrinterURI ] = "ipp://localhost/"
2019-12-26 15:46:08 +00:00
}
2019-12-26 16:14:15 +00:00
if firstJobId > 0 {
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeFirstJobID ] = firstJobId
2019-12-26 16:14:15 +00:00
}
if limit > 0 {
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeLimit ] = limit
2019-12-26 16:14:15 +00:00
}
if myJobs {
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeRequestingUserName ] = c . username
2019-12-26 16:14:15 +00:00
}
2019-03-15 15:20:02 +00:00
if attributes == nil {
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeRequestedAttributes ] = DefaultJobAttributes
2019-03-15 15:20:02 +00:00
} else {
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeRequestedAttributes ] = append ( attributes , AttributeJobID )
2019-03-15 15:20:02 +00:00
}
2019-12-26 15:46:08 +00:00
resp , err := c . SendRequest ( c . getHttpUri ( "" , nil ) , req , nil )
2019-03-15 15:20:02 +00:00
if err != nil {
return nil , err
}
jobIDMap := make ( map [ int ] Attributes )
2020-03-05 15:31:05 +00:00
for _ , jobAttributes := range resp . JobAttributes {
2020-03-09 09:36:29 +00:00
jobIDMap [ jobAttributes [ AttributeJobID ] [ 0 ] . Value . ( int ) ] = jobAttributes
2019-03-15 15:20:02 +00:00
}
return jobIDMap , nil
}
2020-03-27 23:27:56 +00:00
// CancelJob cancels a job. if purge is true, the job will also be removed
2019-03-15 15:20:02 +00:00
func ( c * IPPClient ) CancelJob ( jobID int , purge bool ) error {
req := NewRequest ( OperationCancelJob , 1 )
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeJobURI ] = c . getJobUri ( jobID )
req . OperationAttributes [ AttributePurgeJobs ] = purge
2019-03-15 15:20:02 +00:00
2019-12-26 15:46:08 +00:00
_ , err := c . SendRequest ( c . getHttpUri ( "jobs" , "" ) , req , nil )
2019-03-15 15:20:02 +00:00
return err
}
2020-03-27 23:30:48 +00:00
// CancelAllJob cancels all jobs for a specified printer. if purge is true, the jobs will also be removed
2019-03-15 15:20:02 +00:00
func ( c * IPPClient ) CancelAllJob ( printer string , purge bool ) error {
2019-03-17 12:40:08 +00:00
req := NewRequest ( OperationCancelJobs , 1 )
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributePrinterURI ] = c . getPrinterUri ( printer )
req . OperationAttributes [ AttributePurgeJobs ] = purge
2019-03-15 15:20:02 +00:00
2019-12-26 15:46:08 +00:00
_ , err := c . SendRequest ( c . getHttpUri ( "admin" , "" ) , req , nil )
2019-03-15 15:20:02 +00:00
return err
}
2020-03-27 23:27:56 +00:00
// RestartJob restarts a job
2019-03-15 15:20:02 +00:00
func ( c * IPPClient ) RestartJob ( jobID int ) error {
req := NewRequest ( OperationRestartJob , 1 )
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeJobURI ] = c . getJobUri ( jobID )
2019-03-15 15:20:02 +00:00
2019-12-26 15:46:08 +00:00
_ , err := c . SendRequest ( c . getHttpUri ( "jobs" , "" ) , req , nil )
2019-03-15 15:20:02 +00:00
return err
}
2020-03-27 23:30:48 +00:00
// HoldJobUntil holds a job
2019-03-15 15:20:02 +00:00
func ( c * IPPClient ) HoldJobUntil ( jobID int , holdUntil string ) error {
req := NewRequest ( OperationRestartJob , 1 )
2020-03-09 09:36:29 +00:00
req . OperationAttributes [ AttributeJobURI ] = c . getJobUri ( jobID )
req . JobAttributes [ AttributeHoldJobUntil ] = holdUntil
2019-03-15 15:20:02 +00:00
2019-12-26 15:46:08 +00:00
_ , err := c . SendRequest ( c . getHttpUri ( "jobs" , "" ) , req , nil )
2019-03-15 15:20:02 +00:00
return err
}
2020-03-27 23:27:56 +00:00
// TestConnection tests if a tcp connection to the remote server is possible
2019-03-15 15:20:02 +00:00
func ( c * IPPClient ) TestConnection ( ) error {
2021-02-26 08:40:29 +00:00
return c . adapter . TestConnection ( )
2019-03-13 21:54:08 +00:00
}