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}