Contesto essenziale #
Su una multifunzione Toshiba e-STUDIO2525AC sono attivi i codici di reparto. Da Windows il driver Toshiba chiede il codice a ogni stampa. Da Linux, con la coda driverless creata da CUPS, non compare nessuna richiesta e le stampe non escono.
I problemi sono due e si sommano. La stampante scarta in silenzio i lavori senza un codice valido. Il PPD generato in automatico contiene un errore che impedisce a CUPS di accettare qualsiasi lavoro, anche se il codice c’è.
Le soluzioni sono due:
- coda driverless con
job-account-id(procedura principale): un solo codice predefinito per tutta la coda, nessun driver da installare, connessione IPPS cifrata; - PPD Toshiba corretto (procedura alternativa): il codice si imposta per utente, dalla finestra di stampa e dall’interfaccia web di CUPS.
Il caso è su Fedora 44 con CUPS 2.4 e libppd 2.1.1, ma la diagnosi vale per qualsiasi stampante che dichiari attributi IPP obbligatori.
Prerequisiti #
- Accesso
sudo(i PPD in/etc/cups/ppd/sono leggibili solo da root) ipptoolper interrogare la stampante- Un codice di reparto valido, fornito da chi amministra la stampante
Installazione rapida #
Fedora / RHEL #
sudo dnf install cups-ipptoolDebian/Ubuntu #
sudo apt install cups-ipp-utilsArch Linux #
sudo pacman -S cupsProcedura passo-passo #
1. Vedere cosa chiede la stampante #
ipptool -tv ipps://<ip-stampante>/ipp/print get-printer-attributes.test \
| grep -E 'mandatory|account'Output nel caso reale:
job-account-id-supported (boolean) = true
printer-mandatory-job-attributes (keyword) = job-account-id
job-accounting-user-id-supported (boolean) = falseprinter-mandatory-job-attributes indica che ogni lavoro deve contenere job-account-id. È l’attributo IPP standard in cui la stampante si aspetta il codice di reparto: non serve il driver Toshiba.
2. Provare a stampare dalla coda #
lp -d <stampante> -o job-account-id=<codice> <file>Nel caso reale il lavoro viene rifiutato prima ancora di partire:
lp: L'attributo """" è richiesto per i processi di stampa.L’errore viene da CUPS locale, non dalla stampante. Il nome dell’attributo richiesto è vuoto, il che fa pensare a una configurazione della coda rovinata.
3. Controllare gli attributi della coda locale #
ipptool -tv ipp://localhost/printers/<stampante> get-printer-attributes.test \
| grep mandatory | cut -c1-300Output nel caso reale (accorciato):
printer-mandatory-job-attributes (1setOf keyword) = \"\",\"\"job-account-id\",\"11.990551181102,\"278.985826771654,...,*OpenUI,*PageSize,...Invece del solo job-account-id, la coda considera obbligatori centinaia di frammenti del PPD: misure di pagina, parole chiave *OpenUI, codice PostScript. Nessun lavoro può soddisfarli.
4. Trovare la riga difettosa nel PPD #
sudo grep -n 'cupsMandatory' /etc/cups/ppd/<stampante>.ppd25:*cupsMandatory: ""job-account-id"C’è una virgoletta di troppo all’inizio del valore. Il parser chiude la stringa subito dopo "" e il resto del file viene letto come elenco di attributi obbligatori.
Un controllo con cupstestppd conferma che il file è illeggibile dopo quella riga:
sudo cat /etc/cups/ppd/<stampante>.ppd > /tmp/stampante.ppd
cupstestppd -W none /tmp/stampante.ppd | head -4 **FAIL** RICHIESTA DefaultImageableArea
**FAIL** RICHIESTA DefaultPaperDimensionIl PPD è stato generato dal driverless di libppd 2.1.1 (*NickName: "TOSHIBA Printer, driverless, 2.1.1"). Nel journal di CUPS, al momento della creazione della coda, compare anche questo avviso:
The PPD file for printer e-STUDIO2525AC contains no media options and is therefore invalid.5. Correggere il PPD #
sudo cp /etc/cups/ppd/<stampante>.ppd /etc/cups/ppd/<stampante>.ppd.bak
sudo sed -i 's/^\*cupsMandatory: ""job-account-id"$/*cupsMandatory: "job-account-id"/' /etc/cups/ppd/<stampante>.ppd
sudo systemctl restart cupsVerifica:
ipptool -tv ipp://localhost/printers/<stampante> get-printer-attributes.test \
| grep mandatoryprinter-mandatory-job-attributes (keyword) = job-account-id6. Impostare il codice di reparto predefinito #
Linux non chiede il codice al momento della stampa come il driver Toshiba su Windows. Se l’host è usato da una sola persona o da un solo reparto, conviene impostarlo sulla coda:
sudo lpadmin -p <stampante> -o job-account-id-default=<codice>Il valore viene salvato in /etc/cups/printers.conf come Option job-account-id <codice> e CUPS lo aggiunge a ogni lavoro che non ne specifica uno.
Da solo però funziona solo per la riga di comando. lp ci riesce perché libcups aggiunge al lavoro le opzioni predefinite della coda prima di inviarlo. Le applicazioni GTK non lo fanno, e il passo successivo serve per loro.
7. Togliere cupsMandatory per le applicazioni grafiche #
Con il codice predefinito impostato, una stampa da Firefox, LibreOffice o qualsiasi applicazione GTK viene comunque rifiutata. La finestra di stampa mostra “Terminato” e non segnala nessun errore, ma nel journal compare:
Returning IPP client-error-conflicting-attributes for Print-Job (ipp://localhost:631/printers/e-STUDIO2525AC) from localhost.Con il log di debug di CUPS attivo (sudo cupsctl --debug-logging, da disattivare poi con --no-debug-logging) si vede il motivo:
Print-Job client-error-conflicting-attributes: L'attributo "job-account-id" è richiesto per i processi di stampa.CUPS controlla gli attributi obbligatori dichiarati da *cupsMandatory prima di applicare i valori predefiniti della coda. La soluzione è togliere la riga dal PPD e lasciare *cupsJobAccountId: True, che fa inoltrare il codice alla stampante:
sudo sed -i '/^\*cupsMandatory:/d' /etc/cups/ppd/<stampante>.ppd
sudo systemctl restart cupsOgni comando lpadmin su questa coda, sia -o sia -R, reinserisce la riga *cupsMandatory: job-account-id all’inizio del PPD. L’ordine giusto è sempre: prima lpadmin, poi la rimozione della riga.
Verifica:
sudo grep -c cupsMandatory /etc/cups/ppd/<stampante>.ppdIl risultato deve essere 0. Senza la riga, CUPS non scarta più i lavori privi di codice. Per questo il codice predefinito del passo 6 serve: è lui a garantire che ogni lavoro ne abbia uno.
8. Verificare la stampa #
lp -d <stampante> <file>
lpstat -W completed -o <stampante> | tail -1CUPS può segnare il lavoro come completato anche se la stampante l’ha scartato. Per esserne certi bisogna chiedere lo stato direttamente alla stampante. Il test di ipptool get-jobs.test restituisce i lavori ancora attivi. Per quelli completati serve un file di test con which-jobs completed:
cat > get-completed.test <<'EOF'
{
NAME "Get-Jobs completed"
OPERATION Get-Jobs
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
ATTR naturalLanguage attributes-natural-language en
ATTR uri printer-uri $uri
ATTR keyword which-jobs completed
ATTR keyword requested-attributes job-id,job-name,job-state-reasons,job-impressions-completed
STATUS successful-ok
}
EOF
ipptool -tv ipps://<ip-stampante>/ipp/print get-completed.test | grep -E 'job-(id|name|state-reasons|impressions)'Un lavoro stampato davvero ha job-completed-successfully e job-impressions-completed maggiore di zero.
Se la risposta non elenca nessun lavoro, provare con Get-Job-Attributes e un job-id preciso: sulla e-STUDIO2525AC del caso reale Get-Jobs non restituiva i lavori completati. Nel caso reale il risultato è stato questo:
| Lavoro | Codice | Stato sulla stampante | Pagine |
|---|---|---|---|
| diretto via IPP | valido | job-completed-successfully |
1 |
| diretto via IPP | assente | job-completed-with-errors |
0 |
| diretto via IPP | non valido | job-completed-with-errors |
0 |
dalla coda con lp, con codice predefinito |
(predefinito) | job-completed-successfully |
1 |
| da un’applicazione GTK, dopo il passo 7 | (predefinito) | job-completed-successfully |
1 |
Procedura alternativa: PPD Toshiba con codice per utente #
Con la coda driverless il codice è uno solo per tutta la coda: le applicazioni grafiche ignorano lpoptions e il campo Informazioni fatturazione viene scavalcato dal predefinito. Il driver Linux ufficiale Toshiba invece espone il codice di reparto come opzione del PPD, e le opzioni del PPD si possono impostare per utente, dalla finestra di stampa e dall’interfaccia web di CUPS.
Così com’è, però, il PPD Toshiba invia il codice nel formato sbagliato e va corretto.
1. Verificare che la stampante accetti PostScript #
Il PPD Toshiba produce PostScript e mette il codice dentro il flusso di stampa. Via IPP la e-STUDIO2525AC dichiara solo PDF, URF e JPEG, ma sulla porta raw 9100 accetta anche PostScript:
avahi-browse -rtp _pdl-datastream._tcp | grep '^=' | grep -o '"pdl=[^"]*"'"pdl=text/plain,application/postscript,application/vnd.hp-PCL,application/vnd.hp-PCLXL,application/octet-stream"2. Scaricare il driver ufficiale ed estrarre il PPD #
mkdir toshiba && cd toshiba
curl -LO https://business.toshiba.com/downloads/KB/f1Ulds/15178/TOSHIBA_ColorMFP_CUPS.tar
tar -xf TOSHIBA_ColorMFP_CUPS.tar
gunzip -c usr/share/cups/model/Toshiba/TOSHIBA_ColorMFP_CUPS.gz > TOSHIBA_ColorMFP_CUPS.ppdL’archivio (versione 7.89 del 2017) contiene due file: il PPD e il filtro est6550_Authentication. Il filtro è uno script Perl offuscato che aggiunge le copertine e le righe DOMAINNAME/CERTIFIED: per il codice di reparto non serve e qui non viene installato.
La e-STUDIO2525AC non compare tra i modelli dichiarati nel PPD. Il codice di reparto e la stampa di base funzionano. Fronte-retro, cassetti e finitura non sono stati verificati.
Le opzioni che interessano sono DeptCode (attiva o disattiva il codice) e DCDigit1…DCDigit5 (le cinque cifre):
grep -E '^\*OpenUI \*(DeptCode|DCDigit)' TOSHIBA_ColorMFP_CUPS.ppd3. Capire perché il PPD originale non funziona #
Ogni cifra vale un multiplo di 10 (DCDigit1 1 mette 10000, DCDigit2 2 mette 2000…) e DeptCode somma i valori e scrive il risultato in una stringa di cinque caratteri inizializzata a 00000. Un codice di quattro cifre arriva quindi alla stampante con uno zero davanti:
DSSC PRINT ACCESSCODE=0<codice>La stampante confronta il codice come stringa e lo scarta. Inviando a mano il PostScript sulla porta 9100 e controllando il registro stampe di TopAccess, il risultato è stato questo:
| Codice inviato | Righe DOMAINNAME/CERTIFIED |
Esito |
|---|---|---|
| a 5 cifre, con zero iniziale | no | scartato |
| a 5 cifre, con zero iniziale | sì | scartato |
| a 4 cifre, come configurato | sì | stampato |
| a 4 cifre, come configurato | no | stampato |
Conta solo il formato del codice. Le righe aggiunte dal filtro Toshiba non servono.
4. Correggere il PPD #
Lo script seguente toglie il riferimento al filtro Toshiba e riscrive le opzioni: ogni cifra diventa un carattere, le cifre vengono concatenate senza riempimento e ogni cifra ha anche la scelta - (nessuna). Così il PPD funziona con codici da 1 a 5 cifre:
cat > fix-toshiba-ppd.py <<'EOF'
import re, sys
src, dst = sys.argv[1], sys.argv[2]
t = open(src, encoding='latin-1').read()
t = re.sub(r'^\*cupsFilter:.*\n', '', t, flags=re.M)
m = re.search(r'\*DeptCode True/Enabled: ".*?"\n\*End\n', t, re.S)
t = t[:m.start()] + (
'*DeptCode True/Enabled: "\n'
'\tuserdict /tsbdc { userdict exch 2 copy known { get } { pop pop () } ifelse } bind put\n'
'\tuserdict /tsbcat { 2 copy length exch length add string dup 0 4 index putinterval'
' dup 3 index length 3 index putinterval 3 1 roll pop pop } bind put\n'
'\t<</TSBPrivate (DSSC PRINT ACCESSCODE=) /DCDigit1 tsbdc tsbcat /DCDigit2 tsbdc tsbcat'
' /DCDigit3 tsbdc tsbcat /DCDigit4 tsbdc tsbcat /DCDigit5 tsbdc tsbcat >> setpagedevice"\n'
'*End\n') + t[m.end():]
for n in range(1, 6):
b = re.search(r'(\*OpenUI \*DCDigit%d/[^\n]*\n\*OrderDependency:[^\n]*\n)\*DefaultDCDigit%d: 0\n.*?(\*CloseUI: \*DCDigit%d\n)' % (n, n, n), t, re.S)
ch = '*DCDigit%d None/-: "userdict /DCDigit%d () put"\n' % (n, n)
ch += ''.join('*DCDigit%d %d/%d: "userdict /DCDigit%d (%d) put"\n' % (n, d, d, n, d) for d in range(10))
t = t[:b.start()] + b.group(1) + '*DefaultDCDigit%d: None\n' % n + ch + b.group(2) + t[b.end():]
open(dst, 'w', encoding='latin-1').write(t)
EOF
python3 fix-toshiba-ppd.py TOSHIBA_ColorMFP_CUPS.ppd toshiba-dc.ppd
cupstestppd -W none toshiba-dc.ppdOutput atteso dell’ultima riga:
toshiba-dc.ppd: OPERAZIONE RIUSCITA CON SUCCESSO5. Creare la coda con il codice predefinito #
La coda usa il backend socket sulla porta 9100. Il codice predefinito si imposta come normali opzioni del PPD, una cifra per opzione:
sudo lpadmin -p <stampante> -E -v socket://<ip-stampante>:9100 -P toshiba-dc.ppd \
-o PageSize=A4 -o DeptCode=True \
-o DCDigit1=<cifra1> -o DCDigit2=<cifra2> -o DCDigit3=<cifra3> -o DCDigit4=<cifra4>lpadmin avvisa che i driver basati su PPD sono deprecati: in CUPS 2.4 è solo un avviso.
Se esisteva una coda driverless con lo stesso nome, va eliminata prima con sudo lpadmin -x <stampante>.
6. Verificare il codice prima di stampare #
cupsfilter genera il PostScript che CUPS invierebbe e Ghostscript lo esegue, con setpagedevice ridefinito in modo da stampare a schermo i comandi Toshiba invece di applicarli:
sudo cat /etc/cups/ppd/<stampante>.ppd > coda.ppd
cupsfilter -p coda.ppd -m application/vnd.cups-postscript <file>.pdf 2>/dev/null > prova.ps
echo '/setpagedevice { dup /TSBPrivate known { /TSBPrivate get print (\n) print } { pop } ifelse } bind def' > spy.ps
gs -q -dNODISPLAY -dBATCH -dNOPAUSE -dNOSAFER spy.ps prova.ps | grep ACCESSCODEOutput atteso:
DSSC PRINT ACCESSCODE=<codice>I lavori inviati sulla porta 9100 non compaiono tra i lavori IPP della stampante. L’unico riscontro dopo la stampa è il registro stampe di TopAccess (Registri > Visualizza registri > Registro stampe): un lavoro scartato per codice non valido non viene registrato.
7. Cambiare il codice: per utente, da GUI, da WebGUI #
Per un singolo utente, salvato in ~/.cups/lpoptions. Vale per lp e viene caricato anche dalla finestra di stampa delle applicazioni GTK:
lpoptions -p <stampante> -o DeptCode=True \
-o DCDigit1=<cifra1> -o DCDigit2=<cifra2> -o DCDigit3=<cifra3> -o DCDigit4=<cifra4>Dalla finestra di stampa: scheda delle opzioni avanzate, voci Department Code e Department Code (DC) - Digit 1…5.
Dall’interfaccia web di CUPS (http://localhost:631): pagina della coda, menu Amministrazione, voce delle opzioni predefinite. Cambia il predefinito per tutti gli utenti e richiede le credenziali di amministratore.
Esempi pratici #
Codice diverso per una singola stampa, che sostituisce quello predefinito:
lp -d <stampante> -o job-account-id=<altro-codice> <file>Codice predefinito solo per il proprio utente, senza toccare la coda. Vale per lp e lpr, non per le applicazioni GTK, che continuano a usare il predefinito della coda:
lpoptions -p <stampante> -o job-account-id=<codice>Rimuovere il codice predefinito dalla coda (poi ripetere il passo 7):
sudo lpadmin -p <stampante> -R job-account-id-defaultErrori comuni #
-
lp: L'attributo """" è richiesto per i processi di stampa.PPD con la riga*cupsMandatorymalformata. Applicare il passo 5 -
CUPS segna il lavoro come completato, ma non esce nulla La stampante ha ricevuto il lavoro senza codice o con un codice non valido e l’ha scartato senza avvisare. Controllare il codice e verificare lo stato del lavoro sulla stampante come al passo 8
-
Da riga di comando stampa, dalle applicazioni grafiche no La finestra di stampa dice “Terminato” ma nel journal c’è
client-error-conflicting-attributes. Nel PPD c’è ancora*cupsMandatory: applicare il passo 7 -
Le applicazioni grafiche hanno smesso di stampare dopo una modifica alla coda
lpadminha reinserito*cupsMandatorynel PPD. Ripetere il passo 7 -
Dopo aver ricreato la coda il problema torna Il PPD viene rigenerato con lo stesso errore. Ripetere i passi 5, 6 e 7
-
Con il PPD Toshiba originale le stampe non escono Il PPD invia il codice a cinque cifre con zeri iniziali. Applicare il passo 4 della procedura alternativa
-
Non si trova il campo per il codice nella finestra di stampa Con la coda driverless nessuna finestra di stampa Linux lo chiama “codice di reparto”. Nelle applicazioni GTK c’è il campo Informazioni fatturazione nella scheda Lavoro: CUPS lo registra come
job-billinge il backend IPP lo inoltra alla stampante comejob-account-id. Funziona solo se la coda non ha un codice predefinito: se c’è, vince sempre il predefinito e il campo viene ignorato. Le finestre di stampa di LibreOffice e Chrome non hanno il campo
Note operative #
ipptoolcon l’operazioneValidate-Jobnon serve a verificare il codice: sulla e-STUDIO2525AC passa anche senzajob-account-id. Il controllo avviene solo quando la stampante elabora il lavoro- Con la coda driverless e un codice predefinito, tutte le stampe dalle applicazioni grafiche vengono addebitate allo stesso reparto:
lpoptionsper utente vale solo da riga di comando. Se servono più reparti sullo stesso host, le strade sono due: il PPD Toshiba corretto oppure una coda driverless per reparto, ognuna con il suo codice predefinito - Con la coda driverless l’interfaccia web di CUPS non permette di impostare il codice: la pagina delle opzioni predefinite mostra solo le opzioni del PPD, e
job-account-idnon lo è. Con il PPD Toshiba invece il codice è un’opzione del PPD e compare - Con la coda driverless il codice viaggia dentro la richiesta IPPS, cifrato. Con il PPD Toshiba viaggia nel PostScript sulla porta 9100, in chiaro sulla rete locale
- Con il PPD Toshiba la stampante non restituisce lo stato dei lavori e CUPS li segna come completati appena consegnati. Un codice errato porta a un lavoro scartato senza avviso
- Il PPD Toshiba sostituisce la coda driverless e non ne eredita i problemi: niente
*cupsMandatory, niente righe reinserite dalpadmin - L’errore di quoting è nel generatore di PPD driverless di
libppd2.1.1 e non è stata trovata una segnalazione pubblica. Conviene ricontrollare la riga*cupsMandatorydopo ogni aggiornamento dilibppdocups-filtersche rigeneri la coda - Lo stesso schema vale per altri attributi obbligatori: se una stampante dichiara
printer-mandatory-job-attributes, la coda locale deve riportarli correttamente e ogni lavoro deve contenerli
Riferimenti #
- Pagina di manuale di lpadmin, con le opzioni -o e -R.
- Pagina di manuale di ipptool, per interrogare stampanti IPP.
- Estensioni CUPS al formato PPD, tra cui cupsMandatory e cupsJobAccountId.
- Repository di libppd su GitHub, per segnalare il bug.
- Pagina di manuale di cupsfilter, per generare l’output di una coda senza stampare.
- Area download di Toshiba Business, da cui scaricare i driver e-STUDIO.