code wiki / _hdl_build / nx_email_retrieve_gate.nx
nx_email_retrieve_gate.nx source
↩ module page · 130 lines · 6360 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"
19
20const RET_LOG: *u8 = "knowledge/status/email_retrieve.log"
21
22func 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 }
23func ewn(fd: i64, v: i64) -> i64 {
24 let b: *u8 = sys_mmap(28); var m: i64 = v
25 if m < 0 { m = 0 - m; sys_write(fd, "-" as *u8, 1) }
26 let t: *u8 = sys_mmap(28); var k: i64 = 0
27 if m == 0 { t[0] = 48; k = 1 }
28 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
29 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 }
30 sys_write(fd, b, k); return 0
31}
32func 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 }
33func slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
34func 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 }
35
36func main() -> i64 {
37 var ok: i64 = 1
38 let out: *u8 = sys_mmap(1024)
39 let oc: *i64 = sys_mmap(8) as *i64
40 let oo: *i64 = sys_mmap(8) as *i64
41 let st: *i64 = sys_mmap(8) as *i64
42 let lit: *i64 = sys_mmap(8) as *i64
43
44 // ---- POP3 status ----
45 var pop_ok: i64 = 0
46 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 }
47 var pop_err: i64 = 0
48 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 }
49 var pop_garbage: i64 = 0
50 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 }
51
52 // ---- POP3 STAT ----
53 var pop_stat: i64 = 0
54 if nx_pop3_parse_stat("+OK 2 320\r\n" as *u8, slen("+OK 2 320\r\n" as *u8), oc, oo) == 1 {
55 if *oc == 2 && *oo == 320 { pop_stat = 1 }
56 }
57 if pop_stat != 1 { ok = 0 }
58
59 // ---- POP3 build ----
60 let bl: i64 = nx_pop3_build(out, 1024, "RETR" as *u8, "1" as *u8, 1)
61 var pop_build: i64 = 0
62 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 }
63 let bl2: i64 = nx_pop3_build(out, 1024, "STAT" as *u8, "" as *u8, 0)
64 if memeq(out, "STAT\r\n" as *u8, bl2) != 1 { ok = 0 }
65
66 // ---- POP3 de-dot-stuff ----
67 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)
68 var pop_dedot: i64 = 0
69 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 }
70
71 // ---- POP3 multi-line completeness ----
72 var pop_complete: i64 = 0
73 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
74 && nx_pop3_multiline_complete("partial\r\n" as *u8, slen("partial\r\n" as *u8)) == 0 { pop_complete = 1 } else { ok = 0 }
75
76 // ---- IMAP build ----
77 let il: i64 = nx_imap_build_tagged(out, 1024, "A001" as *u8, 4, "LOGIN user pass" as *u8, 15)
78 var imap_build: i64 = 0
79 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 }
80
81 // ---- IMAP tagged status, skipping untagged "* OK" ----
82 let resp: *u8 = "* 2 EXISTS\r\n* OK [UIDVALIDITY 1]\r\nA001 OK LOGIN completed\r\n" as *u8
83 var imap_ok: i64 = 0
84 if nx_imap_reply_status(resp, slen(resp), "A001" as *u8, 4, st) == 1 {
85 if *st == 0 { imap_ok = 1 }
86 }
87 if imap_ok != 1 { ok = 0 }
88 // untagged-only -> incomplete
89 var imap_incomplete: i64 = 0
90 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 }
91 // NO status
92 var imap_no: i64 = 0
93 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 {
94 if *st == 1 { imap_no = 1 }
95 }
96 if imap_no != 1 { ok = 0 }
97
98 // ---- IMAP literal size ----
99 var imap_lit: i64 = 0
100 if nx_imap_literal_size("* 1 FETCH (BODY[] {42}\r\n" as *u8, slen("* 1 FETCH (BODY[] {42}\r\n" as *u8), lit) == 1 {
101 if *lit == 42 { imap_lit = 1 }
102 }
103 if imap_lit != 1 { ok = 0 }
104
105 var fd: i64 = 1
106 while fd >= 1 {
107 ew(fd, "RETRIEVEGATE authored=organ rfc=1939+3501 " as *u8)
108 epf(fd, "pop3_ok=" as *u8, pop_ok)
109 epf(fd, " pop3_err=" as *u8, pop_err)
110 epf(fd, " pop3_garbage_negctrl=" as *u8, pop_garbage)
111 epf(fd, " pop3_stat=" as *u8, pop_stat)
112 epf(fd, " pop3_build=" as *u8, pop_build)
113 epf(fd, " pop3_dedot=" as *u8, pop_dedot)
114 epf(fd, " pop3_complete=" as *u8, pop_complete)
115 epf(fd, " imap_build=" as *u8, imap_build)
116 epf(fd, " imap_status_ok=" as *u8, imap_ok)
117 epf(fd, " imap_untagged_skip_incomplete=" as *u8, imap_incomplete)
118 epf(fd, " imap_status_no=" as *u8, imap_no)
119 ew(fd, " imap_literal=" as *u8); ewn(fd, *lit)
120 epf(fd, " imap_literal_ok=" as *u8, imap_lit)
121 if ok == 1 { ew(fd, " verdict=GREEN\n" as *u8) } else { ew(fd, " verdict=RED\n" as *u8) }
122 if fd == 1 {
123 let lf: i64 = sys_openat_append(RET_LOG, 420)
124 if lf >= 1 { fd = lf } else { fd = 0 }
125 } else { sys_close(fd); fd = 0 }
126 }
127
128 if ok == 1 { return 0 }
129 return 1
130}