# kydriv — Kyocera 3505ci Treiber für Apple Silicon ## Kontext Der Kyocera/TA 3505ci Multifunktionsdrucker erfordert zur Nutzung einen Abteilungscode (Kostenstelle). Der bisherige Intel-Mac-Treiber bot dafür ein Textfeld im Druckdialog. Der aktuelle Apple-Silicon-Treiber von Kyocera hat diese Funktion nicht. Dieses Projekt entwickelt einen Ersatztreiber für macOS auf Apple Silicon, der die fehlenden Funktionen — insbesondere die Kostenstelle — wiederherstellt. ## Ursachenanalyse Der alte Intel-Treiber bestand aus drei Schichten: 1. **APDialogExtension-Plugins** (`.plugin`-Bundles) — Objective-C/Cocoa-Panels im Druckdialog. Intel-only, von Apple deprecated. Zuständig für die UI (Textfelder, Checkboxen). 2. **CUPS-Filter** (`kyoprefilter_E`, `kyofilter_E`) — kompilierte Intel-Binaries. Zuständig für PostScript-Verarbeitung und Einschleusen von Gerätebefehlen. 3. **PPD-Datei** — Textdatei, architekturunabhängig. Auf Apple Silicon fehlen die Punkte 1 und 2. Der neue Kyocera-Treiber hat nur eine abgespeckte PPD ohne die Plugin-Mechanismen. ## Lösungsansatz **PPD + Python CUPS-Filter**, verteilt als signiertes `.pkg`. - Die APDialogExtension-Plugins werden nicht ersetzt (deprecated API). Stattdessen werden Kostenstellen als benannte Optionen in der PPD geführt und per Preset gespeichert. - Die Intel-Filter werden durch ein Python-Script ersetzt, das architekturunabhängig ist. - Der Kyocera-Treiber wird vollständig umgangen — die Lösung ist eigenständig. ## Komponenten ``` kydriv/ ├── ppd/ │ └── TA3505ci_AS.ppd # modifizierte PPD ├── filter/ │ └── kyofilter # Python CUPS-Filter ├── installer/ │ ├── root/ # Dateisystem-Abbild für pkgbuild │ │ ├── Library/Printers/PPDs/Contents/Resources/TA3505ci_AS.ppd │ │ └── usr/libexec/cups/filter/kyofilter │ ├── scripts/ │ │ └── postinstall │ └── build.sh └── docs/superpowers/specs/ ``` **Datenfluss:** ``` macOS App (PDF) → CUPS pdftops → PostScript → kyofilter (Python) → Drucker ``` ## PPD-Datei (`TA3505ci_AS.ppd`) Basis: `TA3505ci.PPD` (Intel-Treiber, Version 8.6006). **Entfernt:** - Alle 11 `*APDialogExtension:`-Zeilen - `*cupsPreFilter: "application/pdf 0 kyoprefilter_E"` **Geändert:** ```diff - *cupsFilter: "application/vnd.cups-postscript 0 kyofilter_E" + *cupsFilter: "application/vnd.cups-postscript 0 kyofilter" ``` **KmManagment-Sektion** (ersetzt die alte Liste 00000000–00000030): ```ppd *% Kostenstelle (5-stellig) direkt eintragen — keine führenden Nullen nötig. *% Zeile kopieren und Zahl ersetzen: *% *KmManagment MG12345/Code 12345: "" *OpenUI *KmManagment/Job Accounting: PickOne *DefaultKmManagment: Default *OrderDependency: 60 AnySetup *KmManagment *KmManagment Default/Aus: "" *KmManagment MG12345/Code 12345: "" *?KmManagment: "" *End *CloseUI: *KmManagment ``` Der PPD-Wert bleibt leer (`""`), da der Filter die PostScript-Injection übernimmt. **Unverändert:** alle anderen Optionen — InputSlot, PageSize, KCStaple, OutputBin, Duplex, Farbe etc. ## Python CUPS-Filter (`kyofilter`) **Installationspfad:** `/usr/libexec/cups/filter/kyofilter` **Rechte:** 755, root:wheel **Interpreter:** `/usr/bin/python3` (macOS vorinstalliert) **CUPS-Schnittstelle:** ``` kyofilter <copies> <options> [filename] ``` - Eingabe: PostScript (stdin oder Datei) - Ausgabe: PostScript (stdout) - Logs: stderr → CUPS error_log **Logik:** 1. `argv[5]` parsen → Key=Value-Dict 2. `KmManagment`-Wert lesen 3. Startet mit `MG` und ist numerisch → Code extrahieren, auf 8 Stellen zero-padden 4. Sonst → reiner Passthrough 5. PostScript-Stream zeilenweise lesen: - Vor `%%EndSetup`: `(XXXXXXXX) statusdict /setmanagementnumber get exec` injizieren - Alle anderen Zeilen unverändert weiterleiten 6. Fallback: falls kein `%%EndSetup` gefunden → vor erstem `%%Page:` injizieren, Warning ins Log **Beispiel:** Kostenstelle `12345` → `(00012345) statusdict /setmanagementnumber get exec` ## Installer (`.pkg`) **Gebaut mit:** `pkgbuild` + Developer ID Installer Zertifikat **Bundle-ID:** `de.kydriv.driver` ```bash pkgbuild \ --root installer/root \ --scripts installer/scripts \ --identifier "de.kydriv.driver" \ --version "1.0.0" \ --sign "Developer ID Installer: NAME (TEAM-ID)" \ kydriv-driver-1.0.0.pkg ``` **postinstall-Script:** ```bash #!/bin/bash chmod 755 /usr/libexec/cups/filter/kyofilter chown root:wheel /usr/libexec/cups/filter/kyofilter launchctl kickstart -k system/org.cups.cupsd ``` **Notarisierung** (einmalig pro Release): ```bash xcrun notarytool submit kydriv-driver-1.0.0.pkg \ --apple-id EMAIL --team-id TEAM-ID --password APP-PASSWORT --wait xcrun stapler staple kydriv-driver-1.0.0.pkg ``` Notarisierte `.pkg`-Dateien bleiben dauerhaft gültig, auch nach Ablauf des Entwicklerzertifikats. ## Benutzer-Workflow nach Installation 1. Kostenstelle in PPD eintragen (einmalig, Texteditor) 2. `.pkg` installieren 3. Drucker in Systemeinstellungen hinzufügen → `TA3505ci_AS.ppd` auswählen 4. Druckdialog → Job Accounting → eigene Kostenstelle wählen 5. Preset speichern 6. Ab sofort: Preset auswählen → drucken ## Testing | Stufe | Methode | Erfolgskriterium | |-------|---------|-----------------| | 1 | Filter mit Beispiel-PS über stdin aufrufen | Injection vor `%%EndSetup` im Output | | 2 | `cupstestppd ppd/TA3505ci_AS.ppd` | Ausgabe: PASS | | 3 | Manuelle Installation, Testseite drucken | Seite kommt raus | | 4 | CUPS-Log + Kyocera-Webinterface Job-Log | Kostenstelle korrekt erfasst | | 5 | `.pkg` auf frischem System installieren | End-to-End-Workflow funktioniert | ## Offene Fragen / Nächste Schritte - Genaue Kostenstellen-Codes für die PPD erfragen und eintragen - Verifizieren, dass `setmanagementnumber` auf dem 3505ci die Kostenstelle korrekt bucht (Stufe 4) - Ggf. weitere Kyocera-spezifische PPD-Optionen aus dem alten Treiber übernehmen