code wiki / _hdl_build / nx_vizsla_notify.nx
nx_vizsla_notify.nx source
↩ module page · 685 lines · 25191 B
1// nx_vizsla_notify.nx -- NISHI VIZSLA OUTWARD DELIVERY (census PA18): the reminder actually REACHES you.
2// Operator 2026-07-08: "birthday and important event reminder ... engagement partner ... state of the art".
3// The reminder ENGINE (nx_vizsla_remind) computes WHAT is due; this organ DELIVERS it. Two honest channels:
4// * ON-SITE (default, fully sovereign, no consent needed -- it surfaces on YOUR first-party page):
5// `deliver` composes remind-due, and for each DUE notice NOT already delivered, appends a notification
6// record. The notification store IS the once-only delivery ledger (additive, CID plane) -- re-running
7// the same day delivers nothing new. This is "never make users do what the system can": the assistant
8// pushes the reminder to your surface without you asking.
9// * EMAIL (compose-ready): `email` composes ONE digest message of all due notices as a valid RFC5322
10// message (From/To/Subject/Date headers + body) written to a .eml -- ready for the DKIM-sign + submit
11// step (nx_email_send/nx_email_submit). The final external SMTP hop is the operator-consent boundary;
12// everything up to a submittable message is sovereign here.
13//
14// Commands:
15// deliver <notifprefix> <calprefix|-> <contacts|-> <today> <leads> [channel] compose remind-due -> on-site records
16// feed <notifprefix> [kind|-] list delivered notifications
17// email <calprefix|-> <contacts|-> <today> <leads> <from> <to> <out.eml> compose the digest email
18// Composes the BLESSED _offc/nx_vizsla_remind.elf (run from the nxc2 dir). Loud-fail: remind errors, bad dates.
19// spec: knowledge/research/2026-06-22-vizsla-sclass-roadmap.md license_tier: ORIGINAL
20import "nx_syscalls.nx"
21import "nx_canon_cid.nx"
22import "nx_seg_store.nx"
23const K_MAGIC_1970: i64 = 1970
24const K_MAGIC_146097: i64 = 146097
25const K_MAGIC_719468: i64 = 719468
26const K_MAGIC_2048: i64 = 2048
27const K_MAGIC_65536: i64 = 65536
28const K_MAGIC_1024: i64 = 1024
29const K_MAGIC_131072: i64 = 131072
30const K_MAGIC_146096: i64 = 146096
31const K_MAGIC_1460: i64 = 1460
32const K_MAGIC_36524: i64 = 36524
33
34func nt_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
35func nt_p(s: *u8) -> i64 { sys_write(1, s, nt_slen(s)); return 0 }
36
37func nt_eq(a: *u8, b: *u8) -> i64 {
38 var i: i64 = 0
39 var go: i64 = 1
40 while go == 1 {
41 if a[i] != b[i] { return 0 }
42 if a[i] == (0 as u8) { return 1 }
43 i = i + 1
44 }
45 return 0
46}
47
48func nt_dup(s: *u8) -> *u8 {
49 let n: i64 = nt_slen(s)
50 let d: *u8 = sys_mmap(n + 2)
51 var i: i64 = 0
52 while i <= n { d[i] = s[i]; i = i + 1 }
53 return d
54}
55
56func nt_atoi(s: *u8) -> i64 {
57 var v: i64 = 0
58 var i: i64 = 0
59 while s[i] != (0 as u8) {
60 let d: i64 = (s[i] as i64) - 48
61 if d >= 0 { if d <= 9 { v = v * 10 + d } }
62 i = i + 1
63 }
64 return v
65}
66
67func nt_cat(dst: *u8, off: i64, s: *u8) -> i64 {
68 var i: i64 = 0
69 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 }
70 return off + i
71}
72
73func nt_catn(dst: *u8, off: i64, v: i64) -> i64 {
74 var o: i64 = off
75 var m: i64 = v
76 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m }
77 let t: *u8 = sys_mmap(28)
78 var k: i64 = 0
79 if m == 0 { t[0] = 48 as u8; k = 1 }
80 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
81 var i: i64 = 0
82 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 }
83 return o + k
84}
85
86func nt_kmemeq(b: *u8, off: i64, n: i64, s: *u8) -> i64 {
87 if nt_slen(s) != n { return 0 }
88 var i: i64 = 0
89 while i < n {
90 if b[off + i] != s[i] { return 0 }
91 i = i + 1
92 }
93 return 1
94}
95
96func nt_field(rec: *u8, rl: i64, want: *u8, out: *u8, cap: i64) -> i64 {
97 if rl < 8 { return 0 }
98 let nf: i64 = ss_r32(rec, 4)
99 var off: i64 = 8
100 var fi: i64 = 0
101 while fi < nf {
102 if off + 8 > rl { return 0 }
103 let kl: i64 = ss_r32(rec, off)
104 let koff: i64 = off + 4
105 let vl: i64 = ss_r32(rec, koff + kl)
106 let voff: i64 = koff + kl + 4
107 if nt_kmemeq(rec, koff, kl, want) == 1 {
108 var t: i64 = 0
109 while t < vl {
110 if t < cap - 1 { out[t] = rec[voff + t] }
111 t = t + 1
112 }
113 if t > cap - 1 { t = cap - 1 }
114 out[t] = 0 as u8
115 return 1
116 }
117 off = voff + vl
118 fi = fi + 1
119 }
120 return 0
121}
122
123func nt_iskind(b: *u8, koff: i64, kl: i64, pfx: *u8) -> i64 {
124 if kl <= 4 { return 0 }
125 return nt_kmemeq(b, koff, 4, pfx)
126}
127
128func nt_datedays(s: *u8) -> i64 {
129 let nums: *i64 = sys_mmap(8 * 4) as *i64
130 var nn: i64 = 0
131 var cur: i64 = 0
132 var indig: i64 = 0
133 var i: i64 = 0
134 var go: i64 = 1
135 while go == 1 {
136 let c: i64 = s[i] as i64
137 var isd: i64 = 0
138 if c >= 48 { if c <= 57 { isd = 1 } }
139 if isd == 1 { cur = cur * 10 + (c - 48); indig = 1 }
140 if isd == 0 {
141 if indig == 1 {
142 if nn < 4 { nums[nn] = cur; nn = nn + 1 }
143 cur = 0
144 indig = 0
145 }
146 }
147 if c == 0 { go = 0 }
148 i = i + 1
149 }
150 if nn != 3 { return 0 - 1 }
151 var y: i64 = nums[0]
152 let m: i64 = nums[1]
153 let d: i64 = nums[2]
154 if y < K_MAGIC_1970 { return 0 - 1 }
155 if m < 1 { return 0 - 1 }
156 if m > 12 { return 0 - 1 }
157 if d < 1 { return 0 - 1 }
158 if d > 31 { return 0 - 1 }
159 if m <= 2 { y = y - 1 }
160 let era: i64 = y / 400
161 let yoe: i64 = y - era * 400
162 var mp: i64 = m - 3
163 if m <= 2 { mp = m + 9 }
164 let doy: i64 = (153 * mp + 2) / 5 + d - 1
165 let doe: i64 = yoe * 365 + yoe / 4 - yoe / 100 + doy
166 return era * K_MAGIC_146097 + doe - K_MAGIC_719468
167}
168
169func nt_find(list: *i64, n: i64, s: *u8) -> i64 {
170 var i: i64 = 0
171 while i < n {
172 if nt_eq(list[i] as *u8, s) == 1 { return i }
173 i = i + 1
174 }
175 return 0 - 1
176}
177
178func nt_put(keys: *i64, vals: *i64, nf: i64, kp: *u8, st: *i64) -> i64 {
179 let enc: *u8 = sys_mmap(K_MAGIC_2048)
180 let el: i64 = canon_encode(keys, vals, nf, enc)
181 let cid: *u8 = sys_mmap(96)
182 cid_of(enc, el, cid)
183 let kbuf: *u8 = sys_mmap(128)
184 var ko: i64 = 0
185 ko = nt_cat(kbuf, ko, kp)
186 ko = nt_cat(kbuf, ko, cid)
187 kbuf[ko] = 0 as u8
188 let seen: *i64 = st[1] as *i64
189 var fresh: i64 = 1
190 if nt_find(seen, st[2], kbuf) >= 0 { fresh = 0; st[4] = st[4] + 1 }
191 if fresh == 1 {
192 if st[2] < K_MAGIC_2048 {
193 let dk: *u8 = nt_dup(kbuf)
194 seen[st[2]] = dk as i64
195 st[2] = st[2] + 1
196 }
197 }
198 if fresh == 1 {
199 let pp: *i64 = sys_mmap(16) as *i64
200 let ll: *i64 = sys_mmap(16) as *i64
201 if ss_get_idx(st[6] as *u8, kbuf, pp, ll) == 1 { fresh = 0; st[5] = st[5] + 1 }
202 }
203 if fresh == 1 {
204 if ss_add(st[0] as *i64, 1, kbuf, enc, el) != 0 { return 0 - 1 }
205 st[3] = st[3] + 1
206 }
207 return 0
208}
209
210// fork the blessed remind engine `due <cal> <contacts> <today> <leads>`, stdout -> outpath
211func nt_run_due(cal: *u8, contacts: *u8, today: *u8, leads: *u8, outpath: *u8) -> i64 {
212 let pid: i64 = sys_fork()
213 if pid == 0 {
214 let ofd: i64 = sys_openat_wr(outpath, 0x1a4)
215 if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) }
216 let argv: *i64 = sys_mmap(64) as *i64
217 argv[0] = "_offc/nx_vizsla_remind.elf" as *u8 as i64
218 argv[1] = "due" as *u8 as i64
219 argv[2] = cal as i64
220 argv[3] = contacts as i64
221 argv[4] = today as i64
222 argv[5] = leads as i64
223 argv[6] = 0
224 let envp: *i64 = sys_mmap(16) as *i64
225 envp[0] = 0
226 sys_execve("_offc/nx_vizsla_remind.elf" as *u8, argv, envp)
227 sys_exit(127)
228 }
229 let st: *i64 = sys_mmap(16) as *i64
230 sys_wait4(pid, st, 0)
231 let sig: i64 = st[0] & 0x7f
232 if sig != 0 { return 128 + sig }
233 return (st[0] >> 8) & 0xff
234}
235
236func nt_readall(path: *u8, szout: *i64) -> *u8 {
237 let fd: i64 = sys_openat_rd(path)
238 if fd < 0 { szout[0] = 0 - 1; return 0 as *u8 }
239 let sz: i64 = sys_lseek(fd, 0, 2)
240 sys_lseek(fd, 0, 0)
241 let buf: *u8 = sys_mmap(sz + 64)
242 var got: i64 = 0
243 var n: i64 = 1
244 while n > 0 {
245 n = sys_read(fd, (buf as i64 + got) as *u8, K_MAGIC_65536)
246 if n > 0 { got = got + n }
247 }
248 sys_close(fd)
249 szout[0] = got
250 return buf
251}
252
253// line[off..] starts with kw?
254func nt_starts(line: *u8, llen: i64, off: i64, kw: *u8) -> i64 {
255 let kl: i64 = nt_slen(kw)
256 if off + kl > llen { return 0 }
257 var j: i64 = 0
258 while j < kl { if line[off + j] != kw[j] { return 0 } j = j + 1 }
259 return 1
260}
261
262// extract " key=" value from line[0,llen) into out; tillend=1 -> rest of line, else until next space
263func nt_lfield(line: *u8, llen: i64, key: *u8, out: *u8, cap: i64, tillend: i64) -> i64 {
264 let kl: i64 = nt_slen(key)
265 var i: i64 = 0
266 while i + kl <= llen {
267 var ok: i64 = 1
268 var j: i64 = 0
269 while j < kl { if line[i + j] != key[j] { ok = 0; j = kl } else { j = j + 1 } }
270 if ok == 1 {
271 var p: i64 = i + kl
272 var t: i64 = 0
273 var go: i64 = 1
274 while go == 1 {
275 if p >= llen { go = 0 } else {
276 if tillend == 0 { if line[p] == (32 as u8) { go = 0 } }
277 if go == 1 { if t < cap - 1 { out[t] = line[p]; t = t + 1 } p = p + 1 }
278 }
279 }
280 out[t] = 0 as u8
281 return 1
282 }
283 i = i + 1
284 }
285 out[0] = 0 as u8
286 return 0
287}
288
289// ---------------- DELIVER (on-site) ----------------
290func nt_cmd_deliver(argc: i64, argv: *i64) -> i64 {
291 if argc < 7 { nt_p("VIZSLA-NOTIFY deliver needs <notifprefix> <cal|-> <contacts|-> <today> <leads> [channel] -- fail loud\n" as *u8); return 1 }
292 let prefix: *u8 = argv[2] as *u8
293 let cal: *u8 = argv[3] as *u8
294 let contacts: *u8 = argv[4] as *u8
295 let today: *u8 = argv[5] as *u8
296 let leads: *u8 = argv[6] as *u8
297 if nt_datedays(today) < 0 { nt_p("VIZSLA-NOTIFY deliver bad today date -- fail loud\n" as *u8); return 1 }
298 var channel: *u8 = "onsite" as *u8
299 if argc > 7 { channel = argv[7] as *u8 }
300
301 // compose the reminder engine (no sent-prefix -> ALL due surfaced; THIS store is the delivery ledger)
302 let due: *u8 = sys_mmap(256)
303 var do2: i64 = 0
304 do2 = nt_cat(due, do2, "/tmp/nt_due_" as *u8)
305 do2 = nt_catn(due, do2, sys_now_us())
306 do2 = nt_cat(due, do2, ".txt" as *u8)
307 due[do2] = 0 as u8
308 let rc: i64 = nt_run_due(cal, contacts, today, leads, due)
309 if rc != 0 { nt_p("VIZSLA-NOTIFY remind-due FAILED -- fail loud\n" as *u8); return 1 }
310
311 let szp: *i64 = sys_mmap(16) as *i64
312 let bb: *u8 = nt_readall(due, szp)
313 let bn: i64 = szp[0]
314
315 // existing delivered keys (ntkind|id|date) = the once-only ledger
316 let delk: *i64 = sys_mmap(8 * 512) as *i64
317 var ndk: i64 = 0
318 let segs: *i64 = sys_mmap(8 * 260) as *i64
319 let ns: i64 = ss_manifest(prefix, segs)
320 let f1: *u8 = sys_mmap(256)
321 let f2: *u8 = sys_mmap(256)
322 let f3: *u8 = sys_mmap(128)
323 var s: i64 = 0
324 while s < ns {
325 let path: *u8 = sys_mmap(512)
326 var po: i64 = 0
327 po = nt_cat(path, po, prefix)
328 po = nt_cat(path, po, segs[s] as *u8)
329 po = nt_cat(path, po, ".docs" as *u8)
330 path[po] = 0 as u8
331 let szp2: *i64 = sys_mmap(16) as *i64
332 let b: *u8 = ss_readall(path, szp2)
333 let sz: i64 = szp2[0]
334 var j: i64 = 0
335 while j + 9 <= sz {
336 let kind: i64 = b[j]
337 let kl: i64 = ss_r32(b, j + 1)
338 let koff: i64 = j + 5
339 let vl: i64 = ss_r32(b, koff + kl)
340 let voff: i64 = koff + kl + 4
341 var take: i64 = 0
342 if kind == 1 { take = nt_iskind(b, koff, kl, "ntf:" as *u8) }
343 if take == 1 {
344 let rec: *u8 = (b as i64 + voff) as *u8
345 nt_field(rec, vl, "ntkind" as *u8, f1, 256)
346 nt_field(rec, vl, "id" as *u8, f2, 256)
347 nt_field(rec, vl, "date" as *u8, f3, 128)
348 let key: *u8 = sys_mmap(512)
349 var ko: i64 = 0
350 ko = nt_cat(key, ko, f1)
351 key[ko] = 124 as u8; ko = ko + 1
352 ko = nt_cat(key, ko, f2)
353 key[ko] = 124 as u8; ko = ko + 1
354 ko = nt_cat(key, ko, f3)
355 key[ko] = 0 as u8
356 if ndk < 512 { delk[ndk] = key as i64; ndk = ndk + 1 }
357 }
358 j = voff + vl
359 }
360 s = s + 1
361 }
362
363 let keys: *i64 = sys_mmap(8 * 8) as *i64
364 let vals: *i64 = sys_mmap(8 * 8) as *i64
365 keys[0] = "kind" as *u8 as i64
366 keys[1] = "channel" as *u8 as i64
367 keys[2] = "ntkind" as *u8 as i64
368 keys[3] = "id" as *u8 as i64
369 keys[4] = "date" as *u8 as i64
370 keys[5] = "title" as *u8 as i64
371 keys[6] = "on" as *u8 as i64
372 vals[0] = "ntf" as *u8 as i64
373 vals[1] = channel as i64
374 vals[6] = today as i64
375
376 let st: *i64 = sys_mmap(8 * 8) as *i64
377 st[0] = ss_begin() as i64
378 st[1] = sys_mmap(8 * K_MAGIC_2048)
379 st[2] = 0
380 st[3] = 0
381 st[4] = 0
382 st[5] = 0
383 st[6] = prefix as i64
384
385 let segid: i64 = sys_now_us()
386 var delivered: i64 = 0
387 var skipped: i64 = 0
388 let lk: *u8 = sys_mmap(256)
389 let lid: *u8 = sys_mmap(256)
390 let ldt: *u8 = sys_mmap(128)
391 let ltl: *u8 = sys_mmap(256)
392
393 var i: i64 = 0
394 while i < bn {
395 var e: i64 = i
396 var go: i64 = 1
397 while go == 1 { if e >= bn { go = 0 } else { if bb[e] == (10 as u8) { go = 0 } else { e = e + 1 } } }
398 let line: *u8 = (bb as i64 + i) as *u8
399 let llen: i64 = e - i
400 if nt_starts(line, llen, 0, "VIZSLA-REM-DUE" as *u8) == 1 {
401 nt_lfield(line, llen, "kind=" as *u8, lk, 256, 0)
402 nt_lfield(line, llen, "id=" as *u8, lid, 256, 0)
403 nt_lfield(line, llen, "date=" as *u8, ldt, 128, 0)
404 nt_lfield(line, llen, "title=" as *u8, ltl, 256, 1)
405 let key: *u8 = sys_mmap(512)
406 var ko: i64 = 0
407 ko = nt_cat(key, ko, lk)
408 key[ko] = 124 as u8; ko = ko + 1
409 ko = nt_cat(key, ko, lid)
410 key[ko] = 124 as u8; ko = ko + 1
411 ko = nt_cat(key, ko, ldt)
412 key[ko] = 0 as u8
413 if nt_find(delk, ndk, key) >= 0 {
414 skipped = skipped + 1
415 } else {
416 delk[ndk] = key as i64; ndk = ndk + 1
417 vals[2] = nt_dup(lk) as i64
418 vals[3] = nt_dup(lid) as i64
419 vals[4] = nt_dup(ldt) as i64
420 vals[5] = nt_dup(ltl) as i64
421 if nt_put(keys, vals, 7, "ntf:" as *u8, st) != 0 { nt_p("VIZSLA-NOTIFY writer full -- fail loud\n" as *u8); return 1 }
422 delivered = delivered + 1
423 }
424 }
425 i = e + 1
426 }
427
428 var committed: i64 = 0
429 if st[3] > 0 {
430 if ss_commit(prefix, st[0] as *i64, segid) != 0 { nt_p("VIZSLA-NOTIFY commit FAILED -- fail loud\n" as *u8); return 1 }
431 committed = 1
432 }
433
434 let rep: *u8 = sys_mmap(K_MAGIC_1024)
435 var o: i64 = 0
436 o = nt_cat(rep, o, "VIZSLA-NOTIFY-DELIVER channel=" as *u8)
437 o = nt_cat(rep, o, channel)
438 o = nt_cat(rep, o, " today=" as *u8)
439 o = nt_cat(rep, o, today)
440 o = nt_cat(rep, o, " delivered=" as *u8)
441 o = nt_catn(rep, o, delivered)
442 o = nt_cat(rep, o, " skipped=" as *u8)
443 o = nt_catn(rep, o, skipped)
444 o = nt_cat(rep, o, " segment=" as *u8)
445 if committed == 1 {
446 o = nt_cat(rep, o, "seg-" as *u8)
447 o = nt_catn(rep, o, segid)
448 } else {
449 o = nt_cat(rep, o, "none" as *u8)
450 }
451 o = nt_cat(rep, o, "\n" as *u8)
452 sys_write(1, rep, o)
453 return 0
454}
455
456// ---------------- FEED ----------------
457func nt_cmd_feed(argc: i64, argv: *i64) -> i64 {
458 if argc < 4 { nt_p("VIZSLA-NOTIFY feed needs <notifprefix> <kind|-> -- fail loud\n" as *u8); return 1 }
459 let prefix: *u8 = argv[2] as *u8
460 let kindf: *u8 = argv[3] as *u8
461 let segs: *i64 = sys_mmap(8 * 260) as *i64
462 let ns: i64 = ss_manifest(prefix, segs)
463 let fch: *u8 = sys_mmap(128)
464 let fnk: *u8 = sys_mmap(128)
465 let fid: *u8 = sys_mmap(256)
466 let fdt: *u8 = sys_mmap(128)
467 let fon: *u8 = sys_mmap(128)
468 let ftl: *u8 = sys_mmap(256)
469 let rep: *u8 = sys_mmap(K_MAGIC_131072)
470 var o: i64 = 0
471 var cnt: i64 = 0
472 var s: i64 = 0
473 while s < ns {
474 let path: *u8 = sys_mmap(512)
475 var po: i64 = 0
476 po = nt_cat(path, po, prefix)
477 po = nt_cat(path, po, segs[s] as *u8)
478 po = nt_cat(path, po, ".docs" as *u8)
479 path[po] = 0 as u8
480 let szp: *i64 = sys_mmap(16) as *i64
481 let b: *u8 = ss_readall(path, szp)
482 let sz: i64 = szp[0]
483 var j: i64 = 0
484 while j + 9 <= sz {
485 let kind: i64 = b[j]
486 let kl: i64 = ss_r32(b, j + 1)
487 let koff: i64 = j + 5
488 let vl: i64 = ss_r32(b, koff + kl)
489 let voff: i64 = koff + kl + 4
490 var take: i64 = 0
491 if kind == 1 { take = nt_iskind(b, koff, kl, "ntf:" as *u8) }
492 if take == 1 {
493 let rec: *u8 = (b as i64 + voff) as *u8
494 nt_field(rec, vl, "ntkind" as *u8, fnk, 128)
495 var show: i64 = 1
496 if nt_eq(kindf, "-" as *u8) == 0 { if nt_eq(fnk, kindf) == 0 { show = 0 } }
497 if show == 1 {
498 nt_field(rec, vl, "channel" as *u8, fch, 128)
499 nt_field(rec, vl, "id" as *u8, fid, 256)
500 nt_field(rec, vl, "date" as *u8, fdt, 128)
501 nt_field(rec, vl, "on" as *u8, fon, 128)
502 nt_field(rec, vl, "title" as *u8, ftl, 256)
503 o = nt_cat(rep, o, "VIZSLA-NOTIFY channel=" as *u8)
504 o = nt_cat(rep, o, fch)
505 o = nt_cat(rep, o, " kind=" as *u8)
506 o = nt_cat(rep, o, fnk)
507 o = nt_cat(rep, o, " id=" as *u8)
508 o = nt_cat(rep, o, fid)
509 o = nt_cat(rep, o, " date=" as *u8)
510 o = nt_cat(rep, o, fdt)
511 o = nt_cat(rep, o, " on=" as *u8)
512 o = nt_cat(rep, o, fon)
513 o = nt_cat(rep, o, " title=" as *u8)
514 o = nt_cat(rep, o, ftl)
515 o = nt_cat(rep, o, "\n" as *u8)
516 cnt = cnt + 1
517 }
518 }
519 j = voff + vl
520 }
521 s = s + 1
522 }
523 o = nt_cat(rep, o, "VIZSLA-NOTIFY-FEED kind=" as *u8)
524 o = nt_cat(rep, o, kindf)
525 o = nt_cat(rep, o, " notifications=" as *u8)
526 o = nt_catn(rep, o, cnt)
527 o = nt_cat(rep, o, "\n" as *u8)
528 sys_write(1, rep, o)
529 return 0
530}
531
532// ---------------- EMAIL (compose a valid RFC5322 digest, ready to submit) ----------------
533func nt_dow(dst: *u8, off: i64, days: i64) -> i64 {
534 let idx: i64 = ((days % 7) + 7 + 4) % 7 // 0=Sun (K_MAGIC_1970-01-01 = Thu -> +4)
535 var o: i64 = off
536 if idx == 0 { o = nt_cat(dst, o, "Sun" as *u8) }
537 if idx == 1 { o = nt_cat(dst, o, "Mon" as *u8) }
538 if idx == 2 { o = nt_cat(dst, o, "Tue" as *u8) }
539 if idx == 3 { o = nt_cat(dst, o, "Wed" as *u8) }
540 if idx == 4 { o = nt_cat(dst, o, "Thu" as *u8) }
541 if idx == 5 { o = nt_cat(dst, o, "Fri" as *u8) }
542 if idx == 6 { o = nt_cat(dst, o, "Sat" as *u8) }
543 return o
544}
545
546func nt_mon(dst: *u8, off: i64, m: i64) -> i64 {
547 var o: i64 = off
548 if m == 1 { o = nt_cat(dst, o, "Jan" as *u8) }
549 if m == 2 { o = nt_cat(dst, o, "Feb" as *u8) }
550 if m == 3 { o = nt_cat(dst, o, "Mar" as *u8) }
551 if m == 4 { o = nt_cat(dst, o, "Apr" as *u8) }
552 if m == 5 { o = nt_cat(dst, o, "May" as *u8) }
553 if m == 6 { o = nt_cat(dst, o, "Jun" as *u8) }
554 if m == 7 { o = nt_cat(dst, o, "Jul" as *u8) }
555 if m == 8 { o = nt_cat(dst, o, "Aug" as *u8) }
556 if m == 9 { o = nt_cat(dst, o, "Sep" as *u8) }
557 if m == 10 { o = nt_cat(dst, o, "Oct" as *u8) }
558 if m == 11 { o = nt_cat(dst, o, "Nov" as *u8) }
559 if m == 12 { o = nt_cat(dst, o, "Dec" as *u8) }
560 return o
561}
562
563func nt_cmd_email(argc: i64, argv: *i64) -> i64 {
564 if argc < 9 { nt_p("VIZSLA-NOTIFY email needs <cal|-> <contacts|-> <today> <leads> <from> <to> <out.eml> -- fail loud\n" as *u8); return 1 }
565 let cal: *u8 = argv[2] as *u8
566 let contacts: *u8 = argv[3] as *u8
567 let today: *u8 = argv[4] as *u8
568 let leads: *u8 = argv[5] as *u8
569 let from: *u8 = argv[6] as *u8
570 let to: *u8 = argv[7] as *u8
571 let outp: *u8 = argv[8] as *u8
572 let tdays: i64 = nt_datedays(today)
573 if tdays < 0 { nt_p("VIZSLA-NOTIFY email bad today date -- fail loud\n" as *u8); return 1 }
574
575 let due: *u8 = sys_mmap(256)
576 var do2: i64 = 0
577 do2 = nt_cat(due, do2, "/tmp/nt_edue_" as *u8)
578 do2 = nt_catn(due, do2, sys_now_us())
579 do2 = nt_cat(due, do2, ".txt" as *u8)
580 due[do2] = 0 as u8
581 let rc: i64 = nt_run_due(cal, contacts, today, leads, due)
582 if rc != 0 { nt_p("VIZSLA-NOTIFY remind-due FAILED -- fail loud\n" as *u8); return 1 }
583 let szp: *i64 = sys_mmap(16) as *i64
584 let bb: *u8 = nt_readall(due, szp)
585 let bn: i64 = szp[0]
586
587 let ymd: *i64 = sys_mmap(8 * 4) as *i64
588 // civil from tdays (inline Hinnant inverse)
589 var z: i64 = tdays + K_MAGIC_719468
590 var era: i64 = z / K_MAGIC_146097
591 if z < 0 { era = (z - K_MAGIC_146096) / K_MAGIC_146097 }
592 let doe: i64 = z - era * K_MAGIC_146097
593 let yoe: i64 = (doe - doe / K_MAGIC_1460 + doe / K_MAGIC_36524 - doe / K_MAGIC_146096) / 365
594 let y0: i64 = yoe + era * 400
595 let doy: i64 = doe - (365 * yoe + yoe / 4 - yoe / 100)
596 let mp: i64 = (5 * doy + 2) / 153
597 let dd: i64 = doy - (153 * mp + 2) / 5 + 1
598 var mm: i64 = mp + 3
599 if mp >= 10 { mm = mp - 9 }
600 var yy: i64 = y0
601 if mm <= 2 { yy = y0 + 1 }
602
603 let msg: *u8 = sys_mmap(K_MAGIC_131072)
604 var o: i64 = 0
605 o = nt_cat(msg, o, "From: " as *u8)
606 o = nt_cat(msg, o, from)
607 o = nt_cat(msg, o, "\r\nTo: " as *u8)
608 o = nt_cat(msg, o, to)
609 o = nt_cat(msg, o, "\r\nSubject: Your reminders for " as *u8)
610 o = nt_cat(msg, o, today)
611 o = nt_cat(msg, o, "\r\nDate: " as *u8)
612 o = nt_dow(msg, o, tdays)
613 o = nt_cat(msg, o, ", " as *u8)
614 if dd < 10 { msg[o] = 48 as u8; o = o + 1 }
615 o = nt_catn(msg, o, dd)
616 msg[o] = 32 as u8; o = o + 1
617 o = nt_mon(msg, o, mm)
618 msg[o] = 32 as u8; o = o + 1
619 o = nt_catn(msg, o, yy)
620 o = nt_cat(msg, o, " 09:00:00 +0000\r\nMIME-Version: 1.0\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n" as *u8)
621 o = nt_cat(msg, o, "Nishi Vizsla reminders:\r\n\r\n" as *u8)
622
623 var due_cnt: i64 = 0
624 let lnk: *u8 = sys_mmap(128)
625 let lid: *u8 = sys_mmap(256)
626 let ldt: *u8 = sys_mmap(128)
627 let ltl: *u8 = sys_mmap(256)
628 let lin: *u8 = sys_mmap(64)
629 var i: i64 = 0
630 while i < bn {
631 var e: i64 = i
632 var go: i64 = 1
633 while go == 1 { if e >= bn { go = 0 } else { if bb[e] == (10 as u8) { go = 0 } else { e = e + 1 } } }
634 let line: *u8 = (bb as i64 + i) as *u8
635 let llen: i64 = e - i
636 if nt_starts(line, llen, 0, "VIZSLA-REM-DUE" as *u8) == 1 {
637 nt_lfield(line, llen, "kind=" as *u8, lnk, 128, 0)
638 nt_lfield(line, llen, "id=" as *u8, lid, 256, 0)
639 nt_lfield(line, llen, "date=" as *u8, ldt, 128, 0)
640 nt_lfield(line, llen, "in=" as *u8, lin, 64, 0)
641 nt_lfield(line, llen, "title=" as *u8, ltl, 256, 1)
642 o = nt_cat(msg, o, " * " as *u8)
643 o = nt_cat(msg, o, ltl)
644 o = nt_cat(msg, o, " (" as *u8)
645 o = nt_cat(msg, o, lnk)
646 o = nt_cat(msg, o, ") on " as *u8)
647 o = nt_cat(msg, o, ldt)
648 o = nt_cat(msg, o, " -- in " as *u8)
649 o = nt_cat(msg, o, lin)
650 o = nt_cat(msg, o, " days\r\n" as *u8)
651 due_cnt = due_cnt + 1
652 }
653 i = e + 1
654 }
655 o = nt_cat(msg, o, "\r\n-- Nishi Vizsla, on your hardware.\r\n" as *u8)
656
657 let fd: i64 = sys_openat_wr(outp, 0x1a4)
658 if fd < 0 { nt_p("VIZSLA-NOTIFY cannot write out.eml -- fail loud\n" as *u8); return 1 }
659 sys_write(fd, msg, o)
660 sys_close(fd)
661
662 let rep: *u8 = sys_mmap(512)
663 var ro: i64 = 0
664 ro = nt_cat(rep, ro, "VIZSLA-NOTIFY-EMAIL today=" as *u8)
665 ro = nt_cat(rep, ro, today)
666 ro = nt_cat(rep, ro, " reminders=" as *u8)
667 ro = nt_catn(rep, ro, due_cnt)
668 ro = nt_cat(rep, ro, " bytes=" as *u8)
669 ro = nt_catn(rep, ro, o)
670 ro = nt_cat(rep, ro, " -> " as *u8)
671 ro = nt_cat(rep, ro, outp)
672 ro = nt_cat(rep, ro, " (RFC5322, DKIM-signable via nx_email_send; external submit operator-gated)\n" as *u8)
673 sys_write(1, rep, ro)
674 return 0
675}
676
677func main(argc: i64, argv: *i64) -> i64 {
678 if argc < 2 { nt_p("VIZSLA-NOTIFY usage: deliver|feed|email -- fail loud\n" as *u8); return 1 }
679 let cmd: *u8 = argv[1] as *u8
680 if nt_eq(cmd, "deliver" as *u8) == 1 { return nt_cmd_deliver(argc, argv) }
681 if nt_eq(cmd, "feed" as *u8) == 1 { return nt_cmd_feed(argc, argv) }
682 if nt_eq(cmd, "email" as *u8) == 1 { return nt_cmd_email(argc, argv) }
683 nt_p("VIZSLA-NOTIFY unknown command (deliver|feed|email) -- fail loud\n" as *u8)
684 return 1
685}