FreeCalypso > hg > themwi-system-sw
comparison utils/themwi-update-numdb2.c @ 226:28441920fb35
beginning of number database version 2
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 13 Aug 2023 22:01:25 -0800 |
parents | utils/themwi-update-numdb.c@4ad5deafaa87 |
children | 7ea6acdb8364 |
comparison
equal
deleted
inserted
replaced
225:243ed87880a1 | 226:28441920fb35 |
---|---|
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 || own_rec.usage != NUMBER_USAGE_TYPE_GSM_SUB) | |
244 return; | |
245 bzero(&short_rec, sizeof short_rec); | |
246 short_rec.short_num = suffix; | |
247 short_rec.short_num_type = SHORT_NUM_TYPE_ABBREV; | |
248 short_rec.fullnum_flags = own_rec.number_flags; | |
249 short_rec.fullnum_prefix[0] = prefix_buf[0]; | |
250 short_rec.fullnum_prefix[1] = prefix_buf[1]; | |
251 enter_short_number(&short_rec); | |
252 } | |
253 | |
254 static void | |
255 handle_full10_line(cp) | |
256 char *cp; | |
257 { | |
258 char *np, full10[11]; | |
259 struct owned_number_rec own_rec; | |
260 | |
261 prefix_set = 0; /* cancel any previous prefix line */ | |
262 for (np = cp; *cp && !isspace(*cp); cp++) | |
263 ; | |
264 if (*cp) | |
265 *cp++ = '\0'; | |
266 if (grok_number_string(np, 1) != 10) { | |
267 fprintf(stderr, | |
268 "number-db2 line %d: full10 requires 10-digit argument\n", | |
269 lineno); | |
270 exit(1); | |
271 } | |
272 dehyphen_number_string(np, full10); | |
273 if (!is_nanp_valid_prefix(full10)) { | |
274 fprintf(stderr, | |
275 "number-db2 line %d: number violates NANP rules\n", | |
276 lineno); | |
277 exit(1); | |
278 } | |
279 bzero(&own_rec, sizeof own_rec); | |
280 own_rec.number[0] = digits3_to_uint16(full10); | |
281 own_rec.number[1] = digits3_to_uint16(full10 + 3); | |
282 own_rec.number[2] = digits4_to_uint16(full10 + 6); | |
283 handle_number_attr(&own_rec, cp); | |
284 enter_owned_number(&own_rec); | |
285 } | |
286 | |
287 static void | |
288 handle_itn_line(cp) | |
289 char *cp; | |
290 { | |
291 char *np; | |
292 struct short_number_rec short_rec; | |
293 | |
294 prefix_set = 0; /* cancel any previous prefix line */ | |
295 for (np = cp; *cp && !isspace(*cp); cp++) | |
296 ; | |
297 if (*cp) | |
298 *cp++ = '\0'; | |
299 if (grok_number_string(np, 0) != 4) { | |
300 fprintf(stderr, | |
301 "number-db2 line %d: itn requires 4-digit argument\n", | |
302 lineno); | |
303 exit(1); | |
304 } | |
305 bzero(&short_rec, sizeof short_rec); | |
306 short_rec.short_num = digits4_to_uint16(np); | |
307 short_rec.short_num_type = SHORT_NUM_TYPE_ITN; | |
308 enter_short_number(&short_rec); | |
309 } | |
310 | |
311 static void | |
312 process_line() | |
313 { | |
314 char *cp, *np; | |
315 void (*handler)(); | |
316 | |
317 if (!index(linebuf, '\n')) { | |
318 fprintf(stderr, | |
319 "number-db2 line %d: too long or missing newline\n", | |
320 lineno); | |
321 exit(1); | |
322 } | |
323 for (cp = linebuf; isspace(*cp); cp++) | |
324 ; | |
325 if (*cp == '\0' || *cp == '#') | |
326 return; | |
327 for (np = cp; *cp && !isspace(*cp); cp++) | |
328 ; | |
329 if (*cp) | |
330 *cp++ = '\0'; | |
331 if (!strcmp(np, "prefix")) | |
332 handler = handle_prefix_line; | |
333 else if (!strcmp(np, "suffix")) | |
334 handler = handle_suffix_line; | |
335 else if (!strcmp(np, "full10")) | |
336 handler = handle_full10_line; | |
337 else if (!strcmp(np, "itn")) | |
338 handler = handle_itn_line; | |
339 else { | |
340 fprintf(stderr, | |
341 "number-db2 line %d: non-understood keyword \"%s\"\n", | |
342 lineno, np); | |
343 exit(1); | |
344 } | |
345 while (isspace(*cp)) | |
346 cp++; | |
347 if (*cp == '\0' || *cp == '#') { | |
348 fprintf(stderr, | |
349 "number-db2 line %d: missing argument after \"%s\" keyword\n", | |
350 lineno, np); | |
351 exit(1); | |
352 } | |
353 handler(cp); | |
354 } | |
355 | |
356 static int | |
357 compare_owned_num(p1, p2) | |
358 struct owned_number_rec *p1, *p2; | |
359 { | |
360 if (p1->number[0] < p2->number[0]) | |
361 return(-1); | |
362 if (p1->number[0] > p2->number[0]) | |
363 return(1); | |
364 if (p1->number[1] < p2->number[1]) | |
365 return(-1); | |
366 if (p1->number[1] > p2->number[1]) | |
367 return(1); | |
368 if (p1->number[2] < p2->number[2]) | |
369 return(-1); | |
370 if (p1->number[2] > p2->number[2]) | |
371 return(1); | |
372 return(0); | |
373 } | |
374 | |
375 static int | |
376 compare_short_num(p1, p2) | |
377 struct short_number_rec *p1, *p2; | |
378 { | |
379 if (p1->short_num < p2->short_num) | |
380 return(-1); | |
381 if (p1->short_num > p2->short_num) | |
382 return(1); | |
383 return(0); | |
384 } | |
385 | |
386 static void | |
387 owned_num_check_dup() | |
388 { | |
389 struct owned_number_rec *p, *endp; | |
390 | |
391 endp = owned_number_buf + owned_number_count - 1; | |
392 for (p = owned_number_buf; p < endp; p++) { | |
393 if (p[0].number[0] == p[1].number[0] && | |
394 p[0].number[1] == p[1].number[1] && | |
395 p[0].number[2] == p[1].number[2]) { | |
396 fprintf(stderr, | |
397 "error: NANP number %03u-%03u-%04u appears more than once\n", | |
398 p[0].number[0], p[0].number[1], p[0].number[2]); | |
399 exit(1); | |
400 } | |
401 } | |
402 } | |
403 | |
404 static void | |
405 short_num_check_dup() | |
406 { | |
407 struct short_number_rec *p, *endp; | |
408 | |
409 endp = short_number_buf + short_number_count - 1; | |
410 for (p = short_number_buf; p < endp; p++) { | |
411 if (p[0].short_num == p[1].short_num) { | |
412 fprintf(stderr, | |
413 "error: short number %04u appears more than once\n", | |
414 (unsigned) p->short_num); | |
415 exit(1); | |
416 } | |
417 } | |
418 } | |
419 | |
420 static void | |
421 emit_output() | |
422 { | |
423 FILE *outf; | |
424 struct numdb_file_hdr hdr; | |
425 | |
426 outf = fopen("number-db2.newbin", "w"); | |
427 if (!outf) { | |
428 perror("creating number-db2.newbin"); | |
429 exit(1); | |
430 } | |
431 hdr.owned_number_count = owned_number_count; | |
432 hdr.short_number_count = short_number_count; | |
433 if (fwrite(&hdr, sizeof hdr, 1, outf) != 1) { | |
434 write_err: fprintf(stderr, "error writing to new binary file\n"); | |
435 exit(1); | |
436 } | |
437 if (fwrite(owned_number_buf, sizeof(owned_number_buf[0]), | |
438 owned_number_count, outf) != owned_number_count) | |
439 goto write_err; | |
440 if (fwrite(short_number_buf, sizeof(short_number_buf[0]), | |
441 short_number_count, outf) != short_number_count) | |
442 goto write_err; | |
443 fclose(outf); | |
444 } | |
445 | |
446 main(argc, argv) | |
447 char **argv; | |
448 { | |
449 if (argc > 2) { | |
450 fprintf(stderr, "usage: %s [directory]\n", argv[0]); | |
451 exit(1); | |
452 } | |
453 if (argv[1]) | |
454 system_dir = argv[1]; | |
455 else | |
456 system_dir = "/var/gsm"; | |
457 if (chdir(system_dir) < 0) { | |
458 perror(system_dir); | |
459 exit(1); | |
460 } | |
461 inf = fopen("number-db2", "r"); | |
462 if (!inf) { | |
463 perror("opening number-db2"); | |
464 exit(1); | |
465 } | |
466 for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) | |
467 process_line(); | |
468 fclose(inf); | |
469 if (owned_number_count >= 2) { | |
470 qsort(owned_number_buf, owned_number_count, | |
471 sizeof(owned_number_buf[0]), compare_owned_num); | |
472 owned_num_check_dup(); | |
473 } | |
474 if (short_number_count >= 2) { | |
475 qsort(short_number_buf, short_number_count, | |
476 sizeof(short_number_buf[0]), compare_short_num); | |
477 short_num_check_dup(); | |
478 } | |
479 emit_output(); | |
480 /* make it live */ | |
481 if (rename("number-db2.newbin", "number-db2.bin") < 0) { | |
482 perror("rename"); | |
483 exit(1); | |
484 } | |
485 exit(0); | |
486 } |