<*+M2EXTENSIONS *> <*-CHECKDIV *> <*-CHECKRANGE *> <*-COVERFLOW *> <*-IOVERFLOW*> <*+NOPTRALIAS*> <*-CHECKNIL *> <*-CHECKINDEX*> <*-CHECKDINDEX *> <*-CHECKSET*> <*CPU="PENTIUM"*> <* IF __GEN_C__ THEN *> <*-GENCTYPES*> <*+COMMENT*> <*-GENDEBUG*> <*-LINENO*> <*-GENHISTORY*> <*-GENDATE*> <*-DOREORDER *> <*-PROCINLINE*> <*+GENCDIV*> <*-GENKRC*> <*+NOOPTIMIZE*> <*-GENSIZE*> <*-ASSERT*> <* ELSE *> <*+GENDEBUG*> <*+LINENO*> <*+GENHISTORY*> <*+CHECKNIL *> <*+CHECKINDEX*> <*+CHECKDINDEX *> <*+CHECKDIV *> <*-DOREORDER *> <*-PROCINLINE*> <* END *> <*NEW PROXY*> <*-PROXY*> <*NEW SONDE*> <*+SONDE*> <*NEW SRTM*> <*+SRTM*> MODULE udpgate4; (* axudp / tcpip aprs-is gateway (message relay and query answers removed) by OE5DXL *) IMPORT udp, tcp; FROM osi IMPORT WrLn, WrStr, WrStrLn, WrInt, WrHex, NextArg, WrFixed, sqrt, arctan, OpenRead, OpenAppend, OpenWrite, Close, Rename, keepalive, WrBin, RdBin, Size, Seek, Exists, pi, time, ALLOCATE, DEALLOCATE, DIRSEP, DIRCONTEXT, OpenDir, CloseDir, ReadDirLine, OpenNONBLOCK; FROM Select IMPORT selectrw, fdclr, fdsetr, fdsetw, issetr, issetw; FROM SYSTEM IMPORT CAST, SHIFT, ADR, CARD8, CARD16, INT8, INT16, FILL; FROM aprspos IMPORT RAD, posvalid, distance, GetPos, GetSym, KNOTS, wgs84s, azimuth, ENCODEGPS, ENCODEMICE, ENCODECOMP, ENCODEGPSDAO, ENCODEMICEDAO; FROM aprsstr IMPORT TIME, Assign, Append, Length, IntToStr, FixToStr, StrToFix, Delstr, StrCmp, InStr, TimeToStr, DateToStr, CtrlHex, IPNUM, UDPPORT, SET8, postoloc, AppCRC, mon2raw, raw2mon, GetIp2, CardToStr, extrudp2, GHOSTSET, POSITION, showctrl; FROM signal IMPORT signal, SIGHUP; <* IF SRTM THEN *> FROM libsrtm IMPORT srtmdir, srtmmaxmem, egm96, getsrtm; <* END *> CONST CALLLEN=7; HASHSIZE=65536; <* IF __GEN_C__ THEN *> VERS="udpgate 0.81"; <* ELSE *> VERS="udpgate(m) 0.81"; <* END *> CPUTEMPFN="/sys/class/thermal/thermal_zone0/temp"; CONNECTS="connects"; INDEXHTML="index.html"; INFOHTML="info.html"; CANTBIND="trying to bind to port "; KEEPALIVE_IDLE_USER=300; KEEPALIVE_INTERVALL_USER=60; KEEPALIVE_COUNT_USER=3; KEEPALIVE_IDLE_IS=180; KEEPALIVE_INTERVALL_IS=30; KEEPALIVE_COUNT_IS=2; TOCALL="APNL51"; HTTPTIMEOUT=60; APRSLISTENSOCKS=4; (* max same time tcp connects *) WWWLISTENSOCKS=16; (* max same time www tcp connects *) UDPSHOWTIME=600; (* show udp in html *) GATECONNDELAY=30; MAXINTERNALDELAY=5; (* max seconds between udp ports read to not discard data *) DEFAULTPONGTIME=30; (* s after last #ping stop datatransfer *) DAYSEC=86400; PI=3.14159265358979323844; DEGSYM=260C; MAXAFC=1000000; TYPE MONCALL=ARRAY[0..9] OF CHAR; FILENAME=ARRAY[0..1023] OF CHAR; FRAMEBUF=ARRAY[0..511] OF CHAR; FILTERST=ARRAY[0..255] OF CHAR; RES=(resOK, resDUP, resMSG, resQUERY, resUNGATE, resBADPATH, resNOPASS, resLEN, resSRCCAL, resDESTCAL, resVIACAL, resNCAL, resQAZ, resDELAY, resFILT, resLOG); SORTBY=ARRAY[0..3] OF ARRAY[0..1] OF CHAR; (* FRAMEBUF=ARRAY[0..256+3+11*10] OF CHAR; *) CHSET=SET OF [0C..177C]; BEACON=RECORD bintervall: TIME; bfile : FILENAME; btime : TIME; END; POSCALL=RECORD call:MONCALL; typ:CHAR; pos:POSITION; END; FILTERCALLS=ARRAY[0..8] OF MONCALL; FILTERS=RECORD typ :CHAR; base, edge :POSITION; radius :REAL; viacalls :FILTERCALLS; notvia :BOOLEAN; entrycalls :FILTERCALLS; notentry :BOOLEAN; prefixes :FILTERCALLS; notprefix :BOOLEAN; bud :FILTERCALLS; notbud :BOOLEAN; objects :FILTERCALLS; notobject :BOOLEAN; destcalls :FILTERCALLS; notdestcall :BOOLEAN; msgs :FILTERCALLS; notmsgs :BOOLEAN; q :FILTERCALLS; notq :BOOLEAN; symbols :FILTERCALLS; notsymbols :BOOLEAN; typs :ARRAY[0..12] OF CHAR; nottyps :BOOLEAN; END; WWWB=ARRAY[0..1400] OF CHAR; pWWWBUF=POINTER TO WWWBUF; WWWBUF=RECORD buf :WWWB; tlen :INTEGER; push :BOOLEAN; next :pWWWBUF; END; QWatch=RECORD lasttb :CARDINAL; qsize :INTEGER; lastqb :INTEGER; txbyte :ARRAY[0..59] OF INTEGER; END; pTCPSOCK=POINTER TO TCPSOCK; TCPSOCK=RECORD next : pTCPSOCK; fd : INTEGER; beacont, connt, pongtime: TIME; slowlink, passvalid, pingout : BOOLEAN; (* ping timeout state *) service : CHAR; gatepri : CARDINAL; ipnum : ARRAY[0..63] OF CHAR; port : ARRAY[0..5] OF CHAR; user : POSCALL; vers : ARRAY[0..20] OF CHAR; wwwst : CARDINAL; reload : CARDINAL; sortby : SORTBY; qwatch : QWatch; txframes, txbytes, txbytesh, rxframes, rxbytes, rxbytesh, losttxframes, lostrxframes : CARDINAL; filters : FILTERS; outfilterst : FILTERST; (* for www show outconn filters *) rpos, tlen : INTEGER; rbuf : FRAMEBUF; tbuf : ARRAY[0..1023] OF CHAR; get : ARRAY[0..255] OF CHAR; txbuf : pWWWBUF; END; pUDPSOCK=POINTER TO UDPSOCK; UDPSOCK=RECORD next : pUDPSOCK; fd : INTEGER; ghosts : GHOSTSET; rawread, checkip : BOOLEAN; ip : IPNUM; bindport, dport : UDPPORT; lasttxtime : TIME; (* for net to rf bit/s limit *) laststat : CARDINAL; torfradius : REAL; (* radius 0 no gateing *) maxbytes, (* byte/s tx *) lasttxbytes, (* for tx byte/s limit *) txframes, txbytes : CARDINAL; allpathkey, (* keyword on comment for allpath *) portname : ARRAY[0..9] OF CHAR; stat:ARRAY[0..15] OF RECORD uip : IPNUM; uport : UDPPORT; rxframes, rxbytes : CARDINAL; utime, dtime : TIME; END; END; GATEFILT=(gUNGATE, gRFONLY, gNOGATE, gTCPIP, gTCPXX, gQ); GFILTSET=SET OF GATEFILT; UDPSET=RECORD txd, level, quali, afc, snr :INTEGER; longcalls:BOOLEAN; END; CONST MAXHEARD=500; cUSERMSG=":"; USERACK="{"; cTHIRDPARTY="}"; ICONDIR="icon"; CALLINKFN="calllink.txt"; (* build an URL for a klicked mh call *) SERVERLINKFN="serverlink.txt"; (* build an URL for a klicked server ip *) OBJECTLINKFN="objectlink.txt"; (* build an URL for a klicked mh object *) MAPLINKFN="maplink.txt"; (* build an URL for map on klicked raw object *) MHSTEPS=48; tCELSIUS="C"; tSPEED="S"; tJUNK="J"; tUNK="U"; tPOS=0C; UNACKRET=1; MSGLEN=67; TYPE SOURCE=(OBSOLET, NET, INDIR, DIR); pRAWTEXT=POINTER TO RAWTEXT; RAWTEXT=RECORD next :pRAWTEXT; htime :TIME; txd, quali, len :CARDINAL; afc, snr :INTEGER; position:POSITION; text :ARRAY[0..1023] OF CHAR; END; pHEARD=POINTER TO HEARD; HEARD=RECORD next :pHEARD; fromrx :CARDINAL; mhtime :TIME; call :MONCALL; cntt :TIME; position:POSITION; dir :CARDINAL; objtimediff, altitude:INTEGER; sym,symt:CHAR; cnt :ARRAY[0..MHSTEPS] OF RECORD pack, junk: CARD16 END; head :ARRAY[0..40] OF CHAR; datatyp :CHAR; mhz, clb, data :REAL; sortval :LONGREAL; (* sort value inserted depending on sort by *) altfromsrtm, ungate :BOOLEAN; (* flag set by user to not igate this direct heard *) txd :CARD16; quali :CARD8; level :INT16; snr :INT8; afc :INTEGER; rawtext :ARRAY[0..1] OF pRAWTEXT; (* normal / junk raw frame storage *) END; CONST POLYNOM=BITSET{3,10,15}; CRCINIT=BITSET{0..15}; CRCRESULT=BITSET(40715); CR=015C; LF=012C; cUSERMESSAGE=":"; cISGATEWAY="G"; cISSERVER="S"; cISWWW="W"; cTELEMETRY="T"; -- STYLE=' srtmdir :ARRAY[0..1023] OF CHAR; <*END*> PROCEDURE spintime; (* make monotonic systime out of jumping realtime *) VAR t, dt:TIME; BEGIN t:=time(); dt:=t-realtime; realtime:=t; IF dt<60 THEN INC(systime, dt) END; END spintime; PROCEDURE Err(text-:ARRAY OF CHAR); BEGIN WrStr("udpgate4: "); WrStr(text); WrStrLn(" error abort"); HALT END Err; PROCEDURE Max(a,b:CARDINAL):CARDINAL; BEGIN IF a>b THEN RETURN a ELSE RETURN b END; END Max; PROCEDURE Min(a,b:CARDINAL):CARDINAL; BEGIN IF a0.0 THEN el:=(360.0/PI)*arctan(r/sb)-90.0 ELSE el:=90.0 END; END elevation; PROCEDURE skipblank(s-:ARRAY OF CHAR; VAR p:CARDINAL); BEGIN WHILE (p0C THEN IF s[0]<>0C THEN Append(s," ") END; IF not THEN Append(s,"-") END; Append(s,sym); j:=0; WHILE tab[j][0]<>0C DO Append(s,"/"); IF tab[j][0]>" " THEN Append(s, tab[j]) END; INC(j); END; END; END wrcalls; BEGIN s[0]:=0C; WITH f DO IF typ="a" THEN Assign(s, "a"); app(base.lat, TRUE); app(base.long, TRUE); app(edge.lat, TRUE); app(edge.long, TRUE); ELSIF typ="r" THEN Assign(s, "r"); app(base.lat, TRUE); app(base.long, TRUE); app(radius, FALSE); ELSIF typ="m" THEN Assign(s, "m"); app(radius, FALSE); END; wrcalls(viacalls, notvia, "d"); wrcalls(entrycalls, notentry, "e"); wrcalls(prefixes, notprefix, "p"); wrcalls(bud, notbud, "b"); wrcalls(objects, notobject, "o"); wrcalls(destcalls, notdestcall, "u"); wrcalls(msgs, notmsgs, "g"); wrcalls(q, notq, "q"); wrcalls(symbols, notsymbols, "s"); IF typs[0]<>0C THEN Append(s," "); IF nottyps THEN Append(s,"-") END; Append(s,"t/"); Append(s, typs); END; END; END FiltToStr; PROCEDURE Watchclock(VAR t:TIME; intervall:TIME):BOOLEAN; VAR tn:TIME; BEGIN IF (intervall>0) OR (t=0) THEN (* send once *) tn:=systime; IF t<=tn THEN INC(t, intervall); IF t<=tn THEN t:=tn+intervall END; RETURN TRUE END; END; RETURN FALSE END Watchclock; PROCEDURE call2pass(c-:ARRAY OF CHAR):CARDINAL; CONST ROOT=CAST(BITSET, 073E2H); VAR i:CARDINAL; s:BITSET; BEGIN s:=ROOT; i:=0; WHILE (i<=HIGH(c)) & (c[i]<>0C) & (c[i]<>"-") DO s:=s/SHIFT(CAST(BITSET, ORD(CAP(c[i]))),VAL(INTEGER,NOT ODD(i))*8); INC(i); END; RETURN CAST(CARDINAL, s*BITSET{0..14}) END call2pass; PROCEDURE GetSec(h:ARRAY OF CHAR; VAR p, n:CARDINAL):INTEGER; VAR ok:BOOLEAN; BEGIN h[HIGH(h)]:=0C; n:=0; ok:=FALSE; WHILE (h[p]>="0") & (h[p]<="9") DO ok:=TRUE; n:=n*10+ORD(h[p])-ORD("0"); INC(p); END; IF NOT ok THEN RETURN -1 END; RETURN 0 END GetSec; PROCEDURE callok(h-:ARRAY OF CHAR):BOOLEAN; VAR i,num,lit:CARDINAL; c:CHAR; BEGIN num:=0; lit:=0; i:=0; LOOP c:=h[i]; IF (c>="0") & (c<="9") THEN INC(num) ELSIF (c>="A") & (c<="Z") THEN INC(lit) ELSE EXIT END; INC(i); END; IF (lit<2) OR (num=0) OR (num>2) THEN RETURN FALSE END; IF h[i]="-" THEN INC(i); IF h[i]="1" THEN INC(i); IF (h[i]>="0") & (h[i]<="5") THEN INC(i) END; ELSIF (h[i]<"1") OR (h[i]>"9") THEN RETURN FALSE ELSE INC(i) END; END; RETURN h[i]=0C END callok; PROCEDURE readurlsfile(gatesfn-:ARRAY OF CHAR); VAR n,i:CARDINAL; fd, len, ii:INTEGER; h:FILENAME; BEGIN IF verb THEN WrStrLn("read url-file") END; FILL(ADR(gateways), 0C, SIZE(gateways)); fd:=OpenRead(gatesfn); IF fd<0 THEN h:="-g :file <"; Append(h, gatesfn); Append(h, "> not readable"); WrStrLn(h); RETURN END; n:=0; REPEAT i:=0; LOOP len:=RdBin(fd, h[i], 1); IF (len<=0) OR (i>=HIGH(h)) OR (h[i]=CR) OR (h[i]=LF) THEN h[i]:=0C; EXIT END; INC(i); END; IF (h[0]<>0C) & (h[0]<>"#") THEN IF h[0]="[" THEN ii:=1; WHILE (h[ii]<>0C) & (h[ii]<>"]") DO INC(ii) END; IF (h[ii]<>"]") OR (h[ii+1]<>":") THEN WrStrLn("udpgate: urlfile: [url]:port") END; h[ii]:=0C; i:=1; WHILE i<=HIGH(h) DO h[i-1]:=h[i]; INC(i) END; ELSE ii:=InStr(h, ":") END; IF ii>=0 THEN h[ii]:=0C END; Assign(gateways[n].url, h); IF ii>0 THEN (* port number *) INC(ii); i:=0; WHILE ii<=HIGH(h) DO h[i]:=h[ii]; INC(i); INC(ii) END; ELSE WrStrLn("urlfile: [url]:port") END; ii:=InStr(h, "#"); IF ii>=0 THEN h[ii]:=0C END; IF h[0]=0C THEN WrStrLn("urlfile: [url]:port#filters") END; Assign(gateways[n].port, h); IF ii>0 THEN (* we have a filter string *) INC(ii); i:=0; WHILE ii<=HIGH(h) DO IF h[ii]="," THEN h[ii]:=" " END; h[i]:=h[ii]; INC(i); INC(ii); END; Assign(gateways[n].filterst, h); END; INC(n); END; UNTIL (len<=0) OR (n>HIGH(gateways)); Close(fd); END readurlsfile; PROCEDURE corrpath(VAR s:ARRAY OF CHAR); VAR i:CARDINAL; BEGIN i:=Length(s); IF (i>0) & (s[i-1]<>DIRSEP) THEN Append(s, DIRSEP) END; END corrpath; PROCEDURE parms; VAR h : ARRAY[0..4095] OF CHAR; hh : ARRAY[0..99] OF CHAR; ghost : GHOSTSET; err : BOOLEAN; lasth : CHAR; i, n : CARDINAL; gatecnt : CARDINAL; fd, len : INTEGER; usock, ush : pUDPSOCK; ii : INTEGER; allkey : ARRAY[0..9] OF CHAR; BEGIN err:=FALSE; verb:=FALSE; datafilter:=FALSE; gatecnt:=0; ghost:=GHOSTSET{}; keeptime:=0; (*600*) (* default keep connected to gateway time *) allkey[0]:=0C; showctrl:=TRUE; LOOP NextArg(h); IF h[0]=0C THEN EXIT END; IF (h[0]="-") & (h[1]<>0C) & (h[2]=0C) THEN lasth:=h[1]; IF (lasth="R") OR (lasth="M") THEN NextArg(h); ALLOCATE(usock, SIZE(usock^)); IF usock=NIL THEN Err("out of memory") END; FILL(usock, 0C, SIZE(usock^)); WITH usock^ DO IF GetIp2(h, ip, dport, bindport, checkip)<0 THEN Err("-R or -M need ip:port:port") END; fd:=udp.openudp(); rawread:=lasth="R"; IF (fd<0) OR (udp.bindudp(fd, bindport)<0) THEN h:="-R or -M cannot bind udpport "; CardToStr(bindport, 1, hh); Append(h, hh); Err(h); END; len:=udp.socknonblock(fd); ii:=InStr(h, "+"); IF ii>0 THEN i:=ii+1; IF (GetSec(h,i,n)>=0) THEN maxbytes:=n; INC(i); IF (h[i-1]=":") & (GetSec(h,i,n)>=0) THEN torfradius:=FLOAT(n) END; END; END; ii:=InStr(h, "#"); (* get port name *) IF ii>0 THEN INC(ii); i:=0; WHILE (i<=HIGH(portname)) & (ii<=HIGH(h)) & (h[ii]<>0C) DO portname[i]:=h[ii]; INC(i); INC(ii); END; END; ghosts:=ghost; Assign(allpathkey, allkey); next:=NIL; END; IF udpsocks=NIL THEN udpsocks:=usock; ELSE ush:=udpsocks; WHILE ush^.next<>NIL DO ush:=ush^.next END; ush^.next:=usock; END; ghost:=GHOSTSET{}; ELSIF lasth="a" THEN NextArg(h); IF NOT StrToFix(homealt, h) THEN Err("-a altitude in m") END; ELSIF lasth="B" THEN NextArg(h); IF h[0]="+" THEN Delstr(h, 0, 1); objmhfromtcp:=TRUE; END; i:=0; IF GetSec(h,i,n)>=0 THEN heardtimeobj:=n*60 ELSE Err("-B minutes") END; ELSIF lasth="c" THEN callsrc:=TRUE; ELSIF CAP(lasth)="S" THEN rfcallchk:=lasth="s"; NextArg(h); Assign(servercall, h); IF (servercall[0]=0C) OR (servercall[0]="-") OR (rfcallchk & NOT callok(h)) THEN Err("-s call-ssid") END; ELSIF lasth="p" THEN NextArg(h); IF (h[0]>="0") & (h[0]<="9") THEN i:=0; WHILE (i<=HIGH(passwd)) & (h[i]>=" ") DO passwd[i]:=h[i]; INC(i) END; ELSE fd:=OpenRead(h); IF fd<0 THEN Err("-p passcode or passwordfile") END; len:=RdBin(fd, passwd, SIZE(passwd)-1); IF len>=0 THEN passwd[len]:=0C ELSE Err("-p error with password file") END; Close(fd); END; passwd[HIGH(passwd)]:=0C; i:=0; WHILE (passwd[i]>="0") & (passwd[i]<="9") DO INC(i) END; IF (i=0) OR (passwd[i]<>0C) THEN Err("-p invalid passcode") END; ELSIF lasth="m" THEN NextArg(h); i:=0; IF GetSec(h,i,n)>=0 THEN maxusers:=n ELSE Err("-m number") END; ELSIF lasth="A" THEN NextArg(h); IF (h[0]=0C) OR (h[0]="-") THEN Err("-A directory") END; Assign(srtmdir, h); corrpath(srtmdir); ELSIF lasth="D" THEN NextArg(h); IF (h[0]=0C) OR (h[0]="-") THEN Err("-D directory") END; Assign(wwwdir, h); corrpath(wwwdir); ELSIF lasth="d" THEN NextArg(h); i:=0; IF GetSec(h,i,n)>=0 THEN dupetime:=n ELSE Err("-d number") END; IF dupetime<27 THEN WrStrLn("-d do not set dupefilter less 27s!") END; ELSIF lasth="e" THEN NextArg(h); i:=0; IF GetSec(h,i,n)>=0 THEN IF n=0 THEN n:=1 END; gateconndelay:=n; ELSE Err("-e seconds") END; ELSIF lasth="C" THEN NextArg(h); i:=0; IF GetSec(h,i,n)>=0 THEN heardtimetcp:=n*60 ELSE Err("-C minutes") END; ELSIF lasth="H" THEN NextArg(h); i:=0; IF GetSec(h,i,n)>=0 THEN heardtimew:=n*60 ELSE Err("-H minutes") END; ELSIF lasth="I" THEN NextArg(h); i:=0; IF GetSec(h,i,n)>=0 THEN heardtimevia:=n*60 ELSE Err("-I minutes") END; ELSIF lasth="l" THEN NextArg(h); i:=0; IF (GetSec(h,i,n)>=0) & (h[i]=":") THEN logframes:=n; INC(i); FOR n:=0 TO HIGH(logframename) DO IF i<=HIGH(h) THEN logframename[n]:=h[i]; INC(i); END; END; IF logframename[0]<=" " THEN Err("-l loglevel:filename") END; ELSE Err("log format is level:file") END; ELSIF lasth="r" THEN NextArg(rawlogname); IF rawlogname[0]<=" " THEN Err("-r rawlogfilename") END; ELSIF lasth="F" THEN NextArg(h); i:=0; IF (GetSec(h,i,n)>=0) & (h[i]=":") THEN mhfilelines:=n; INC(i); FOR n:=0 TO HIGH(mhfilename) DO IF i<=HIGH(h) THEN mhfilename[n]:=h[i]; INC(i); END; END; IF mhfilename[0]<=" " THEN Err("-F MHfilename") END; ELSE Err("MH File lines:file") END; ELSIF lasth="n" THEN NextArg(h); i:=0; IF (GetSec(h,i,n)>=0) & (h[i]=":") THEN netbeaconintervall:=n*60; INC(i); FOR n:=0 TO HIGH(netbeaconfn) DO IF i<=HIGH(h) THEN netbeaconfn[n]:=h[i]; INC(i); END; END; IF netbeaconfn[0]<=" " THEN Err("-n netbeacon filename") END; ELSE Err("-n netbeacon format is minutes:file") END; ELSIF lasth="E" THEN showctrl:=FALSE; ELSIF lasth="t" THEN NextArg(h); Assign(tcpbindport, h); IF (h[0]=0C) OR (h[0]="-") THEN Err("-t port") END; ELSIF lasth="w" THEN NextArg(h); Assign(wwwbindport, h); IF (h[0]=0C) OR (h[0]="-") THEN Err("-w port") END; ELSIF lasth="X" THEN NextArg(h); Assign(qau, h); IF (h[0]=0C) OR (h[0]="-") THEN Err("-X q-construct") END; IF qau[0]<>"q" THEN Err('-X q-construct needs "q" at begin') END; ELSIF lasth="f" THEN NextArg(h); Assign(serverrangefilter, h); IF (h[0]=0C) OR (h[0]="-") THEN Err("-f rangefilter") END; FOR i:=0 TO Length(serverrangefilter) DO IF serverrangefilter[i]="," THEN serverrangefilter[i]:=" " END; END; ELSIF lasth="g" THEN (* "url port" or "url:port" or "url:port#filter" *) NextArg(h); IF h[0]=0C THEN Err("-g url port") END; IF h[0]=":" THEN (* get urls later from file *) FOR i:=1 TO HIGH(h) DO h[i-1]:=h[i] END; h[HIGH(h)]:=0C; Assign(gatesfn, h); ELSE IF gatecnt>HIGH(gateways) THEN Err("-g gateway table full") END; h[HIGH(h)]:=0C; IF h[0]="[" THEN ii:=1; WHILE (h[ii]<>0C) & (h[ii]<>"]") DO INC(ii) END; IF (h[ii]<>"]") OR (h[ii+1]<>":") THEN Err("-g [url]:port") END; h[ii]:=0C; i:=1; WHILE i<=HIGH(h) DO h[i-1]:=h[i]; INC(i) END; ELSE ii:=InStr(h, ":") END; IF ii>=0 THEN h[ii]:=0C END; Assign(gateways[gatecnt].url, h); IF ii>0 THEN (* port number *) INC(ii); i:=0; WHILE ii<=HIGH(h) DO h[i]:=h[ii]; INC(i); INC(ii) END; ELSE NextArg(h) END; h[HIGH(h)]:=0C; ii:=InStr(h, "#"); IF ii>=0 THEN h[ii]:=0C END; IF h[0]=0C THEN Err("-g url:port") END; Assign(gateways[gatecnt].port, h); IF ii>0 THEN (* we have a filter string *) INC(ii); i:=0; WHILE ii<=HIGH(h) DO IF h[ii]="," THEN h[ii]:=" " END; h[i]:=h[ii]; INC(i); INC(ii); END; Assign(gateways[gatecnt].filterst, h); END; INC(gatecnt); END; ELSIF lasth="h" THEN WrStrLn(" "+VERS); WrStrLn(" -0 send no Data (only Messages and ack) to User with no Filter"); WrStrLn(" -A srtm directory path to enable overground calculation (-A /usr/srtm/)"); WrStrLn(' for objects with "Clb=" file WW15MGH.DAC will be needed on this path'); WrStrLn(" -a Altitude of Igate for elevation calulation (overrides value from srtm)"); WrStrLn(' -B [+]