u-isdn/isdn_4/match.c

863 lines
26 KiB
C

/*
* This file is part of the ISDN master program.
*
* Copyright (C) 1995 Matthias Urlichs.
* See the file COPYING for license details.
*/
#include "master.h"
void
syncflags(conninfo conn, char set)
{
if(conn->cg == NULL)
return;
if(((conn->cg->flags & F_MASKFLAGS) == 0) || ((conn->cg->flags & F_MASKFLAGS) == F_DIALFLAGS)) {
conn->flags = (conn->flags & F_MASKFLAGS) | (conn->cg->flags & ~F_MASKFLAGS);
} else {
if(set)
conn->flags |= (conn->cg->flags & F_MOVEFLAGS & ~F_DIALFLAGS);
else
conn->flags = conn->cg->flags;
}
}
/* Verify that the connection mode matches the stated flags. */
long
matchflag(long flags, char *ts)
{
char inc,outg,leas,perm,dial,mdial,ini,aft;
ini = (strchr(ts,'u') != NULL);
aft = (strchr(ts,'a') != NULL);
inc = (strchr(ts,'i') != NULL);
outg= (strchr(ts,'o') != NULL);
leas= (strchr(ts,'f') != NULL);
perm= (strchr(ts,'p') != NULL);
dial= (strchr(ts,'d') != NULL);
mdial=(strchr(ts,'m') != NULL);
if(flags & F_SETINITIAL) { if (aft && !ini) return 0; }
if(flags & F_SETLATER) { if (!aft && ini) return 0; }
if(flags & F_OUTGOING) { if (inc && !outg) return 0; }
if(flags & F_INCOMING) { if (!inc && outg) return 0; }
if(!(leas || dial || perm)) goto set;
if(!(flags & (F_LEASED|F_PERMANENT|F_MULTIDIALUP|F_DIALUP))) goto set;
if((flags & F_LEASED) && leas) goto set;
if((flags & F_PERMANENT) && perm) goto set;
if((flags & F_DIALUP) && dial) goto set;
if((flags & F_MULTIDIALUP) && mdial) goto set;
return 0;
set:
if(ini) flags |= F_SETINITIAL;
if(aft) flags |= F_SETLATER;
if(inc) flags |= F_INCOMING;
if(outg) flags |= F_OUTGOING;
if(leas) flags |= F_LEASED;
if(perm) flags |= F_PERMANENT;
if(dial) flags |= F_DIALUP;
if(mdial)flags |= F_MULTIDIALUP;
return flags | F_FOOBAR;
}
/* Check if this P-line matches a connection request */
char *
pmatch1 (cf prot, conngrab *cgm)
{
char *sit, *pro, *cla, *car;
long flg;
ulong_t sub;
char first = 1;
conngrab cg = *cgm;
chkone(prot); chkone(cg);
/* Basic preprocessing */
sit = wildmatch(cg->site, prot->site); if(sit == NULL) return "7ERR Match SITE";
pro = wildmatch(cg->protocol,prot->protocol);if(pro == NULL) return "7ERR Match PROTOCOL";
car = wildmatch(cg->card, prot->card); if(car == NULL) return "5ERR Match CARD";
cla =classmatch(cg->cclass, prot->cclass); if(cla == NULL) return "4ERR Match CLASS";
sub = maskmatch(cg->mask, prot->mask); if(sub == 0) return "6ERR Match SUBCARD";
if(!classmatch(cla,theclass)) return("2Not Now");
/* OK, that fits. Make a copy to assign the values to. */
cg = newgrab(cg);
if(cg == NULL)
return "0OUT OF MEMORY";
cg->site = sit; cg->protocol = pro; cg->card = car; cg->cclass = cla;
cg->mask = sub;
/* Now scan this line's, and all matching followup lines', flags. */
for (first = 1; prot != NULL; prot = prot->next, first = 0) {
#define ARG_IN 01
#define ARG_OUT 02
char nrt = ARG_IN|ARG_OUT;
ushort_t id;
conngrab cgc = NULL;
mblk_t *cand = NULL;
streamchar *mbs_in = NULL, *mbs_out = NULL;
if((flg = matchflag(cg->flags,prot->type)) == 0) { if(first) {
if(0)printf(":BadFlag %s for 0%o\n",prot->type,cg->flags);
dropgrab(cg); return "5ERR BadFlag"; } else continue;}
if (first) {
if (strchr (prot->type, 'M')) { /* First Match not allowed. */
dropgrab(cg);
return "7ERR FIND NotFirst";
}
} else {
if (strchr (prot->type, 'R')) /* First Match only. */
goto Ex;
sit = wildmatch(cg->site, prot->site); if(sit==NULL) continue;
pro = wildmatch(cg->protocol,prot->protocol);if(pro==NULL) continue;
car = wildmatch(cg->card, prot->card); if(car==NULL) continue;
cla =classmatch(cg->cclass, prot->cclass); if(cla==NULL) continue;
sub = maskmatch(cg->mask, prot->mask); if(sub==0) continue;
if(!classmatch(cla,theclass)) continue;
}
/* Now make another copy for the parameters. If they don't fit
we'll have to undo everything. This is stupid but there is no
other way to do it, for now -- we'll use a cache sometime soon. */
cgc = newgrab(cg);
if(cgc == NULL) {
dropgrab(cg);
return "0OUT OF MEMORY";
}
if(!first) {
cgc->site = sit; cgc->protocol = pro; cgc->card = car; cgc->cclass = cla;
cgc->mask = sub; cgc->flags = flg;
}
if(cgc->retries == 0 && prot->num != 0)
cgc->retries = prot->num;
if(cgc->mintime == 0 && prot->num2 != 0)
cgc->mintime = prot->num2;
if(cgc->par_out == NULL) { /* No outgoing parameter list? Yet! */
if ((cgc->par_out = allocb(256,BPRI_LO)) == NULL) {
dropgrab(cgc); dropgrab(cg);
return "0OUT of MEMORY";
}
}
#define DG(str,a,b) do { if(first) { \
char sf[50]; sprintf(sf,"%s %s %s",(str),(a),(b)); \
dropgrab(cgc); dropgrab(cg); \
return str_enter(sf); \
} goto Ex; } while(0)
/* Remember pointers into the parameter strings. */
mbs_in = ((cgc->par_in !=NULL)? cgc->par_in->b_rptr : NULL);
mbs_out= ((cgc->par_out!=NULL)? cgc->par_out->b_rptr: NULL);
/* Allocate a new candidate string for outgoing parameters. */
cand = allocsb (strlen (prot->args), (streamchar *)prot->args);
if(cand == NULL)
goto Ex;
while (m_getsx (cand, &id) == 0) {
/* Check that an incoming parameter matches. */
#define CHKI(_what,_t) \
({ __label__ ex; long xx,yy; ushort_t id2; \
yy = 0; \
if(m_get##_what(cand,(_t *)&yy) != 0) break; \
if(cgc->par_in != NULL) { \
while(m_getsx(cgc->par_in,&id2) == 0) { \
if(id != id2) continue; \
xx = 0; \
if(m_get##_what (cgc->par_in,(_t *)&xx) != 0) continue; \
if(xx == yy) goto ex; \
if(0)if(!strchr(prot->type,'F') && !first) break;\
cgc->par_in->b_rptr = mbs_in; \
freeb(cand); \
if(0)printf("MatchI %x: %lx vs %lx\n",id,xx,yy); \
dropgrab(cgc); dropgrab(cg); return "3ERR FIND Match Arg"; \
} \
} \
ex:; }) /**/
/* Dto., outgoing parameter; if it's not there yet and we need it, add it. */
#define CHKO(_what,_t) \
({ __label__ ex; long xx,yy; ushort_t id2; \
yy = 0; \
if(m_get##_what(cand,(_t *)&yy) != 0) break; \
if(cgc->par_out != NULL) { \
while(m_getsx(cgc->par_out,&id2) == 0) { \
if(id != id2) continue; \
xx = 0; \
if(m_get##_what (cgc->par_out,(_t *)&xx) != 0) continue; \
if(xx == yy) goto ex; \
if(0)if(!strchr(prot->type,'F') && !first) break;\
cgc->par_out->b_rptr = mbs_out; \
freeb(cand); \
if(0)printf("MatchO %x: %lx vs %lx\n",id,xx,yy); \
dropgrab(cgc); dropgrab(cg); return "3ERR FIND Match Arg"; \
} \
if(!(cgc->flags & F_OUTCOMPLETE)) { \
m_putsx(cgc->par_out,id); \
m_put##_what(cgc->par_out,*(_t *)&yy); \
} \
} \
ex:; }) /**/
/* Put it all together. */
#define CHK(_what,_t) { \
if((nrt & ARG_OUT)&& (cgc->flags & F_OUTGOING) && (cgc->par_out!= NULL)) CHKO(_what,_t); \
if((nrt & ARG_IN) && (cgc->flags & F_INCOMING) && (cgc->par_in != NULL)) CHKI(_what,_t); } break
/* Same as above, but for vectorized parameters with optional bitmasks. */
/* You are not supposed to understand this code. */
#define CHKVI() \
({ __label__ ex; int xx,yy,xm; streamchar *vx,*vy,*vm; ushort_t id2; \
yy = m_gethexlen(cand); \
if (yy <= 0 || (vy=gcxmalloc(yy))==NULL) break; \
if(m_gethex(cand,vy,yy) != 0) { gfree(vy); break; } \
if ((xm = m_gethexlen(cand)) > 0) { \
if ((vm=xmalloc(xm)) == NULL) \
{ gfree(vy); break; } \
if(m_gethex(cand,vm,xm) != 0) \
{ gfree(vy); gfree(vm); break; } \
} else \
{ vm=NULL; xm=0; } \
if(cgc->par_in != NULL) { \
while(m_getsx(cgc->par_in,&id2) == 0) { \
if(id != id2) continue; \
xx = m_gethexlen(cgc->par_in); \
if (xx <= 0 || (vx=gcxmalloc(xx))==NULL) break; \
if(m_gethex(cgc->par_in,vx,xx) != 0) \
{ gfree(vx); break; } \
if(abs(vectcmp(vx,xx,vy,yy,vm,xm)) < 5) \
{ gfree(vx); gfree(vy); if(xm>0)gfree(vm); goto ex; } \
if(0)if(!strchr(prot->type,'F') && !first) continue; \
cgc->par_in->b_rptr = mbs_in; \
freeb(cand); \
if(0)printf("MatchVI %x: %s vs %s\n",id,vx,vy); \
gfree(vx); gfree(vy); if(xm>0)gfree(vm); \
dropgrab(cgc); dropgrab(cg); return "3ERR FIND Match Arg"; \
} \
gfree(vy); if(xm>0)gfree(vm); \
} \
ex:; }) /**/
#define CHKVO() \
({ __label__ ex; int xx,yy,xm; streamchar *vx,*vy,*vm; ushort_t id2; \
yy = m_gethexlen(cand); \
if (yy <= 0 || (vy=gcxmalloc(yy))==NULL) break; \
if(m_gethex(cand,vy,yy) != 0) { gfree(vy); break; } \
if ((xm = m_gethexlen(cand)) > 0) { \
if ((vm=gcxmalloc(xm)) == NULL) \
{ gfree(vy); break; } \
if(m_gethex(cand,vm,xm) != 0) \
{ gfree(vy); gfree(vm); break; } \
} else \
{ vm=NULL; xm=0; } \
if(cgc->par_out != NULL) { \
while(m_getsx(cgc->par_out,&id2) == 0) { \
if(id != id2) continue; \
xx = m_gethexlen(cgc->par_out); \
if (xx <= 0 || (vx=gcxmalloc(xx))==NULL) break; \
if(m_gethex(cgc->par_out,vx,xx) != 0) \
{ gfree(vx); break; } \
if(abs(vectcmp(vx,xx,vy,yy,vm,xm)) < 5) \
{ gfree(vx); gfree(vy); if(xm>0)gfree(vm); goto ex; } \
if(0)if(!strchr(prot->type,'F') && !first) continue; \
cgc->par_out->b_rptr = mbs_out; \
if(0)printf("MatchVO %x: %s vs %s\n",id,vx,vy); \
freeb(cand); \
gfree(vx); gfree(vy); if(xm>0)gfree(vm); \
dropgrab(cgc); dropgrab(cg); return "3ERR FIND Match Arg"; \
} \
if(!(cgc->flags & F_OUTCOMPLETE)) { \
m_putsx(cgc->par_out,id); \
m_puthex(cgc->par_out,vy,yy); \
} \
gfree(vy); if(xm>0)gfree(vm); \
} \
ex:; }) /**/
#define CHKV() { \
if((nrt & ARG_OUT)&& (cgc->flags & F_OUTGOING) && (cgc->par_out!= NULL)) CHKVO(); \
if((nrt & ARG_IN) && (cgc->flags & F_INCOMING) && (cgc->par_in != NULL)) CHKVI(); } break
/* Simple one-shot labels that can't be undone (and don't need to be). */
#define CHKX() \
({ __label__ ex; ushort_t id2; \
if(cgc->par_out != NULL) { \
while(m_getsx(cgc->par_out,&id2) == 0) { \
if(id != id2) continue; \
goto ex; \
} \
if(!(cgc->flags & F_OUTCOMPLETE)) \
m_putsx(cgc->par_out,id); \
} \
ex:; }); break /**/
switch (id) {
/* Direction-specific arguments. */
case ARG_INNUMS : nrt=ARG_IN; break;
case ARG_OUTNUMS : nrt=ARG_OUT; break;
case ARG_BOTHNUMS: nrt=ARG_IN|ARG_OUT; break;
/* Flags, ob lokale / entfernte Nummern präsent sein sollen
oder nicht. Logischerweise nur bei ankommenden Anrufen
interessant. */
case ARG_NEEDNOLOCAL:
if((cg->flags & F_INCOMING) && (cg->lnr != NULL))
DG("3LocalNrGiven","","");
break;
case ARG_NEEDNOREMOTE:
if((cg->flags & F_INCOMING) && (cg->nr != NULL))
DG("3RemoteNrGiven","","");
break;
case ARG_NEEDLOCAL:
if((cg->flags & F_INCOMING) && (cg->lnr == NULL))
DG("3LocalNrRequired","","");
break;
case ARG_NEEDREMOTE:
if((cg->flags & F_INCOMING) && (cg->nr == NULL))
DG("3RemoteNrRequired","","");
break;
/* Suffix fuer entfernte Nummer. */
case ARG_NUMBER:
{
char yy[MAXNR + 2];
if (m_getstr (cand, yy, MAXNR) != 0)
break;
if ((nrt & ARG_IN) && (cgc->flags & F_INCOMING)) {
if (cgc->nrsuf != NULL) {
if(0)printf("MatchSuffix %s and %s\n",cgc->nrsuf,yy);
if(match_suffix(cgc->nrsuf,yy) <= 0) DG("3WrongNrSuffix2",cgc->nrsuf,yy);
} else
cgc->nrsuf = str_enter(yy);
}
if((nrt & ARG_OUT) &&(cgc->flags & F_OUTGOING)) {
if (cgc->nrsuf == NULL)
cgc->nrsuf = str_enter(yy);
else if(match_suffix(cgc->nrsuf,yy) <= 0)
DG("4NrMatch_Out",cgc->nrsuf,yy);
if((cgc->nr != NULL) && !(cgc->flags & F_NRCOMPLETE)) {
char *foo = append_nr(cgc->nr,yy);
if(1)printf("Append1 %s,%s -> %s\n",cgc->nr,yy,foo);
cgc->nr = foo;
if(cgc->nr != NULL) {
if(0)printf("Strip1 %s -> %s\n",cg->nr,strip_nr(cg->nr,0));
if(strip_nr(cgc->nr,0) != NULL)
cgc->flags |= F_NRCOMPLETE;
} else DG("3WrongNrSuffix_Out",yy,"");
}
}
}
break;
/* Suffix fuer lokale Nummer. */
case ARG_LNUMBER:
{
char yy[MAXNR + 2];
int suf;
if (m_getstr (cand, yy, MAXNR) != 0)
break;
if ((nrt & ARG_IN) && (cgc->flags & F_INCOMING)) {
if(cgc->lnrsuf != NULL) {
if(0)printf("MatchLSuffix %s and %s\n",cgc->lnrsuf,yy);
if((suf = match_suffix(cgc->lnrsuf,yy)) <= 0)
DG(suf ? "1LocalNrIncompleteSuffix" : "2LocalNrWrongSuffix",cgc->lnrsuf,yy);
} else
DG("4LNrIncompSuffix3",cgc->lnrsuf,yy);
}
if((nrt & ARG_OUT) && (cgc->flags & F_OUTGOING)) {
if(cgc->lnrsuf == NULL)
cgc->lnrsuf = str_enter(yy);
else if(match_suffix(cgc->lnrsuf,yy) <= 0)
DG("4LNrOutMatch",cgc->lnrsuf,yy);
if((cgc->lnr != NULL) && !(cgc->flags & F_LNRCOMPLETE)) {
char *foo = append_nr(cgc->lnr,yy);
if(0)printf("Append2 %s,%s -> %s\n",cgc->lnr,yy,foo);
if(foo != NULL) {
cgc->lnr = foo;
if(0)printf("Strip2 %s -> %s\n",cg->lnr,strip_nr(cg->lnr,1));
if(strip_nr(cgc->lnr,1) != NULL)
cgc->flags |= F_LNRCOMPLETE;
} else {
if((cgc->lnrsuf != 0) && (match_suffix(cgc->lnrsuf,yy) < 0))
DG("2LocalNrIncompleteSuffix",cgc->lnrsuf,yy);
else
DG("2WrongLocalNrSuffix",cgc->lnr,yy);
}
}
}
}
break;
/* Protokollkrempel... */
case ARG_LLC:
CHKV ();
case ARG_ULC:
CHKV ();
case ARG_BEARER:
CHKV ();
case ARG_SERVICE:
CHK (x, ulong_t);
case ARG_PROTOCOL:
CHK (i, long);
case ARG_SUBPROT:
CHK (i, long);
case ARG_CHANNEL:
CHK (i, long);
/* Flags... */
case ARG_CHANBUSY: cgc->flags |= F_CHANBUSY; goto argdup;
case ARG_FASTREDIAL: cgc->flags |= F_FASTREDIAL; goto argdup;
case ARG_FASTDROP: cgc->flags |= F_FASTDROP; break;
case ARG_IGNORELIMIT:cgc->flags |= F_IGNORELIMIT;goto argdup;
case ARG_FORCEOUT: cgc->flags |= F_FORCEOUT; goto argdup;
case ARG_FORCEIN: cgc->flags |= F_FORCEIN; goto argdup;
case ARG_BACKCALL: cgc->flags |= F_BACKCALL; goto argdup;
case ARG_NOREJECT: cgc->flags |= F_NOREJECT; goto argdup;
case ARG_PREFOUT: cgc->flags |= F_PREFOUT; goto argdup;
case ARG_INT: cgc->flags |= F_INTERRUPT; break;
case ARG_SPV:
argdup:
CHKX();
}
/* Reset der Stringpointer. */
if(cgc->par_in != NULL) cgc->par_in->b_rptr = mbs_in;
if(cgc->par_out!= NULL) cgc->par_out->b_rptr= mbs_out;
}
/* At this point, everything fit (so far). Kill the intermediate copy. */
dropgrab(cg);
cg = cgc;
cgc = NULL;
Ex:
if(cand != NULL)
freeb (cand);
if (strchr(prot->type,'X')) /* Cut off here. */
break;
if(cgc != NULL) { /* If we have an intermediate copy, toss it. */
if(cgc->par_in != NULL) cgc->par_in->b_rptr = mbs_in;
if(cgc->par_out!= NULL) cgc->par_out->b_rptr= mbs_out;
dropgrab(cgc);
}
}
/* Done. Return the result. */
dropgrab(*cgm);
*cgm = cg;
return NULL;
}
/* Scan all the P lines, search for a matching block of entries and incorporate into *cgm. */
char *
pmatch (conngrab *cgm)
{
char *errstr = "8no P config entries";
cf prot;
chkone(*cgm);
for (prot = cf_P; prot != NULL; prot = prot->next) {
char *errstrx;
if ((errstrx = pmatch1 (prot, cgm)) != NULL) {
if(*errstrx < *errstr)
errstr = errstrx;
continue;
}
return NULL;
}
return errstr;
}
/* Scan the configuration, incorporate matching entries into *foo. */
char *
findsite (conngrab *foo, int ignbusy)
{
cf dp = NULL;
cf dl = NULL;
cf d = NULL;
char *errstr = "8No matching ISDN card / DL entry";
char *errstrx;
int numwrap;
conngrab cg = *foo;
conngrab errcg = NULL;
char no_site = 1;
chkone(cg);
cg->refs++;
for (dl = cf_DL; dl != NULL; dl = dl->next) { /* find a matching local number. */
char *matcrd;
char *matclass;
ulong_t matsub;
if(0)printf("%s.%s.!.",cg->site,cg->card); /* I hate debugging. */
if ((matclass = classmatch (cg->cclass, dl->cclass)) == NULL)
continue;
if ((matcrd = wildmatch (cg->card, dl->card)) == NULL)
continue;
if ((matsub = maskmatch (cg->mask, dl->mask)) == 0)
continue;
if(!classmatch(matclass,theclass)) continue;
if(!(cg->flags & F_LEASED)) { /* ... and a working dial prefix. */
char *crd;
ulong_t sub;
for (dp = cf_DP; dp != NULL; dp = dp->next) {
if ((crd = wildmatch (cg->card, dp->card)) == NULL)
continue;
if ((sub = maskmatch (cg->mask, dp->mask)) == 0)
continue;
break;
}
if (dp == NULL) {
if(no_site && (*errstr >= '8'))
errstr = "8No matching DP entry";
continue;
}
matcrd = crd;
matsub = sub;
}
/* Now find a site to call out to. */
/* The numwrap stuff makes sure that we restart where we left off last
time, which ensures that calling a system with more than one
number does what it's supposed to. */
/* Incoming calls start at the beginning and don't hit the
wraparound. */
/* "numidx" holds the position of the next number to try. */
for (d = cf_D, numwrap = ((cg->flags & F_INCOMING) == 0);
(d != NULL) || (numwrap > 0);
d = (numwrap ? d->next : d)) {
char *matcla;
char *matsit;
char *matcar;
char *matpro;
ulong_t matsub;
long matflg;
if(d == NULL) { /* Restart at the beginning */
numwrap = 0;
numidx = 0;
if((d = cf_D) == NULL)
break; /* no D lines at all... */
}
if (numwrap > 0 && numidx >= numwrap++)
continue; /* scan and skip */
else if(numwrap == 0)
numwrap = -1;
if(!(cg->flags & F_INCOMING))
numidx++;
/* Yes, we did increment the refcount, above. */
dropgrab(cg);
cg = *foo;
cg->refs++;
if((matflg = matchflag(cg->flags,d->type)) == 0) continue;
if((matsit = wildmatch(cg->site,d->site)) == NULL) continue;
if((matpro = wildmatch(cg->protocol,d->protocol)) == NULL) continue;
if((matcar = wildmatch(matcrd,d->card)) == NULL) continue;
if((matcla = classmatch(matclass,d->cclass)) == NULL) continue;
if((matsub = maskmatch(cg->mask,d->mask)) == 0) continue;
if(!classmatch(matcla,theclass)) continue;
if(cg->d_level != d->num) {
if((cg->d_level < d->num) && (cg->d_nextlevel < d->num))
cg->d_nextlevel = d->num;
continue;
}
/* Preliminary match OK, remember the data so far. */
dropgrab(cg);
cg = newgrab(*foo);
if(cg == NULL) return "0OUT OF MEM";
cg->site = matsit; cg->cclass = matcla;
cg->card = matcar; cg->protocol = matpro;
cg->mask = matsub; cg->flags = matflg;
if(!(cg->flags & F_LEASED)) {
/* Now figure out the numbers... */
if(cg->nr != NULL) {
cg->nrsuf = match_nr(cg->nr,d->arg, ((cg->flags&F_INCOMING) && (dp->args != NULL)) ? dp->args : dp->arg);
if(cg->nrsuf == NULL) {
if(no_site && (*errstr >= '8')) {
dropgrab(errcg); errcg = cg; cg->refs++;
errstr = "8NrRemMatch";
}
continue;
}
} else if(!(cg->flags & F_INCOMING)) {
cg->nr = build_nr(d->arg,dl->arg,((cg->flags&F_INCOMING) && (dp->args != NULL)) ? dp->args : dp->arg, 0);
if(cg->nr == NULL) {
if(no_site && (*errstr >= '8')) {
dropgrab(errcg); errcg = cg; cg->refs++;
errstr="8RemNrMatch";
}
continue;
}
} else { /* dialin, but no number given */
if(strcmp(cg->site,"unknown"))
continue;
}
if(cg->lnr != NULL) {
cg->lnrsuf = match_nr(cg->lnr,dl->arg, ((cg->flags&F_INCOMING) && (dp->args != NULL)) ? dp->args : dp->arg);
if(cg->lnrsuf == NULL) {
if(no_site && (*errstr > '3')) {
dropgrab(errcg); errcg = cg; cg->refs++;
errstr = "6NrLocMatch";
}
continue;
}
} else if(!(cg->flags & F_INCOMING)) { /* Hmmm... */
cg->lnr = build_nr(dl->arg,dl->arg,((cg->flags&F_INCOMING) && (dp->args != NULL)) ? dp->args : dp->arg, 3);
if(cg->lnr == NULL) {
if(no_site && (*errstr > '4')) {
dropgrab(errcg); errcg = cg; cg->refs++;
errstr="6LocNrMatch";
}
continue;
}
}
}
no_site = 0;
/* Do we have a matching P line? */
if ((errstrx = pmatch (&cg)) == NULL) {
/* We should have what we need. Now figure out if we can use it... */
cf cl = NULL;
int nrbchan = 0;
if(cg->nr != NULL && (cg->flags & (F_INCOMING|F_OUTGOING)) && !(cg->flags & F_NRCOMPLETE)) {
if(strip_nr(cg->nr,0) != NULL)
cg->flags |= F_NRCOMPLETE;
else {
if(*errstr > '3') {
errstr = "3RemoteNr incomplete";
errcg = cg; cg->refs++;
}
continue;
}
}
if(cg->lnr != NULL && (cg->flags & (F_INCOMING|F_OUTGOING)) && !(cg->flags & F_LNRCOMPLETE)) {
if(strip_nr(cg->lnr,1) != NULL)
cg->flags |= F_LNRCOMPLETE;
else {
if(*errstr > '3') {
errstr = "3LocalNr incomplete";
errcg = cg; cg->refs++;
}
continue;
}
}
/* Check if we know how many B channels the card has */
{
struct isdncard *ca;
for(ca = isdn4_card; ca != NULL; ca = ca->next) {
if(ca->is_down)
continue;
if(!strcmp(cg->card, ca->name)) {
nrbchan = ca->nrbchan;
break;
}
}
}
if((nrbchan > 0) && !ignbusy) {
int nrconn = 0;
struct conninfo *conn;
for(conn = isdn4_conn; conn != NULL; conn = conn->next) {
if(conn->ignore || !conn->cg)
continue;
if(conn->state >= c_going_up) {
if(wildmatch(conn->cg->card, cg->card) == NULL)
continue;
nrconn ++;
}
}
if(nrconn >= nrbchan) {
errstr = "0BUSY";
dropgrab(errcg); errcg = cg; cg->refs++;
continue; /* try the next D line */
}
}
/* Check if there's a limiter. Actually, there may be more
than one. */
for(cl = ignbusy ? NULL : cf_CL; cl != NULL; cl = cl->next) {
struct conninfo *conn;
int naconn = 0;
if(classmatch(theclass,classmatch(cg->cclass,cl->cclass)) == NULL)
continue;
if(wildmatch(cg->card, cl->card) == NULL)
continue;
if(wildmatch(cg->site, cl->site) == NULL)
continue;
if(wildmatch(cg->protocol, cl->protocol) == NULL)
continue;
if(maskmatch(cg->mask, cl->mask) == 0)
continue;
for(conn = isdn4_conn; conn != NULL; conn = conn->next) {
char *prot,*sit;
if(conn->ignore || !conn->cg)
continue;
if(conn->state < c_going_up)
continue;
if(wildmatch(conn->cg->card, cl->card) == NULL)
continue;
if((prot = wildmatch(conn->cg->protocol, cl->protocol)) == NULL)
continue;
if((sit = wildmatch(conn->cg->site, cl->site)) == NULL)
continue;
if(classmatch(theclass,classmatch(conn->cg->cclass, cl->cclass)) == NULL)
continue;
if(maskmatch(conn->cg->mask,cl->mask) == 0)
continue;
if(conn->state == c_going_up &&
wildmatch(sit,cg->site) != NULL &&
wildmatch(prot,cg->protocol) != NULL)
continue;
if(conn->flags & F_IGNORELIMIT)
continue;
naconn++;
}
if((cl != NULL) && (naconn >= cl->num) && !(cg->flags & F_IGNORELIMIT)) {
errstr = "0BUSY";
dropgrab(errcg); errcg = cg; cg->refs++;
break;
}
}
if(cl == NULL) { /* checked all of them */
if (cg->par_out != NULL && strchr(d->type, 'H') != NULL && !(cg->flags & F_OUTCOMPLETE))
m_putsx (cg->par_out, ARG_SUPPRESS);
dropgrab(errcg);
dropgrab(*foo); *foo = cg;
return NULL;
}
}
/* No go. Remember the error, if appropriate. */
if((no_site || (*errstr >= '8')) && (errstrx != NULL) && (*errstr > *errstrx)) {
errstr = errstrx;
errcg = cg; cg->refs++;
}
/* p->b_rptr = olds; */
}
}
/* Nothing matched. Grrr. */
dropgrab(cg);
if(errcg != NULL) {
dropgrab(*foo);
*foo = errcg;
}
return errstr;
}
/* Wrapper stuff. Take numbers out of the incoming argument vector, find
the card, et al. */
char *
findit (conngrab *foo, int ignbusy)
{
ushort_t id;
mblk_t *p;
char *errstr = "9No card known";
char *errstrx;
struct isdncard *c;
conngrab cg = newgrab(*foo), cgc = NULL;
conngrab errcg = NULL;
int cardwrap;
if(cg == NULL)
return "NoMemFoo";
p = cg->par_in;
if(p != NULL) {
streamchar *olds = p->b_rptr;
char st[MAXNR + 2];
long x;
while (m_getsx (p, &id) == 0) {
switch (id) {
case ARG_NUMBER:
if(cg->nr == NULL) {
m_getstr (p, st, MAXNR);
cg->nr = str_enter(st);
}
break;
case ARG_LNUMBER:
if(cg->lnr == NULL) {
m_getstr (p, st, MAXNR);
cg->lnr = str_enter(st);
}
break;
case ARG_CARD:
{
char *foo;
m_getstr (p, st, 4);
if((foo = wildmatch(str_enter(st),cg->card)) == NULL) {
char buf[80];
sprintf(buf,"9CARD MISMATCH %s %s",st,cg->card);
dropgrab(cg);
return str_enter(buf);
}
cg->card = foo;
}
break;
case ARG_SUBCARD:
if((m_geti(p,&x) == 0) && (x > 0))
cg->mask = 1<<(x-1);
break;
}
}
p->b_rptr = olds;
if(cg->site == NULL && cg->nr == NULL)
cg->site = "unknown";
}
for(c = isdn4_card, cardwrap = ((cg->flags & F_INCOMING) == 0);
(c != NULL) || (cardwrap > 0);
c = (cardwrap ? c->next : c)) {
if(c == NULL) { /* Restart at the beginning */
cardwrap = 0;
cardidx = 0;
if((c = isdn4_card) == NULL)
break; /* no D lines at all... */
}
if (cardwrap > 0 && cardidx >= cardwrap++)
continue; /* scan and skip */
else if(cardwrap == 0)
cardwrap = -1;
if(!(cg->flags & F_INCOMING))
cardidx++;
if(c->is_down)
continue;
cg->mask = 1; /* XXX TODO: enhance for multiple interfaces */
dropgrab(cgc);
cgc = newgrab(cg);
if(cgc == NULL) return "0NoMemFind";
cgc->card = c->name;
if ((errstrx = findsite (&cgc,ignbusy)) == NULL) { /* Found it */
cgc->flags |= F_OUTCOMPLETE;
dropgrab(*foo); dropgrab(cg);
*foo = cgc;
return NULL;
}
if(*errstrx < *errstr) {
errstr = errstrx;
dropgrab(errcg); errcg = cgc;
errcg->refs++;
}
}
if(errcg != NULL) {
dropgrab(*foo);
*foo = errcg;
}
dropgrab(cg); dropgrab(cgc);
return errstr;
}