/* Copyright 2022-2026 Kurt Nienhaus
 *
 * This file is part of VgaGames.
 * VgaGames is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 * VgaGames is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with VgaGames.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include "nw.h"

void cl_dgram2nwpack(const char *, const unsigned char *, size_t, struct nwdata_packets *);
size_t cl_nwpack2dgram(const struct nwdata_packets *, unsigned char *);


/* set data in client-received dgram to nwpack, return remaining bytes */
void
cl_dgram2nwpack(const char *remaddr, const unsigned char *dgram, size_t slen, struct nwdata_packets *nwpack)
{
  size_t tlen;
#ifdef NWPACK_DUMP
  char rembuf[160];
#endif

  if (dgram == NULL || nwpack == NULL) { return; }
  (void)remaddr;
#ifdef NWPACK_DUMP
  if (remaddr != NULL) {
    snprintf(rembuf, sizeof(rembuf), " [%s]", remaddr);
  } else {
    *rembuf = '\0';
  }
#endif
  memset(nwpack, 0, sizeof(*nwpack));
  if (slen > NW_MAXPAKET) { return; }  /* too big */
  if (slen < 2) { return; }  /* kenner and action */

  /* read kenner and action */
  nwpack->kenner = (int)dgram[0];
  nwpack->action = (int)dgram[1];
  dgram += 2; slen -= 2;

  if (nwpack->kenner == NWDATA_KENNER_GETCONN) {  /* get connections */

    if (nwpack->action == NWDATA_ACTION_NEWCONN) {  /* reply to new connection */
      /* read 1 byte: bytes of hostnames */
      if (slen == 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read bytes of hostnames: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_getconn.a_newconn.s2c.hnamelen = (int)dgram[0];
      dgram++; slen--;

      /* read hnamelen bytes: hostnames */
      if (slen == 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read hostnames: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      tlen = sizeof(nwpack->u.k_getconn.a_newconn.s2c.hname);
      if (tlen < (size_t)nwpack->u.k_getconn.a_newconn.s2c.hnamelen) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read hostnames: too much data: %d of max. %d", nwpack->kenner, nwpack->action, nwpack->u.k_getconn.a_newconn.s2c.hnamelen, (int)tlen);
        goto end_d2n;
      }
      tlen = (size_t)nwpack->u.k_getconn.a_newconn.s2c.hnamelen;
      if (slen < tlen) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read hostnames: not enough data: %d of %d", nwpack->kenner, nwpack->action, (int)slen, (int)tlen);
        goto end_d2n;
      }
      memcpy(nwpack->u.k_getconn.a_newconn.s2c.hname, dgram, tlen);
      dgram += tlen; slen -= tlen;

      /* done */
      if (slen > 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-CL%s: GETCONN-NEWCONN:\n", rembuf);
      fprintf(stderr, " - hnamelen: %d\n", nwpack->u.k_getconn.a_newconn.s2c.hnamelen);
      fprintf(stderr, " - hname: \"%.*s\"\n", nwpack->u.k_getconn.a_newconn.s2c.hnamelen, nwpack->u.k_getconn.a_newconn.s2c.hname);
#endif

    } else if (nwpack->action == NWDATA_ACTION_ENDCONN) {  /* final reply to new connection */
      /* read 1 byte: client-number */
      if (slen == 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read client-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_getconn.a_endconn.s2c.clnr = (int)dgram[0];
      dgram++; slen--;

      /* read sizeof(nw_seed) bytes: network-seed */
      tlen = sizeof(nwpack->u.k_getconn.a_endconn.s2c.nw_seed);
      if (slen < tlen) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read network-seed: not enough data: %d of %d", nwpack->kenner, nwpack->action, (int)slen, (int)tlen);
        goto end_d2n;
      }
      memcpy(nwpack->u.k_getconn.a_endconn.s2c.nw_seed, dgram, tlen);
      dgram += tlen; slen -= tlen;

      /* read 1 byte: bytes of hostnames */
      if (slen == 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read bytes of hostnames: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_getconn.a_endconn.s2c.hnamelen = (int)dgram[0];
      dgram++; slen--;

      /* read hnamelen bytes: hostnames */
      if (slen == 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read hostnames: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      tlen = sizeof(nwpack->u.k_getconn.a_endconn.s2c.hname);
      if (tlen < (size_t)nwpack->u.k_getconn.a_endconn.s2c.hnamelen) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read hostnames: too much data: %d of max. %d", nwpack->kenner, nwpack->action, nwpack->u.k_getconn.a_endconn.s2c.hnamelen, (int)tlen);
        goto end_d2n;
      }
      tlen = (size_t)nwpack->u.k_getconn.a_endconn.s2c.hnamelen;
      if (slen < tlen) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read hostnames: not enough data: %d of %d", nwpack->kenner, nwpack->action, (int)slen, (int)tlen);
        goto end_d2n;
      }
      memcpy(nwpack->u.k_getconn.a_endconn.s2c.hname, dgram, tlen);
      dgram += tlen; slen -= tlen;

      /* done */
      if (slen > 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-CL%s: GETCONN-ENDCONN:\n", rembuf);
      fprintf(stderr, " - clnr: %d\n", nwpack->u.k_getconn.a_endconn.s2c.clnr);
      fprintf(stderr, " - nw_seed: %u\n", (unsigned int)SML3_strtoui(nwpack->u.k_getconn.a_endconn.s2c.nw_seed, sizeof(nwpack->u.k_getconn.a_endconn.s2c.nw_seed), NULL, 36));
      fprintf(stderr, " - hnamelen: %d\n", nwpack->u.k_getconn.a_endconn.s2c.hnamelen);
      fprintf(stderr, " - hname: \"%.*s\"\n", nwpack->u.k_getconn.a_endconn.s2c.hnamelen, nwpack->u.k_getconn.a_endconn.s2c.hname);
#endif

    } else {  /* unknown */
      outerr("cl_dgram2nwpack(k=%d): invalid action: %d", nwpack->kenner, nwpack->action);
      goto end_d2n;
    }

  } else if (nwpack->kenner == NWDATA_KENNER_RUNCONN) {  /* run connections */

    if (nwpack->action == NWDATA_ACTION_CLOSE) {  /* close */
      /* no data */
      if (slen > 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-CL%s: RUNCONN-CLOSE: (no data)\n", rembuf);
#endif

    } else if (nwpack->action == NWDATA_ACTION_PAUSE) {  /* pause */
      /* no data */
      if (slen > 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-CL%s: RUNCONN-PAUSE: (no data)\n", rembuf);
#endif

    } else if (nwpack->action == NWDATA_ACTION_CONTINUE) {  /* continue */
      /* no data */
      if (slen > 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-CL%s: RUNCONN-CONTINUE: (no data)\n", rembuf);
#endif

    } else if (nwpack->action == NWDATA_ACTION_KEYS) {  /* keys */
      int ianz = 0;

#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-CL%s: RUNCONN-KEYS:\n", rembuf);
#endif
      while (slen > 0) {
        /* read 2 bytes: sequence-number */
        if (slen < 2) {
          outerr("cl_dgram2nwpack(k=%d, a=%d): read sequence-number[%d]: out of data", nwpack->kenner, nwpack->action, ianz + 1);
          goto end_d2n;
        }
        USHORT_SET(nwpack->u.k_runconn.a_keys.s2c.data[ianz].seqnr, dgram[0], dgram[1]);
        dgram += 2; slen -= 2;

        /* read 1 byte: client-connection-bits */
        if (slen == 0) {
          outerr("cl_dgram2nwpack(k=%d, a=%d): read client-connection-bits[%d]: out of data", nwpack->kenner, nwpack->action, ianz + 1);
          goto end_d2n;
        }
        nwpack->u.k_runconn.a_keys.s2c.data[ianz].conncl = dgram[0];
        dgram++; slen--;

        /* read 1 byte: client-keyset-bits */
        if (slen == 0) {
          outerr("cl_dgram2nwpack(k=%d, a=%d): read client-keyset-bits[%d]: out of data", nwpack->kenner, nwpack->action, ianz + 1);
          goto end_d2n;
        }
        nwpack->u.k_runconn.a_keys.s2c.data[ianz].keyset = dgram[0];
        dgram++; slen--;

        /* read MAX_KEYSBYT * MAX_CLIENTS bytes: keys-data of all clients */
        tlen = MAX_KEYSBYT * MAX_CLIENTS;
        if (slen < tlen) {
          outerr("cl_dgram2nwpack(k=%d, a=%d): read keys-data[%d]: out of data", nwpack->kenner, nwpack->action, ianz + 1);
          goto end_d2n;
        }
        memcpy(nwpack->u.k_runconn.a_keys.s2c.data[ianz].keysdata, dgram, tlen);
        dgram += tlen; slen -= tlen;

        /* read 1 byte: length of additional-data */
        if (slen == 0) {
          outerr("cl_dgram2nwpack(k=%d, a=%d): read additional-data-length[%d]: out of data", nwpack->kenner, nwpack->action, ianz + 1);
          goto end_d2n;
        }
        nwpack->u.k_runconn.a_keys.s2c.data[ianz].zdatalen = (int)dgram[0];
        dgram++; slen--;

        /* read nwpack->u.k_runconn.a_keys.s2c.data[ianz].zdatalen bytes: additional-data */
        tlen = nwpack->u.k_runconn.a_keys.s2c.data[ianz].zdatalen;
        if (tlen > 0) {
          if (slen < tlen) {
            outerr("cl_dgram2nwpack(k=%d, a=%d): read additional-data[%d]: out of data", nwpack->kenner, nwpack->action, ianz + 1);
            goto end_d2n;
          }
          memcpy(nwpack->u.k_runconn.a_keys.s2c.data[ianz].zdata, dgram, tlen);
          dgram += tlen; slen -= tlen;
        }

#ifdef NWPACK_DUMP
        fprintf(stderr, " - packet %d\n", ianz + 1);
        fprintf(stderr, "   - seqnr: %d\n", (int)nwpack->u.k_runconn.a_keys.s2c.data[ianz].seqnr);
        fprintf(stderr, "   - conncl: %02x\n", nwpack->u.k_runconn.a_keys.s2c.data[ianz].conncl);
        fprintf(stderr, "   - keyset: %02x\n", nwpack->u.k_runconn.a_keys.s2c.data[ianz].keyset);
        fprintf(stderr, "   - keysdata:\n");
        { int ikey, icli;
          for (icli = 0; icli < MAX_CLIENTS; icli++) {
            fprintf(stderr, "     - client %d: ", NW_ICONN2CLNR(icli));
            for (ikey = 0; ikey < MAX_KEYSBYT; ikey++) {
              if (ikey == MOUSE_BYTES) { fprintf(stderr, "|"); }
              fprintf(stderr, "%02x", nwpack->u.k_runconn.a_keys.s2c.data[ianz].keysdata[ikey + icli * MAX_KEYSBYT]);
            }
            fprintf(stderr, "\n");
          }
        }
        fprintf(stderr, "   - zdatalen: %d\n", nwpack->u.k_runconn.a_keys.s2c.data[ianz].zdatalen);
        if (nwpack->u.k_runconn.a_keys.s2c.data[ianz].zdatalen > 0) {
          char *bcode;
          SML3_base64_encode(&bcode, NULL, nwpack->u.k_runconn.a_keys.s2c.data[ianz].zdata, nwpack->u.k_runconn.a_keys.s2c.data[ianz].zdatalen, 0, NULL);
          fprintf(stderr, "   - zdata: base64[%s]\n", bcode);
          free(bcode);
        }
#endif

        ianz++;
        if (ianz == MAX_KEYSPACKETS && slen > 0) {  /* should be impossible */
          outerr("cl_dgram2nwpack(k=%d, a=%d): too much data (%lu bytes remaining)", nwpack->kenner, nwpack->action, (unsigned long)slen);
          abort();
        }
      }

      nwpack->u.k_runconn.a_keys.s2c.anz = ianz;

    } else if (nwpack->action == NWDATA_ACTION_CONNECTED) {  /* server sends connected-client-info */
      if (slen == 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read connected-client-info: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_runconn.a_connected.s2c.conncl = dgram[0];
      dgram++; slen--;

      if (slen > 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-CL%s: RUNCONN-CONNECTED:\n", rembuf);
      fprintf(stderr, " - conncl: %02x\n", nwpack->u.k_runconn.a_connected.s2c.conncl);
#endif

    } else if (nwpack->action == NWDATA_ACTION_XDATA_RECV) {  /* acknowledgement for client's sent exchange-data */
      /* read 2 bytes: sequence-number */
      if (slen < 2) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read sequence-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      USHORT_SET(nwpack->u.k_runconn.a_xdata_recv.s2c.seqnr, dgram[0], dgram[1]);
      dgram += 2; slen -= 2;

      if (slen > 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-CL%s: RUNCONN-XDATA_RECV:\n", rembuf);
      fprintf(stderr, " - seqnr: %d\n", (int)nwpack->u.k_runconn.a_xdata_recv.s2c.seqnr);
#endif

    } else if (nwpack->action == NWDATA_ACTION_XDATA_SEND) {  /* server sends exchange-data */
      /* read 2 bytes: sequence-number */
      if (slen < 2) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read sequence-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      USHORT_SET(nwpack->u.k_runconn.a_xdata_send.s2c.seqnr, dgram[0], dgram[1]);
      dgram += 2; slen -= 2;

      /* read 2 bytes: length of exchange-data */
      if (slen == 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read exchange-data-length: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      USHORT_SET(nwpack->u.k_runconn.a_xdata_send.s2c.xdatalen, dgram[0], dgram[1]);
      dgram += 2; slen -= 2;
      if (nwpack->u.k_runconn.a_xdata_send.s2c.xdatalen > MAX_XDATA) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): read exchange-data-length: too much bytes (%d > %d)",
               nwpack->kenner, nwpack->action, nwpack->u.k_runconn.a_xdata_send.s2c.xdatalen, MAX_XDATA);
        goto end_d2n;
      }

      /* read nwpack->u.k_runconn.a_xdata_send.s2c.xdatalen bytes: exchange-data */
      tlen = nwpack->u.k_runconn.a_xdata_send.s2c.xdatalen;
      if (tlen > 0) {
        if (slen < tlen) {
          outerr("cl_dgram2nwpack(k=%d, a=%d): read exchange-data: out of data", nwpack->kenner, nwpack->action);
          goto end_d2n;
        }
        memcpy(nwpack->u.k_runconn.a_xdata_send.s2c.xdata, dgram, tlen);
        dgram += tlen; slen -= tlen;
      }

      if (slen > 0) {
        outerr("cl_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-CL%s: RUNCONN-XDATA_SEND:\n", rembuf);
      fprintf(stderr, " - seqnr: %d\n", (int)nwpack->u.k_runconn.a_xdata_send.s2c.seqnr);
      fprintf(stderr, " - xdatalen: %d\n", nwpack->u.k_runconn.a_xdata_send.s2c.xdatalen);
      if (nwpack->u.k_runconn.a_xdata_send.s2c.xdatalen > 0) {
        char *bcode;
        SML3_base64_encode(&bcode, NULL, nwpack->u.k_runconn.a_xdata_send.s2c.xdata, nwpack->u.k_runconn.a_xdata_send.s2c.xdatalen, 0, NULL);
        fprintf(stderr, " - xdata: base64[%s]\n", bcode);
        free(bcode);
      }
#endif

    } else {  /* unknown */
      outerr("cl_dgram2nwpack(k=%d): invalid action: %d", nwpack->kenner, nwpack->action);
      goto end_d2n;
    }

  } else {  /* unknown */
    outerr("cl_dgram2nwpack: invalid kenner: %d", nwpack->kenner);
    goto end_d2n;
  }

  return;

end_d2n:
  memset(nwpack, 0, sizeof(*nwpack));
} /* Ende cl_dgram2nwpack */


/* set data in nwpack to send-to-server dgram */
size_t
cl_nwpack2dgram(const struct nwdata_packets *nwpack, unsigned char *dgram)
{
  size_t slen, tlen;
#ifdef NWPACK_DUMP
  unsigned char *dgram0 = dgram;
#endif

  if (nwpack == NULL || dgram == NULL) { return 0; }

  memset(dgram, 0, NW_MAXPAKET);
  slen = 0;

  /* set kenner and action */
  dgram[0] = (unsigned char)nwpack->kenner;
  dgram[1] = (unsigned char)nwpack->action;
  dgram += 2; slen += 2;

  if (nwpack->kenner == NWDATA_KENNER_GETCONN) {  /* get connections */

    if (nwpack->action == NWDATA_ACTION_NEWCONN) {  /* request new connection */
      /* set 1 byte: maxclients */
      if (slen + 1 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set maxclients: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = (unsigned char)nwpack->u.k_getconn.a_newconn.c2s.maxcl;
      dgram++; slen++;

      /* set rest of bytes: nullterminated hostname */
      tlen = strlen(nwpack->u.k_getconn.a_newconn.c2s.hname) + 1;
      if (slen + tlen > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set hostname: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      memcpy(dgram, nwpack->u.k_getconn.a_newconn.c2s.hname, tlen);
      dgram += tlen;
      slen += tlen;
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; sv_dgram2nwpack(NULL, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_ENDCONN) {  /* request stop getting connections */
      ;  /* no data */
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; sv_dgram2nwpack(NULL, dgram0, slen, &nwp); }
#endif

    } else {  /* unknown */
      outerr("cl_nwpack2dgram(k=%d): invalid action: %d", nwpack->kenner, nwpack->action);
      goto end_n2d;
    }

  } else if (nwpack->kenner == NWDATA_KENNER_RUNCONN) {  /* run connections */

    if (nwpack->action == NWDATA_ACTION_CLOSE) {  /* close */
      /* set 1 byte: client-number */
      if (slen + 1 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set client-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = (unsigned char)nwpack->u.k_runconn.a_close.c2s.clnr;
      dgram++; slen++;
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; sv_dgram2nwpack(NULL, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_PING) {  /* ping */
      /* set 1 byte: client-number */
      if (slen + 1 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set client-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = (unsigned char)nwpack->u.k_runconn.a_ping.c2s.clnr;
      dgram++; slen++;
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; sv_dgram2nwpack(NULL, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_PAUSE) {  /* pause */
      /* set 1 byte: client-number */
      if (slen + 1 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set client-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = (unsigned char)nwpack->u.k_runconn.a_pause.c2s.clnr;
      dgram++; slen++;
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; sv_dgram2nwpack(NULL, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_CONTINUE) {  /* continue */
      /* set 1 byte: client-number */
      if (slen + 1 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set client-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = (unsigned char)nwpack->u.k_runconn.a_continue.c2s.clnr;
      dgram++; slen++;
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; sv_dgram2nwpack(NULL, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_KEYS) {  /* keys */
      /* set 1 byte: client-number */
      if (slen + 1 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set client-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = (unsigned char)nwpack->u.k_runconn.a_keys.c2s.clnr;
      dgram++; slen++;

      /* set 2 bytes: sequence-number */
      if (slen + 2 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set sequence-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      USHORT_GET(nwpack->u.k_runconn.a_keys.c2s.seqnr, dgram[0], dgram[1]);
      dgram += 2; slen += 2;

      /* set MAX_KEYSBYT bytes: keys-data */
      if (slen + MAX_KEYSBYT > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set keys-data: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      memcpy(dgram, nwpack->u.k_runconn.a_keys.c2s.keysdata, MAX_KEYSBYT);
      dgram += MAX_KEYSBYT; slen += MAX_KEYSBYT;

      /* set 1 byte: length of additional-data */
      if (slen + 1 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set additional-data-length: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = nwpack->u.k_runconn.a_keys.c2s.zdatalen;
      dgram++; slen++;

      /* set nwpack->u.k_runconn.a_keys.c2s.zdatalen bytes: additional-data */
      tlen = nwpack->u.k_runconn.a_keys.c2s.zdatalen;
      if (tlen > 0) {
        if (slen + tlen > NW_MAXPAKET) {
          outerr("cl_nwpack2dgram(k=%d, a=%d): set additional-data: out of space", nwpack->kenner, nwpack->action);
          goto end_n2d;
        }
        memcpy(dgram, nwpack->u.k_runconn.a_keys.c2s.zdata, tlen);
        dgram += tlen; slen += tlen;
      }
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; sv_dgram2nwpack(NULL, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_CONNECTED) {  /* wants to receive connected-client-info */
      /* set 1 byte: client-number */
      if (slen + 1 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set client-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = (unsigned char)nwpack->u.k_runconn.a_connected.c2s.clnr;
      dgram++; slen++;
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; sv_dgram2nwpack(NULL, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_XDATA_RECV) {  /* wants server to send exchange-data */
      /* set 1 byte: client-number */
      if (slen + 1 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set client-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = (unsigned char)nwpack->u.k_runconn.a_xdata_recv.c2s.clnr;
      dgram++; slen++;

      /* set 2 bytes: sequence-number */
      if (slen + 2 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set sequence-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      USHORT_GET(nwpack->u.k_runconn.a_xdata_recv.c2s.seqnr, dgram[0], dgram[1]);
      dgram += 2; slen += 2;
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; sv_dgram2nwpack(NULL, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_XDATA_SEND) {  /* send exchange-data */
      /* set 1 byte: client-number */
      if (slen + 1 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set client-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = (unsigned char)nwpack->u.k_runconn.a_xdata_send.c2s.clnr;
      dgram++; slen++;

      /* set 2 bytes: sequence-number */
      if (slen + 2 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set sequence-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      USHORT_GET(nwpack->u.k_runconn.a_xdata_send.c2s.seqnr, dgram[0], dgram[1]);
      dgram += 2; slen += 2;

      /* set 2 bytes: length of exchange-data */
      if (slen + 1 > NW_MAXPAKET) {
        outerr("cl_nwpack2dgram(k=%d, a=%d): set exchange-data-length: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      USHORT_GET(nwpack->u.k_runconn.a_xdata_send.c2s.xdatalen, dgram[0], dgram[1]);
      dgram += 2; slen += 2;

      /* set nwpack->u.k_runconn.a_xdata_send.c2s.xdatalen bytes: exchange-data */
      tlen = nwpack->u.k_runconn.a_xdata_send.c2s.xdatalen;
      if (tlen > 0) {
        if (slen + tlen > NW_MAXPAKET) {
          outerr("cl_nwpack2dgram(k=%d, a=%d): set exchange-data: out of space", nwpack->kenner, nwpack->action);
          goto end_n2d;
        }
        memcpy(dgram, nwpack->u.k_runconn.a_xdata_send.c2s.xdata, tlen);
        dgram += tlen; slen += tlen;
      }
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; sv_dgram2nwpack(NULL, dgram0, slen, &nwp); }
#endif

    } else {  /* unknown */
      outerr("cl_nwpack2dgram(k=%d): invalid action: %d", nwpack->kenner, nwpack->action);
      goto end_n2d;
    }

  } else {  /* unknown */
    outerr("cl_nwpack2dgram: invalid kenner: %d", nwpack->kenner);
    goto end_n2d;
  }

  return slen;

end_n2d:
  return 0;
} /* Ende cl_nwpack2dgram */
