/*
 * dxlAPRS toolchain
 *
 * Copyright (C) Christian Rabler <oe5dxl@oevsv.at>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */


#define X2C_int32
#define X2C_index32
#ifndef X2C_H_
#include "X2C.h"
#endif
#define udpbox_C_
#ifndef udp_H_
#include "udp.h"
#endif
#ifndef osi_H_
#include "osi.h"
#endif
#include <osic.h>
#ifndef Select_H_
#include "Select.h"
#endif
#ifndef aprspos_H_
#include "aprspos.h"
#endif
#ifndef aprsstr_H_
#include "aprsstr.h"
#endif

/* axudp in/out ui/aprs stream splitter, filter, digipeater by OE5DXL */
/*FROM FdSet IMPORT FdSet, FD_ZERO, FD_SET, FD_ISSET, TimeVal;*/
/*FROM mlib IMPORT select*/
/*FROM Storage IMPORT ALLOCATE; */
/*FROM Lib IMPORT NextArg; */
/*FROM TimeConv IMPORT time;  */
#define udpbox_CALLLEN 7

#define udpbox_HASHSIZE 16384

#define udpbox_NOTFIRSTDIGI 3

#define udpbox_NOUPLINKCHECK 4

#define udpbox_SENDTRACE 5

#define udpbox_SENDWIDE 6

#define udpbox_DOWNPATHDIGICALL 7

#define udpbox_DOWNPATHRELAY 8

#define udpbox_DOWNPATHWIDE 9

#define udpbox_NOVIADIGICALL 10

#define udpbox_NOVIARELAY 11

#define udpbox_NOVIATRACE 12

#define udpbox_NOVIAWIDEN 13

#define udpbox_NOCALLBEFOREWIDE 14

#define udpbox_SSIDTOWIDE 15

#define udpbox_NULLSSID 16

#define udpbox_KILLWIDE 17

#define udpbox_VIAGATE 18

#define udpbox_RELAYECHO 19
/*      FINGERPRINT=20; */

#define udpbox_STDIN 0

#define udpbox_STDINIP 0x0FFFFFFFF

typedef uint32_t SET256[8];

typedef char RAWCALL[7];

typedef char MONCALL[9];

typedef char FILENAME[1024];

struct DIGIPARMS;

typedef struct DIGIPARMS * pDIGIPARMS;


struct DIGIPARMS {
   RAWCALL digicall;
   uint32_t pathcheck;
   uint32_t duptime;
   uint32_t messagetime;
   uint32_t timehash[16384];
};

struct BEACON;


struct BEACON {
   uint32_t bintervall;
   uint32_t piggytime; /* time send beacons earlier if sending some else */
   char piggyback; /* sent something so append beacon immediately */
   FILENAME bfile;
   uint32_t btime;
   uint32_t bline;
};

struct CALLS;

typedef struct CALLS * pCALLS;


struct CALLS {
   pCALLS next;
   RAWCALL call;
};

struct OUTPORT;

typedef struct OUTPORT * pOUTPORT;


struct OUTPORT {
   pOUTPORT next;
   uint32_t toip;
   uint32_t toport;
   pCALLS filtercalls;
   char echo;
   char rawwrite;
   char crlfwrite;
   char passnoUI;
   char axudp2;
   char satgate;
   SET256 aprspass;
   pDIGIPARMS digiparm;
   struct BEACON beacon0;
   struct aprspos_POSITION mypos;
   int32_t maxkm;
};

struct INSOCK;

typedef struct INSOCK * pINSOCK;


struct INSOCK {
   pINSOCK next;
   int32_t fd;
   char rawread;
   MONCALL rflinkname;
   uint32_t fromip;
   uint32_t bindport;
   pOUTPORT outchain;
};

struct MSGHASH;

typedef struct MSGHASH * pMSGHASH;

struct _0;


struct _0 {
   uint32_t sums;
   uint32_t ackcnt;
   uint32_t acktime;
   pINSOCK source;
   MONCALL froms;
   char acks[6];
};


struct MSGHASH {
   pMSGHASH next;
   MONCALL usercall;
   FILENAME msgfile;
   uint32_t wpos;
   struct _0 hash[16];
};

#define udpbox_MAXLEN 338

#define udpbox_MINLEN 17

static char udpbox_BLANKH = '@';

#define udpbox_HBIT 128

#define udpbox_ACKMSG "ack"

static uint32_t udpbox_POLYNOM = 0x8408UL;

#define udpbox_cFILTPASS "p"

#define udpbox_cFILTDEL "d"

#define udpbox_DEFAULTMESSAGETIME 28
/* block seconds user message frames */

#define udpbox_DEFAULTDUPTIME 1740
/* block seconds invariant payload frames */

#define udpbox_CR "\015"

#define udpbox_LF "\012"

#define udpbox_SENDACKS 4

#define udpbox_OLDMSG 600
/* s long kill dupe user message */

#define udpbox_TOCALL "APNL01"

#define udpbox_DEFAULTACK "WIDE2-2"

#define udpbox_cUSERMSG ":"

#define udpbox_cTELEMETRY "T"

static char show;

static pINSOCK insocks;

static uint32_t showip;

static uint32_t showport;

static pMSGHASH msgusers;

static char ackpath[64];

static uint32_t stdinpos;

static char stdinbuf[256];


static void Err(const char text[], uint32_t text_len)
{
   osi_WrStr("udpbox: ", 9ul);
   osi_WrStr(text, text_len);
   osi_WrStrLn(" error abort", 13ul);
   X2C_ABORT();
} /* end Err() */


static void Stomsg(pMSGHASH user, const char from[], uint32_t from_len,
                 const char to[], uint32_t to_len,
                const char msg[], uint32_t msg_len,
                const char ack[], uint32_t ack_len, pINSOCK fromsock)
{
   uint32_t h;
   uint32_t i;
   uint32_t t;
   int32_t f;
   char mb[256];
   struct MSGHASH * anonym;
   struct _0 * anonym0;
   { /* with */
      struct MSGHASH * anonym = user;
      i = 0UL;
      while (i<=msg_len-1 && msg[i]) ++i;
      t = osic_time();
      h = aprsstr_Hash(msg, msg_len, 0L, (int32_t)i)&16383UL;
      i = 0UL;
      while (i<=15UL && !(((h==anonym->hash[i].sums && anonym->hash[i]
                .acktime+600UL>=t) && aprsstr_StrCmp(ack, ack_len,
                anonym->hash[i].acks, 6ul)) && aprsstr_StrCmp(from, from_len,
                 anonym->hash[i].froms, 9ul))) ++i;
      if (i>15UL) {
         /* new msg*/
         aprsstr_DateToStr(t, mb, 256ul);
         aprsstr_Append(mb, 256ul, " from ", 7ul);
         aprsstr_Append(mb, 256ul, from, from_len);
         aprsstr_Append(mb, 256ul, " to ", 5ul);
         aprsstr_Append(mb, 256ul, to, to_len);
         aprsstr_Append(mb, 256ul, " <", 3ul);
         aprsstr_Append(mb, 256ul, msg, msg_len);
         aprsstr_Append(mb, 256ul, "> (", 4ul);
         aprsstr_Append(mb, 256ul, ack, ack_len);
         aprsstr_Append(mb, 256ul, ")", 2ul);
         if (show) {
            osi_WrStr(" <", 3ul);
            osi_WrStr(mb, 256ul);
            osi_WrStr("> ", 3ul);
         }
         aprsstr_Append(mb, 256ul, "\012", 2ul);
         if (anonym->msgfile[0U]) {
            f = osi_OpenAppend(anonym->msgfile, 1024ul);
            if (f<0L) f = osi_OpenWrite(anonym->msgfile, 1024ul);
            if (f>=0L) {
               osi_WrBin(f, (char *)mb, 256u/1u, aprsstr_Length(mb,
                256ul));
               osic_Close(f);
            }
         }
         { /* with */
            struct _0 * anonym0 = &anonym->hash[anonym->wpos];
            anonym0->sums = h;
            aprsstr_Assign(anonym0->acks, 6ul, ack, ack_len);
            aprsstr_Assign(anonym0->froms, 9ul, from, from_len);
            if ((uint8_t)ack[0UL]>' ') {
               anonym0->ackcnt = 4UL;
               anonym0->acktime = 0UL;
            }
            anonym0->source = fromsock;
         }
         ++anonym->wpos;
         if (anonym->wpos>15UL) anonym->wpos = 0UL;
      }
      else {
         /* old msg */
         anonym->hash[i].ackcnt = 4UL;
      }
   }
} /* end Stomsg() */

#define udpbox_THIRDPARTY "}"

#define udpbox_HEADEREND ":"

#define udpbox_FROMEND ">"

#define udpbox_USERACK "{"


static char Usermsg(const char b[], uint32_t b_len,
                int32_t len, int32_t p, pINSOCK fromsock,
                char * selfmsg)
{
   int32_t pf;
   uint32_t j;
   pMSGHASH user;
   char to[9];
   char from[9];
   char ack[6];
   char msg[69];
   char ok0;
   *selfmsg = 0;
   pf = 0L; /* from whom */
   while (b[p]=='}') {
      /* remove third party header */
      pf = p+1L;
      while (p<len && b[p]!=':') ++p;
      ++p;
   }
   if ((p+10L<len && b[p]==':') && b[p+10L]==':') {
      /* user message */
      ++p;
      j = 0UL; /* message from */
      if (pf==0L) ok0 = aprsstr_Call2Str(b, b_len, from, 9ul, 7UL, &j);
      else {
         while ((pf<len && j<=8UL) && b[pf]!='>') {
            from[j] = b[pf];
            ++pf;
            ++j;
         }
      }
      while (j<=8UL) {
         from[j] = ' ';
         ++j;
      }
      ok0 = 0;
      for (j = 0UL; j<=8UL; j++) {
         /* message to */
         to[j] = b[p+(int32_t)j];
         if (to[j]!=from[j]) ok0 = 1;
      } /* end for */
      if (!ok0) {
         /* msg from to same call */
         if (show) osi_WrStr(" msg to it self ", 17ul);
         *selfmsg = 1;
         return 0;
      }
      /*WrStr("<"); WrStr(from); WrStr(">"); WrStr("<"); WrStr(to);
                WrStrLn(">"); */
      user = msgusers;
      while (user) {
         j = 0UL;
         while (j<=8UL && user->usercall[j]==to[j]) ++j;
         if (j==9UL) {
            /*
                    j:=0;
                    IF pf=0 THEN
                      IF Call2Str(b, from, 7, j) THEN END;
                    ELSE 
                      WHILE (pf<len) & (j<=HIGH(from)) & (b[pf]<>FROMEND)
                DO from[j]:=b[pf]; INC(pf); INC(j); END;
                    END;
                    WHILE j<=HIGH(from) DO from[j]:=" "; INC(j) END; 
            
                    FOR j:=0 TO 8 DO to[j]:=b[p]; INC(p) END;
            */
            p += 10L;
            j = 0UL;
            while ((p<len && j<68UL) && b[p]!='{') {
               msg[j] = b[p];
               ++j;
               ++p;
            }
            msg[j] = 0;
            j = 0UL;
            for (;;) {
               if ((uint8_t)"ack"[j]<=' ') return 0;
               /* "ack" in text field is not for delete */
               if ("ack"[j]!=msg[j]) break;
               ++j;
            }
            ++p;
            j = 0UL;
            while (p<len && j<5UL) {
               ack[j] = b[p];
               ++j;
               ++p;
            }
            ack[j] = 0;
            Stomsg(user, from, 9ul, to, 9ul, msg, 69ul, ack, 6ul, fromsock);
            return 1;
         }
         user = user->next;
      }
   }
   return 0;
} /* end Usermsg() */

