Research 027 asked for cups with the printer's driver. Measured: both Brother queues already print through IPP Everywhere, so cups and cups-filters are the whole driver, and the AUR vendor packages beside them serve no queue. The desktop's Canon is the exception: its 2012 driver is AUR-only and waits for the mesh's package repository; it stays as found. Seven Go tools: printers (state, device, driverless or not, supply levels), queue, cancel (the account first, sudo -n when CUPS refuses it), print, default, resume, and drivers (which packages bring drivers, which are foreign, which no queue uses).
178 lines
6.2 KiB
Go
178 lines
6.2 KiB
Go
// The cups module's tools (novox/hq research 027/02, 026/05): the printers, their state, supplies and
|
|
// driver, the queue, and printing, cancelling and choosing the default. A Go bundle the node's runtime
|
|
// launches over stdio (ADR 0188, ADR 0193); it runs as the operator account. An act CUPS keeps for
|
|
// its administrators goes through `sudo -n`.
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
stdio "git.novox.be/novox/mesh-sdk/go"
|
|
)
|
|
|
|
var providedBy = map[string]string{
|
|
"lpstat": "the cups package, which this module installs",
|
|
"lpoptions": "the cups package, which this module installs",
|
|
"lp": "the cups package, which this module installs",
|
|
"cancel": "the cups package, which this module installs",
|
|
"lpadmin": "the cups package, which this module installs",
|
|
"lpinfo": "the cups package, which this module installs",
|
|
"cupsenable": "the cups package, which this module installs",
|
|
"cupsaccept": "the cups package, which this module installs",
|
|
"pacman": "this is not an Arch machine",
|
|
}
|
|
|
|
func main() {
|
|
if err := stdio.Serve("", tools()); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
var printerArg = map[string]any{"type": "string", "description": "the printer's queue name, as cups_printers answers it"}
|
|
|
|
func tools() []stdio.Tool {
|
|
return []stdio.Tool{
|
|
{
|
|
Name: "cups_printers",
|
|
Description: "Every printer queue: state, whether it is enabled and accepting jobs, the default, its device " +
|
|
"address, make and model, whether it prints driverless (IPP Everywhere), the reasons for its state, and " +
|
|
"supply levels where the printer reports them. (r)",
|
|
Input: map[string]any{},
|
|
Run: func(map[string]any) (any, error) { return Printers() },
|
|
},
|
|
{
|
|
Name: "cups_queue",
|
|
Description: "The jobs waiting or printing, on every printer or one; or, with completed, the finished ones. " +
|
|
"Each with its id, printer, owner, size and when it was submitted. (r)",
|
|
Input: map[string]any{
|
|
"printer": printerArg,
|
|
"completed": map[string]any{"type": "boolean", "description": "the finished jobs instead"},
|
|
"limit": map[string]any{"type": "integer", "description": "at most this many, newest first (default 50, at most 500)"},
|
|
},
|
|
Run: func(args map[string]any) (any, error) {
|
|
p, err := optText(args, "printer", "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
done, err := optFlag(args, "completed", false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
limit, err := optWhole(args, "limit", 50, 1, 500)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return Queue(p, done, limit)
|
|
},
|
|
},
|
|
{
|
|
Name: "cups_cancel",
|
|
Description: "Cancel one job by its id (\"Brother-12\" or 12), or every job on a printer with all. Another " +
|
|
"account's job is cancelled through sudo -n. (a)",
|
|
Input: map[string]any{
|
|
"job": map[string]any{"type": "string", "description": "the job id"},
|
|
"printer": printerArg,
|
|
"all": map[string]any{"type": "boolean", "description": "every job on printer"},
|
|
},
|
|
Run: func(args map[string]any) (any, error) {
|
|
job, err := optText(args, "job", "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
p, err := optText(args, "printer", "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
all, err := optFlag(args, "all", false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return Cancel(job, p, all)
|
|
},
|
|
},
|
|
{
|
|
Name: "cups_print",
|
|
Description: "Print a file on this machine, to a printer or the default, with copies and IPP options such as " +
|
|
"sides=two-sided-long-edge or media=A4. Answers the job id. (a)",
|
|
Input: map[string]any{
|
|
"file": map[string]any{"type": "string", "description": "the file's absolute path on this machine"},
|
|
"printer": printerArg,
|
|
"copies": map[string]any{"type": "integer", "description": "copies (default 1, at most 99)"},
|
|
"options": map[string]any{"type": "object", "additionalProperties": map[string]any{"type": "string"}, "description": "IPP options, name to value"},
|
|
"title": map[string]any{"type": "string", "description": "the job's title (default the file's name)"},
|
|
},
|
|
Run: func(args map[string]any) (any, error) {
|
|
file, err := text(args, "file")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
p, err := optText(args, "printer", "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copies, err := optWhole(args, "copies", 1, 1, 99)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
opts, err := optionsOf(args)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
title, err := optText(args, "title", "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return Print(file, p, copies, opts, title)
|
|
},
|
|
},
|
|
{
|
|
Name: "cups_default",
|
|
Description: "The machine's default printer; with printer, make that printer the default (through sudo -n). " +
|
|
"The default is CUPS's own setting, kept as the operator chose it: the mesh does not declare it. (r/a)",
|
|
Input: map[string]any{"printer": printerArg},
|
|
Run: func(args map[string]any) (any, error) {
|
|
p, err := optText(args, "printer", "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return Default(p)
|
|
},
|
|
},
|
|
{
|
|
Name: "cups_resume",
|
|
Description: "Enable a printer and make it accept jobs again, after CUPS stopped it on an error. Through sudo -n. (a)",
|
|
Input: map[string]any{"printer": printerArg},
|
|
Run: func(args map[string]any) (any, error) {
|
|
p, err := text(args, "printer")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return Resume(p)
|
|
},
|
|
},
|
|
{
|
|
Name: "cups_drivers",
|
|
Description: "What each printer prints through (driverless or a driver's PPD), the packages that bring drivers " +
|
|
"and backends, which of them are from outside the official repositories, and the driver models CUPS " +
|
|
"offers, filtered by match. (r)",
|
|
Input: map[string]any{
|
|
"match": map[string]any{"type": "string", "description": "only models whose description contains this, any case"},
|
|
"limit": map[string]any{"type": "integer", "description": "at most this many models (default 50, at most 1000)"},
|
|
},
|
|
Run: func(args map[string]any) (any, error) {
|
|
match, err := optText(args, "match", "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
limit, err := optWhole(args, "limit", 50, 0, 1000)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return Drivers(match, limit)
|
|
},
|
|
},
|
|
}
|
|
}
|