code wiki / _hdl_build / nx_email_retrieve_gate.nx
nx_email_retrieve_gate.nx source
↩ module page · 138 lines · 6900 B
1// nx_email_retrieve_gate.nx -- GATE for EMAIL R4 (POP3/IMAP, nx_email_retrieve).
2//
3// COMPLETENESS : POP3 +OK/-ERR status, STAT count/octets, command
4// build, multi-line de-dot-stuffing + terminator; IMAP
5// tagged command build, tagged completion status,
6// literal "{n}" size.
7// NEG-CONTROL : a non-status POP3 line -> -1; an IMAP response with
8// only untagged data -> incomplete (0).
9// TAMPER : IMAP status scan SKIPS untagged "* OK [...]" lines and
10// returns the real tagged "A001 OK" (untagged-confusion
11// defense); POP3 de-dot turns "..x" into ".x" and stops
12// exactly at the lone "." terminator.
13//
14// Evidence -> knowledge/status/email_retrieve.log
15// (RETRIEVEGATE authored=organ ... verdict=GREEN)
16// license_tier: ORIGINAL
17import "nx_email_retrieve.nx"
18import "nx_syscalls.nx"
19import "nx_gate_verdict.nx"
20
21const RET_LOG: *u8 = "knowledge/status/email_retrieve.log"
22
23func ew(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
24func ewn(fd: i64, v: i64) -> i64 {
25 let b: *u8 = sys_mmap(28); var m: i64 = v
26 if m < 0 { m = 0 - m; sys_write(fd, "-" as *u8, 1) }
27 let t: *u8 = sys_mmap(28); var k: i64 = 0
28 if m == 0 { t[0] = 48; k = 1 }
29 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
30 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 }
31 sys_write(fd, b, k); return 0
32}
33func epf(fd: i64, label: *u8, pass: i64) -> i64 { ew(fd, label); if pass == 1 { ew(fd, "PASS" as *u8) } else { ew(fd, "FAIL" as *u8) } return 0 }
34func slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
35func memeq(a: *u8, b: *u8, len: i64) -> i64 { var i: i64 = 0; while i < len { if a[i] != b[i] { return 0 } i = i + 1 } return 1 }
36
37func main() -> i64 {
38 var ok: i64 = 1
39 let out: *u8 = sys_mmap(1024)
40 let oc: *i64 = sys_mmap(8) as *i64
41 let oo: *i64 = sys_mmap(8) as *i64
42 let st: *i64 = sys_mmap(8) as *i64
43 let lit: *i64 = sys_mmap(8) as *i64
44
45 // ---- POP3 status ----
46 var pop_ok: i64 = 0
47 if nx_pop3_reply_ok("+OK 5 messages\r\n" as *u8, slen("+OK 5 messages\r\n" as *u8)) == 1 { pop_ok = 1 } else { ok = 0 }
48 var pop_err: i64 = 0
49 if nx_pop3_reply_ok("-ERR no such\r\n" as *u8, slen("-ERR no such\r\n" as *u8)) == 0 { pop_err = 1 } else { ok = 0 }
50 var pop_garbage: i64 = 0
51 if nx_pop3_reply_ok("garbage line\r\n" as *u8, slen("garbage line\r\n" as *u8)) == (0 - 1) { pop_garbage = 1 } else { ok = 0 }
52
53 // ---- POP3 STAT ----
54 var pop_stat: i64 = 0
55 if nx_pop3_parse_stat("+OK 2 320\r\n" as *u8, slen("+OK 2 320\r\n" as *u8), oc, oo) == 1 {
56 if *oc == 2 && *oo == 320 { pop_stat = 1 }
57 }
58 if pop_stat != 1 { ok = 0 }
59
60 // ---- POP3 build ----
61 let bl: i64 = nx_pop3_build(out, 1024, "RETR" as *u8, "1" as *u8, 1)
62 var pop_build: i64 = 0
63 if bl == slen("RETR 1\r\n" as *u8) && memeq(out, "RETR 1\r\n" as *u8, bl) == 1 { pop_build = 1 } else { ok = 0 }
64 let bl2: i64 = nx_pop3_build(out, 1024, "STAT" as *u8, "" as *u8, 0)
65 if memeq(out, "STAT\r\n" as *u8, bl2) != 1 { ok = 0 }
66
67 // ---- POP3 de-dot-stuff ----
68 let dd: i64 = nx_pop3_dedot("Hello\r\n..stuffed\r\n.\r\n" as *u8, slen("Hello\r\n..stuffed\r\n.\r\n" as *u8), out, 1024)
69 var pop_dedot: i64 = 0
70 if dd == slen("Hello\r\n.stuffed\r\n" as *u8) && memeq(out, "Hello\r\n.stuffed\r\n" as *u8, dd) == 1 { pop_dedot = 1 } else { ok = 0 }
71
72 // ---- POP3 multi-line completeness ----
73 var pop_complete: i64 = 0
74 if nx_pop3_multiline_complete("line1\r\nline2\r\n.\r\n" as *u8, slen("line1\r\nline2\r\n.\r\n" as *u8)) == 1
75 && nx_pop3_multiline_complete("partial\r\n" as *u8, slen("partial\r\n" as *u8)) == 0 { pop_complete = 1 } else { ok = 0 }
76
77 // ---- IMAP build ----
78 let il: i64 = nx_imap_build_tagged(out, 1024, "A001" as *u8, 4, "LOGIN user pass" as *u8, 15)
79 var imap_build: i64 = 0
80 if memeq(out, "A001 LOGIN user pass\r\n" as *u8, il) == 1 && il == slen("A001 LOGIN user pass\r\n" as *u8) { imap_build = 1 } else { ok = 0 }
81
82 // ---- IMAP tagged status, skipping untagged "* OK" ----
83 let resp: *u8 = "* 2 EXISTS\r\n* OK [UIDVALIDITY 1]\r\nA001 OK LOGIN completed\r\n" as *u8
84 var imap_ok: i64 = 0
85 if nx_imap_reply_status(resp, slen(resp), "A001" as *u8, 4, st) == 1 {
86 if *st == 0 { imap_ok = 1 }
87 }
88 if imap_ok != 1 { ok = 0 }
89 // untagged-only -> incomplete
90 var imap_incomplete: i64 = 0
91 if nx_imap_reply_status("* 2 EXISTS\r\n" as *u8, slen("* 2 EXISTS\r\n" as *u8), "A001" as *u8, 4, st) == 0 { imap_incomplete = 1 } else { ok = 0 }
92 // NO status
93 var imap_no: i64 = 0
94 if nx_imap_reply_status("A002 NO [AUTHENTICATIONFAILED] bad\r\n" as *u8, slen("A002 NO [AUTHENTICATIONFAILED] bad\r\n" as *u8), "A002" as *u8, 4, st) == 1 {
95 if *st == 1 { imap_no = 1 }
96 }
97 if imap_no != 1 { ok = 0 }
98
99 // ---- IMAP literal size ----
100 var imap_lit: i64 = 0
101 if nx_imap_literal_size("* 1 FETCH (BODY[] {42}\r\n" as *u8, slen("* 1 FETCH (BODY[] {42}\r\n" as *u8), lit) == 1 {
102 if *lit == 42 { imap_lit = 1 }
103 }
104 if imap_lit != 1 { ok = 0 }
105
106 var fd: i64 = 1
107 while fd >= 1 {
108 ew(fd, "RETRIEVEGATE authored=organ rfc=1939+3501 " as *u8)
109 epf(fd, "pop3_ok=" as *u8, pop_ok)
110 epf(fd, " pop3_err=" as *u8, pop_err)
111 epf(fd, " pop3_garbage_negctrl=" as *u8, pop_garbage)
112 epf(fd, " pop3_stat=" as *u8, pop_stat)
113 epf(fd, " pop3_build=" as *u8, pop_build)
114 epf(fd, " pop3_dedot=" as *u8, pop_dedot)
115 epf(fd, " pop3_complete=" as *u8, pop_complete)
116 epf(fd, " imap_build=" as *u8, imap_build)
117 epf(fd, " imap_status_ok=" as *u8, imap_ok)
118 epf(fd, " imap_untagged_skip_incomplete=" as *u8, imap_incomplete)
119 epf(fd, " imap_status_no=" as *u8, imap_no)
120 ew(fd, " imap_literal=" as *u8); ewn(fd, *lit)
121 epf(fd, " imap_literal_ok=" as *u8, imap_lit)
122 if ok == 1 { ew(fd, " verdict=GREEN\n" as *u8) } else { ew(fd, " verdict=RED\n" as *u8) }
123 if fd == 1 {
124 let lf: i64 = sys_openat_append(RET_LOG, 420)
125 if lf >= 1 { fd = lf } else { fd = 0 }
126 } else { sys_close(fd); fd = 0 }
127 }
128
129 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
130 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
131 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
132 let ctr__dry: *i64 = gv_ctr()
133 ctr__dry[0] = ok
134 ctr__dry[1] = 1
135 let rc__dry: i64 = gv_verdict("EMAIL-RETRIEVE-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
136 sys_exit(rc__dry)
137 return rc__dry
138}