static char udpbox_WILDH = 'T';


static char CallFilt(pCALLS calls, const char s[],
                uint32_t s_len, int32_t len)
{
   int32_t j;
   int32_t i;
   pCALLS c;
   char b;
   char ok0;
   i = 0L;
   do {
      c = calls;
      while (c) {
         j = 0L;
         for (;;) {
            if (c->call[j]!='T' && c->call[j]!=s[i+j]) break;
            ++j;
            if (j>=6L) {
               if (c->call[j] && ((uint8_t)(uint8_t)c->call[j]&0x1EU)
                !=((uint8_t)(uint8_t)s[i+j]&0x1EU)) break;
               return 1;
            }
         }
         c = c->next;
      }
      i += 7L;
   } while (!(i>=len || ((uint32_t)(uint8_t)s[i-1L]&1)));
   i += 2L;
   if (s[i]=='}') {
      ++i;
      for (;;) {
         if (i>=len) break;
         c = calls;
         while (c) {
            j = 0L;
            ok0 = 1;
            for (;;) {
               b = s[i+j];
               if (((((i+j>=len || b=='*') || b==',') || b=='>') || b==':')
                || b=='-') break;
               if (j>=6L || c->call[j]!='T' && b!=(char)((uint32_t)
                (uint8_t)c->call[j]>>1)) ok0 = 0;
               ++j;
            }
            if (ok0 && (j>=6L || c->call[j]=='@')) return 1;
            c = c->next;
         }
         while (((i<len && s[i]!=',') && s[i]!='>') && s[i]!=':') ++i;
         if (s[i]==':') {
            ++i;
            if (s[i]!='}') break;
         }
         ++i;
      }
   }
   return 0;
} /* end CallFilt() */


static int32_t DistFilt(struct aprspos_POSITION mypos, char b[],
                uint32_t b_len, uint32_t payload, uint32_t len)
{
   uint32_t course;
   uint32_t speed;
   uint32_t i;
   char comment0[501];
   int32_t alt;
   char postyp;
   char symt;
   char sym;
   struct aprspos_POSITION pos;
   int32_t DistFilt_ret;
   X2C_PCOPY((void **)&b,b_len);
   for (i = 6UL;; i--) {
      b[i+1UL] = (char)X2C_LSH((uint8_t)(uint8_t)b[i],8,-1);
      if (i==0UL) break;
   } /* end for */
   b[len] = 0;
   aprspos_GetPos(&pos, &speed, &course, &alt, &sym, &symt, b, b_len, 1UL,
                payload, comment0, 501ul, &postyp);
   if (aprspos_posvalid(pos)) {
      DistFilt_ret = (int32_t)(uint32_t)
                X2C_TRUNCC(aprspos_distance(mypos, pos),0UL,
                X2C_max_longcard);
   }
   else DistFilt_ret = -1L;
   X2C_PFREE(b);
   return DistFilt_ret;
} /* end DistFilt() */


static char Filter(const char b[], uint32_t b_len,
                int32_t len, pOUTPORT parm, pINSOCK fromsock)
{
   int32_t i;
   int32_t km;
   char selfmsg;
   len -= 2L; /* crc */
   if (len<=0L) {
      if (parm->passnoUI) {
         if (show) osi_WrStrLn(" pass axudp2", 13ul);
         return 1;
      }
      else return 0;
   }
   i = 13L;
   while (i<len && !((uint32_t)(uint8_t)b[i]&1)) i += 7L;
   i += 3L;
   if (i>len || ((uint8_t)(uint8_t)b[i-2L]&~0x10U)!=0x3U) {
      if (show) osi_WrStr(" not UI ", 9ul);
      return parm->passnoUI;
   }
   /* not UI frame */
   /* is UI frame */
   if (Usermsg(b, b_len, len, i, fromsock, &selfmsg)) return 0;
   if (parm->filtercalls && CallFilt(parm->filtercalls, b, b_len, len)) {
      if (show) osi_WrStrLn(" callfilter match", 18ul);
      return 0;
   }
   if (!X2C_INL((uint8_t)b[i],256,
                parm->aprspass) || selfmsg && !X2C_INL((int32_t)84,256,
                parm->aprspass)) {
      if (show) osi_WrStrLn(" message type filter", 21ul);
      return 0;
   }
   if (parm->maxkm>0L && (b[i]!=':' || b[i+10L]!=':')) {
      /* dist filter on and no user message */
      km = DistFilt(parm->mypos, b, b_len, (uint32_t)i, (uint32_t)len);
      if (km<0L) {
         if (show) osi_WrStrLn(" no pos", 8ul);
         return 0;
      }
      if (show) {
         osi_WrStrLn(" ", 2ul);
         osic_WrINT32((uint32_t)km, 1UL);
         osi_WrStr("km", 3ul);
      }
      if (km>=parm->maxkm) {
         if (show) osi_WrStrLn(" too far", 9ul);
         return 0;
      }
   }
   if ((parm->satgate && !((uint32_t)(uint8_t)b[13UL]&1)) && (uint8_t)
                b[20UL]<(uint8_t)'\200') {
      /* has >=1 vias and first via no h-bit */
      if (show) osi_WrStrLn(" sat gate and direct heard", 27ul);
      return 0;
   }
   return 1;
} /* end Filter() */


static int32_t getstdin(char buf[], uint32_t buf_len)
{
   char c;
   while (osi_RdBin(0L, (char *) &c, 1u/1u, 1UL)==1L) {
      if (c=='\012') c = 0;
      if (stdinpos<255UL) {
         stdinbuf[stdinpos] = c;
         ++stdinpos;
      }
      if (c==0) {
         aprsstr_Assign(buf, buf_len, stdinbuf, 256ul);
         stdinpos = 0UL;
         return (int32_t)aprsstr_Length(buf, buf_len);
      }
   }
   return -1L;
} /* end getstdin() */


static int32_t getudp(int32_t fd, char buf[], uint32_t buf_len,
                uint32_t fromip, char addcrc)
{
   uint32_t fromport;
   uint32_t ip;
   char crc2;
   char crc1;
   int32_t len;
   len = udpreceive(fd, buf, (int32_t)(buf_len), &fromport, &ip);
   if ((len>2L && len<(int32_t)(buf_len)) && (fromip==0UL || fromip==ip)) {
      showip = ip;
      showport = fromport;
      if (!addcrc) return len;
      crc1 = buf[len-2L];
      crc2 = buf[len-1L];
      aprsstr_AppCRC(buf, buf_len, len-2L);
      if (crc1==buf[len-2L] && crc2==buf[len-1L]) return len;
      if (show) osi_WrStrLn(" raw crc error ", 16ul);
   }
   /*
         IO.WrHex(ORD(crc1)+ORD(crc2)*256, 1);
         IO.WrStr("<>");
         IO.WrHex(ORD(buf[len-2])+ORD(buf[len-1])*256, 1);
         IO.WrStr("  ");
   */
   return -1L;
} /* end getudp() */


static void checkhamnet(char b[], uint32_t b_len, int32_t * len,
                const char rflinkname[], uint32_t rflinkname_len,
                RAWCALL hamup0)
{
   int32_t j;
   int32_t i;
   uint32_t s;
   int32_t tmp;
   if (rflinkname[0UL]==0) return;
   hamup0[0U] = 0;
   i = 0L;
   while (b[i]!='>') {
      /* skip fromcall */
      ++i;
      if (i>=*len) {
         *len = 0L;
         return;
      }
   }
   ++i;
   j = 0L;
   while (j<=(int32_t)(rflinkname_len-1) && rflinkname[j]) {
      /* compare rflink name */
      if (b[i]!=rflinkname[j]) {
         *len = 0L;
         return;
      }
      ++i;
      ++j;
   }
   if (b[i]==',') {
      ++i;
      j = 0L;
      while (((i<*len && b[i]!='-') && b[i]!=',') && b[i]!=':') {
         /* make rawcall of rflink uplink */
         s = (uint32_t)(uint8_t)b[i]*2UL&255UL;
         if (s<=64UL) {
            *len = 0L;
            return;
         }
         hamup0[j] = (char)s;
         ++i;
         ++j;
         if (j>=7L) {
            *len = 0L;
            return;
         }
      }
      while (j<6L) {
         hamup0[j] = '@';
         ++j;
      }
      s = 0UL;
      if (b[i]=='-') {
         ++i;
         while ((uint8_t)b[i]>='0' && (uint8_t)b[i]<='9') {
            s = (s*10UL+(uint32_t)(uint8_t)b[i])-48UL;
            ++i;
         }
         if (s>15UL) {
            *len = 0L;
            return;
         }
      }
      hamup0[j] = (char)((s+48UL+64UL)*2UL); /* set H bit */
   }
   if (b[i]!=',' && b[i]!=':') {
      *len = 0L;
      return;
   }
   while (b[i]!='}') {
      /* find end of rflink head */
      ++i;
      if (i>=*len) {
         *len = 0L;
         return;
      }
   }
   ++i;
   *len -= i; /* payload len */
   tmp = *len;
   j = 0L;
   if (j<=tmp) for (;; j++) {
      b[j] = b[i]; /* remove rflink head */
      ++i;
      if (j==tmp) break;
   } /* end for */
/* DIGICALL>HAMNAME,UPLINKCALL,.... :}payload */
} /* end checkhamnet() */

