nx_printers_render.nx source
↩ module page · 201 lines · 9704 B
1// nx_printers_render.nx -- render the full honest printer audit as an HTML page (the standing UI law:
2// every capability gets a live UI). PURE emitter: takes a parsed IPP Get-Printer-Attributes response and
3// composes the status (nx_printer_health) + security (nx_printer_security) + waste (nx_printer_waste)
4// verdicts into a styled, self-contained HTML page. No syscalls -> never-brick. Read-only status = safe to
5// publish (controls/sensitive actions stay operator-only per the UI law).
6// genealogy_id: project-printer-management-ipp-sclass-2026-06-20 ; license_tier: ORIGINAL
7
8import "nx_ipp_codec.nx"
9import "nx_printer_health.nx"
10import "nx_printer_security.nx"
11import "nx_printer_waste.nx"
12
13func nx_pr_h(out: *u8, off: i64, s: *u8) -> i64 {
14 var o: i64 = off
15 var i: i64 = 0
16 while s[i] != (0 as u8) { out[o] = s[i]; o = o + 1; i = i + 1 }
17 return o
18}
19func nx_pr_hi(out: *u8, off: i64, v: i64) -> i64 {
20 var o: i64 = off
21 if v == 0 { out[o] = 48 as u8; return o + 1 }
22 var m: i64 = v
23 if m < 0 { out[o] = 45 as u8; o = o + 1; m = 0 - m }
24 let t: *u8 = sys_mmap(24)
25 var k: i64 = 0
26 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
27 var j: i64 = k - 1
28 while j >= 0 { out[o] = t[j]; o = o + 1; j = j - 1 }
29 return o
30}
31// copy a raw IPP string attribute value (vlen bytes) into out, or "(not reported)"
32func nx_pr_attr(out: *u8, off: i64, body: *u8, n: i64, name: *u8, sc3: *i64) -> i64 {
33 let p_tag: *i64 = sc3
34 let p_voff: *i64 = ((sc3 as i64) + 8) as *i64
35 let p_vlen: *i64 = ((sc3 as i64) + 16) as *i64
36 if nx_ipp_find(body, n, name, p_tag, p_voff, p_vlen) != NX_IPP_OK { return nx_pr_h(out, off, "(not reported)") }
37 var o: i64 = off
38 var i: i64 = 0
39 while i < p_vlen[0] { out[o] = body[p_voff[0] + i]; o = o + 1; i = i + 1 }
40 return o
41}
42
43func nx_pr_canprint(v: i64) -> *u8 {
44 if v == NX_PR_CAN_PRINT { return "READY" as *u8 }
45 if v == NX_PR_DEGRADED { return "DEGRADED" as *u8 }
46 if v == NX_PR_BLOCKED { return "BLOCKED" as *u8 }
47 return "UNKNOWN" as *u8
48}
49func nx_pr_canclass(v: i64) -> *u8 {
50 if v == NX_PR_CAN_PRINT { return "ok" as *u8 }
51 if v == NX_PR_DEGRADED { return "warn" as *u8 }
52 return "bad" as *u8
53}
54func nx_pr_secname(v: i64) -> *u8 {
55 if v == NX_PSEC_SECURE { return "SECURE" as *u8 }
56 if v == NX_PSEC_WEAK { return "WEAK" as *u8 }
57 if v == NX_PSEC_EXPOSED { return "EXPOSED" as *u8 }
58 return "UNKNOWN" as *u8
59}
60func nx_pr_sevname(s: i64) -> *u8 {
61 if s == NX_SEV_ERROR { return "ERROR" as *u8 }
62 if s == NX_SEV_WARNING { return "WARNING" as *u8 }
63 if s == NX_SEV_REPORT { return "report" as *u8 }
64 return "none" as *u8
65}
66
67// emit each printer-state-reasons value as an <li> with its severity (the bit the vendor UI hides)
68func nx_pr_reasons(out: *u8, off: i64, body: *u8, n: i64, pstate: i64) -> i64 {
69 var o: i64 = off
70 if n < 8 { return o }
71 var p: i64 = 8
72 var in_reasons: i64 = 0
73 var keep: i64 = 1
74 while keep == 1 {
75 if p >= n { keep = 0 }
76 else {
77 let tag: i64 = body[p] as i64
78 if tag == NX_IPP_TAG_END { keep = 0 }
79 else {
80 if tag <= 0x0f { p = p + 1; in_reasons = 0 }
81 else {
82 if (p + 3) > n { keep = 0 }
83 else {
84 let nlen: i64 = nx_ipp_get_u16(body, p + 1)
85 let name_off: i64 = p + 3
86 if (name_off + nlen + 2) > n { keep = 0 }
87 else {
88 let vlen_off: i64 = name_off + nlen
89 let vlen: i64 = nx_ipp_get_u16(body, vlen_off)
90 let val_off: i64 = vlen_off + 2
91 if (val_off + vlen) > n { keep = 0 }
92 else {
93 if nlen > 0 {
94 if nx_ipp_name_eq(body, name_off, "printer-state-reasons", 21) == 1 { in_reasons = 1 }
95 else { in_reasons = 0 }
96 }
97 if in_reasons == 1 {
98 let sev: i64 = nx_ph_reason_severity(body, val_off, vlen, pstate)
99 o = nx_pr_h(out, o, "<li><code>")
100 var i: i64 = 0
101 while i < vlen { out[o] = body[val_off + i]; o = o + 1; i = i + 1 }
102 o = nx_pr_h(out, o, "</code> <span class=sev>")
103 o = nx_pr_h(out, o, nx_pr_sevname(sev))
104 o = nx_pr_h(out, o, "</span></li>")
105 }
106 p = val_off + vlen
107 }
108 }
109 }
110 }
111 }
112 }
113 }
114 return o
115}
116
117// Render the whole page. scratch = caller i64[8]. toner_bp = real toner remaining in basis points (or -1
118// if not tracked yet); toner_pages = std-pages left. Returns HTML length.
119func nx_printers_render(out: *u8, body: *u8, n: i64, scratch: *i64, toner_bp: i64, toner_pages: i64) -> i64 {
120 let o_state: *i64 = scratch
121 let o_sev: *i64 = ((scratch as i64) + 8) as *i64
122 let o_cnt: *i64 = ((scratch as i64) + 16) as *i64
123 let o_acc: *i64 = ((scratch as i64) + 24) as *i64
124 let sc3: *i64 = ((scratch as i64) + 32) as *i64 // 3 cells for find
125 let verdict: i64 = nx_printer_diagnose(body, n, sc3, o_state, o_sev, o_cnt, o_acc)
126 let secfl: *i64 = ((scratch as i64) + 56) as *i64
127 let secv: i64 = nx_printer_security(body, n, sc3, secfl)
128 let w_cnt: *i64 = ((scratch as i64) + 64) as *i64
129 let w_pct: *i64 = ((scratch as i64) + 72) as *i64
130 let w_dup: *i64 = ((scratch as i64) + 80) as *i64
131 let w_sc: *i64 = ((scratch as i64) + 88) as *i64 // 4 cells
132 let supv: i64 = nx_printer_waste(body, n, w_sc, w_cnt, w_pct, w_dup)
133
134 var o: i64 = 0
135 o = nx_pr_h(out, o, "<!DOCTYPE html><html><head><meta charset=utf-8><title>Nishi Printer Status</title><style>")
136 o = nx_pr_h(out, o, "body{font:15px/1.5 system-ui,sans-serif;max-width:760px;margin:2rem auto;padding:0 1rem;color:#1a1a1a}")
137 o = nx_pr_h(out, o, "h1{font-size:1.4rem}.card{border:1px solid #ddd;border-radius:10px;padding:1rem 1.2rem;margin:1rem 0}")
138 o = nx_pr_h(out, o, ".ok{color:#137333}.warn{color:#b06000}.bad{color:#c5221f;font-weight:600}")
139 o = nx_pr_h(out, o, ".big{font-size:1.2rem;font-weight:600}.sev{font-size:.8rem;color:#666}code{background:#f3f3f3;padding:1px 4px;border-radius:4px}")
140 o = nx_pr_h(out, o, "</style></head><body><h1>\xF0\x9F\x96\xA8\xEF\xB8\x8F Nishi Printer Status</h1>")
141 o = nx_pr_h(out, o, "<p>Sovereign IPP audit — the truth your vendor UI hides. Read-only.</p>")
142
143 // identity
144 o = nx_pr_h(out, o, "<div class=card><b>")
145 o = nx_pr_attr(out, o, body, n, "printer-make-and-model", sc3)
146 o = nx_pr_h(out, o, "</b></div>")
147
148 // can-print
149 o = nx_pr_h(out, o, "<div class=card><div class=big><span class=")
150 o = nx_pr_h(out, o, nx_pr_canclass(verdict))
151 o = nx_pr_h(out, o, ">Can print now: ")
152 o = nx_pr_h(out, o, nx_pr_canprint(verdict))
153 o = nx_pr_h(out, o, "</span></div><ul>")
154 o = nx_pr_reasons(out, o, body, n, o_state[0])
155 o = nx_pr_h(out, o, "</ul></div>")
156
157 // security
158 o = nx_pr_h(out, o, "<div class=card><b>Security:</b> <span class=")
159 var seccls: *u8 = "ok"
160 if secv == NX_PSEC_EXPOSED { seccls = "bad" }
161 if secv == NX_PSEC_WEAK { seccls = "warn" }
162 o = nx_pr_h(out, o, seccls)
163 o = nx_pr_h(out, o, ">")
164 o = nx_pr_h(out, o, nx_pr_secname(secv))
165 o = nx_pr_h(out, o, "</span>")
166 if secv == NX_PSEC_EXPOSED {
167 o = nx_pr_h(out, o, "<p class=bad>Wide open: anyone on this network can read your documents and submit jobs (same class as CUPS CVE-2024-47176).</p>")
168 }
169 o = nx_pr_h(out, o, "</div>")
170
171 // supplies & waste
172 o = nx_pr_h(out, o, "<div class=card><b>Supplies & waste</b><br>Lowest supply: ")
173 if w_pct[0] < 0 { o = nx_pr_h(out, o, "unknown") }
174 else { o = nx_pr_hi(out, o, w_pct[0]); o = nx_pr_h(out, o, "%") }
175 if supv == NX_SUP_EMPTY { o = nx_pr_h(out, o, " <span class=bad>(EMPTY)</span>") }
176 if supv == NX_SUP_LOW { o = nx_pr_h(out, o, " <span class=warn>(LOW)</span>") }
177 if w_dup[0] == NX_DUP_WASTE {
178 o = nx_pr_h(out, o, "<br><span class=warn>Paper waste: duplex supported but defaults to one-sided.</span> Fix: print two-sided to halve paper.")
179 }
180 o = nx_pr_h(out, o, "</div>")
181
182 // real toner (measured by ink coverage -- the printer's gauge ignored)
183 o = nx_pr_h(out, o, "<div class=card><b>Real toner</b> <span class=sev>(measured by ink coverage, not the printer)</span><br>")
184 if toner_bp < 0 {
185 o = nx_pr_h(out, o, "not yet tracked — prints calibrate it")
186 } else {
187 o = nx_pr_h(out, o, "<span class=big class=ok>")
188 o = nx_pr_hi(out, o, toner_bp / 100)
189 o = nx_pr_h(out, o, ".")
190 let f: i64 = toner_bp % 100
191 if f < 10 { o = nx_pr_h(out, o, "0") }
192 o = nx_pr_hi(out, o, f)
193 o = nx_pr_h(out, o, "%</span> — ~")
194 o = nx_pr_hi(out, o, toner_pages)
195 o = nx_pr_h(out, o, " pages left<br><span class=warn>Printer claims 0% / Replace Toner — ignored.</span>")
196 }
197 o = nx_pr_h(out, o, "</div>")
198 o = nx_pr_h(out, o, "<p style=color:#999;font-size:.8rem>Generated by sovereign Nishi organs (nx_ipp_codec/health/security/waste/toner). No vendor driver, no cloud.</p>")
199 o = nx_pr_h(out, o, "</body></html>")
200 return o
201}