FreeCalypso > hg > themwi-nanp
comparison utils/themwi-update-numdb.c @ 2:1773886ef54e
themwi-update-numdb: old source as starting point
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Wed, 13 Dec 2023 01:23:47 +0000 |
parents | |
children | 5bf2648e5413 |
comparison
equal
deleted
inserted
replaced
1:6534965175dd | 2:1773886ef54e |
---|---|
1 /* | |
2 * This program reads (parses) ThemWi config file /var/gsm/number-db2, | |
3 * generates the compiled binary form of this database, and then makes | |
4 * it live via atomic rename. | |
5 */ | |
6 | |
7 #include <ctype.h> | |
8 #include <stdio.h> | |
9 #include <stdint.h> | |
10 #include <stdlib.h> | |
11 #include <string.h> | |
12 #include <strings.h> | |
13 #include <unistd.h> | |
14 #include "../include/number_db_v2.h" | |
15 | |
16 #define MAX_OWNED_NUMBERS 1000 | |
17 #define MAX_SHORT_NUMBERS 1000 | |
18 | |
19 static struct owned_number_rec owned_number_buf[MAX_OWNED_NUMBERS]; | |
20 static struct short_number_rec short_number_buf[MAX_SHORT_NUMBERS]; | |
21 static unsigned owned_number_count, short_number_count; | |
22 | |
23 static char *system_dir; | |
24 static FILE *inf; | |
25 static int lineno; | |
26 static char linebuf[256]; | |
27 static int prefix_set, prefix_allows_abbrev; | |
28 static uint16_t prefix_buf[2]; | |
29 | |
30 static void | |
31 enter_owned_number(rec) | |
32 struct owned_number_rec *rec; | |
33 { | |
34 if (owned_number_count >= MAX_OWNED_NUMBERS) { | |
35 fprintf(stderr, "error: MAX_OWNED_NUMBERS exceeded\n"); | |
36 exit(1); | |
37 } | |
38 bcopy(rec, owned_number_buf + owned_number_count, | |
39 sizeof(struct owned_number_rec)); | |
40 owned_number_count++; | |
41 } | |
42 | |
43 static void | |
44 enter_short_number(rec) | |
45 struct short_number_rec *rec; | |
46 { | |
47 if (short_number_count >= MAX_SHORT_NUMBERS) { | |
48 fprintf(stderr, "error: MAX_SHORT_NUMBERS exceeded\n"); | |
49 exit(1); | |
50 } | |
51 bcopy(rec, short_number_buf + short_number_count, | |
52 sizeof(struct short_number_rec)); | |
53 short_number_count++; | |
54 } | |
55 | |
56 static void | |
57 handle_prefix_line(cp) | |
58 char *cp; | |
59 { | |
60 char *np, prefix[7]; | |
61 | |
62 for (np = cp; *cp && !isspace(*cp); cp++) | |
63 ; | |
64 if (*cp) | |
65 *cp++ = '\0'; | |
66 if (grok_number_string(np, 1) != 6) { | |
67 fprintf(stderr, | |
68 "number-db2 line %d: prefix requires 6-digit argument\n", | |
69 lineno); | |
70 exit(1); | |
71 } | |
72 dehyphen_number_string(np, prefix); | |
73 if (!is_nanp_valid_prefix(prefix)) { | |
74 fprintf(stderr, | |
75 "number-db2 line %d: prefix violates NANP rules\n", | |
76 lineno); | |
77 exit(1); | |
78 } | |
79 prefix_buf[0] = digits3_to_uint16(prefix); | |
80 prefix_buf[1] = digits3_to_uint16(prefix + 3); | |
81 prefix_set = 1; | |
82 while (isspace(*cp)) | |
83 cp++; | |
84 if (*cp == '\0' || *cp == '#') { | |
85 prefix_allows_abbrev = 0; | |
86 return; | |
87 } | |
88 for (np = cp; *cp && !isspace(*cp); cp++) | |
89 ; | |
90 if (*cp) | |
91 *cp++ = '\0'; | |
92 if (!strcmp(np, "allow-abbrev")) { | |
93 prefix_allows_abbrev = 1; | |
94 return; | |
95 } | |
96 fprintf(stderr, | |
97 "number-db2 line %d: non-understood notation \"%s\" after prefix\n", | |
98 lineno, np); | |
99 exit(1); | |
100 } | |
101 | |
102 static int | |
103 parse_extra_number(rec, numstr) | |
104 struct owned_number_rec *rec; | |
105 char *numstr; | |
106 { | |
107 char buf[11]; | |
108 int rc; | |
109 | |
110 rc = grok_number_string(numstr, 1); | |
111 switch (rc) { | |
112 case 4: | |
113 if (!prefix_set) | |
114 return(-1); | |
115 dehyphen_number_string(numstr, buf); | |
116 rec->remap[0] = prefix_buf[0]; | |
117 rec->remap[1] = prefix_buf[1]; | |
118 rec->remap[2] = digits4_to_uint16(buf); | |
119 return(0); | |
120 case 10: | |
121 dehyphen_number_string(numstr, buf); | |
122 rec->remap[0] = digits3_to_uint16(buf); | |
123 rec->remap[1] = digits3_to_uint16(buf + 3); | |
124 rec->remap[2] = digits4_to_uint16(buf + 6); | |
125 return(0); | |
126 default: | |
127 return(-1); | |
128 } | |
129 } | |
130 | |
131 static void | |
132 handle_number_attr(rec, tail) | |
133 struct owned_number_rec *rec; | |
134 char *tail; | |
135 { | |
136 char *cp, *np; | |
137 int rc; | |
138 | |
139 for (cp = tail; ; ) { | |
140 while (isspace(*cp)) | |
141 cp++; | |
142 if (*cp == '\0' || *cp == '#') | |
143 return; | |
144 for (np = cp; *cp && !isspace(*cp); cp++) | |
145 ; | |
146 if (*cp) | |
147 *cp++ = '\0'; | |
148 if (!strcmp(np, "sms")) | |
149 rec->number_flags |= NUMBER_FLAG_SMSPROV; | |
150 else if (!strcmp(np, "e911")) | |
151 rec->number_flags |= NUMBER_FLAG_E911PROV; | |
152 else if (!strcmp(np, "gsm-sub")) | |
153 rec->usage = NUMBER_USAGE_TYPE_GSM_SUB; | |
154 else if (!strcmp(np, "map-to")) { | |
155 rec->usage = NUMBER_USAGE_TYPE_ALIAS; | |
156 while (isspace(*cp)) | |
157 cp++; | |
158 if (*cp == '\0' || *cp == '#') { | |
159 fprintf(stderr, | |
160 "number-db2 line %d: map-to requires an argument\n", | |
161 lineno); | |
162 exit(1); | |
163 } | |
164 for (np = cp; *cp && !isspace(*cp); cp++) | |
165 ; | |
166 if (*cp) | |
167 *cp++ = '\0'; | |
168 rc = parse_extra_number(rec, np); | |
169 if (rc < 0) { | |
170 fprintf(stderr, | |
171 "number-db2 line %d: map-to argument is invalid\n", | |
172 lineno); | |
173 exit(1); | |
174 } | |
175 } else if (!strcmp(np, "e911-via")) { | |
176 if (rec->usage != NUMBER_USAGE_TYPE_GSM_SUB) { | |
177 fprintf(stderr, | |
178 "number-db2 line %d: invalid usage of e911-via\n", | |
179 lineno); | |
180 exit(1); | |
181 } | |
182 rec->usage |= NUMBER_USAGE_FLAG_E911_VIA; | |
183 while (isspace(*cp)) | |
184 cp++; | |
185 if (*cp == '\0' || *cp == '#') { | |
186 fprintf(stderr, | |
187 "number-db2 line %d: e911-via requires an argument\n", | |
188 lineno); | |
189 exit(1); | |
190 } | |
191 for (np = cp; *cp && !isspace(*cp); cp++) | |
192 ; | |
193 if (*cp) | |
194 *cp++ = '\0'; | |
195 rc = parse_extra_number(rec, np); | |
196 if (rc < 0) { | |
197 fprintf(stderr, | |
198 "number-db2 line %d: e911-via argument is invalid\n", | |
199 lineno); | |
200 exit(1); | |
201 } | |
202 } else { | |
203 fprintf(stderr, | |
204 "number-db2 line %d: invalid attribute \"%s\"\n", | |
205 lineno, np); | |
206 exit(1); | |
207 } | |
208 } | |
209 } | |
210 | |
211 static void | |
212 handle_suffix_line(cp) | |
213 char *cp; | |
214 { | |
215 char *np; | |
216 uint16_t suffix; | |
217 struct owned_number_rec own_rec; | |
218 struct short_number_rec short_rec; | |
219 | |
220 if (!prefix_set) { | |
221 fprintf(stderr, | |
222 "number-db2 line %d: suffix not valid without preceding prefix\n", | |
223 lineno); | |
224 exit(1); | |
225 } | |
226 for (np = cp; *cp && !isspace(*cp); cp++) | |
227 ; | |
228 if (*cp) | |
229 *cp++ = '\0'; | |
230 if (grok_number_string(np, 0) != 4) { | |
231 fprintf(stderr, | |
232 "number-db2 line %d: suffix requires 4-digit argument\n", | |
233 lineno); | |
234 exit(1); | |
235 } | |
236 suffix = digits4_to_uint16(np); | |
237 bzero(&own_rec, sizeof own_rec); | |
238 own_rec.number[0] = prefix_buf[0]; | |
239 own_rec.number[1] = prefix_buf[1]; | |
240 own_rec.number[2] = suffix; | |
241 handle_number_attr(&own_rec, cp); | |
242 enter_owned_number(&own_rec); | |
243 if (!prefix_allows_abbrev) | |
244 return; | |
245 if ((own_rec.usage & NUMBER_USAGE_MASK) != NUMBER_USAGE_TYPE_GSM_SUB) | |
246 return; | |
247 bzero(&short_rec, sizeof short_rec); | |
248 short_rec.short_num = suffix; | |
249 short_rec.short_num_type = SHORT_NUM_TYPE_ABBREV; | |
250 short_rec.fullnum_flags = own_rec.number_flags; | |
251 short_rec.fullnum_prefix[0] = prefix_buf[0]; | |
252 short_rec.fullnum_prefix[1] = prefix_buf[1]; | |
253 enter_short_number(&short_rec); | |
254 } | |
255 | |
256 static void | |
257 handle_full10_line(cp) | |
258 char *cp; | |
259 { | |
260 char *np, full10[11]; | |
261 struct owned_number_rec own_rec; | |
262 | |
263 prefix_set = 0; /* cancel any previous prefix line */ | |
264 for (np = cp; *cp && !isspace(*cp); cp++) | |
265 ; | |
266 if (*cp) | |
267 *cp++ = '\0'; | |
268 if (grok_number_string(np, 1) != 10) { | |
269 fprintf(stderr, | |
270 "number-db2 line %d: full10 requires 10-digit argument\n", | |
271 lineno); | |
272 exit(1); | |
273 } | |
274 dehyphen_number_string(np, full10); | |
275 if (!is_nanp_valid_prefix(full10)) { | |
276 fprintf(stderr, | |
277 "number-db2 line %d: number violates NANP rules\n", | |
278 lineno); | |
279 exit(1); | |
280 } | |
281 bzero(&own_rec, sizeof own_rec); | |
282 own_rec.number[0] = digits3_to_uint16(full10); | |
283 own_rec.number[1] = digits3_to_uint16(full10 + 3); | |
284 own_rec.number[2] = digits4_to_uint16(full10 + 6); | |
285 handle_number_attr(&own_rec, cp); | |
286 enter_owned_number(&own_rec); | |
287 } | |
288 | |
289 static void | |
290 handle_itn_line(cp) | |
291 char *cp; | |
292 { | |
293 char *np; | |
294 struct short_number_rec short_rec; | |
295 | |
296 prefix_set = 0; /* cancel any previous prefix line */ | |
297 for (np = cp; *cp && !isspace(*cp); cp++) | |
298 ; | |
299 if (*cp) | |
300 *cp++ = '\0'; | |
301 if (grok_number_string(np, 0) != 4) { | |
302 fprintf(stderr, | |
303 "number-db2 line %d: itn requires 4-digit argument\n", | |
304 lineno); | |
305 exit(1); | |
306 } | |
307 bzero(&short_rec, sizeof short_rec); | |
308 short_rec.short_num = digits4_to_uint16(np); | |
309 short_rec.short_num_type = SHORT_NUM_TYPE_ITN; | |
310 enter_short_number(&short_rec); | |
311 } | |
312 | |
313 static void | |
314 handle_test_sink_line(cp) | |
315 char *cp; | |
316 { | |
317 char *np; | |
318 struct short_number_rec short_rec; | |
319 | |
320 prefix_set = 0; /* cancel any previous prefix line */ | |
321 for (np = cp; *cp && !isspace(*cp); cp++) | |
322 ; | |
323 if (*cp) | |
324 *cp++ = '\0'; | |
325 if (grok_number_string(np, 0) != 4) { | |
326 fprintf(stderr, | |
327 "number-db2 line %d: test-sink requires 4-digit argument\n", | |
328 lineno); | |
329 exit(1); | |
330 } | |
331 bzero(&short_rec, sizeof short_rec); | |
332 short_rec.short_num = digits4_to_uint16(np); | |
333 short_rec.short_num_type = SHORT_NUM_TYPE_TEST_SINK; | |
334 enter_short_number(&short_rec); | |
335 } | |
336 | |
337 static void | |
338 process_line() | |
339 { | |
340 char *cp, *np; | |
341 void (*handler)(); | |
342 | |
343 if (!index(linebuf, '\n')) { | |
344 fprintf(stderr, | |
345 "number-db2 line %d: too long or missing newline\n", | |
346 lineno); | |
347 exit(1); | |
348 } | |
349 for (cp = linebuf; isspace(*cp); cp++) | |
350 ; | |
351 if (*cp == '\0' || *cp == '#') | |
352 return; | |
353 for (np = cp; *cp && !isspace(*cp); cp++) | |
354 ; | |
355 if (*cp) | |
356 *cp++ = '\0'; | |
357 if (!strcmp(np, "prefix")) | |
358 handler = handle_prefix_line; | |
359 else if (!strcmp(np, "suffix")) | |
360 handler = handle_suffix_line; | |
361 else if (!strcmp(np, "full10")) | |
362 handler = handle_full10_line; | |
363 else if (!strcmp(np, "itn")) | |
364 handler = handle_itn_line; | |
365 else if (!strcmp(np, "test-sink")) | |
366 handler = handle_test_sink_line; | |
367 else { | |
368 fprintf(stderr, | |
369 "number-db2 line %d: non-understood keyword \"%s\"\n", | |
370 lineno, np); | |
371 exit(1); | |
372 } | |
373 while (isspace(*cp)) | |
374 cp++; | |
375 if (*cp == '\0' || *cp == '#') { | |
376 fprintf(stderr, | |
377 "number-db2 line %d: missing argument after \"%s\" keyword\n", | |
378 lineno, np); | |
379 exit(1); | |
380 } | |
381 handler(cp); | |
382 } | |
383 | |
384 static int | |
385 compare_owned_num(p1, p2) | |
386 uint16_t *p1, *p2; | |
387 { | |
388 if (p1[0] < p2[0]) | |
389 return(-1); | |
390 if (p1[0] > p2[0]) | |
391 return(1); | |
392 if (p1[1] < p2[1]) | |
393 return(-1); | |
394 if (p1[1] > p2[1]) | |
395 return(1); | |
396 if (p1[2] < p2[2]) | |
397 return(-1); | |
398 if (p1[2] > p2[2]) | |
399 return(1); | |
400 return(0); | |
401 } | |
402 | |
403 static int | |
404 compare_short_num(p1, p2) | |
405 uint16_t *p1, *p2; | |
406 { | |
407 if (*p1 < *p2) | |
408 return(-1); | |
409 if (*p1 > *p2) | |
410 return(1); | |
411 return(0); | |
412 } | |
413 | |
414 static void | |
415 owned_num_check_dup() | |
416 { | |
417 struct owned_number_rec *p, *endp; | |
418 | |
419 endp = owned_number_buf + owned_number_count - 1; | |
420 for (p = owned_number_buf; p < endp; p++) { | |
421 if (p[0].number[0] == p[1].number[0] && | |
422 p[0].number[1] == p[1].number[1] && | |
423 p[0].number[2] == p[1].number[2]) { | |
424 fprintf(stderr, | |
425 "error: NANP number %03u-%03u-%04u appears more than once\n", | |
426 p[0].number[0], p[0].number[1], p[0].number[2]); | |
427 exit(1); | |
428 } | |
429 } | |
430 } | |
431 | |
432 static void | |
433 short_num_check_dup() | |
434 { | |
435 struct short_number_rec *p, *endp; | |
436 | |
437 endp = short_number_buf + short_number_count - 1; | |
438 for (p = short_number_buf; p < endp; p++) { | |
439 if (p[0].short_num == p[1].short_num) { | |
440 fprintf(stderr, | |
441 "error: short number %04u appears more than once\n", | |
442 (unsigned) p->short_num); | |
443 exit(1); | |
444 } | |
445 } | |
446 } | |
447 | |
448 static void | |
449 check_secondnum_mapto(src) | |
450 struct owned_number_rec *src; | |
451 { | |
452 struct owned_number_rec *dest; | |
453 | |
454 dest = bsearch(src->remap, owned_number_buf, owned_number_count, | |
455 sizeof(struct owned_number_rec), compare_owned_num); | |
456 if (!dest) { | |
457 fprintf(stderr, | |
458 "error: NANP %03u-%03u-%04u map-to target is not in the database\n", | |
459 src->number[0], src->number[1], src->number[2]); | |
460 exit(1); | |
461 } | |
462 if ((dest->usage & NUMBER_USAGE_MASK) != NUMBER_USAGE_TYPE_GSM_SUB) { | |
463 fprintf(stderr, | |
464 "error: NANP %03u-%03u-%04u map-to target is not a gsm-sub number\n", | |
465 src->number[0], src->number[1], src->number[2]); | |
466 exit(1); | |
467 } | |
468 } | |
469 | |
470 static void | |
471 check_secondnum_e911via(src) | |
472 struct owned_number_rec *src; | |
473 { | |
474 struct owned_number_rec *dest; | |
475 | |
476 dest = bsearch(src->remap, owned_number_buf, owned_number_count, | |
477 sizeof(struct owned_number_rec), compare_owned_num); | |
478 if (!dest) { | |
479 fprintf(stderr, | |
480 "error: NANP %03u-%03u-%04u e911-via target is not in the database\n", | |
481 src->number[0], src->number[1], src->number[2]); | |
482 exit(1); | |
483 } | |
484 if (!(dest->number_flags & NUMBER_FLAG_E911PROV)) { | |
485 fprintf(stderr, | |
486 "error: NANP %03u-%03u-%04u e911-via target is not an E911 number\n", | |
487 src->number[0], src->number[1], src->number[2]); | |
488 exit(1); | |
489 } | |
490 } | |
491 | |
492 static void | |
493 check_secondary_numbers() | |
494 { | |
495 struct owned_number_rec *p, *endp; | |
496 | |
497 endp = owned_number_buf + owned_number_count; | |
498 for (p = owned_number_buf; p < endp; p++) { | |
499 if ((p->usage & NUMBER_USAGE_MASK) == NUMBER_USAGE_TYPE_ALIAS) | |
500 check_secondnum_mapto(p); | |
501 if (p->usage & NUMBER_USAGE_FLAG_E911_VIA) | |
502 check_secondnum_e911via(p); | |
503 } | |
504 } | |
505 | |
506 static void | |
507 emit_output() | |
508 { | |
509 FILE *outf; | |
510 struct numdb_file_hdr hdr; | |
511 | |
512 outf = fopen("number-db2.newbin", "w"); | |
513 if (!outf) { | |
514 perror("creating number-db2.newbin"); | |
515 exit(1); | |
516 } | |
517 hdr.owned_number_count = owned_number_count; | |
518 hdr.short_number_count = short_number_count; | |
519 if (fwrite(&hdr, sizeof hdr, 1, outf) != 1) { | |
520 write_err: fprintf(stderr, "error writing to new binary file\n"); | |
521 exit(1); | |
522 } | |
523 if (fwrite(owned_number_buf, sizeof(owned_number_buf[0]), | |
524 owned_number_count, outf) != owned_number_count) | |
525 goto write_err; | |
526 if (fwrite(short_number_buf, sizeof(short_number_buf[0]), | |
527 short_number_count, outf) != short_number_count) | |
528 goto write_err; | |
529 fclose(outf); | |
530 } | |
531 | |
532 main(argc, argv) | |
533 char **argv; | |
534 { | |
535 if (argc > 2) { | |
536 fprintf(stderr, "usage: %s [directory]\n", argv[0]); | |
537 exit(1); | |
538 } | |
539 if (argv[1]) | |
540 system_dir = argv[1]; | |
541 else | |
542 system_dir = "/var/gsm"; | |
543 if (chdir(system_dir) < 0) { | |
544 perror(system_dir); | |
545 exit(1); | |
546 } | |
547 inf = fopen("number-db2", "r"); | |
548 if (!inf) { | |
549 perror("opening number-db2"); | |
550 exit(1); | |
551 } | |
552 for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) | |
553 process_line(); | |
554 fclose(inf); | |
555 if (owned_number_count >= 2) { | |
556 qsort(owned_number_buf, owned_number_count, | |
557 sizeof(owned_number_buf[0]), compare_owned_num); | |
558 owned_num_check_dup(); | |
559 } | |
560 check_secondary_numbers(); | |
561 if (short_number_count >= 2) { | |
562 qsort(short_number_buf, short_number_count, | |
563 sizeof(short_number_buf[0]), compare_short_num); | |
564 short_num_check_dup(); | |
565 } | |
566 emit_output(); | |
567 /* make it live */ | |
568 if (rename("number-db2.newbin", "number-db2.bin") < 0) { | |
569 perror("rename"); | |
570 exit(1); | |
571 } | |
572 exit(0); | |
573 } |