/*
PROCEDURE MakeDupeTime(s-:ARRAY OF CHAR; p:INTEGER; parm:pDIGIPARMS):TIME;
VAR le,nu:CARDINAL;
    i:INTEGER; 
BEGIN
  le:=0;
  nu:=0;
  FOR i:=p+3 TO p+5 DO 
    IF (s[i]>="A") & (s[i]<="Z") THEN INC(le) END;
    IF (s[i]>="0") & (s[i]<="9") THEN INC(nu) END;
  END;
  IF (s[p+2]=cUSERMSG) & (le>0) & (nu>0) & (le+nu=3)
                THEN        (* looks like a user message *)
    RETURN parm^.messagetime
  END;
  RETURN parm^.duptime
END MakeDupeTime;
*/

static char IsCall(const char raw[], uint32_t raw_len,
                uint32_t pos, uint32_t div0)
{
   uint32_t i;
   uint32_t nu;
   uint32_t le;
   char c;
   uint32_t tmp;
   le = 0UL;
   nu = 0UL;
   tmp = pos+2UL;
   i = pos;
   if (i<=tmp) for (;; i++) {
      c = (char)((uint32_t)(uint8_t)raw[i]/div0);
      if ((uint8_t)c>='A' && (uint8_t)c<='Z') ++le;
      if ((uint8_t)c>='0' && (uint8_t)c<='9') ++nu;
      if (i==tmp) break;
   } /* end for */
   return (le>0UL && nu>0UL) && le+nu==3UL;
/* looks like a call */
} /* end IsCall() */


static char Dup(const char raw[], uint32_t raw_len,
                uint32_t pathlen, uint32_t rawlen, uint32_t * sum)
{
   uint32_t i;
   uint32_t len;
   uint8_t hashh;
   uint8_t hashl;
   char h[256];
   char ok0;
   /*
     PROCEDURE hash(c:CHAR);
     VAR b:CARD8;
     BEGIN
   (*
   IO.WrStr("<");IO.WrChar(c);IO.WrStr(">");
   *)
       IF c<>" " THEN
         b:=CAST(CARD8, CAST(SET8, c) / hashl);
         hashl:=CRCL[b] / hashh;
         hashh:=CRCH[b];
       END;
     END hash;
   */
   hashl = 0U;
   hashh = 0U;
   pathlen += 2UL; /* skip frametyp pid */
   if (raw[pathlen]!='}') {
      len = 0UL;
      ok0 = aprsstr_Call2Str(raw, raw_len, h, 256ul, 7UL, &len);
      i = 0UL;
      while (i<len) {
         aprsstr_HashCh(h[i], &hashl, &hashh);
         ++i;
      }
      len = 0UL;
      ok0 = aprsstr_Call2Str(raw, raw_len, h, 256ul, 0UL, &len);
      i = 0UL;
      while (i<len && h[i]!='-') {
         aprsstr_HashCh(h[i], &hashl, &hashh);
         ++i;
      }
   }
   else {
      i = pathlen+1UL;
      for (;;) {
         ++pathlen;
         if (pathlen>=rawlen) break;
         if (raw[pathlen-1UL]==':') {
            if (raw[pathlen]=='}') i = pathlen+1UL;
            else break;
         }
      }
      while (i<pathlen-1UL && raw[i]!='>') {
         aprsstr_HashCh(raw[i], &hashl, &hashh);
         ++i;
      }
      ++i;
      while ((i<pathlen-1UL && raw[i]!='-') && raw[i]!=',') {
         aprsstr_HashCh(raw[i], &hashl, &hashh);
         ++i;
      }
   }
   i = pathlen;
   while ((i<rawlen && raw[i]!='\015') && raw[i]!='\012') {
      aprsstr_HashCh(raw[i], &hashl, &hashh);
      ++i;
   }
   *sum = (uint32_t)(uint8_t)(char)hashl+(uint32_t)(uint8_t)
                (char)hashh*256UL&16383UL;
   if (raw[pathlen]!=':') return 0;
   return IsCall(raw, raw_len, pathlen+1UL, 1UL);
/* if call it is user msg */
} /* end Dup() */


static char Cmp(const char s[], uint32_t s_len,
                uint32_t start, const char word[],
                uint32_t word_len)
{
   uint32_t i;
   i = 0UL;
   while (word[i]) {
      if (word[i]!=(char)((uint32_t)(uint8_t)s[start]/2UL)) return 0;
      ++i;
      ++start;
   }
   return 1;
} /* end Cmp() */


static char ChkNN(uint32_t ssid, char c)
{
   c = (char)((uint32_t)(uint8_t)c/2UL);
   return c==' ' && ssid==0UL || ((uint8_t)c>='1' && (uint8_t)c<='7')
                && (uint8_t)c>=(uint8_t)(char)(48UL+ssid);
} /* end ChkNN() */


static char NeqN(uint32_t ssid, char c, int32_t pos)
{
   return pos<=14L && (ssid+48UL==(uint32_t)(uint8_t)
                c/2UL || ssid==0UL && c=='@');
} /* end NeqN() */


static void setSSID(char * c, uint32_t ssid)
{
   *c = (char)((uint8_t)(uint8_t)*c&~0x1EU|(uint8_t)(ssid*2UL));
} /* end setSSID() */


static uint32_t getSSID(char c)
{
   return (uint32_t)(uint8_t)c/2UL&15UL;
} /* end getSSID() */


static void killwide(int32_t * startpath, int32_t downpath, char s[],
                 uint32_t s_len)
{
   int32_t j;
   int32_t i;
   int32_t tmp;
   int32_t tmp0;
   tmp = downpath-1L;
   i = *startpath;
   if (i<=tmp) for (tmp = (uint32_t)(tmp-i)/7L;;) {
      if (((s[i]=='\256' && s[i+1L]=='\222') && s[i+2L]=='\210')
                && s[i+3L]=='\212') {
         tmp0 = *startpath;
         j = i-1L;
         if (j>=tmp0) for (;; j--) {
            s[j+7L] = s[j];
            if (j==tmp0) break;
         } /* end for */
         *startpath += 7L;
      }
      if (!tmp) break;
      --tmp;
      i += 7L;
   } /* end for */
} /* end killwide() */


