491 lines
12 KiB
C
491 lines
12 KiB
C
/*
|
|
* Destination handling
|
|
*
|
|
* Copyright 1999 by Leopold Toetsch <lt@toetsch.at>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* Changes:
|
|
*
|
|
* 1.00 08.10.1999 lt Initial Version
|
|
* 1.01 26.07.2000 lt Added cdb support
|
|
*/
|
|
|
|
/* #define DEBUG */
|
|
|
|
#define _DEST_C_
|
|
|
|
#ifdef STANDALONE
|
|
# include <stdlib.h>
|
|
# include <stddef.h>
|
|
# include <stdio.h>
|
|
# ifdef __GLIBC__
|
|
# define __USE_GNU /* for declaration of basename() */
|
|
# endif
|
|
# include <string.h>
|
|
# include <ctype.h>
|
|
# include <stdarg.h>
|
|
# include <time.h>
|
|
# include <unistd.h>
|
|
# include <errno.h>
|
|
|
|
# if !defined(__GLIBC__) && !defined(basename)
|
|
extern const char *basename(const char *name);
|
|
# endif
|
|
|
|
#else
|
|
# include "isdnlog.h"
|
|
# include "tools.h"
|
|
#endif
|
|
|
|
#include "dest.h"
|
|
#include "zone/config.h"
|
|
#include "zone/common.h"
|
|
|
|
#ifndef LENGTH
|
|
#define LENGTH 256
|
|
#endif
|
|
#ifndef UNKNOWN
|
|
#define UNKNOWN -1
|
|
#endif
|
|
#ifdef DESTTEST
|
|
char *Strncpy(char *dest, const char *src, int len);
|
|
char *Strncat(char *dest, const char *src, int len);
|
|
#endif
|
|
|
|
#ifndef min
|
|
#define min(x,y) (x)<(y)?(x):(y)
|
|
#endif
|
|
|
|
static char version[] = "1.01";
|
|
static _DB db; /* our dest.db */
|
|
static int init_ok=0;
|
|
|
|
typedef struct {
|
|
char number[TN_MAX_NUM_LEN];
|
|
TELNUM num;
|
|
int lru;
|
|
} num_cache_t;
|
|
|
|
#define CACHE_SIZE 10
|
|
static num_cache_t num_cache[CACHE_SIZE];
|
|
|
|
static void add_cache(char *number, TELNUM *num) {
|
|
int i, mlru,m;
|
|
mlru=9999;
|
|
m=0;
|
|
for (i=0; i<CACHE_SIZE; i++) {
|
|
if(!*num_cache[i].number) {
|
|
Strncpy(num_cache[i].number, number, TN_MAX_NUM_LEN);
|
|
memcpy(&num_cache[i].num, num, sizeof(TELNUM));
|
|
break;
|
|
}
|
|
if(num_cache[i].lru<mlru) {
|
|
m=i;
|
|
mlru=num_cache[i].lru;
|
|
}
|
|
}
|
|
if(i==CACHE_SIZE) {
|
|
Strncpy(num_cache[m].number, number, TN_MAX_NUM_LEN);
|
|
memcpy(&num_cache[m].num, num, sizeof(TELNUM));
|
|
num_cache[m].lru=1;
|
|
}
|
|
}
|
|
|
|
static int get_cache(char *number, TELNUM *num) {
|
|
int i;
|
|
for (i=0; i<CACHE_SIZE; i++) {
|
|
if (!num_cache[i].number)
|
|
break;
|
|
num_cache[i].lru--;
|
|
if(strcmp(num_cache[i].number, number) == 0) {
|
|
num_cache[i].lru++;
|
|
memcpy((char*)num+offsetof(TELNUM,scountry),
|
|
(char*)&num_cache[i].num+offsetof(TELNUM,scountry),
|
|
sizeof(TELNUM)-offsetof(TELNUM,scountry));
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void warning(char *fmt,...)
|
|
{
|
|
va_list ap;
|
|
char msg[BUFSIZ];
|
|
|
|
va_start(ap, fmt);
|
|
vsnprintf(msg, BUFSIZ, fmt, ap);
|
|
va_end(ap);
|
|
#ifdef STANDALONE
|
|
fprintf(stderr, "WARNING: %s\n", msg);
|
|
#else
|
|
print_msg(PRT_NORMAL, "WARNING: %s\n", msg);
|
|
#endif
|
|
}
|
|
|
|
void exitDest(void)
|
|
{
|
|
CLOSE(db);
|
|
init_ok=0;
|
|
}
|
|
|
|
int initDest(char *path, char **msg)
|
|
{
|
|
static char message[LENGTH];
|
|
char vinfo[] = "vErSiO";
|
|
datum key, value;
|
|
|
|
if (msg)
|
|
*(*msg = message) = '\0';
|
|
if (init_ok == 1)
|
|
return 0;
|
|
else if(init_ok == -1)
|
|
return -1;
|
|
if (!path || !*path) {
|
|
if (msg)
|
|
snprintf(message, LENGTH,
|
|
"Dest V%s: Error: no destination database specified!", version);
|
|
return init_ok = -1;
|
|
}
|
|
if ((db = OPEN(path, READ)) == 0) {
|
|
if (msg)
|
|
snprintf(message, LENGTH,
|
|
"Dest V%s: Error: open '%s': '%s'",
|
|
version, path, GET_ERR);
|
|
return -1;
|
|
}
|
|
/* read info */
|
|
key.dptr = vinfo;
|
|
key.dsize = 7;
|
|
value = FETCH(db, key);
|
|
if (value.dptr == 0) {
|
|
if (msg)
|
|
snprintf(message, LENGTH,
|
|
"Dest V%s: Error: File '%s': no Vinfo",
|
|
version, path);
|
|
exitDest();
|
|
return init_ok = -1;
|
|
}
|
|
if (msg)
|
|
snprintf(message, LENGTH,
|
|
"Dest V%s: File '%s' opened fine - %s", version, path, value.dptr);
|
|
|
|
if (*dbv == 'G')
|
|
free(value.dptr);
|
|
init_ok = 1;
|
|
return 0;
|
|
}
|
|
|
|
static void append(char *dest, char *what)
|
|
{
|
|
if (!what || !*what)
|
|
return;
|
|
if (strcmp(dest, what)) {
|
|
if(*dest)
|
|
Strncat(dest, "/", TN_MAX_SAREA_LEN);
|
|
Strncat(dest, what, TN_MAX_SAREA_LEN);
|
|
}
|
|
}
|
|
|
|
static bool isKey(const char *p)
|
|
{
|
|
bool key;
|
|
|
|
if ( (key = !isdigit(*p)) )
|
|
for (; key && *p; p++)
|
|
if(!isupper(*p) && *p != '_' && !isdigit(*p)) { /* e.g. _DEMD1 */
|
|
key = false;
|
|
break;
|
|
}
|
|
return key;
|
|
}
|
|
|
|
int getDest(char *onumber, TELNUM * num)
|
|
{
|
|
bool first = true;
|
|
size_t len;
|
|
datum key, value, nvalue;
|
|
static char unknown[] = "Unknown";
|
|
char *p, *q, *r = 0, *city = 0, *s, *name;
|
|
int arealen, countrylen, prefixlen;
|
|
char *number = strdup(onumber);
|
|
char dummy[100]; /* V2.7.2.3 kills stack */
|
|
char tld[TN_MAX_TLD_LEN];
|
|
char cc_ndc[TN_MAX_COUNTRY_LEN+TN_MAX_AREA_LEN];
|
|
char dummy2[100]; /* V2.7.2.3 kills stack */
|
|
|
|
#ifdef DEBUG
|
|
printf("getD. %s\n", number);
|
|
#endif
|
|
*dummy = *dummy2 = '\0'; /* for keeping gcc happy */
|
|
*tld='\0';
|
|
*cc_ndc='\0';
|
|
if (get_cache(number, num)) {
|
|
#ifdef DEBUG
|
|
printf("getD (cache). %s %s\n", number, formatNumber("%f",num));
|
|
#endif
|
|
free(number);
|
|
return 0;
|
|
}
|
|
len = strlen(number);
|
|
if (len==2 && isalpha(*number) && isupper(*number))
|
|
Strncpy(tld,number,TN_MAX_TLD_LEN);
|
|
|
|
if (isdigit(*number)) {
|
|
warning("getDest called with local number '%s'", number);
|
|
add_cache(number, num);
|
|
return UNKNOWN;
|
|
}
|
|
countrylen = arealen = prefixlen = 0;
|
|
num->ncountry = 0;
|
|
num->narea = 0;
|
|
*num->area = '\0';
|
|
*num->sarea = '\0';
|
|
*num->scountry = '\0';
|
|
*num->country = '\0';
|
|
*num->msn = '\0';
|
|
*num->keys = '\0';
|
|
if (len > 1 && !isdigit(number[1]) && !isKey(number))
|
|
city = strdup(number);
|
|
again:
|
|
key.dptr = number;
|
|
key.dsize = len;
|
|
value = FETCH(db, key);
|
|
again2:
|
|
if (value.dptr != 0) {
|
|
/* we have a value:
|
|
* it could be
|
|
* :RKEY ... pointer to a KEY
|
|
* :city ... pointer to a city
|
|
* name;code ... top level entry i.e country
|
|
* name;codes[;:KEY] ... region
|
|
* [#len];code;:KEY ... city
|
|
*/
|
|
while (value.dptr && *value.dptr == ':') {
|
|
/* check for city, i.e. lowercase chars */
|
|
if (!isKey(value.dptr + 1)) {
|
|
city = strdup(value.dptr + 1);
|
|
#ifdef DEBUG
|
|
printf("C. %s\n", city);
|
|
#endif
|
|
}
|
|
else {
|
|
append(num->keys, value.dptr + 1);
|
|
Strncpy(tld,value.dptr+1,TN_MAX_TLD_LEN);
|
|
}
|
|
key.dptr = value.dptr + 1;
|
|
key.dsize = value.dsize - 2; /* w/o : and \x0 */
|
|
nvalue = FETCH(db, key);
|
|
if (*dbv == 'G')
|
|
free(value.dptr);
|
|
value = nvalue;
|
|
}
|
|
/* do we have something valid */
|
|
if (value.dptr == 0 && first) {
|
|
strcpy(num->scountry, unknown);
|
|
strcpy(num->sarea, unknown);
|
|
Strncpy(num->msn, number, TN_MAX_MSN_LEN);
|
|
free(number);
|
|
if (city)
|
|
free(city);
|
|
return 0;
|
|
}
|
|
/* now we must have a name or city */
|
|
first = false;
|
|
s = value.dptr;
|
|
p = strsep(&s, ";");
|
|
/* name or #len or empty */
|
|
name = 0;
|
|
#ifdef DEBUG
|
|
printf("1. %s\n", p);
|
|
#endif
|
|
if (p && *p) {
|
|
if (*p == '#')
|
|
prefixlen = atoi(p + 1);
|
|
else
|
|
name = strdup(p);
|
|
}
|
|
|
|
p = strsep(&s, ";");
|
|
/* codes or empty */
|
|
#ifdef DEBUG
|
|
printf("2. %s\n", p);
|
|
#endif
|
|
if (p && *p) {
|
|
q = strtok(p, ","); /* we could have multiple codes */
|
|
if (arealen == 0) { /* first, longest, best matching area code */
|
|
char *n;
|
|
/* for number as input get area code from this number, which is already
|
|
* shortened if necessary (full number in onumber), for name as input
|
|
* use the first number from the dest.DB lookup for this name */
|
|
n = (*number == '+') ? number : q;
|
|
arealen = strlen(n);
|
|
Strncpy(cc_ndc, n, TN_MAX_COUNTRY_LEN+TN_MAX_AREA_LEN);
|
|
}
|
|
if (strstr(cc_ndc, q)) /* only if new number has same prefix */
|
|
countrylen = strlen(q); /* last one must be country */
|
|
else
|
|
r = strtok(NULL, ";"); /* save remaining number codes if any */
|
|
}
|
|
|
|
p = strsep(&s, ";");
|
|
/* :KEY or empty */
|
|
#ifdef DEBUG
|
|
printf("3. %s\n", p);
|
|
#endif
|
|
/* we should be at toplevel i.e country */
|
|
if (!p) {
|
|
|
|
append(num->scountry, name);
|
|
if (!countrylen) /* countrylen missing */
|
|
while (r) { /* test remaining number codes */
|
|
q = strsep(&r, ",");
|
|
if (strstr(cc_ndc, q)) {
|
|
countrylen = strlen(q);
|
|
break;
|
|
}
|
|
}
|
|
if (countrylen && (arealen || prefixlen)) {
|
|
append(num->sarea, city);
|
|
/* if country or area are too long, the exceeding digits will be
|
|
* stored in area or msn. */
|
|
countrylen = min(countrylen, TN_MAX_COUNTRY_LEN-1);
|
|
Strncpy(num->country, cc_ndc, countrylen+1);
|
|
num->ncountry = atoi(num->country+1);
|
|
strcpy(num->tld,tld);
|
|
p = cc_ndc + countrylen;
|
|
arealen -= countrylen;
|
|
if(prefixlen)
|
|
arealen=prefixlen;
|
|
arealen = min(arealen, TN_MAX_AREA_LEN-1);
|
|
Strncpy(num->area, p, 1 + arealen);
|
|
num->narea = atoi(num->area);
|
|
if (*onumber == '+' && strlen(onumber) > arealen + countrylen)
|
|
Strncpy(num->msn, onumber + arealen + countrylen, TN_MAX_MSN_LEN);
|
|
add_cache(onumber, num);
|
|
}
|
|
}
|
|
else if (p && *p == ':') {
|
|
/* do we have a code */
|
|
append(num->sarea, name);
|
|
append(num->keys, p + 1);
|
|
Strncpy(tld,p+1,TN_MAX_TLD_LEN);
|
|
key.dptr = p + 1;
|
|
key.dsize = strlen(p + 1);
|
|
nvalue = FETCH(db, key);
|
|
if (*dbv == 'G')
|
|
free(value.dptr);
|
|
value = nvalue;
|
|
goto again2;
|
|
}
|
|
if (*dbv == 'G')
|
|
free(value.dptr);
|
|
free(number);
|
|
if (city)
|
|
free(city);
|
|
return 0;
|
|
} /* if value */
|
|
else if (first && len && *number == '+') { /* try shorter nums */
|
|
number[--len] = '\0';
|
|
goto again; /* I like it */
|
|
}
|
|
if (number)
|
|
free(number);
|
|
if (city)
|
|
free(city);
|
|
return UNKNOWN;
|
|
}
|
|
|
|
#ifdef STANDALONE
|
|
char *Strncpy(char *dest, const char *src, int len)
|
|
{
|
|
int l = strlen(src);
|
|
|
|
if (l > len - 1)
|
|
l = len - 1;
|
|
strncpy(dest, src, l);
|
|
dest[l] = '\0';
|
|
return dest;
|
|
}
|
|
char *Strncat(char *dest, const char *src, int len)
|
|
{
|
|
int destlen = strlen(dest);
|
|
|
|
return Strncpy(dest + destlen, src, len - destlen);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef DESTTEST
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
char *msg;
|
|
TELNUM num;
|
|
int i = 1, res, verbose = 0;
|
|
|
|
if (initDest("./dest" RDBEXT, &msg)) {
|
|
fprintf(stderr, "%s\n", msg);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
fprintf(stderr, "%s\n", msg);
|
|
if (argc == 1) {
|
|
fprintf(stderr, "Usage:\n\t%s [-v] number|name ...\n", basename(argv[0]));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (!strcmp(argv[i],"-v")) { /* handle verbose option in a pragmatic way */
|
|
verbose++;
|
|
i++;
|
|
argc--;
|
|
}
|
|
memset(&num, 0, sizeof(num));
|
|
while (--argc) {
|
|
res = getDest(argv[i++], &num);
|
|
printf("%s %s(%d)=%s %s(%s) %s - %s\n",
|
|
res == 0 ? "Ok." : "Err", num.country, num.ncountry, num.scountry,
|
|
num.sarea, num.area,
|
|
num.msn, num.keys);
|
|
|
|
if (verbose) { /* show TELNUM structure in detail */
|
|
printf("\nThe struct TELNUM for it:\n");
|
|
printf(" .vbn (%2d of %2d): %s\n",
|
|
strlen(num.vbn), TN_MAX_VBN_LEN-1, num.vbn);
|
|
printf(" .provider (%2d of %2d): %s\n",
|
|
strlen(num.provider), TN_MAX_PROVIDER_LEN-1, num.provider);
|
|
printf(" .nprovider : %i\n", num.nprovider);
|
|
printf(" .scountry (%2d of %2d): %s\n",
|
|
strlen(num.scountry), TN_MAX_SCOUNTRY_LEN-1, num.scountry);
|
|
printf(" .country (%2d of %2d): %s\n",
|
|
strlen(num.country), TN_MAX_COUNTRY_LEN-1, num.country);
|
|
printf(" .keys (%2d of %2d): %s\n",
|
|
strlen(num.keys), TN_MAX_SCOUNTRY_LEN-1, num.keys);
|
|
printf(" .tld (%2d of %2d): %s\n",
|
|
strlen(num.tld), TN_MAX_TLD_LEN-1, num.tld);
|
|
printf(" .ncountry : %i\n", num.ncountry);
|
|
printf(" .area (%2d of %2d): %s\n",
|
|
strlen(num.area), TN_MAX_AREA_LEN-1, num.area);
|
|
printf(" .narea : %i\n", num.narea);
|
|
printf(" .sarea (%2d of %2d): %s\n",
|
|
strlen(num.sarea), TN_MAX_SAREA_LEN-1, num.sarea);
|
|
printf(" .msn (%2d of %2d): %s\n\n",
|
|
strlen(num.msn), TN_MAX_MSN_LEN-1, num.msn);
|
|
}
|
|
}
|
|
exitDest();
|
|
return (EXIT_SUCCESS);
|
|
}
|
|
#endif
|