view utils/themwi-update-numdb.c @ 201:d3c99b41fb04

sip-manual-out TFO: rework for continuous output of TFO_REQ
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 02 Apr 2023 18:01:34 -0800
parents 4ad5deafaa87
children
line wrap: on
line source

/*
 * This program reads (parses) ThemWi config file /var/gsm/number-db,
 * generates the compiled binary form of this database, and then makes
 * it live via atomic rename.
 */

#include <ctype.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "../include/number_db_file.h"

#define	MAX_OWNED_NUMBERS	1000
#define	MAX_SHORT_NUMBERS	1000

static uint64_t owned_number_buf[MAX_OWNED_NUMBERS];
static struct short_number_map short_number_buf[MAX_SHORT_NUMBERS];
static unsigned owned_number_count, short_number_count;

static char *system_dir;
static FILE *inf;
static int lineno;
static char linebuf[256], prefix[7];
static int prefix_allows_abbrev;
static uint32_t prefix_int;

static void
enter_owned_number(numstr)
	char *numstr;
{
	if (owned_number_count >= MAX_OWNED_NUMBERS) {
		fprintf(stderr, "error: MAX_OWNED_NUMBERS exceeded\n");
		exit(1);
	}
	owned_number_buf[owned_number_count++] = strtoull(numstr, 0, 10);
}

static void
enter_short_number(numstr, prefix)
	char *numstr;
	uint32_t prefix;
{
	if (short_number_count >= MAX_SHORT_NUMBERS) {
		fprintf(stderr, "error: MAX_SHORT_NUMBERS exceeded\n");
		exit(1);
	}
	short_number_buf[short_number_count].short_code =
		strtoul(numstr, 0, 10);
	short_number_buf[short_number_count].prefix = prefix;
	short_number_count++;
}