static void Digi(char raw[], uint32_t raw_len, char send[],
                uint32_t send_len, int32_t inlen0, int32_t * outlen0,
                const RAWCALL hamup0, pDIGIPARMS parm, char duponly)
{
   int32_t goodpath;
   int32_t downpath;
   int32_t actdigi;
   int32_t startpath;
   int32_t pathlen;
   int32_t j;
   int32_t i;
   uint32_t ssidroute;
   uint32_t hash;
   uint32_t ssid;
   uint32_t tt;
   uint32_t t;
   char noloop;
   char nodigicall;
   char ok0;
   int32_t tmp;
   if ((uint8_t)parm->digicall[0U]<='@') duponly = 1;
   *outlen0 = 0L;
   inlen0 -= 2L; /* crc bytes */
   pathlen = 13L;
   while (pathlen<inlen0 && !((uint32_t)(uint8_t)raw[pathlen]&1)) {
      pathlen += 7L; /* find end of path */
   }
   ++pathlen;
   ok0 = 0;
   downpath = 0L;
   if (!duponly) {
      /*  IF (FINGERPRINT IN parm^.pathcheck) OR ((raw[6]>=200C)
                <>(raw[13]>=200C)) THEN */
      actdigi = 14L;
      noloop = 1;
      if ((0x8UL & parm->pathcheck)) {
         /* need not be first repeater */
         while (actdigi<pathlen && (uint8_t)raw[actdigi+6L]>=(uint8_t)
                '\200') {
            /* test if own digicall in path */
            ok0 = 0;
            for (i = 0L; i<=5L; i++) {
               if (raw[i+actdigi]!=parm->digicall[i]) ok0 = 1;
            } /* end for */
            if (getSSID(raw[(actdigi+7L)-1L])!=getSSID(parm->digicall[6U])) {
               ok0 = 1;
            }
            if (!ok0) noloop = 0;
            actdigi += 7L;
         }
      }
      if (noloop) {
         /* not looping thru own digi */
         startpath = actdigi+7L;
         nodigicall = 0;
         if ((0x80UL & parm->pathcheck)) downpath = pathlen;
         /* test for ssid routing*/
         ssid = (uint32_t)(int32_t)(parm->pathcheck&0x7UL);
                /* limit ssid routing hopps */
         ssidroute = getSSID(raw[6UL]); /* destination call ssid */
         goodpath = 14L;
         while ((goodpath<pathlen && (uint8_t)raw[goodpath+6L]>=(uint8_t)
                '\200') && IsCall(raw, raw_len, (uint32_t)goodpath, 2UL)) {
            goodpath += 7L; /* repeated via callsigns */
         }
         if ((((ssidroute>0UL && ssid>0UL) && goodpath==pathlen)
                && pathlen<49L) && ((0x8UL & parm->pathcheck)
                || goodpath==14L)) {
            ok0 = 1;
            if (ssidroute>7UL) ssidroute = 1UL;
            if (ssidroute>ssid) ssidroute = ssid;
            if (ssidroute==1UL || (0x8000UL & parm->pathcheck)==0) {
               /* use decrement dest ssid routing */
               setSSID(&raw[6UL], ssidroute-1UL);
                /* chain by dec dest ssid */
               ssidroute = 0UL;
            }
            else {
               /* expand to digicall + wideN-N */
               --ssidroute;
               setSSID(&raw[6UL], 0UL); /* switch to via routing */
            }
            downpath = 0L; /* delete rest of path */
            if (show) osi_WrStr(" via ssid routing ", 19ul);
         }
         else {
            ssidroute = 0UL;
            if (goodpath<=14L) goodpath = 0L;
            if ((0x10UL & parm->pathcheck)) goodpath = actdigi;
            ok0 = pathlen>actdigi && (uint8_t)raw[actdigi+6L]<(uint8_t)
                '\200'; /* there are via calls & is not digipeated */
            if (ok0) {
               ssid = getSSID(raw[actdigi+6L]);
               if ((0x400UL & parm->pathcheck)) ok0 = 0;
               else {
                  for (i = 0L; i<=5L; i++) {
                     if (raw[i+actdigi]!=parm->digicall[i]) {
                        ok0 = 0;
                     }
                  } /* end for */
                  if (ssid!=getSSID(parm->digicall[6U])) ok0 = 0;
               }
               if (ok0) {
                  if ((0x80UL & parm->pathcheck)) downpath = pathlen;
                  if (show) osi_WrStr(" via digicall ", 15ul);
               }
               else if ((0x800UL & parm->pathcheck)==0) {
                  ok0 = Cmp(raw, raw_len, (uint32_t)actdigi, "RELAY ",
                7ul);
                  if (!ok0 && (0x80000UL & parm->pathcheck)) {
                     ok0 = Cmp(raw, raw_len, (uint32_t)actdigi, "ECHO  ",
                7ul);
                  }
                  if (ok0) {
                     if ((0x100UL & parm->pathcheck)) downpath = pathlen;
                     if (show) osi_WrStr(" via RELAY ", 12ul);
                  }
               }
               if (!ok0) {
                  if ((0x40000UL & parm->pathcheck)) {
                     ok0 = Cmp(raw, raw_len, (uint32_t)actdigi, "GATE  ",
                7ul);
                     if (ok0) {
                        if ((0x100UL & parm->pathcheck)) {
                           downpath = pathlen;
                        }
                        if (show) osi_WrStr(" via GATE ", 11ul);
                     }
                  }
               }
               if (!ok0) {
                  if ((((0x1000UL & parm->pathcheck)==0 && Cmp(raw, raw_len,
                (uint32_t)actdigi, "TRACE", 6ul)) && ChkNN(ssid,
                raw[actdigi+5L])) && (goodpath==actdigi || NeqN(ssid,
                raw[actdigi+5L], actdigi))) {
                     ok0 = 1;
                     if (ssid>(uint32_t)((0x10000UL & parm->pathcheck)==0)
                && (0x20UL & parm->pathcheck)) {
                        setSSID(&raw[actdigi+6L], ssid-1UL);
                /* dec(N) of WIDEn-N */
                        startpath = actdigi;
                     }
                     if ((0x100UL & parm->pathcheck)==0) {
                        downpath = actdigi+7L;
                     }
                  }
                  if (show && ok0) osi_WrStr(" via TRACEn-n ", 15ul);
               }
               if (!ok0) {
                  if (((((0x2000UL & parm->pathcheck)==0 && Cmp(raw, raw_len,
                 (uint32_t)actdigi, "WIDE",
                5ul)) && raw[actdigi+5L]=='@') && ChkNN(ssid,
                raw[actdigi+4L])) && (goodpath==actdigi || NeqN(ssid,
                raw[actdigi+4L], actdigi))) {
                     ok0 = 1;
                     if (raw[actdigi+4L]!='@' && (0x40UL & parm->pathcheck)) {
                        if ((0x4000UL & parm->pathcheck)
                || goodpath!=actdigi && !NeqN(ssid, raw[actdigi+4L],
                actdigi)) nodigicall = 1;
                        if (ssid>(uint32_t)((0x10000UL & parm->pathcheck)
                ==0)) {
                           setSSID(&raw[actdigi+6L], ssid-1UL);
                           startpath = actdigi;
                        }
                        else if (nodigicall) {
                           raw[actdigi+6L] = '\340'; /* WIDE* */
                        }
                        if (nodigicall) startpath = actdigi;
                     }
                     if ((0x200UL & parm->pathcheck)==0) {
                        downpath = actdigi+7L;
                     }
                  }
                  if (show && ok0) osi_WrStr(" via WIDEn-n ", 14ul);
               }
               if (show && !ok0) osi_WrStr(" no source path ", 17ul);
            }
            else if (show) osi_WrStr(" already digipeated ", 21ul);
         }
      }
      else if (show) osi_WrStr(" we have already digipeated ", 29ul);
   }
   /*    ELSIF show THEN WrStr(" fingerprint filtered " ) END; */
   if (duponly || ok0) {
      /*
      IO.WrLn; IO.WrStr("<<<");IO.WrHex(ORD(raw[pathlen+2]),1);
                IO.WrStr(">>> ");
      */
      tt = parm->duptime;
      if (Dup(raw, raw_len, (uint32_t)pathlen, (uint32_t)inlen0, &hash)) {
         tt = parm->messagetime;
      }
      t = osic_time(); /* time in s */
      if (parm->timehash[hash]+tt<=t) {
         /* not a duplicate */
         parm->timehash[hash] = t;
         if (duponly) {
            /* dupfilter only */
            *outlen0 = inlen0+2L;
            tmp = *outlen0-1L;
            i = 0L;
            if (i<=tmp) for (;; i++) {
               send[i] = raw[i];
               if (i==tmp) break;
            } /* end for */
         }
         else {
            /* digipeater */
            i = 0L;
            while (i<actdigi) {
               send[i] = (char)((uint8_t)(uint8_t)raw[i]&0xFEU);
                /* copy from-to and clear address end bit */
               ++i;
            }
            if (!nodigicall) {
               if (hamup0[0U]) {
                  for (j = 0L; j<=6L; j++) {
                     send[i] = hamup0[j]; /* append uplink via digicall */
                     ++i;
                  } /* end for */
               }
               for (j = 0L; j<=6L; j++) {
                  send[i] = parm->digicall[j]; /* append new via digicall */
                  ++i;
               } /* end for */
            }
            if (ssidroute>0UL) {
               send[i] = '\256';
               ++i;
               send[i] = '\222';
               ++i;
               send[i] = '\210';
               ++i;
               send[i] = '\212';
               ++i;
               send[i] = (char)((48UL+ssidroute)*2UL);
               ++i;
               send[i] = '@';
               ++i;
               send[i] = (char)((48UL+ssidroute)*2UL); /* no H bit set */
               ++i;
            }
            if ((0x20000UL & parm->pathcheck)) {
               killwide(&startpath, downpath, raw, raw_len);
            }
            j = startpath; /* append rest of path */
            while (j<downpath && i<70L) {
               send[i] = raw[j];
               ++i;
               ++j;
            }
            send[i-1L] = (char)((uint8_t)(uint8_t)send[i-1L]|0x1U);
                /* set address end bit */
            tmp = inlen0-1L;
            j = pathlen;
            if (j<=tmp) for (;; j++) {
               send[i] = raw[j]; /* append data field no crc */
               ++i;
               if (j==tmp) break;
            } /* end for */
            aprsstr_AppCRC(send, send_len, i);
            *outlen0 = i+2L;
         }
      }
      else if (show) {
         osi_WrStr(" ", 2ul);
         osic_WrINT32(t-parm->timehash[hash], 1UL);
         osi_WrStr("s since same payload ", 22ul);
      }
   }
} /* end Digi() */


static int32_t GetIp(char h[], uint32_t h_len, uint32_t * p,
                uint32_t * ip, uint32_t * port)
{
   uint32_t n;
   uint32_t i;
   char ok0;
   int32_t GetIp_ret;
   X2C_PCOPY((void **)&h,h_len);
   *p = 0UL;
   h[h_len-1] = 0;
   *ip = 0UL;
   for (i = 0UL; i<=4UL; i++) {
      n = 0UL;
      ok0 = 0;
      while ((uint8_t)h[*p]>='0' && (uint8_t)h[*p]<='9') {
         ok0 = 1;
         n = (n*10UL+(uint32_t)(uint8_t)h[*p])-48UL;
         ++*p;
      }
      if (!ok0) {
         GetIp_ret = -1L;
         goto label;
      }
      if (i<3UL) {
         if (h[*p]!='.' || n>255UL) {
            GetIp_ret = -1L;
            goto label;
         }
         *ip =  *ip*256UL+n;
      }
      else if (i==3UL) {
         *ip =  *ip*256UL+n;
         if (h[*p]!=':' || n>255UL) {
            GetIp_ret = -1L;
            goto label;
         }
      }
      else if (n>65535UL) {
         GetIp_ret = -1L;
         goto label;
      }
      *port = n;
      ++*p;
   } /* end for */
   GetIp_ret = 0L;
   label:;
   X2C_PFREE(h);
   return GetIp_ret;
} /* end GetIp() */


static int32_t GetSec(char h[], uint32_t h_len, uint32_t * p,
                uint32_t * n)
{
   char ok0;
   int32_t GetSec_ret;
   X2C_PCOPY((void **)&h,h_len);
   h[h_len-1] = 0;
   *n = 0UL;
   ok0 = 0;
   while ((uint8_t)h[*p]>='0' && (uint8_t)h[*p]<='9') {
      ok0 = 1;
      *n = ( *n*10UL+(uint32_t)(uint8_t)h[*p])-48UL;
      ++*p;
   }
   if (!ok0) {
      GetSec_ret = -1L;
      goto label;
   }
   /*
   IO.WrCard(n,10); IO.WrLn;
   */
   GetSec_ret = 0L;
   label:;
   X2C_PFREE(h);
   return GetSec_ret;
} /* end GetSec() */


static void MakeRawCall(RAWCALL c, char s[], uint32_t s_len,
                uint32_t j)
{
   uint32_t n;
   uint32_t i;
   X2C_PCOPY((void **)&s,s_len);
   i = 0UL;
   while (i<6UL) {
      if ((s[j] && s[j]!=',') && s[j]!='-') {
         c[i] = (char)((uint32_t)(uint8_t)s[j]*2UL);
         ++j;
      }
      else c[i] = '@';
      ++i;
   }
   n = 0UL;
   if (s[j]=='-') {
      ++j;
      while ((uint8_t)s[j]>='0' && (uint8_t)s[j]<='9') {
         n = (n*10UL+(uint32_t)(uint8_t)s[j])-48UL;
         ++j;
      }
   }
   if (n>15UL) Err("wrong SSID", 11ul);
   if (s[j]=='*') c[6U] = 0;
   else c[6U] = (char)(n*2UL+224UL);
   X2C_PFREE(s);
} /* end MakeRawCall() */


