view utils/themwi-update-numdb.c @ 124:7e04d28fae8b

sip-in: default use-100rel to no BulkVS servers act badly when we send a reliable 180 Ringing response to an incoming call, even though they advertise 100rel support in the Supported header in the INVITE packet, and we probably won't be implementing 100rel for outbound because doing per-the-spec PRACK as a UAC is just too burdensome. Therefore, we need to consider 100rel extension as not-really-supported in themwi-system-sw.
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 01 Oct 2022 15:54:50 -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);
}