static void
handle_prefix_line(cp)
	char *cp;
{
	char *np;

	for (np = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	if (grok_number_string(np, 1) != 6) {
		fprintf(stderr,
			"number-db line %d: prefix requires 6-digit argument\n",
			lineno);
		exit(1);
	}
	dehyphen_number_string(np, prefix);
	if (!is_nanp_valid_prefix(prefix)) {
		fprintf(stderr,
			"number-db line %d: prefix violates NANP rules\n",
			lineno);
		exit(1);
	}
	while (isspace(*cp))
		cp++;
	if (*cp == '\0' || *cp == '#') {
		prefix_allows_abbrev = 0;
		return;
	}
	for (np = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	if (!strcmp(np, "allow-abbrev")) {
		prefix_allows_abbrev = 1;
		prefix_int = strtoul(prefix, 0, 10);
		return;
	}
	fprintf(stderr,
	    "number-db line %d: non-understood notation \"%s\" after prefix\n",
		lineno, np);
	exit(1);
}

static void
handle_suffix_line(cp)
	char *cp;
{
	char *np, full10[11];

	if (!prefix[0]) {
		fprintf(stderr,
	      "number-db line %d: suffix not valid without preceding prefix\n",
			lineno);
		exit(1);
	}
	for (np = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	if (grok_number_string(np, 0) != 4) {
		fprintf(stderr,
			"number-db line %d: suffix requires 4-digit argument\n",
			lineno);
		exit(1);
	}
	strcpy(full10, prefix);
	strcat(full10, np);
	enter_owned_number(full10);
	if (!prefix_allows_abbrev)
		return;
	enter_short_number(np, prefix_int);
}

static void
handle_full10_line(cp)
	char *cp;
{
	char *np, full10[11];

	prefix[0] = '\0';	/* cancel any previous prefix line */
	for (np = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	if (grok_number_string(np, 1) != 10) {
		fprintf(stderr,
		"number-db line %d: full10 requires 10-digit argument\n",
			lineno);
		exit(1);
	}
	dehyphen_number_string(np, full10);
	if (!is_nanp_valid_prefix(full10)) {
		fprintf(stderr,
			"number-db line %d: number violates NANP rules\n",
			lineno);
		exit(1);
	}
	enter_owned_number(full10);
}

static void
handle_itn_line(cp)
	char *cp;
{
	char *np;

	prefix[0] = '\0';	/* cancel any previous prefix line */
	for (np = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	if (grok_number_string(np, 0) != 4) {
		fprintf(stderr,
			"number-db line %d: itn requires 4-digit argument\n",
			lineno);
		exit(1);
	}
	enter_short_number(np, 0);
}

static void
process_line()
{
	char *cp, *np;
	void (*handler)();

	if (!index(linebuf, '\n')) {
		fprintf(stderr,
			"number-db line %d: too long or missing newline\n",
			lineno);
		exit(1);
	}
	for (cp = linebuf; isspace(*cp); cp++)
		;
	if (*cp == '\0' || *cp == '#')
		return;
	for (np = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	if (!strcmp(np, "prefix"))
		handler = handle_prefix_line;
	else if (!strcmp(np, "suffix"))
		handler = handle_suffix_line;
	else if (!strcmp(np, "full10"))
		handler = handle_full10_line;
	else if (!strcmp(np, "itn"))
		handler = handle_itn_line;
	else {
		fprintf(stderr,
			"number-db line %d: non-understood keyword \"%s\"\n",
			lineno, np);
		exit(1);
	}
	while (isspace(*cp))
		cp++;
	if (*cp == '\0' || *cp == '#') {
		fprintf(stderr,
		"number-db line %d: missing argument after \"%s\" keyword\n",
			lineno, np);
		exit(1);
	}
	handler(cp);
}

static int
compare_owned_num(p1, p2)
	uint64_t *p1, *p2;
{
	if (*p1 < *p2)
		return(-1);
	else if (*p1 > *p2)
		return(1);
	else
		return(0);
}

static int
compare_short_num(p1, p2)
	struct short_number_map *p1, *p2;
{
	if (p1->short_code < p2->short_code)
		return(-1);
	else if (p1->short_code > p2->short_code)
		return(1);
	else
		return(0);
}

static void
owned_num_check_dup()
{
	uint64_t *p, *endp;

	endp = owned_number_buf + owned_number_count - 1;
	for (p = owned_number_buf; p < endp; p++) {
		if (p[0] == p[1]) {
			fprintf(stderr,
			"error: NANP number %llu appears more than once\n",
				(unsigned long long) *p);
			exit(1);
		}
	}
}

static void
short_num_check_dup()
{
	struct short_number_map *p, *endp;

	endp = short_number_buf + short_number_count - 1;
	for (p = short_number_buf; p < endp; p++) {
		if (p[0].short_code == p[1].short_code) {
			fprintf(stderr,
			"error: short number %04u appears more than once\n",
				(unsigned) p->short_code);
			exit(1);
		}
	}
}

static void
emit_output()
{
	FILE *outf;
	struct numdb_file_hdr hdr;

	outf = fopen("number-db.newbin", "w");
	if (!outf) {
		perror("creating number-db.newbin");
		exit(1);
	}
	hdr.owned_number_count = owned_number_count;
	hdr.short_number_count = short_number_count;
	if (fwrite(&hdr, sizeof hdr, 1, outf) != 1) {
write_err:	fprintf(stderr, "error writing to new binary file\n");
		exit(1);
	}
	if (fwrite(owned_number_buf, sizeof(owned_number_buf[0]),
		   owned_number_count, outf) != owned_number_count)
		goto write_err;
	if (fwrite(short_number_buf, sizeof(short_number_buf[0]),
		   short_number_count, outf) != short_number_count)
		goto write_err;
	fclose(outf);
}

main(argc, argv)
	char **argv;
{
	if (argc > 2) {
		fprintf(stderr, "usage: %s [directory]\n", argv[0]);
		exit(1);
	}
	if (argv[1])
		system_dir = argv[1];
	else
		system_dir = "/var/gsm";
	if (chdir(system_dir) < 0) {
		perror(system_dir);
		exit(1);
	}
	inf = fopen("number-db", "r");
	if (!inf) {
		perror("opening number-db");
		exit(1);
	}
	for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++)
		process_line();
	fclose(inf);
	if (owned_number_count >= 2) {
		qsort(owned_number_buf, owned_number_count,
			sizeof(owned_number_buf[0]), compare_owned_num);
		owned_num_check_dup();
	}
	if (short_number_count >= 2) {
		qsort(short_number_buf, short_number_count,
			sizeof(short_number_buf[0]), compare_short_num);
		short_num_check_dup();
	}
	emit_output();
	/* make it live */
	if (rename("number-db.newbin", "number-db.bin") < 0) {
		perror("rename");
		exit(1);
	}
	exit(0);
}