static void Ackpath(const char h[], uint32_t h_len)
{
   aprsstr_Assign(ackpath, 64ul, ">", 2ul);
   aprsstr_Append(ackpath, 64ul, "APNL01", 7ul);
   if (h[0UL]) {
      aprsstr_Append(ackpath, 64ul, ",", 2ul);
      aprsstr_Append(ackpath, 64ul, h, h_len);
   }
   aprsstr_Append(ackpath, 64ul, "::", 3ul);
} /* end Ackpath() */


static char getfix(float * x, const char s[], uint32_t s_len,
                 uint32_t * p)
{
   uint32_t i;
   char h[256];
   i = 0UL;
   while (((uint8_t)s[*p]>' ' && s[*p]!='/') && i<255UL) {
      h[i] = s[*p];
      ++i;
      ++*p;
   }
   h[i] = 0;
   if (aprsstr_StrToFix(x, h, 256ul)) return 1;
   return 0;
} /* end getfix() */

static SET256 _cnst0 = {0x00000000UL,0x00000000UL,0x00000000UL,0x00000000UL,
                0x00000000UL,0x00000000UL,0x00000000UL,0x00000000UL};
static SET256 _cnst = {0xFFFFFFFFUL,0xFFFFFFFFUL,0xFFFFFFFFUL,0xFFFFFFFFUL,
                0xFFFFFFFFUL,0xFFFFFFFFUL,0xFFFFFFFFUL,0xFFFFFFFFUL};

