code wiki / _hdl_build / nx_vizsla_remind.nx
nx_vizsla_remind.nx source
↩ module page · 762 lines · 28080 B
1// nx_vizsla_remind.nx -- NISHI VIZSLA REMINDER ENGINE (census PA18 core): birthday +
2// important-event reminders with lead times and a sent-once delivery ledger.
3// Operator 2026-07-07: "birthday and important event reminder". COMPOSES the existing planes:
4// calendar events + recurrences (nx_vizsla_calendar cal:/rec: records, YEARLY included) and the
5// relate contacts file (CONTACT <id> <display> <tier> <MM-DD|->). The organ computes WHAT is
6// due at which lead (14/7/1/0 days -- the leads are an ARGUMENT, data not magic numbers) and
7// the ledger guarantees each (kind,id,date) notice is delivered ONCE (additive snt: records,
8// CID-idempotent). Actual outward push (email/phone) composes the sovereign email stack behind
9// the operator's outward-facing consent -- this organ is the truth of what to send and whether
10// it was sent, deterministic (today is argv, never a clock).
11//
12// Commands:
13// due <calprefix|-> <contactsfile|-> <today> <leads> [sentprefix]
14// leads = comma ints e.g. 14,7,1,0 ; window = [today, today+max(leads)].
15// calendar occurrence / next birthday occurrence (MM-DD; Feb-29 clamps to Feb-28 in
16// non-leap years, mirroring the calendar's YEARLY clamp) with days-until IN the leads set
17// -> VIZSLA-REM-DUE; already in the sent ledger -> VIZSLA-REM-SENT-SKIP (counted, shown).
18// mark <sentprefix> <event|birthday> <id> <date> [segid]
19// append the sent record (idempotent -> new=0 on re-mark).
20// Loud-fail: bad today/leads/date, missing named files, bad kind.
21// spec: knowledge/research/2026-06-22-vizsla-sclass-roadmap.md license_tier: ORIGINAL
22import "nx_syscalls.nx"
23import "nx_canon_cid.nx"
24import "nx_seg_store.nx"
25const K_MAGIC_1970: i64 = 1970
26const K_MAGIC_146097: i64 = 146097
27const K_MAGIC_719468: i64 = 719468
28const K_MAGIC_146096: i64 = 146096
29const K_MAGIC_1460: i64 = 1460
30const K_MAGIC_36524: i64 = 36524
31const K_MAGIC_2048: i64 = 2048
32const K_MAGIC_262144: i64 = 262144
33const K_MAGIC_1024: i64 = 1024
34
35func vr_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
36func vr_p(s: *u8) -> i64 { sys_write(1, s, vr_slen(s)); return 0 }
37
38func vr_eq(a: *u8, b: *u8) -> i64 {
39 var i: i64 = 0
40 var go: i64 = 1
41 while go == 1 {
42 if a[i] != b[i] { return 0 }
43 if a[i] == (0 as u8) { return 1 }
44 i = i + 1
45 }
46 return 0
47}
48
49func vr_dup(s: *u8) -> *u8 {
50 let n: i64 = vr_slen(s)
51 let d: *u8 = sys_mmap(n + 2)
52 var i: i64 = 0
53 while i <= n { d[i] = s[i]; i = i + 1 }
54 return d
55}
56
57func vr_atoi(s: *u8) -> i64 {
58 var v: i64 = 0
59 var i: i64 = 0
60 while s[i] != (0 as u8) {
61 let d: i64 = (s[i] as i64) - 48
62 if d >= 0 { if d <= 9 { v = v * 10 + d } }
63 i = i + 1
64 }
65 return v
66}
67
68func vr_digits(s: *u8) -> i64 {
69 if s[0] == (0 as u8) { return 0 }
70 var i: i64 = 0
71 while s[i] != (0 as u8) {
72 let d: i64 = (s[i] as i64) - 48
73 if d < 0 { return 0 }
74 if d > 9 { return 0 }
75 i = i + 1
76 }
77 return 1
78}
79
80func vr_isws(c: i64) -> i64 {
81 if c == 32 { return 1 }
82 if c == 13 { return 1 }
83 if c == 9 { return 1 }
84 return 0
85}
86
87func vr_tok(b: *u8, off: i64, lend: i64, dst: *u8, cap: i64) -> i64 {
88 var p: i64 = off
89 var go: i64 = 1
90 while go == 1 {
91 if p >= lend { go = 0 } else {
92 if vr_isws(b[p] as i64) == 1 { p = p + 1 } else { go = 0 }
93 }
94 }
95 var t: i64 = 0
96 go = 1
97 while go == 1 {
98 if p >= lend { go = 0 } else {
99 if vr_isws(b[p] as i64) == 1 { go = 0 } else {
100 if t < cap - 1 { dst[t] = b[p]; t = t + 1 }
101 p = p + 1
102 }
103 }
104 }
105 dst[t] = 0 as u8
106 return p
107}
108
109func vr_cat(dst: *u8, off: i64, s: *u8) -> i64 {
110 var i: i64 = 0
111 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 }
112 return off + i
113}
114
115func vr_catn(dst: *u8, off: i64, v: i64) -> i64 {
116 var o: i64 = off
117 var m: i64 = v
118 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m }
119 let t: *u8 = sys_mmap(28)
120 var k: i64 = 0
121 if m == 0 { t[0] = 48 as u8; k = 1 }
122 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
123 var i: i64 = 0
124 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 }
125 return o + k
126}
127
128func vr_kmemeq(b: *u8, off: i64, n: i64, s: *u8) -> i64 {
129 if vr_slen(s) != n { return 0 }
130 var i: i64 = 0
131 while i < n {
132 if b[off + i] != s[i] { return 0 }
133 i = i + 1
134 }
135 return 1
136}
137
138func vr_field(rec: *u8, rl: i64, want: *u8, out: *u8, cap: i64) -> i64 {
139 if rl < 8 { return 0 }
140 let nf: i64 = ss_r32(rec, 4)
141 var off: i64 = 8
142 var fi: i64 = 0
143 while fi < nf {
144 if off + 8 > rl { return 0 }
145 let kl: i64 = ss_r32(rec, off)
146 let koff: i64 = off + 4
147 let vl: i64 = ss_r32(rec, koff + kl)
148 let voff: i64 = koff + kl + 4
149 if vr_kmemeq(rec, koff, kl, want) == 1 {
150 var t: i64 = 0
151 while t < vl {
152 if t < cap - 1 { out[t] = rec[voff + t] }
153 t = t + 1
154 }
155 if t > cap - 1 { t = cap - 1 }
156 out[t] = 0 as u8
157 return 1
158 }
159 off = voff + vl
160 fi = fi + 1
161 }
162 return 0
163}
164
165func vr_iskind(b: *u8, koff: i64, kl: i64, pfx: *u8) -> i64 {
166 if kl <= 4 { return 0 }
167 return vr_kmemeq(b, koff, 4, pfx)
168}
169
170func vr_datedays(s: *u8) -> i64 {
171 let nums: *i64 = sys_mmap(8 * 4) as *i64
172 var nn: i64 = 0
173 var cur: i64 = 0
174 var indig: i64 = 0
175 var i: i64 = 0
176 var go: i64 = 1
177 while go == 1 {
178 let c: i64 = s[i] as i64
179 var isd: i64 = 0
180 if c >= 48 { if c <= 57 { isd = 1 } }
181 if isd == 1 { cur = cur * 10 + (c - 48); indig = 1 }
182 if isd == 0 {
183 if indig == 1 {
184 if nn < 4 { nums[nn] = cur; nn = nn + 1 }
185 cur = 0
186 indig = 0
187 }
188 }
189 if c == 0 { go = 0 }
190 i = i + 1
191 }
192 if nn != 3 { return 0 - 1 }
193 var y: i64 = nums[0]
194 let m: i64 = nums[1]
195 let d: i64 = nums[2]
196 if y < K_MAGIC_1970 { return 0 - 1 }
197 if m < 1 { return 0 - 1 }
198 if m > 12 { return 0 - 1 }
199 if d < 1 { return 0 - 1 }
200 if d > 31 { return 0 - 1 }
201 if m <= 2 { y = y - 1 }
202 let era: i64 = y / 400
203 let yoe: i64 = y - era * 400
204 var mp: i64 = m - 3
205 if m <= 2 { mp = m + 9 }
206 let doy: i64 = (153 * mp + 2) / 5 + d - 1
207 let doe: i64 = yoe * 365 + yoe / 4 - yoe / 100 + doy
208 return era * K_MAGIC_146097 + doe - K_MAGIC_719468
209}
210
211func vr_ymd2days(y0: i64, m: i64, d: i64) -> i64 {
212 var y: i64 = y0
213 if m <= 2 { y = y0 - 1 }
214 let era: i64 = y / 400
215 let yoe: i64 = y - era * 400
216 var mp: i64 = m - 3
217 if m <= 2 { mp = m + 9 }
218 let doy: i64 = (153 * mp + 2) / 5 + d - 1
219 let doe: i64 = yoe * 365 + yoe / 4 - yoe / 100 + doy
220 return era * K_MAGIC_146097 + doe - K_MAGIC_719468
221}
222
223func vr_civil(z0: i64, out: *i64) -> i64 {
224 var z: i64 = z0 + K_MAGIC_719468
225 var era: i64 = z / K_MAGIC_146097
226 if z < 0 { era = (z - K_MAGIC_146096) / K_MAGIC_146097 }
227 let doe: i64 = z - era * K_MAGIC_146097
228 let yoe: i64 = (doe - doe / K_MAGIC_1460 + doe / K_MAGIC_36524 - doe / K_MAGIC_146096) / 365
229 let y0: i64 = yoe + era * 400
230 let doy: i64 = doe - (365 * yoe + yoe / 4 - yoe / 100)
231 let mp: i64 = (5 * doy + 2) / 153
232 let d: i64 = doy - (153 * mp + 2) / 5 + 1
233 var m: i64 = mp + 3
234 if mp >= 10 { m = mp - 9 }
235 var y: i64 = y0
236 if m <= 2 { y = y0 + 1 }
237 out[0] = y; out[1] = m; out[2] = d
238 return 0
239}
240
241func vr_dim(y: i64, m: i64) -> i64 {
242 if m == 2 {
243 var leap: i64 = 0
244 if y % 4 == 0 { leap = 1 }
245 if y % 100 == 0 { leap = 0 }
246 if y % 400 == 0 { leap = 1 }
247 if leap == 1 { return 29 }
248 return 28
249 }
250 if m == 4 { return 30 }
251 if m == 6 { return 30 }
252 if m == 9 { return 30 }
253 if m == 11 { return 30 }
254 return 31
255}
256
257func vr_occ(freq: *u8, sd0: i64, sy: i64, sm: i64, sd: i64, interval: i64, k: i64) -> i64 {
258 if vr_eq(freq, "DAILY" as *u8) == 1 { return sd0 + k * interval }
259 if vr_eq(freq, "WEEKLY" as *u8) == 1 { return sd0 + k * interval * 7 }
260 var mstep: i64 = interval
261 if vr_eq(freq, "YEARLY" as *u8) == 1 { mstep = interval * 12 }
262 let tot: i64 = (sm - 1) + k * mstep
263 let y2: i64 = sy + tot / 12
264 let m2: i64 = tot - (tot / 12) * 12 + 1
265 var d2: i64 = sd
266 let dim: i64 = vr_dim(y2, m2)
267 if d2 > dim { d2 = dim }
268 return vr_ymd2days(y2, m2, d2)
269}
270
271func vr_daystr(dst: *u8, off: i64, days: i64) -> i64 {
272 let ymd: *i64 = sys_mmap(8 * 4) as *i64
273 vr_civil(days, ymd)
274 var o: i64 = off
275 o = vr_catn(dst, o, ymd[0])
276 dst[o] = 45 as u8; o = o + 1
277 if ymd[1] < 10 { dst[o] = 48 as u8; o = o + 1 }
278 o = vr_catn(dst, o, ymd[1])
279 dst[o] = 45 as u8; o = o + 1
280 if ymd[2] < 10 { dst[o] = 48 as u8; o = o + 1 }
281 o = vr_catn(dst, o, ymd[2])
282 return o
283}
284
285func vr_find(list: *i64, n: i64, s: *u8) -> i64 {
286 var i: i64 = 0
287 while i < n {
288 if vr_eq(list[i] as *u8, s) == 1 { return i }
289 i = i + 1
290 }
291 return 0 - 1
292}
293
294// day-number of the NEXT occurrence (>= today) of an MM-DD birthday; -1 malformed.
295// Feb-29 clamps to Feb-28 in non-leap years (mirrors the calendar's YEARLY clamp).
296func vr_bday_next(mmdd: *u8, today: i64) -> i64 {
297 var mm: i64 = 0 - 1
298 var dd: i64 = 0 - 1
299 if mmdd[0] == (0 as u8) { return 0 - 1 }
300 let c0: i64 = mmdd[0] as i64
301 let c1: i64 = mmdd[1] as i64
302 if c0 < 48 { return 0 - 1 }
303 if c0 > 57 { return 0 - 1 }
304 if c1 < 48 { return 0 - 1 }
305 if c1 > 57 { return 0 - 1 }
306 if (mmdd[2] as i64) != 45 { return 0 - 1 }
307 let c3: i64 = mmdd[3] as i64
308 let c4: i64 = mmdd[4] as i64
309 if c3 < 48 { return 0 - 1 }
310 if c3 > 57 { return 0 - 1 }
311 if c4 < 48 { return 0 - 1 }
312 if c4 > 57 { return 0 - 1 }
313 if mmdd[5] != (0 as u8) { return 0 - 1 }
314 mm = (c0 - 48) * 10 + (c1 - 48)
315 dd = (c3 - 48) * 10 + (c4 - 48)
316 if mm < 1 { return 0 - 1 }
317 if mm > 12 { return 0 - 1 }
318 if dd < 1 { return 0 - 1 }
319 if dd > 31 { return 0 - 1 }
320 let ymd: *i64 = sys_mmap(8 * 4) as *i64
321 vr_civil(today, ymd)
322 var y: i64 = ymd[0]
323 var d2: i64 = dd
324 let dim1: i64 = vr_dim(y, mm)
325 if d2 > dim1 { d2 = dim1 }
326 var cand: i64 = vr_ymd2days(y, mm, d2)
327 if cand < today {
328 y = y + 1
329 d2 = dd
330 let dim2: i64 = vr_dim(y, mm)
331 if d2 > dim2 { d2 = dim2 }
332 cand = vr_ymd2days(y, mm, d2)
333 }
334 return cand
335}
336
337func vr_put(keys: *i64, vals: *i64, nf: i64, kp: *u8, st: *i64) -> i64 {
338 let enc: *u8 = sys_mmap(K_MAGIC_2048)
339 let el: i64 = canon_encode(keys, vals, nf, enc)
340 let cid: *u8 = sys_mmap(96)
341 cid_of(enc, el, cid)
342 let kbuf: *u8 = sys_mmap(128)
343 var ko: i64 = 0
344 ko = vr_cat(kbuf, ko, kp)
345 ko = vr_cat(kbuf, ko, cid)
346 kbuf[ko] = 0 as u8
347 let seen: *i64 = st[1] as *i64
348 var fresh: i64 = 1
349 if vr_find(seen, st[2], kbuf) >= 0 { fresh = 0; st[4] = st[4] + 1 }
350 if fresh == 1 {
351 if st[2] < K_MAGIC_2048 {
352 let dk: *u8 = vr_dup(kbuf)
353 seen[st[2]] = dk as i64
354 st[2] = st[2] + 1
355 }
356 }
357 if fresh == 1 {
358 let pp: *i64 = sys_mmap(16) as *i64
359 let ll: *i64 = sys_mmap(16) as *i64
360 if ss_get_idx(st[6] as *u8, kbuf, pp, ll) == 1 { fresh = 0; st[5] = st[5] + 1 }
361 }
362 if fresh == 1 {
363 if ss_add(st[0] as *i64, 1, kbuf, enc, el) != 0 { return 0 - 1 }
364 st[3] = st[3] + 1
365 }
366 return 0
367}
368
369// gather sent ledger (kind,id,date) triples
370func vr_sent_gather(prefix: *u8, kk: *i64, ii: *i64, dd: *i64, np: *i64) -> i64 {
371 let segs: *i64 = sys_mmap(8 * 260) as *i64
372 let ns: i64 = ss_manifest(prefix, segs)
373 let f1: *u8 = sys_mmap(128)
374 let f2: *u8 = sys_mmap(256)
375 let f3: *u8 = sys_mmap(128)
376 var s: i64 = 0
377 while s < ns {
378 let path: *u8 = sys_mmap(512)
379 var po: i64 = 0
380 po = vr_cat(path, po, prefix)
381 po = vr_cat(path, po, segs[s] as *u8)
382 po = vr_cat(path, po, ".docs" as *u8)
383 path[po] = 0 as u8
384 let szp: *i64 = sys_mmap(16) as *i64
385 let b: *u8 = ss_readall(path, szp)
386 let sz: i64 = szp[0]
387 var j: i64 = 0
388 while j + 9 <= sz {
389 let kind: i64 = b[j]
390 let kl: i64 = ss_r32(b, j + 1)
391 let koff: i64 = j + 5
392 let vl: i64 = ss_r32(b, koff + kl)
393 let voff: i64 = koff + kl + 4
394 var take: i64 = 0
395 if kind == 1 { take = vr_iskind(b, koff, kl, "snt:" as *u8) }
396 if take == 1 {
397 let rec: *u8 = (b as i64 + voff) as *u8
398 if np[0] < 256 {
399 vr_field(rec, vl, "k" as *u8, f1, 128)
400 vr_field(rec, vl, "id" as *u8, f2, 256)
401 vr_field(rec, vl, "date" as *u8, f3, 128)
402 let d1: *u8 = vr_dup(f1)
403 let d2: *u8 = vr_dup(f2)
404 let d3: *u8 = vr_dup(f3)
405 kk[np[0]] = d1 as i64
406 ii[np[0]] = d2 as i64
407 dd[np[0]] = d3 as i64
408 np[0] = np[0] + 1
409 }
410 }
411 j = voff + vl
412 }
413 s = s + 1
414 }
415 return 0
416}
417
418func vr_sent_has(kk: *i64, ii: *i64, dd: *i64, n: i64, k: *u8, id: *u8, date: *u8) -> i64 {
419 var i: i64 = 0
420 while i < n {
421 if vr_eq(kk[i] as *u8, k) == 1 {
422 if vr_eq(ii[i] as *u8, id) == 1 {
423 if vr_eq(dd[i] as *u8, date) == 1 { return 1 }
424 }
425 }
426 i = i + 1
427 }
428 return 0
429}
430
431// ---------------- DUE ----------------
432func vr_cmd_due(argc: i64, argv: *i64) -> i64 {
433 if argc < 6 { vr_p("VIZSLA-REM due needs <calprefix|-> <contacts|-> <today> <leads> [sentprefix] -- fail loud\n" as *u8); return 1 }
434 let calpfx: *u8 = argv[2] as *u8
435 let cfile: *u8 = argv[3] as *u8
436 let today: i64 = vr_datedays(argv[4] as *u8)
437 if today < 0 { vr_p("VIZSLA-REM bad today date -- fail loud\n" as *u8); return 1 }
438 // parse leads
439 let leads: *i64 = sys_mmap(8 * 16) as *i64
440 var nlead: i64 = 0
441 var maxlead: i64 = 0 - 1
442 let ls: *u8 = argv[5] as *u8
443 let tokb: *u8 = sys_mmap(64)
444 var li: i64 = 0
445 var lt: i64 = 0
446 var go: i64 = 1
447 while go == 1 {
448 let c: i64 = ls[li] as i64
449 var flush: i64 = 0
450 if c == 44 { flush = 1 }
451 if c == 0 { flush = 1 }
452 if flush == 1 {
453 tokb[lt] = 0 as u8
454 if lt > 0 {
455 if vr_digits(tokb) == 0 { vr_p("VIZSLA-REM leads not digits -- fail loud\n" as *u8); return 1 }
456 let v: i64 = vr_atoi(tokb)
457 if nlead < 16 { leads[nlead] = v; nlead = nlead + 1 }
458 if v > maxlead { maxlead = v }
459 }
460 lt = 0
461 } else {
462 if lt < 63 { tokb[lt] = c as u8; lt = lt + 1 }
463 }
464 if c == 0 { go = 0 }
465 li = li + 1
466 }
467 if nlead == 0 { vr_p("VIZSLA-REM leads empty -- fail loud\n" as *u8); return 1 }
468 var sentpfx: *u8 = "-" as *u8
469 if argc > 6 { sentpfx = argv[6] as *u8 }
470
471 // sent ledger
472 let skk: *i64 = sys_mmap(8 * 256) as *i64
473 let sii: *i64 = sys_mmap(8 * 256) as *i64
474 let sdd: *i64 = sys_mmap(8 * 256) as *i64
475 let snp: *i64 = sys_mmap(16) as *i64
476 snp[0] = 0
477 if vr_eq(sentpfx, "-" as *u8) == 0 { vr_sent_gather(sentpfx, skk, sii, sdd, snp) }
478
479 let rep: *u8 = sys_mmap(K_MAGIC_262144)
480 var o: i64 = 0
481 var due_ev: i64 = 0
482 var due_bd: i64 = 0
483 var skipped: i64 = 0
484 let dstr: *u8 = sys_mmap(64)
485
486 // calendar events + recurrences
487 if vr_eq(calpfx, "-" as *u8) == 0 {
488 let segs: *i64 = sys_mmap(8 * 260) as *i64
489 let ns: i64 = ss_manifest(calpfx, segs)
490 let fid: *u8 = sys_mmap(128)
491 let fdt: *u8 = sys_mmap(128)
492 let fst: *u8 = sys_mmap(128)
493 let fdu: *u8 = sys_mmap(128)
494 let ffr: *u8 = sys_mmap(64)
495 let fiv: *u8 = sys_mmap(64)
496 let fct: *u8 = sys_mmap(64)
497 let ftl: *u8 = sys_mmap(256)
498 let ymd: *i64 = sys_mmap(8 * 4) as *i64
499 var s: i64 = 0
500 while s < ns {
501 let path: *u8 = sys_mmap(512)
502 var po: i64 = 0
503 po = vr_cat(path, po, calpfx)
504 po = vr_cat(path, po, segs[s] as *u8)
505 po = vr_cat(path, po, ".docs" as *u8)
506 path[po] = 0 as u8
507 let szp: *i64 = sys_mmap(16) as *i64
508 let b: *u8 = ss_readall(path, szp)
509 let sz: i64 = szp[0]
510 var j: i64 = 0
511 while j + 9 <= sz {
512 let kind: i64 = b[j]
513 let kl: i64 = ss_r32(b, j + 1)
514 let koff: i64 = j + 5
515 let vl: i64 = ss_r32(b, koff + kl)
516 let voff: i64 = koff + kl + 4
517 let rec: *u8 = (b as i64 + voff) as *u8
518 var iscal: i64 = 0
519 var isrec: i64 = 0
520 if kind == 1 { iscal = vr_iskind(b, koff, kl, "cal:" as *u8) }
521 if kind == 1 { isrec = vr_iskind(b, koff, kl, "rec:" as *u8) }
522 if iscal == 1 {
523 var ddv: i64 = 0 - 1
524 if vr_field(rec, vl, "date" as *u8, fdt, 128) == 1 { ddv = vr_datedays(fdt) }
525 var inwin: i64 = 0
526 if ddv >= today { if ddv <= today + maxlead { inwin = 1 } }
527 if inwin == 1 {
528 let din: i64 = ddv - today
529 var hit: i64 = 0
530 var lk: i64 = 0
531 while lk < nlead {
532 if leads[lk] == din { hit = 1 }
533 lk = lk + 1
534 }
535 if hit == 1 {
536 vr_field(rec, vl, "id" as *u8, fid, 128)
537 vr_field(rec, vl, "title" as *u8, ftl, 256)
538 if vr_sent_has(skk, sii, sdd, snp[0], "event" as *u8, fid, fdt) == 1 {
539 o = vr_cat(rep, o, "VIZSLA-REM-SENT-SKIP kind=event id=" as *u8)
540 o = vr_cat(rep, o, fid)
541 o = vr_cat(rep, o, " date=" as *u8)
542 o = vr_cat(rep, o, fdt)
543 o = vr_cat(rep, o, "\n" as *u8)
544 skipped = skipped + 1
545 } else {
546 o = vr_cat(rep, o, "VIZSLA-REM-DUE kind=event id=" as *u8)
547 o = vr_cat(rep, o, fid)
548 o = vr_cat(rep, o, " date=" as *u8)
549 o = vr_cat(rep, o, fdt)
550 o = vr_cat(rep, o, " in=" as *u8)
551 o = vr_catn(rep, o, din)
552 o = vr_cat(rep, o, " title=" as *u8)
553 o = vr_cat(rep, o, ftl)
554 o = vr_cat(rep, o, "\n" as *u8)
555 due_ev = due_ev + 1
556 }
557 }
558 }
559 }
560 if isrec == 1 {
561 vr_field(rec, vl, "id" as *u8, fid, 128)
562 vr_field(rec, vl, "sdate" as *u8, fdt, 128)
563 vr_field(rec, vl, "freq" as *u8, ffr, 64)
564 vr_field(rec, vl, "interval" as *u8, fiv, 64)
565 vr_field(rec, vl, "count" as *u8, fct, 64)
566 vr_field(rec, vl, "title" as *u8, ftl, 256)
567 let sd0: i64 = vr_datedays(fdt)
568 vr_civil(sd0, ymd)
569 let iv: i64 = vr_atoi(fiv)
570 let ct: i64 = vr_atoi(fct)
571 var k: i64 = 0
572 while k < ct {
573 let occ: i64 = vr_occ(ffr, sd0, ymd[0], ymd[1], ymd[2], iv, k)
574 var inwin: i64 = 0
575 if occ >= today { if occ <= today + maxlead { inwin = 1 } }
576 if inwin == 1 {
577 let din: i64 = occ - today
578 var hit: i64 = 0
579 var lk: i64 = 0
580 while lk < nlead {
581 if leads[lk] == din { hit = 1 }
582 lk = lk + 1
583 }
584 if hit == 1 {
585 var dso: i64 = vr_daystr(dstr, 0, occ)
586 dstr[dso] = 0 as u8
587 if vr_sent_has(skk, sii, sdd, snp[0], "event" as *u8, fid, dstr) == 1 {
588 o = vr_cat(rep, o, "VIZSLA-REM-SENT-SKIP kind=event id=" as *u8)
589 o = vr_cat(rep, o, fid)
590 o = vr_cat(rep, o, " date=" as *u8)
591 o = vr_cat(rep, o, dstr)
592 o = vr_cat(rep, o, "\n" as *u8)
593 skipped = skipped + 1
594 } else {
595 o = vr_cat(rep, o, "VIZSLA-REM-DUE kind=event id=" as *u8)
596 o = vr_cat(rep, o, fid)
597 o = vr_cat(rep, o, " date=" as *u8)
598 o = vr_cat(rep, o, dstr)
599 o = vr_cat(rep, o, " in=" as *u8)
600 o = vr_catn(rep, o, din)
601 o = vr_cat(rep, o, " title=" as *u8)
602 o = vr_cat(rep, o, ftl)
603 o = vr_cat(rep, o, "\n" as *u8)
604 due_ev = due_ev + 1
605 }
606 }
607 }
608 if occ > today + maxlead { k = ct }
609 k = k + 1
610 }
611 }
612 j = voff + vl
613 }
614 s = s + 1
615 }
616 }
617
618 // contact birthdays
619 if vr_eq(cfile, "-" as *u8) == 0 {
620 let szp: *i64 = sys_mmap(16) as *i64
621 let cb: *u8 = ss_readall(cfile, szp)
622 let csz: i64 = szp[0]
623 if csz <= 0 { vr_p("VIZSLA-REM contacts file MISSING/EMPTY -- fail loud\n" as *u8); return 1 }
624 let t0: *u8 = sys_mmap(128)
625 let cid2: *u8 = sys_mmap(128)
626 let cdisp: *u8 = sys_mmap(256)
627 let ctier: *u8 = sys_mmap(128)
628 let cbd: *u8 = sys_mmap(64)
629 var i: i64 = 0
630 while i < csz {
631 var e: i64 = i
632 var go2: i64 = 1
633 while go2 == 1 {
634 if e >= csz { go2 = 0 } else {
635 if cb[e] == (10 as u8) { go2 = 0 } else { e = e + 1 }
636 }
637 }
638 var p: i64 = vr_tok(cb, i, e, t0, 128)
639 if vr_eq(t0, "CONTACT" as *u8) == 1 {
640 p = vr_tok(cb, p, e, cid2, 128)
641 p = vr_tok(cb, p, e, cdisp, 256)
642 p = vr_tok(cb, p, e, ctier, 128)
643 p = vr_tok(cb, p, e, cbd, 64)
644 if vr_eq(cbd, "-" as *u8) == 0 { if cbd[0] != (0 as u8) {
645 let nxt: i64 = vr_bday_next(cbd, today)
646 if nxt < 0 { vr_p("VIZSLA-REM bad birthday MM-DD -- fail loud\n" as *u8); return 1 }
647 let din: i64 = nxt - today
648 var hit: i64 = 0
649 var lk: i64 = 0
650 while lk < nlead {
651 if leads[lk] == din { hit = 1 }
652 lk = lk + 1
653 }
654 if hit == 1 {
655 var dso: i64 = vr_daystr(dstr, 0, nxt)
656 dstr[dso] = 0 as u8
657 if vr_sent_has(skk, sii, sdd, snp[0], "birthday" as *u8, cid2, dstr) == 1 {
658 o = vr_cat(rep, o, "VIZSLA-REM-SENT-SKIP kind=birthday id=" as *u8)
659 o = vr_cat(rep, o, cid2)
660 o = vr_cat(rep, o, " date=" as *u8)
661 o = vr_cat(rep, o, dstr)
662 o = vr_cat(rep, o, "\n" as *u8)
663 skipped = skipped + 1
664 } else {
665 o = vr_cat(rep, o, "VIZSLA-REM-DUE kind=birthday id=" as *u8)
666 o = vr_cat(rep, o, cid2)
667 o = vr_cat(rep, o, " date=" as *u8)
668 o = vr_cat(rep, o, dstr)
669 o = vr_cat(rep, o, " in=" as *u8)
670 o = vr_catn(rep, o, din)
671 o = vr_cat(rep, o, " title=" as *u8)
672 o = vr_cat(rep, o, cdisp)
673 o = vr_cat(rep, o, "\n" as *u8)
674 due_bd = due_bd + 1
675 }
676 }
677 } }
678 }
679 i = e + 1
680 }
681 }
682
683 o = vr_cat(rep, o, "VIZSLA-REM-VERDICT today=" as *u8)
684 o = vr_cat(rep, o, argv[4] as *u8)
685 o = vr_cat(rep, o, " maxlead=" as *u8)
686 o = vr_catn(rep, o, maxlead)
687 o = vr_cat(rep, o, " due=" as *u8)
688 o = vr_catn(rep, o, due_ev + due_bd)
689 o = vr_cat(rep, o, " due_events=" as *u8)
690 o = vr_catn(rep, o, due_ev)
691 o = vr_cat(rep, o, " due_birthdays=" as *u8)
692 o = vr_catn(rep, o, due_bd)
693 o = vr_cat(rep, o, " skipped_sent=" as *u8)
694 o = vr_catn(rep, o, skipped)
695 o = vr_cat(rep, o, "\n" as *u8)
696 sys_write(1, rep, o)
697 return 0
698}
699
700// ---------------- MARK (sent ledger) ----------------
701func vr_cmd_mark(argc: i64, argv: *i64) -> i64 {
702 if argc < 6 { vr_p("VIZSLA-REM mark needs <sentprefix> <event|birthday> <id> <date> [segid] -- fail loud\n" as *u8); return 1 }
703 let prefix: *u8 = argv[2] as *u8
704 let k: *u8 = argv[3] as *u8
705 let id: *u8 = argv[4] as *u8
706 let date: *u8 = argv[5] as *u8
707 var okk: i64 = 0
708 if vr_eq(k, "event" as *u8) == 1 { okk = 1 }
709 if vr_eq(k, "birthday" as *u8) == 1 { okk = 1 }
710 if okk == 0 { vr_p("VIZSLA-REM mark kind not event|birthday -- fail loud\n" as *u8); return 1 }
711 if vr_datedays(date) < 0 { vr_p("VIZSLA-REM mark bad date -- fail loud\n" as *u8); return 1 }
712 var segid: i64 = 0
713 if argc > 6 { segid = vr_atoi(argv[6] as *u8) }
714 if segid == 0 { segid = sys_now_us() }
715
716 let keys: *i64 = sys_mmap(8 * 8) as *i64
717 let vals: *i64 = sys_mmap(8 * 8) as *i64
718 keys[0] = "kind" as *u8 as i64
719 keys[1] = "k" as *u8 as i64
720 keys[2] = "id" as *u8 as i64
721 keys[3] = "date" as *u8 as i64
722 vals[0] = "snt" as *u8 as i64
723 vals[1] = k as i64
724 vals[2] = id as i64
725 vals[3] = date as i64
726
727 let st: *i64 = sys_mmap(8 * 8) as *i64
728 st[0] = ss_begin() as i64
729 st[1] = sys_mmap(8 * K_MAGIC_2048)
730 st[2] = 0
731 st[3] = 0
732 st[4] = 0
733 st[5] = 0
734 st[6] = prefix as i64
735 if vr_put(keys, vals, 4, "snt:" as *u8, st) != 0 { vr_p("VIZSLA-REM writer full -- fail loud\n" as *u8); return 1 }
736 if st[3] > 0 {
737 if ss_commit(prefix, st[0] as *i64, segid) != 0 { vr_p("VIZSLA-REM commit FAILED -- fail loud\n" as *u8); return 1 }
738 }
739
740 let rep: *u8 = sys_mmap(K_MAGIC_1024)
741 var o: i64 = 0
742 o = vr_cat(rep, o, "VIZSLA-REM-MARK k=" as *u8)
743 o = vr_cat(rep, o, k)
744 o = vr_cat(rep, o, " id=" as *u8)
745 o = vr_cat(rep, o, id)
746 o = vr_cat(rep, o, " date=" as *u8)
747 o = vr_cat(rep, o, date)
748 o = vr_cat(rep, o, " new=" as *u8)
749 o = vr_catn(rep, o, st[3])
750 o = vr_cat(rep, o, "\n" as *u8)
751 sys_write(1, rep, o)
752 return 0
753}
754
755func main(argc: i64, argv: *i64) -> i64 {
756 if argc < 2 { vr_p("VIZSLA-REM usage: due|mark -- fail loud\n" as *u8); return 1 }
757 let cmd: *u8 = argv[1] as *u8
758 if vr_eq(cmd, "due" as *u8) == 1 { return vr_cmd_due(argc, argv) }
759 if vr_eq(cmd, "mark" as *u8) == 1 { return vr_cmd_mark(argc, argv) }
760 vr_p("VIZSLA-REM unknown command (due|mark) -- fail loud\n" as *u8)
761 return 1
762}