///|
pub(all) struct RequestContext {
printer : PrinterUri
user : String
language : String
version : Version
} derive(Eq, Debug)
///|
pub extend RequestContext with Eq::{equal, not_equal}
///|
pub extend RequestContext with @debug.Debug::{to_repr}
///|
pub fn RequestContext::new(
uri : String,
user? : String = "anonymous",
language? : String = "en",
) -> RequestContext raise IppError {
if encode_utf8(user).length() < 1 || encode_utf8(user).length() > 255 {
raise Invalid("requesting user name length out of range")
}
if language.is_empty() || language.length() > 63 {
raise Invalid("invalid natural language")
}
{ printer: PrinterUri::parse(uri), user, language, version: Version::v20(), }
}
///|
fn RequestContext::attributes(self : RequestContext) -> Array[Attribute] {
[
Attribute::new("attributes-charset", Charset("utf-8")),
Attribute::new("attributes-natural-language", Language(self.language)),
Attribute::new("printer-uri", Uri(self.printer.text())),
Attribute::new("requesting-user-name", Name(self.user)),
]
}
///|
fn RequestContext::request(
self : RequestContext,
operation : Operation,
request_id : Int,
attributes : Array[Attribute],
) -> Message raise IppError {
if request_id < 1 {
raise Invalid("request-id must be positive")
}
{
version: self.version,
code: operation.code(),
request_id,
groups: [Group::operation(attributes)],
document: b"",
}
}
///|
pub fn RequestContext::printer_attributes(
self : RequestContext,
request_id : Int,
requested? : Array[String] = [],
) -> Message raise IppError {
let attributes = self.attributes()
if !requested.is_empty() {
attributes.push(Attribute::keywords("requested-attributes", requested))
}
self.request(GetPrinterAttributes, request_id, attributes)
}
///|
pub fn RequestContext::get_jobs(
self : RequestContext,
request_id : Int,
which? : String = "not-completed",
mine? : Bool = false,
limit? : Int = 100,
) -> Message raise IppError {
if which != "not-completed" && which != "completed" && which != "all" {
raise Invalid("which-jobs must be all, completed or not-completed")
}
if limit < 1 || limit > 10000 {
raise Invalid("job limit out of range")
}
let attributes = self.attributes()
attributes.push(Attribute::new("which-jobs", Keyword(which)))
attributes.push(Attribute::new("my-jobs", Boolean(mine)))
attributes.push(Attribute::new("limit", Integer(limit)))
attributes.push(
Attribute::keywords("requested-attributes", [
"job-id", "job-uri", "job-name", "job-state", "job-state-reasons", "job-state-message",
"job-impressions-completed",
]),
)
self.request(GetJobs, request_id, attributes)
}
///|
fn RequestContext::job_request(
self : RequestContext,
operation : Operation,
request_id : Int,
job_id : Int,
) -> Message raise IppError {
if job_id < 1 {
raise Invalid("job-id must be positive")
}
let attributes = self.attributes()
// RFC 8011 requires job-id immediately after the target printer-uri.
attributes.insert(3, Attribute::new("job-id", Integer(job_id)))
self.request(operation, request_id, attributes)
}
///|
pub fn RequestContext::job_attributes(
self : RequestContext,
request_id : Int,
job_id : Int,
) -> Message raise IppError {
self.job_request(GetJobAttributes, request_id, job_id)
}
///|
pub fn RequestContext::cancel_job(
self : RequestContext,
request_id : Int,
job_id : Int,
) -> Message raise IppError {
self.job_request(CancelJob, request_id, job_id)
}
///|
pub fn RequestContext::validate_job(
self : RequestContext,
request_id : Int,
options : JobOptions,
) -> Message raise IppError {
options.validate()
let attributes = self.attributes()
attributes.push(
Attribute::new("document-format", MimeType(options.document_format)),
)
attributes.push(Attribute::new("job-name", Name(options.name)))
attributes.push(Attribute::new("ipp-attribute-fidelity", Boolean(true)))
let request = self.request(ValidateJob, request_id, attributes)
request.groups.push(Group::job(options.attributes()))
request
}
///|
pub fn RequestContext::print_job(
self : RequestContext,
request_id : Int,
options : JobOptions,
document : Bytes,
) -> Message raise IppError {
if document.is_empty() {
raise Invalid("print document must not be empty")
}
let request = self.validate_job(request_id, options)
{ ..request, code: Operation::PrintJob.code(), document, }
}
///|
pub fn RequestContext::create_job(
self : RequestContext,
request_id : Int,
options : JobOptions,
) -> Message raise IppError {
options.validate()
let attributes = self.attributes()
attributes.push(Attribute::new("job-name", Name(options.name)))
attributes.push(Attribute::new("ipp-attribute-fidelity", Boolean(true)))
let request = self.request(CreateJob, request_id, attributes)
request.groups.push(Group::job(options.attributes()))
request
}
///|
pub fn RequestContext::send_document(
self : RequestContext,
request_id : Int,
job_id : Int,
format : String,
document : Bytes,
last? : Bool = true,
) -> Message raise IppError {
if !valid_mime_type(format) || document.is_empty() {
raise Invalid("invalid document format or empty document")
}
let request = self.job_request(SendDocument, request_id, job_id)
let attributes = request.groups[0].attributes
attributes.push(Attribute::new("document-format", MimeType(format)))
attributes.push(Attribute::new("last-document", Boolean(last)))
request.with_document(document)
}