static void parms(void)
{
   char h[4096];
   char actpassui;
   char actsat;
   char actecho;
   char err;
   char lasth;
   pINSOCK actsock0;
   pOUTPORT onext;
   pOUTPORT outsock0;
   SET256 actpass;
   pDIGIPARMS actdigi;
   uint32_t nold;
   uint32_t n;
   uint32_t i;
   struct BEACON actbeacon;
   pMSGHASH user;
   pCALLS callnext;
   pCALLS actcall;
   float actkm;
   struct aprspos_POSITION actpos;
   struct INSOCK * anonym;
   struct BEACON * anonym0;
   struct DIGIPARMS * anonym1;
   struct OUTPORT * anonym2;
   struct MSGHASH * anonym3;
   SET256 tmp;
   msgusers = 0;
   actsock0 = 0;
   actcall = 0;
   err = 0;
   show = 0;
   Ackpath("WIDE2-2", 8ul);
   actkm = 0.0f;
   actpassui = 0;
   actsat = 0;
   for (;;) {
      osi_NextArg(h, 4096ul);
      if (h[0U]==0) break;
      if ((h[0U]=='-' && h[1U]) && h[2U]==0) {
         lasth = h[1U];
         if (lasth=='a') {
            osi_NextArg(h, 4096ul);
            if (h[0U]=='-') h[0U] = 0;
            Ackpath(h, 4096ul);
         }
         else if ((lasth=='R' || lasth=='M') || lasth=='L') {
            osi_NextArg(h, 4096ul);
            actecho = 0;
            memcpy(actpass,_cnst,32u);
            actdigi = 0;
            actcall = 0;
            actkm = 0.0f;
            actpassui = 0;
            actsat = 0;
            actbeacon.bintervall = 0UL;
            actbeacon.piggytime = 0UL;
            actbeacon.piggyback = 0;
            osic_alloc((char * *) &actsock0, sizeof(struct INSOCK));
            if (actsock0==0) Err("out of memory", 14ul);
            { /* with */
               struct INSOCK * anonym = actsock0;
               anonym->outchain = 0;
               anonym->rflinkname[0U] = 0;
               if (GetIp(h, 4096ul, &i, &anonym->fromip,
                &anonym->bindport)<0L) Err("cannot open udp socket", 23ul);
               anonym->fd = openudp();
               anonym->rawread = lasth=='R';
               if (lasth=='L') {
                  n = 0UL;
                  if (h[i-1UL]==':') {
                     for (;;) {
                        if (i>=4095UL) break;
                        if (h[i]==0) break;
                        anonym->rflinkname[n] = h[i];
                        ++i;
                        ++n;
                     }
                  }
                  if (n==0UL) Err("-L ip:port:name", 16ul);
               }
               if ((anonym->fd>=0L && anonym->fromip!=X2C_max_longcard)
                && bindudp(anonym->fd, anonym->bindport)<0L) {
                  Err("cannot bind inport", 19ul);
               }
               anonym->next = 0;
            }
            if (insocks) actsock0->next = insocks;
            insocks = actsock0;
         }
         else if (lasth=='f') {
            osi_NextArg(h, 4096ul);
            if (actsock0==0) Err("need input -M or -R before -f", 30ul);
            memcpy(actpass,_cnst0,32u);
            if (h[0U]!='d' && h[0U]!='p') {
               Err("-f (p)ass or (d)elete needed", 29ul);
            }
            i = 1UL;
            n = 0UL;
            nold = 256UL;
            for (;;) {
               if (i>=4095UL) break;
               if ((uint8_t)h[i]>='0' && (uint8_t)h[i]<='9') {
                  n = (n*10UL+(uint32_t)(uint8_t)h[i])-48UL;
               }
               else {
                  for (;;) {
                     if (n>0UL && n<256UL) X2C_INCL(actpass,n,256);
                     if (n<=nold) break;
                     --n;
                  }
                  nold = 256UL;
                  if (h[i]=='-') nold = n;
                  else if (h[i]!=',') {
                     break;
                  }
                  n = 0UL;
               }
               ++i;
            }
            if (h[0U]=='d') {
               memcpy(actpass,X2C_COMPLEMENT(tmp,actpass,8),32u);
                /* c translate problem */
            }
         }
         else if (lasth=='k') {
            /*
                      FOR i:=0 TO MAX(SET256) DO 
                        IF i IN actpass THEN EXCL(actpass,
                i) ELSE INCL(actpass, i) END;
                      END;
            */
            osi_NextArg(h, 4096ul);
            if (actsock0==0) Err("need input -M or -R before -k", 30ul);
            i = 0UL;
            if (!getfix(&actpos.lat, h, 4096ul, &i)) {
               Err("latitude in deg", 16ul);
            }
            ++i;
            if (h[i-1UL]!='/' || !getfix(&actpos.long0, h, 4096ul, &i)) {
               Err("longitude in deg", 17ul);
            }
            ++i;
            if ((h[i-1UL]!='/' || !getfix(&actkm, h, 4096ul,
                &i)) || actkm>=2.147483647E+9f) Err("distance in km", 15ul);
         }
         else if (lasth=='b') {
            osi_NextArg(h, 4096ul);
            if (actsock0==0) Err("need input -M or -R before -b", 30ul);
            { /* with */
               struct BEACON * anonym0 = &actbeacon;
               i = 0UL;
               if (GetSec(h, 4096ul, &i, &n)>=0L && h[i]==':') {
                  anonym0->bintervall = n;
                  anonym0->btime = anonym0->bintervall+osic_time();
                  anonym0->bline = 0UL;
                  ++i;
                  for (n = 0UL; n<=1023UL; n++) {
                     if (i<=4095UL) {
                        anonym0->bfile[n] = h[i];
                        ++i;
                     }
                  } /* end for */
               }
               else Err("beacon format is time:file", 27ul);
            }
         }
         else if (lasth=='d') {
            osi_NextArg(h, 4096ul);
            if (actsock0==0) Err("need input -M or -R before -d", 30ul);
            osic_alloc((char * *) &actdigi, sizeof(struct DIGIPARMS));
            if (actdigi==0) Err("out of memory", 14ul);
            { /* with */
               struct DIGIPARMS * anonym1 = actdigi;
               MakeRawCall(anonym1->digicall, h, 4096ul, 0UL);
               if (anonym1->digicall[0U]==0 || anonym1->digicall[6U]==0) {
                  Err("wrong digi callsign", 20ul);
               }
               for (i = 0UL; i<=16383UL; i++) {
                  anonym1->timehash[i] = 0UL;
               } /* end for */
               anonym1->duptime = 1740UL;
               anonym1->messagetime = 28UL;
               anonym1->pathcheck = 0UL;
            }
         }
         else if (lasth=='e') actecho = 1;
         else if (((lasth=='r' || lasth=='m') || lasth=='c') || lasth=='l') {
            if (actsock0==0) {
               Err("need input -M or -R before -r or -m or -c", 42ul);
            }
            osi_NextArg(h, 4096ul);
            osic_alloc((char * *) &outsock0, sizeof(struct OUTPORT));
            if (outsock0==0) {
               Err("out of memory", 14ul);
            }
            { /* with */
               struct OUTPORT * anonym2 = outsock0;
               if (GetIp(h, 4096ul, &i, &anonym2->toip,
                &anonym2->toport)<0L) Err("wrong udp:port", 15ul);
               memcpy(anonym2->aprspass,actpass,32u);
               anonym2->echo = actecho;
               anonym2->digiparm = actdigi;
               anonym2->axudp2 = lasth=='l';
               anonym2->rawwrite = lasth=='r' || anonym2->axudp2;
               anonym2->crlfwrite = lasth=='c';
               anonym2->beacon0 = actbeacon;
               actbeacon.bintervall = 0UL;
               anonym2->passnoUI = actpassui;
               anonym2->satgate = actsat;
               anonym2->next = 0;
               anonym2->filtercalls = actcall;
               anonym2->mypos.lat = actpos.lat*1.7453292519444E-2f;
               anonym2->mypos.long0 = actpos.long0*1.7453292519444E-2f;
               anonym2->maxkm = (int32_t)(uint32_t)X2C_TRUNCC(actkm,0UL,
                X2C_max_longcard);
            }
            actdigi = 0;
            actpassui = 0;
            onext = actsock0->outchain;
            if (onext==0) actsock0->outchain = outsock0;
            else {
               while (onext->next) onext = onext->next;
               onext->next = outsock0;
            }
         }
         else {
            if (lasth=='h') {
               osic_WrLn();
               osi_WrStrLn(" -a <paths>     user message ack path eg. WIDE2-2\
 or - for no path", 67ul);
               osi_WrStrLn(" -b <s>:<file>  enable beacon every s(econds) pat\
h and text from <file>", 72ul);
               osi_WrStrLn("                cycles thru lines in file, empty \
lines = no tx (size max 32kb)", 79ul);
               osi_WrStrLn("                \\\\z ddhhmm, \\\\h hhmmss, \\\\:\
filename: insert file, \\\\[filename]", 79ul);
               osi_WrStrLn("                insert file and delete after, \\\\
\(filename) if exists insert", 76ul);
               osi_WrStrLn("                and delete,\\\\\\ is \\\\, \\\\rm\
 delete beacon file", 62ul);
               osi_WrStrLn("                file may be modified any time eg.\
 by telemetry program", 71ul);
               osi_WrStrLn(" -c <ip>:<port> send text monitor udp frame with \
cr lf", 55ul);
               osi_WrStrLn(" -d <call>      digipeater enable (and dupe filte\
r) call", 57ul);
               osi_WrStrLn(" -d -           dupe filter without data modifica\
tion", 54ul);
               osi_WrStrLn(" -e             echo last (filtert) output",
                43ul);
               osi_WrStrLn(" -f <filterparm>  \'p<x>,<x>...\' pass UI frames \
with first char (-f p58,110)", 76ul);
               osi_WrStrLn("                  \'d<x>,<x>...\' pass UI frames \
with not first char (-f d32,65-79)", 82ul);
               osi_WrStrLn("                  Messages to itself are treated \
as Telemetry  (-f d84)", 72ul);
               osi_WrStrLn(" -h             this", 21ul);
               osi_WrStrLn(" -k <deg>/<deg>/<km> distance filter, center/radi\
us -k 48.2/13.5/100", 69ul);
               osi_WrStrLn("                -k 0/0/20000 remove all (not user\
 msg) with no position data", 77ul);
               osi_WrStrLn(" -L <ip>:<port>:<netname>   read monitor rflink h\
eader with netname", 68ul);
               osi_WrStrLn(" -l <ip>:<port> send raw axudp frame and pass thr\
u axudp2 header", 65ul);
               osi_WrStrLn(" -M <ip>:<port> read text monitor udp frame",
                44ul);
               osi_WrStrLn("                ip=255.255.255.255:0 read text mo\
nitor from stdin", 66ul);
               osi_WrStrLn("                ip=255.255.255.255:1 read text mo\
nitor from stdin and terminate", 80ul);
               osi_WrStrLn(" -m <ip>:<port> send text monitor udp frame 0 ter\
minated", 57ul);
               osi_WrStrLn(" -p <n>,<...>   -p 7,8 igate friendly digi relayi\
ng all direct heared", 70ul);
               osi_WrStrLn("                -p 5,6,7,8,9 first hop digi, -p 3\
,4 (noisy) last hop digi", 74ul);
               osi_WrStrLn("                -p 0,1,3,4,5,6,7,8,9,14,16 origin\
al, noisy, path loosing ...", 77ul);
               osi_WrStrLn("                0..2 limit ssid-routing to (bit0 \
+ 2*bit1 + 4*bit2)", 68ul);
               osi_WrStrLn("                dest-3: dest-2,digicall*, dest-3,\
call*: dest-2,call,digicall*", 78ul);
               osi_WrStrLn("                3 allow repeatet before (mostly w\
ith wrong path trace)", 71ul);
               osi_WrStrLn("                4 no uplink check for \'looks lik\
e direct heared\'", 65ul);
               osi_WrStrLn("                  (noisy, wrong path trace possib\
le)", 53ul);
               osi_WrStrLn("                5 resend TRACEn-(N-1), 6 resend W\
IDEn-(N-1)", 60ul);
               osi_WrStrLn("                  so frames may be relayed again \
by loss of downlink trace", 75ul);
               osi_WrStrLn("                7 append remaining digi path afte\
r via digicall", 64ul);
               osi_WrStrLn("                8 append remaining digi path afte\
r RELAY/GATE/TRACE", 68ul);
               osi_WrStrLn("                9 append remaining digi path afte\
r WIDE", 56ul);
               osi_WrStrLn("                  so frames may be relayed again \
by loss of downlink trace", 75ul);
               osi_WrStrLn("                10, 11, 12, 13 switch off via dig\
icall, RELAY, TRACE, WIDE", 75ul);
               osi_WrStrLn("                14 insert not digicall on direct \
heared before WIDEn-N,", 72ul);
               osi_WrStrLn("                   as others do, your digi is hid\
den, and path is shown wrong", 78ul);
               osi_WrStrLn("                15 convert destination ssid routi\
ng to WIDEn-n", 63ul);
               osi_WrStrLn("                16 send n-0 without repeated flag\
", 50ul);
               osi_WrStrLn("                17 remove all WIDE from downlink \
path", 54ul);
               osi_WrStrLn("                18 enable via GATE (use as gate: \
disable via all other)", 72ul);
               osi_WrStrLn("                19 allow ECHO as alias to RELAY",
                 48ul);
               osi_WrStrLn(" -P <s>         piggyback time sending beacon ear\
lier if sent anything now", 75ul);
               osi_WrStrLn(" -R <ip>:<port> read raw axudp frame, 0 ip read f\
rom all (-R 0.0.0.0:2000)", 75ul);
               osi_WrStrLn(" -r <ip>:<port> send raw axudp frame", 37ul);
               osi_WrStrLn(" -S             Satgate, filter out uplink (has v\
ia with no h-bit", 66ul);
               osi_WrStrLn(" -s             pass not-UI-frames too (all PR-Fr\
ames, SABM, RR..)", 67ul);
               osi_WrStrLn("                (raw axudp only) and axudp2 modem\
 to layer2 message frames", 75ul);
               osi_WrStrLn(" -t <s>,<s>     dupe filter time in seconds (all \
types, user messages)", 71ul);
               osi_WrStrLn("                -t 1740,28 29min not same beacon,\
 28s for retrying user message)", 81ul);
               osi_WrStrLn(" -u <call>:<file> global option, receive & ack us\
ermessages to call store in file", 82ul);
               osi_WrStrLn("                repeat -u for more Calls to same \
or different File", 67ul);
               osi_WrStrLn(" -v             show frames and analytics on stdo\
ut", 52ul);
               osi_WrStrLn(" -x <call>{,<call>} delete frames with call in a \
address field, -x TCPIP,UID***-*", 82ul);
               osi_WrStrLn("udpbox -v -M 0.0.0.0:9200 -d MYCALL-10 -p 0,1,7 -\
t 1800,28 -r 192.168.1.24:9400", 80ul);
               osic_WrLn();
               X2C_ABORT();
            }
            if (lasth=='s') actpassui = 1;
            else if (lasth=='S') actsat = 1;
            else if (lasth=='t') {
               if (actdigi==0) Err("need -d before -t", 18ul);
               osi_NextArg(h, 4096ul);
               i = 0UL;
               if (GetSec(h, 4096ul, &i, &n)>=0L) {
                  actdigi->duptime = n;
                  ++i;
                  if (h[i-1UL]==',' && GetSec(h, 4096ul, &i, &n)>=0L) {
                     actdigi->messagetime = n;
                  }
               }
            }
            else if (lasth=='P') {
               if (actsock0==0) Err("need input -M or -R before -P", 30ul);
               osi_NextArg(h, 4096ul);
               i = 0UL;
               if (GetSec(h, 4096ul, &i, &n)>=0L) actbeacon.piggytime = n;
            }
            else if (lasth=='p') {
               if (actdigi==0) Err("need -d before -p", 18ul);
               osi_NextArg(h, 4096ul);
               i = 0UL;
               while (GetSec(h, 4096ul, &i, &n)>=0L) {
                  if (n<31UL) actdigi->pathcheck |= (1UL<<n);
                  if (h[i]==',') ++i;
               }
            }
            else if (lasth=='u') {
               osi_NextArg(h, 4096ul);
               osic_alloc((char * *) &user, sizeof(struct MSGHASH));
               if (user==0) Err("out of memory", 14ul);
               { /* with */
                  struct MSGHASH * anonym3 = user;
                  anonym3->wpos = 0UL;
                  anonym3->msgfile[0U] = 0;
                  for (i = 0UL; i<=15UL; i++) {
                     anonym3->hash[i].ackcnt = 0UL;
                  } /* end for */
                  i = 0UL;
                  n = 0UL;
                  while ((n<=8UL && h[i]) && h[i]!=':') {
                     anonym3->usercall[n] = h[i];
                     ++n;
                     ++i;
                  }
                  while (n<=8UL) {
                     anonym3->usercall[n] = ' ';
                     ++n;
                  }
                  if (h[i]) {
                     ++i;
                     n = 0UL;
                     while (n<=1023UL && h[i]) {
                        anonym3->msgfile[n] = h[i];
                        ++n;
                        ++i;
                     }
                  }
                  anonym3->next = 0;
               }
               if (msgusers) user->next = msgusers;
               msgusers = user;
            }
            else if (lasth=='v') show = 1;
            else if (lasth=='x') {
               osi_NextArg(h, 4096ul);
               if (actsock0==0) Err("need input -M or -R before -x", 30ul);
               i = 0UL;
               for (;;) {
                  osic_alloc((char * *) &callnext,
                sizeof(struct CALLS));
                  if (callnext==0) Err("out of memory", 14ul);
                  MakeRawCall(callnext->call, h, 4096ul, i);
                  callnext->next = actcall;
                  actcall = callnext;
                  while (h[i]!=',') {
                     if (i>=4095UL || (uint8_t)h[i]<=' ') goto loop_exit;
                     ++i;
                  }
                  ++i;
               }
               loop_exit:;
            }
            else err = 1;
         }
      }
      else {
         /*
               h[0]:=0C;
         */
         err = 1;
      }
      if (err) break;
   }
   if (err) {
      osi_WrStr(">", 2ul);
      osi_WrStr(h, 4096ul);
      osi_WrStrLn("< use -h", 9ul);
      X2C_ABORT();
   }
} /* end parms() */


static void showpip(uint32_t ip, uint32_t port)
{
   osic_WrINT32(ip/16777216UL, 1UL);
   osi_WrStr(".", 2ul);
   osic_WrINT32(ip/65536UL&255UL, 1UL);
   osi_WrStr(".", 2ul);
   osic_WrINT32(ip/256UL&255UL, 1UL);
   osi_WrStr(".", 2ul);
   osic_WrINT32(ip&255UL, 1UL);
   osi_WrStr(":", 2ul);
   osic_WrINT32(port, 1UL);
} /* end showpip() */

/*
PROCEDURE showstr(s-:ARRAY OF CHAR);

  PROCEDURE Hex(b:SET8):CHAR;
  VAR d:CARDINAL;
  BEGIN
    d:=CAST(CARDINAL, b*SET8{0..3});
    IF d>9 THEN INC(d, ORD("A")-10-ORD("0")) END;
    RETURN CHR(d+ORD("0"))  
  END Hex;

VAR i,j:CARDINAL;
    h:ARRAY[0..1023] OF CHAR; 
BEGIN
  i:=0;
  j:=0;
  WHILE (i<=HIGH(s)) & (s[i]<>0C) & (j<HIGH(h)-5) DO
    IF s[i]<" " THEN 
      h[j]:="<"; INC(j);
      h[j]:=Hex(SHIFT(CAST(SET8, s[i]), -4)); INC(j);
      h[j]:=Hex(CAST(SET8, s[i])); INC(j);
      h[j]:=">";
    ELSE h[j]:=s[i] END;
    INC(i);
    INC(j);
  END;
  h[j]:=0C;
  WrStrLn(h); 
END showstr;
*/

static void showhex(int32_t * n, int32_t e, char in[],
                uint32_t in_len, int32_t * len, const char s[],
                uint32_t s_len)
{
   int32_t i;
   int32_t tmp;
   char tmp0;
   if (show) {
      osic_WrLn();
      osi_WrStrLn(s, s_len);
      tmp = *len-1L;
      i = 0L;
      if (i<=tmp) for (;; i++) {
         osi_WrHex((uint32_t)(uint8_t)in[i], 3UL);
         if (i==tmp) break;
      } /* end for */
      osic_WrLn();
      tmp = e-1L;
      i = 0L;
      if (i<=tmp) for (;; i++) {
         *n = (int32_t)((uint32_t)(uint8_t)in[i]/2UL);
         if (*n<32L) {
            osi_WrStr("<", 2ul);
            osi_WrHex((uint32_t)*n, 1UL);
            osi_WrStr(">", 2ul);
         }
         else osi_WrStr((char *)(tmp0 = (char)*n,&tmp0), 1u/1u);
         if (i%7L==6L) osi_WrStr(",", 2ul);
         if (i==tmp) break;
      } /* end for */
      osic_WrLn();
   }
} /* end showhex() */


static void cpraw(char in[], uint32_t in_len, char out[],
                uint32_t out_len, int32_t * len)
{
   int32_t e;
   int32_t n;
   int32_t i;
   char c;
   char h;
   int32_t tmp;
   e = 0L;
   tmp = *len-1L;
   i = 0L;
   if (i<=tmp) for (;; i++) {
      c = in[i];
      out[i] = c;
      if (e==0L && ((uint32_t)(uint8_t)c&1)) e = i+1L;
      if (i==tmp) break;
   } /* end for */
   if (*len==2L) return;
   /* crc only, maybe there is a axudp2 head*/
   if (((uint32_t)e%7UL || e<14L) || e>70L) {
      showhex(&n, e, in, in_len, len,
                " bad raw format, no address end found", 38ul);
      *len = 0L;
   }
   else {
      h = 1;
      tmp = e-1L;
      i = 20L;
      if (i<=tmp) for (tmp = (uint32_t)(tmp-i)/7L;;) {
         if ((uint32_t)(uint8_t)in[i]>=128UL) {
            if (!h) {
               showhex(&n, e, in, in_len, len, " bad H bit in raw frame",
                24ul);
               *len = 0L;
            }
            h = 1;
         }
         else h = 0;
         if (!tmp) break;
         --tmp;
         i += 7L;
      } /* end for */
   }
} /* end cpraw() */

#define udpbox_MSYM "\\"

#define udpbox_INSFN ":"
/* insert file and send no beacon if missing */

#define udpbox_INSFNEND ":"

#define udpbox_DELFN "["
/* insert file, delete and send no beacon if missing */

#define udpbox_DELFNEND "]"

#define udpbox_DELFNN "("
/* insert file, delete and insert nothing if missing */

#define udpbox_DELFNNEND ")"


static void beaconmacros(char s[], uint32_t s_len, char * del)
{
   uint32_t i;
   int32_t j;
   int32_t len;
   char ns[256];
   char ds[256];
   char fn[1024];
   int32_t f;
   char fnend;
   char voidok;
   *del = 0;
   i = 0UL;
   ns[0U] = 0;
   while (i<s_len-1 && s[i]) {
      if (s[i]=='\\' && s[i+1UL]=='\\') {
         i += 2UL;
         if (s[i]=='z') {
            /* insert day, hour, min */
            aprsstr_DateToStr(osic_time(), ds, 256ul);
            ds[0U] = ds[8U];
            ds[1U] = ds[9U];
            ds[2U] = ds[11U];
            ds[3U] = ds[12U];
            ds[4U] = ds[14U];
            ds[5U] = ds[15U];
            ds[6U] = 0;
            aprsstr_Append(ns, 256ul, ds, 256ul);
         }
         else if (s[i]=='h') {
            /* insert hour, min, s */
            aprsstr_DateToStr(osic_time(), ds, 256ul);
            ds[0U] = ds[11U];
            ds[1U] = ds[12U];
            ds[2U] = ds[14U];
            ds[3U] = ds[15U];
            ds[4U] = ds[17U];
            ds[5U] = ds[18U];
            ds[6U] = 0;
            aprsstr_Append(ns, 256ul, ds, 256ul);
         }
         else if ((s[i]==':' || s[i]=='[') || s[i]=='(') {
            /* insert file */
            if (s[i]==':') fnend = ':';
            else if (s[i]=='(') fnend = ')';
            else fnend = ']';
            fn[0U] = 0;
            ++i;
            while ((i<s_len-1 && s[i]) && s[i]!=fnend) {
               aprsstr_Append(fn, 1024ul, (char *) &s[i], 1u/1u);
               ++i;
            }
            f = osi_OpenRead(fn, 1024ul);
            if (f>=0L) {
               len = osi_RdBin(f, (char *)ds, 256u/1u, 255UL);
               osic_Close(f);
               if (fnend==']' || fnend==')') {
                  osi_Erase(fn, 1024ul, &voidok);
                /* delete insert file after inserting */
               }
               j = 0L;
               while (((j<len && ds[j]!='\015') && ds[j]!='\012') && ds[j]) {
                  aprsstr_Append(ns, 256ul, (char *) &ds[j], 1u/1u);
                  ++j;
               }
            }
            else if (fnend!=')') {
               /* skip whole beacon line */
               if (show) {
                  osic_WrLn();
                  osi_WrStrLn("beacon macro file not readable ", 32ul);
               }
               s[0UL] = 0;
               return;
            }
         }
         else {
            if (s[i]=='r' && s[i+1UL]=='m') {
               /* delete beacon file */
               s[0UL] = 0;
               *del = 1;
               return;
            }
            if (s[i]=='\\') aprsstr_Append(ns, 256ul, "\\\\", 3ul);
            else {
               if (show) {
                  osic_WrLn();
                  osi_WrStrLn("bad beacon macro ", 18ul);
               }
               s[0UL] = 0;
               return;
            }
         }
      }
      else aprsstr_Append(ns, 256ul, (char *) &s[i], 1u/1u);
      ++i;
   }
   aprsstr_Assign(s, s_len, ns, 256ul);
} /* end beaconmacros() */


static void beacon(pINSOCK insock, char buf[], uint32_t buf_len,
                int32_t * len, pOUTPORT * outsock0)
{
   int32_t lc;
   int32_t eol;
   int32_t bol;
   int32_t i;
   int32_t f;
   char fb[32768];
   uint32_t t;
   char ok0;
   char del;
   struct BEACON * anonym;
   *len = 0L;
   *outsock0 = insock->outchain;
   for (;;) {
      if (*outsock0==0) {
         *len = 0L;
         break;
      }
      { /* with */
         struct BEACON * anonym = &(*outsock0)->beacon0;
         t = osic_time();
         if (anonym->piggyback) t += anonym->piggytime;
         anonym->piggyback = 0;
         if ((anonym->bintervall>0UL && anonym->bfile[0U])
                && anonym->btime<=t) {
            anonym->btime += anonym->bintervall;
            if (anonym->btime<=t) anonym->btime = t+anonym->bintervall;
            f = osi_OpenRead(anonym->bfile, 1024ul);
            if (f>=0L) {
               *len = osi_RdBin(f, (char *)fb, 32768u/1u, 32767UL);
               osic_Close(f);
               while (*len>0L && (uint8_t)fb[*len-1L]<=' ') {
                  --*len; /* remove junk from eof */
               }
               if (*len>0L && *len<32767L) {
                  fb[*len] = '\012';
                  ++*len;
               }
               do {
                  lc = (int32_t)anonym->bline;
                  eol = 0L;
                  for (;;) {
                     bol = eol;
                     while (eol<*len && fb[eol]!='\012') ++eol;
                     if (eol>=*len) {
                        bol = eol;
                        if (anonym->bline) {
                           lc = 1L;
                           anonym->bline = 0UL;
                        }
                        break;
                     }
                     if (fb[bol]!='#') {
                        if (lc==0L) {
                           ++anonym->bline;
                           break;
                        }
                        --lc;
                     }
                     ++eol;
                  }
               } while (lc);
               i = 0L;
               while (bol<eol) {
                  fb[i] = fb[bol];
                  ++i;
                  ++bol;
               }
               fb[i] = 0;
               /*
               IF show THEN WrStrLn(fb) END;
               */
               *len = 0L;
               if (i>0L) {
                  beaconmacros(fb, 32768ul, &del);
                  if (del) osi_Erase(anonym->bfile, 1024ul, &ok0);
                  else aprsstr_mon2raw(fb, 32768ul, buf, buf_len, len);
                  if (show && *len==0L) {
                     osic_WrLn();
                     if (del) osi_WrStrLn("delete beacon file ", 20ul);
                     else osi_WrStrLn("bad beacon format ", 19ul);
                  }
               }
               break;
            }
            if (show) osi_WrStrLn("beacon file not found", 22ul);
         }
         *outsock0 = (*outsock0)->next;
      }
   }
} /* end beacon() */

#define udpbox_ACKTIME 30


static void sendack(char buf[], uint32_t buf_len, int32_t * len,
                pINSOCK fromsock)
{
   int32_t m;
   uint32_t j;
   uint32_t i;
   pMSGHASH user;
   char fb[256];
   uint32_t t;
   struct MSGHASH * anonym;
   struct _0 * anonym0;
   user = msgusers;
   t = osic_time();
   while (user) {
      *len = 0L;
      { /* with */
         struct MSGHASH * anonym = user;
         for (m = 0L; m<=15L; m++) {
            { /* with */
               struct _0 * anonym0 = &anonym->hash[m];
               if ((anonym0->ackcnt>0UL && anonym0->acktime<t)
                && fromsock==anonym0->source) {
                  --anonym0->ackcnt;
                  anonym0->acktime = t+30UL;
                  j = 0UL;
                  i = 0UL;
                  while (i<=8UL && (uint8_t)anonym->usercall[i]>' ') {
                     fb[j] = anonym->usercall[i];
                     ++j;
                     ++i;
                  }
                  i = 0UL;
                  while ((uint8_t)ackpath[i]>' ') {
                     fb[j] = ackpath[i];
                     ++j;
                     ++i;
                  }
                  for (i = 0UL; i<=8UL; i++) {
                     fb[j] = anonym0->froms[i];
                     ++j;
                  } /* end for */
                  fb[j] = ':';
                  ++j;
                  i = 0UL;
                  while ((uint8_t)"ack"[i]>' ') {
                     fb[j] = "ack"[i];
                     ++j;
                     ++i;
                  }
                  /*
                  IO.WrLn; IO.WrStr("    <"); IO.WrStr(hash[m].acks);
                IO.WrStrLn(">");
                  */
                  i = 0UL;
                  while ((uint8_t)anonym0->acks[i]>' ') {
                     fb[j] = anonym0->acks[i];
                     ++j;
                     ++i;
                  }
                  fb[j] = 0;
                  /*
                  IO.WrLn; IO.WrStr("    <"); IO.WrStr(fb); IO.WrStrLn(">");
                  */
                  aprsstr_mon2raw(fb, 256ul, buf, buf_len, len);
                  if (show && *len==0L) {
                     osi_WrStr(fb, 256ul);
                     osi_WrStrLn(" message ack path wrong", 24ul);
                  }
                  return;
               }
            }
         } /* end for */
         user = anonym->next;
      }
   }
} /* end sendack() */


static void appudp2(char ob[], uint32_t ob_len, uint32_t * olen,
                const char ud[], uint32_t ud_len, const char ib[],
                uint32_t ib_len, int32_t len)
/* append axudp2 header */
{
   int32_t j;
   int32_t i;
   i = 0L;
   j = 0L;
   while (ud[i]) {
      ob[i] = ud[i];
      ++i;
   }
   if (i>0L) {
      ob[i] = 0;
      ++i;
   }
   len -= 2L;
   while (j<len) {
      ob[i] = ib[j];
      ++i;
      ++j;
   }
   *olen = (uint32_t)(i+2L);
   aprsstr_AppCRC(ob, ob_len, i);
} /* end appudp2() */

static char ibuf[338];

static char rawbuf[338];

static char rawout[338];

static char workraw[338];

static char udp2[64]; /* axudp2 header */

static char mbuf[512];

static int32_t inlen;

static int32_t outlen;

static int32_t res;

static uint32_t monlen;

static pINSOCK actsock;

static pOUTPORT outsock;

static pOUTPORT isbeacon;

static char nobeacon;

static char piggy;

static RAWCALL hamup;

static aprsstr_GHOSTSET _cnst1 = {0x00000000UL,0x00000000UL,0x00000000UL,
                0x00000000UL,0x00000000UL,0x00000000UL,0x00000000UL,
                0x00000000UL,0x00000000UL};

X2C_STACK_LIMIT(100000l)
extern int main(int argc, char **argv)
{
   X2C_BEGIN(&argc,argv,1,4000000l,8000000l);
   if (sizeof(SET256)!=32) X2C_ASSERT(0);
   if (sizeof(RAWCALL)!=7) X2C_ASSERT(0);
   if (sizeof(MONCALL)!=9) X2C_ASSERT(0);
   if (sizeof(FILENAME)!=1024) X2C_ASSERT(0);
   aprsstr_BEGIN();
   aprspos_BEGIN();
   osi_BEGIN();
   stdinpos = 0UL;
   insocks = 0;
   parms();
   for (;;) {
      fdclr();
      actsock = insocks;
      if (insocks && insocks->fromip==X2C_max_longcard) fdsetr(0UL);
      while (actsock) {
         { /* with */
            struct INSOCK * anonym = actsock;
            if (anonym->fd>=0L) fdsetr((uint32_t)anonym->fd);
            actsock = anonym->next;
         }
      }
      if (selectr(1UL, 0UL)>=0L) {
         actsock = insocks;
         while (actsock) {
            do {
               piggy = 0;
               inlen = 0L;
               if (actsock->fd>=0L && issetr((uint32_t)actsock->fd)) {
                  inlen = getudp(actsock->fd, ibuf, 338ul, actsock->fromip,
                actsock->rawread);
               }
               else if (issetr(0UL) && actsock->fromip==X2C_max_longcard) {
                  inlen = getstdin(ibuf, 338ul);
               }
               udp2[0U] = 0;
               if (inlen>0L && ibuf[0U]=='\001') {
                  aprsstr_extrudp2(ibuf, 338ul, udp2, 64ul, &inlen);
                /* axudp2 */
               }
               hamup[0U] = 0;
               if (inlen>0L) {
                  nobeacon = 1;
                  if (actsock->rawread) {
                     cpraw(ibuf, 338ul, rawbuf, 338ul, &inlen);
                  }
                  else {
                     if (inlen<=337L) ibuf[inlen] = 0;
                     checkhamnet(ibuf, 338ul, &inlen, actsock->rflinkname,
                9ul, hamup);
                     if (inlen>0L) {
                        aprsstr_mon2raw(ibuf, 338ul, rawbuf, 338ul, &inlen);
                        if (show && inlen==0L) {
                           osi_WrStrLn("bad mon format ", 16ul);
                        }
                     }
                     else if (show) {
                        osi_WrStrLn("no rflink head match", 21ul);
                     }
                  }
                  isbeacon = 0;
               }
               else {
                  nobeacon = 0;
                  beacon(actsock, rawbuf, 338ul, &inlen, &isbeacon);
                  if (isbeacon==0) sendack(rawbuf, 338ul, &inlen, actsock);
               }
               if (inlen>=2L) {
                  if (show && inlen>2L) {
                     aprsstr_raw2mon(rawbuf, 338ul, mbuf, 512ul,
                (uint32_t)(inlen-2L), &monlen, _cnst1);
                     osic_WrLn();
                     showpip(showip, showport);
                     osi_WrStr("(", 2ul);
                     osic_WrINT32((uint32_t)inlen, 1UL);
                     osi_WrStr(")", 2ul);
                     osi_WrStr(":", 2ul);
                     if (monlen<=0UL) osi_WrStr("<raw to mon error>", 19ul);
                     aprsstr_CtrlHex(mbuf, 512ul);
                     osi_WrStrLn(mbuf, 512ul);
                  }
                  outsock = actsock->outchain;
                  outlen = 0L;
                  while (outsock) {
                     if (show && inlen>2L) {
                        osi_WrStr(" tx: ", 6ul);
                        showpip(outsock->toip, outsock->toport);
                     }
                     memcpy(workraw,rawbuf,338u);
                     if (((isbeacon==0 || isbeacon==outsock)
                || outsock->echo) && Filter(workraw, 338ul, inlen, outsock,
                actsock)) {
                        if (outsock->digiparm) {
                           Digi(workraw, 338ul, rawout, 338ul, inlen,
                &outlen, hamup, outsock->digiparm, !nobeacon);
                           if (show && outlen>2L) {
                              osi_WrStr(" digi", 6ul);
                           }
                        }
                        else if (!outsock->echo) {
                           memcpy(rawout,workraw,338u);
                           outlen = inlen;
                        }
                        /* else use last filtert */
                        if (outlen>0L) {
                           outsock->beacon0.piggyback = 1;
                           piggy = 1;
                           if (outsock->rawwrite) {
                              if (outsock->axudp2) {
                                 appudp2(mbuf, 512ul, &monlen, udp2, 64ul,
                rawout, 338ul, outlen);
                                 res = udpsend(actsock->fd, mbuf,
                (int32_t)monlen, outsock->toport, outsock->toip);
                              }
                              else {
                                 aprsstr_AppCRC(rawout, 338ul, outlen-2L);
                                 res = udpsend(actsock->fd, rawout, outlen,
                outsock->toport, outsock->toip);
                              }
                              if (show && outlen>2L) {
                                 osi_WrStrLn(" raw", 5ul);
                              }
                           }
                           else {
                              aprsstr_raw2mon(rawout, 338ul, mbuf, 512ul,
                (uint32_t)(outlen-2L), &monlen, _cnst1);
                              if (monlen>0UL) {
                                 if (outsock->crlfwrite) {
                                    mbuf[monlen-1UL] = '\015';
                                    mbuf[monlen] = '\012';
                                    ++monlen;
                                 }
                                 res = udpsend(actsock->fd, mbuf,
                (int32_t)monlen, outsock->toport, outsock->toip);
                                 if (show) {
                                    osi_WrStrLn(" mon", 5ul);
                                 }
                              }
                              else if (show) {
                                 osi_WrStrLn(" monerr", 8ul);
                              }
                           }
                        }
                        else if (show) {
                           osi_WrStrLn(" no tx", 7ul);
                        }
                     }
                     else if (show && outlen>2L) {
                        osi_WrStrLn(" deleted", 9ul);
                     }
                     outsock = outsock->next;
                  }
                  if ((insocks && insocks->fromip==X2C_max_longcard)
                && insocks->bindport==1UL) {
                     goto loop_exit; /* single stdin line mode */
                  }
               }
            } while (piggy);
            actsock = actsock->next;
         }
      }
   }
   loop_exit:;
   X2C_EXIT();
   return 0;
}

X2C_MAIN_DEFINITION
