isdn4k-utils/isdnlog/tools/telnum.c

470 lines
11 KiB
C

/* telnum.c
* (c) 1999 by Leopold Toetsch <lt@toetsch.at>
*
* telefon number utils
*
* 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.
*
*
* Interface
*
* void initTelNum(void)
* ---------------------
* init the package, call this once on startup
*
* int normalizeNumber(char *number, TELNUM *num, int flag)
* --------------------------------------------------------
* number is "[provider] [country] [area] [msn]"
* country may be name of country
* spaces or '_' are allowd to separate parts of number
* fills struct TELNUM *num with parts of number
* for flag look at telnum.h
* ret 0 .. ok
* ret 1 .. area not found
* ret UNKNOWN .. country not found
*
* Input number e.g.
* 10055 0049 89 1234567
* 100550049891234567
* 1033 Deutschland 89 1234567
* +49 89 1234567
* 089 1234567
* 1234567
*
* char * formatNumber(char* format, TELNUM* num)
* ----------------------------------------------
* takes a format string
* %Np .. Provider
* %Nc .. country +49
* %NC .. countryname
* %Nt .. tld = 2 char isdcode for country
* %Na .. area 89 or 089 if no country/Provider
* %NA .. areaname
* %Nm .. msn
* %f .. full +49 89 12356 (Deutschland, Berlin)
* %F .. full +49 89/12345, Berlin
* %s .. short +48 89 123456
* %l .. long +49 89 12356 - Berlin (DE)
* %n .. number 004889123456
*
* N is number of chars to skip in format if part is not present
* e.g. "%1c %1a %m"
* +4930123 => "+49 39 123"
* 123 => "123" not " 123"
*
*
* char* prefix2provider(int prefix, char* provider)
* --------------------------------------------------------------
* returns formatted provider for prefix
*
* int provider2prefix(char* provider, int*prefix)
* ------------------------------------------------------------
* ret len of provider
*
* void clearNum(TELNUM *num)
* --------------------------
* call this if you have a number on stack or want to reuse it
* normalizeNumber calls this for you
*
* void initNum(TELNUM *num)
* inits a number with myarea, mycountry
* you may set the area yourself prior to calling this
*
*/
#include "dest.h"
#define DEFAULT (UNKNOWN-1)
/* #define DEBUG 1 */
static TELNUM defnum;
static void error (char *fmt, ...)
{
va_list ap;
char msg[BUFSIZ];
va_start (ap, fmt);
vsnprintf (msg, BUFSIZ, fmt, ap);
va_end (ap);
#ifdef STANDALONE
fprintf(stderr, "%s\n", msg);
#else
print_msg(PRT_ERR, "%s\n", msg);
#endif
}
static void _init(void);
void initTelNum(void)
{
if(!vbn)
vbn="";
if (!vbnlen || !*vbnlen) {
error("VBNLEN not defined.\n\tPlease read isdnlog/README\n");
exit(1);
}
_init();
} /* pre_init */
#ifndef STANDALONE
static inline int Isspace(c) {
return isspace(c) || c == '_';
}
#endif
static int split_vbn(char **p, TELNUM *num) {
int l;
if ((l = provider2prefix(*p, &num->nprovider))) {
Strncpy(num->provider, *p, l+1);
*p += l;
return l;
}
return 0;
}
static void clearArea(TELNUM *num, int a) {
strcpy(num->area,a==DEFAULT?defnum.area:"");
strcpy(num->sarea,a==DEFAULT?defnum.sarea:"?");
num->narea= a==DEFAULT?defnum.narea:a;
}
static inline void clearCountry(TELNUM *num, int c) {
*num->scountry='\0';
*num->country='\0';
num->ncountry=c;
}
int normalizeNumber(char *target, TELNUM *num, int flag) {
char *origp=strdup(target);
char *p=origp;
int res=0;
char *q;
clearNum(num);
#if DEBUG
print_msg(PRT_V,"NN %s (Prov %d)=> ",target, num->nprovider);
#endif
if (flag & TN_PROVIDER)
if (!split_vbn(&p, num)) {
num->nprovider=preselect;
Strncpy(num->provider, getProvider(preselect),TN_MAX_PROVIDER_LEN);
}
if (flag & TN_COUNTRY) {
/* subst '00' => '+' */
if (p[0]=='0' && p[1]=='0')
*++p='+';
if (getSpecial(p)) { /* sondernummer */
goto is_sonder;
}
if(!isdigit(*p)) {
res=getDest(p, num);
/* isdnrate is coming with +4319430 but this may be a sondernummer */
if (atoi(mycountry+1) == num->ncountry && (*num->area || *num->msn)) {
q = malloc(strlen(num->area)+strlen(num->msn)+1);
strcpy(q, num->area);
strcat(q, num->msn);
if(getSpecial(q)) { /* sondernummer */
clearCountry(num, 0);
*num->sarea='\0';
Strncpy(num->area, q, TN_MAX_AREA_LEN);
num->narea=atoi(num->area);
*num->msn = '\0';
}
free(q);
}
}
else {
if(getSpecial(p)) { /* sondernummer */
is_sonder:
clearCountry(num, 0);
*num->sarea='\0';
Strncpy(num->area, p, TN_MAX_AREA_LEN);
num->narea=atoi(num->area);
*num->msn = '\0';
}
else {
clearArea(num,DEFAULT);
if (*p == '0') { /* must be distant call in country */
q = malloc(strlen(mycountry)+strlen(p));
strcpy(q, mycountry);
strcat(q, p+1);
free(origp);
origp=p=q;
if (getSpecial(p)) { /* sondernummer */
goto is_sonder;
}
res=getDest(p, num);
}
else
Strncpy(num->msn, p, TN_MAX_MSN_LEN);
}
}
}
free(origp);
#if DEBUG
print_msg(PRT_V,"(%d) %s\n",res,formatNumber("%l Prov %p",num));
#endif
return(res);
}
#define VBN_LEN (*vbnlen-'0')
char *prefix2provider(int prefix, char*s) {
if (prefix < 100)
sprintf(s, "%s%0*d", defnum.vbn, VBN_LEN, prefix);
else
sprintf(s, "%s%03d", defnum.vbn, prefix - 100);
return s;
}
int provider2prefix(char *p, int *prefix) {
char prov[TN_MAX_PROVIDER_LEN];
int l1, l2=0;
char *q;
char *vbns=strdup(vbn);
q = strtok(vbns, ":");
while (q) {
l1=strlen(vbns);
if (!memcmp(p, q, l1)) {
/* Strncpy(num->vbn, q, TN_MAX_VBN_LEN); */
#if DEBUG
print_msg(PRT_V, "VBN \"%s\"\n", q);
#endif
if (p[l1] == '0' && strchr(vbnlen,':')) /* dreistellige Verbindungsnetzbetreiberkennzahl? */
l2 = l1 + 3; /* 1002 is provider UTA in AT */
else
l2 = l1 + VBN_LEN;
Strncpy(prov, p+l1, l2+1-l1);
*prefix = (l2==6) ? 100+atoi(prov) : atoi(prov);
break;
}
q = strtok(0, ":");
}
free(vbns);
return l2;
}
void initNum(TELNUM *num) {
char *s;
if(!*num->area)
Strncpy(num->area, myarea, TN_MAX_AREA_LEN);
num->ncountry=defnum.ncountry;
strcpy(num->scountry,defnum.scountry);
strcpy(num->country,defnum.country);
num->narea=atoi(num->area); /* 1.01 */
s=malloc(strlen(mycountry)+strlen(num->area)+1);
strcpy(s,mycountry);
strcat(s,num->area);
getDest(s, num);
free(s);
strcpy(num->vbn, defnum.vbn);
}
static void _init(void) {
char *s;
clearNum(&defnum);
Strncpy(defnum.area, myarea, TN_MAX_AREA_LEN);
s=malloc(strlen(mycountry)+strlen(myarea)+1);
strcpy(s,mycountry);
strcat(s,myarea);
getDest(s, &defnum);
Strncpy(defnum.vbn, vbn, TN_MAX_VBN_LEN);
}
void clearNum(TELNUM *num) {
/* num->nprovider=UNKNOWN;
strcpy(num->provider,""); */
strcpy(num->area,"");
initNum(num);
strcpy(num->msn,"");
Strncpy(num->vbn, vbn, TN_MAX_VBN_LEN);
}
/* %Np .. Provider
* %Nc .. country +49
* %NC .. countryname
* %Na .. area 89 or 089 if no country/Provider
* %NA .. areaname
* %Nm .. msn
* %f .. full +49 89 12356 (Deutschland, Berlin)
* %s .. short +48 89 123456
* %n .. number 004889123456
* N is number of chars to skip in format if part is not present
* e.g. "%1c %1a %m"
* +4930123 => "+49 30 123"
* 123 => "123" not " 123"
*/
#define SKIP if(skip>0) \
while(skip-- && *p && p[1]) \
p++
char * formatNumber(char* format, TELNUM* num) {
char *s=retstr[++retnum];
char *p, *q, *r;
int first=1;
int skip;
retnum %= MAXRET;
*s = '\0';
for (p=format, q=s; *p; p++) {
if (*p =='%') {
skip = 0;
again:
switch (*++p) {
case 'p':
if (num->nprovider>0) {
q=stpcpy(q, num->provider);
first=0;
}
else
SKIP;
break;
case 'c':
if(num->ncountry>0 && num->country) {
q=stpcpy(q,num->country);
first=0;
}
else
SKIP;
break;
case 'C':
if(num->ncountry>0)
q=stpcpy(q, num->scountry);
else
SKIP;
break;
case 't': /* tld */
if(*num->tld)
q=stpcpy(q, num->tld);
else
SKIP;
break;
case 'a':
if(num->narea>0) {
/* if(first) *q++ = '0'; / sondernummber - no country */
q=stpcpy(q,num->area);
}
else
SKIP;
break;
case 'A':
if(*num->sarea)
q=stpcpy(q,num->sarea);
else
SKIP;
break;
case 'm':
if(*num->msn)
q=stpcpy(q,num->msn);
else
SKIP;
break;
case 'f': q=stpcpy(q,formatNumber("%1c %1a %1m (%2C, %A)", num)); break;
case 'F': if (num->ncountry == defnum.ncountry)
q = stpcpy(q, formatNumber("%1c %1a/%1m, %A", num));
else
q = stpcpy(q, formatNumber("%1c %1a/%1m, %2C, %A", num));
break;
case 's': q=stpcpy(q,formatNumber("%1c %1a %m", num)); break;
case 'l': q=stpcpy(q,formatNumber("%1c %1a %1m - %1A (%t)", num)); break;
case 'n':
if(num->ncountry>0) {
q=stpcpy(r=++q,formatNumber("%c%a%m", num));
r[0]=r[1]='0';
}
else
q=stpcpy(q,formatNumber("%a%m", num));
break;
default:
if (isdigit(*p)) {
skip = strtol(p, &p, 10);
p--;
goto again;
}
}
}
else
*q++ = *p;
}
*q = '\0';
return s;
}
#ifdef TEST_TELNUM
int verbose=0;
static char *myshortname;
static void init()
{
auto char *version, **message;
if (readconfig(myshortname) < 0)
exit(1);
if (verbose)
message = &version;
else
message = NULL;
initHoliday(holifile, message);
if (verbose && *version)
print_msg(PRT_V, "%s\n", version);
initDest("/usr/lib/isdn/dest.gdbm", message); /* Fixme: */
if (verbose && *version)
print_msg(PRT_V, "%s\n", version);
initRate(rateconf, ratefile, zonefile, message);
if (verbose && *version)
print_msg(PRT_V, "%s\n", version);
initTelNum();
} /* init */
static void deinit(void)
{
exitRate();
exitDest();
exitHoliday();
}
int main(int argc, char *argv[], char *envp[])
{
register int i;
TELNUM num;
myname = argv[0];
myshortname = basename(myname);
if(argc>1) {
init();
i = argc-1;
argc++;
while (i--) {
normalizeNumber(argv[argc], &num);
printf("%s => %s\n",argv[argc++], formatNumber("%l", &num);
}
}
return EXIT_SUCCESS;
}
#endif