code wiki / (root) / nx_smtp_server.nx

nx_smtp_server.nx

buildroot/runtime/nx_smtp_server.nx

12606 B277 linesdepth 0pulls 0 transitivereach 1 importersview sourcekind librarytopic smtp
docsdependenciesstructsconstsfunctions

about

nx_smtp_server.nx -- EMAIL RUNG R2: SMTP server receive grammar (RFC 5321 server side). module: nishi-core.email.smtp_server depends: (none -- pure RFC 5321 command parser + reply builders + un-dot-stuff + sequence machine) capability: CORE_EMAIL The MIRROR of nx_smtp_client (R1): the conversation grammar a MAIL SERVER speaks to a connecting client, ABOVE the nx_socket TCP rung. Pure (no syscalls -- live socket I/O composes in a later nx_smtp_server_io.nx, mirroring the nx_smtp_client / nx_dns split) so the whole receive protocol is deterministically gateable offline against a scripted CLIENT transcript: 1. COMMAND PARSER -- classify a client command line (EHLO/HELO/MAIL/RCPT/ DATA/QUIT/RSET/NOOP/VRFY) case-insensitively, requiring a delimiter after the 4-char verb (so "MAILBOX" never matches "MAIL"), and extract the <addr> span for MAIL/RCPT and the domain span for EHLO/HELO. 2. REPLY BUILDERS -- 3-digit reply + text, CRLF framed (220 greeting, 250 ok, 354 start-data, 221 bye, 500 syntax, 501 bad-args, 503 bad- sequence, 550 no-such-user). Exact bytes for protocol conformance. 3. UN-DOT-STUFF + DATA TERMINATOR (RFC 5321 4.5.2) -- the receive crux / SECURITY: reverse the client's leading-dot stuffing AND detect the lone "<CRLF>.<CRLF>" end-of-DATA, such that a STUFFED ".." line can never be mistaken for the terminator (premature-termination / truncation / SMTP-smuggling defense -- the exact inverse of nx_smtp_dot_stuff). 4. SEQUENCE STATE MACHINE -- enforce RFC 5321 command ordering: MAIL only from the greeted/idle state; RCPT only after MAIL; DATA only after >=1 RCPT. Any out-of-sequence verb -> 503 with the state LEFT UNCHANGED (no envelope is ever accepted without sender+recipient). A completed DATA body resets to the greeted state (ready for the next transaction). license_tier: INDEPENDENT_REDERIVE genealogy_id: international-research-sources/ietf/rfc_5321 lineage_id: nishi_email_smtp_server_r2 nx_safety_envelope: intended_use: "SMTP server command parse + reply build + un-dot- stuff/terminator + receive-sequence state machine.

dependencies 0 imports · 1 importers

nx_smtp_server.nx nx_smtp_server_gate.nx

imports: none

imported by: nx_smtp_server_gate.nx

structs

none

consts

55const NX_SMTPS_BAD_LINE: i64 = 2 // command line empty / no verb
56const NX_SMTPS_BAD_ADDR: i64 = 3 // MAIL/RCPT missing <...> address
57const NX_SMTPS_BUF_FULL: i64 = 4 // builder ran out of caller buffer
58const NX_SMTPS_N: i64 = 5
61const SV_EHLO: i64 = 0
62const SV_HELO: i64 = 1
63const SV_MAIL: i64 = 2
64const SV_RCPT: i64 = 3
65const SV_DATA: i64 = 4
66const SV_QUIT: i64 = 5
67const SV_RSET: i64 = 6
68const SV_NOOP: i64 = 7
69const SV_VRFY: i64 = 8
70const SV_UNKNOWN: i64 = 9
73const SS_INIT: i64 = 0 // 220 greeting sent; awaiting EHLO/HELO
74const SS_GREETED: i64 = 1 // EHLO ok; transaction idle; awaiting MAIL FROM
75const SS_MAIL: i64 = 2 // MAIL FROM accepted; awaiting RCPT TO
76const SS_RCPT: i64 = 3 // >=1 RCPT accepted; awaiting more RCPT or DATA
77const SS_DATA: i64 = 4 // DATA accepted (354 sent); reading the body
78const SS_QUIT: i64 = 5 // QUIT seen; 221 sent; conversation closed

functions

80func nx_smtp_srv_verb_name(v: i64) -> *u8
94func ss_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
95func ss_cat(out: *u8, oi: i64, s: *u8) -> i64 { var k: i64 = 0; while s[k] != (0 as u8) { out[oi] = s[k]; oi = oi + 1; k = k + 1 } return oi }
called by 1: nx_smtp_srv_reply
96func ss_upper(c: i64) -> i64 { if c >= 97 { if c <= 122 { return c - 32 } } return c }
called by 1: ss_kw_ci
97func ss_is_delim(c: i64) -> i64 { if c == 32 { return 1 } if c == 13 { return 1 } if c == 10 { return 1 } return 0 }
called by 1: ss_verb_is
100func ss_kw_ci(buf: *u8, off: i64, len: i64, lit: *u8, litlen: i64) -> i64
called by 1: ss_verb_is calls 1: ss_upper
112func ss_verb_is(buf: *u8, len: i64, lit: *u8) -> i64
121func ss_span_after_sp(buf: *u8, start: i64, len: i64, out_off: *i64, out_len: *i64) -> i64
called by 1: nx_smtp_srv_parse
139func ss_addr_angle(buf: *u8, start: i64, len: i64, out_off: *i64, out_len: *i64) -> i64
called by 1: nx_smtp_srv_parse
164func nx_smtp_srv_parse(buf: *u8, len: i64, out_aoff: *i64, out_alen: *i64) -> i64
181func nx_smtp_srv_reply(out: *u8, cap: i64, code: i64, text: *u8) -> i64
called by 1: main calls 1: ss_cat
207func nx_smtp_srv_undot(recv: *u8, n: i64, out: *u8, cap: i64, out_complete: *i64) -> i64
called by 1: main
247func nx_smtp_srv_advance(state: i64, verb: i64, out_code: *i64) -> i64
called by 1: main
277func nx_smtp_srv_data_complete(out_code: *i64) -> i64 { *out_code = 250; return SS_GREETED }
called by 1: main