/*
 * mars-nwe-dosutils - NetWare/DOS utility tools.
 *
 * Copyright (C) 2026 Mario Fetka
 * Copyright (C) 1993,1996 Martin Stover, Marburg, Germany
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

/*
 * Purpose: Low-level NCP requester and Client32 transport helpers for the NetWare DOS tools.
 * Depends on: net.h, ncpapi.h, netcall.c requester glue, and ncp.asm/doc/kern.asm Net_Call/Client32 request entry points.
 *
 * The public ncpXX_YY_* protocol wrappers live in ncpapi.c. This file keeps
 * the lower-level requester/transport helpers used by those API wrappers.
 */

#include "net.h"
#include "ncpapi.h"

/* Client32 raw requester transport helpers used by the NCP API wrappers. */

/*
 * ncp_build_handle_path
 *
 * Purpose:
 *   Builds the Client32-compatible NWHandlePathStruct used by NCP87 request
 *   wrappers when the caller already has one to three path components.
 *
 * Parameters:
 *   dhandle/dirbase/style describe the starting directory context.  c1..c3
 *   are written as length-prefixed path components.
 *
 * Returns:
 *   Number of bytes used by the path structure.
 */
UI ncp_build_handle_path(uint8 *buf, uint8 dhandle,
                                uint16 dirbase, uint8 style,
                                int count,
                                const char *c1, const char *c2, const char *c3)
{
  uint8 *p;
  int l;
  UI used;

  /*
   * DeveloperNet/ncpdos16 path structure used by NCP87/S6 through
   * Client32 COMPATNcpRequestReply.
   *
   * This is the exact shape verified by TESTS NCP87C32AUTO:
   *   00 02 00 00 00 00 01 09 4C 4F 47 49 4E 2E 45 58 45
   *
   * Meaning:
   *   word[1] = short dir handle
   *   word[3] = dir base
   *   byte[5] = dirstyle
   *   byte[6] = component count
   *   then len/name components
   *
   * The old/simple struct used by the INT 21h F257 fallback is not accepted
   * by this Client32 path.
   */
  memset(buf, 0, 0x140);

  if (dhandle) {
    tool_put_word_lh(buf + 1, (uint16)dhandle);
    tool_put_word_lh(buf + 3, dirbase);
    buf[5] = style;
  } else {
    buf[5] = 0xff;
  }

  p = buf + 6;
  *p++ = (uint8)count;

  if (count > 0 && c1) {
    l = strlen(c1);
    if (l > 255) l = 255;
    *p++ = (uint8)l;
    memcpy(p, c1, l);
    p += l;
  }

  if (count > 1 && c2) {
    l = strlen(c2);
    if (l > 255) l = 255;
    *p++ = (uint8)l;
    memcpy(p, c2, l);
    p += l;
  }

  if (count > 2 && c3) {
    l = strlen(c3);
    if (l > 255) l = 255;
    *p++ = (uint8)l;
    memcpy(p, c3, l);
    p += l;
  }

  used = (UI)(p - buf);
  tool_put_word_lh(buf + 0x13c, used);
  return(used);
}


/*
 * ncp_build_handle_path_from_dos_path
 *
 * Purpose:
 *   Converts a DOS-style path string into the Client32-compatible
 *   NWHandlePathStruct used by the NCP87 wrappers.
 *
 * Notes:
 *   Drive prefixes, leading slashes and simple current-directory components
 *   are skipped so tool callers can pass ordinary DOS paths.
 */
UI ncp_build_handle_path_from_dos_path(uint8 *buf, uint8 dhandle,
                                              uint16 dirbase, uint8 style,
                                              const char *dospath)
{
  uint8 *p;
  uint8 *countp;
  int count = 0;
  const char *s;
  UI used;

  memset(buf, 0, 0x140);

  if (dhandle) {
    tool_put_word_lh(buf + 1, (uint16)dhandle);
    tool_put_word_lh(buf + 3, dirbase);
    buf[5] = style;
  } else {
    buf[5] = 0xff;
  }

  p = buf + 6;
  countp = p++;

  s = dospath;
  if (!s) s = "";

  /*
   * DOS tools mostly pass relative paths against the current directory
   * handle.  Accept simple DOS decoration here so RIGHTS can pass "." or
   * ".\\UDIR\\FILE" without constructing path components in the caller.
   */
  if (s[0] && s[1] == ':')
    s += 2;

  while (*s == '\\' || *s == '/')
    s++;

  while (*s && p < buf + 0x138 && count < 32) {
    const char *start;
    int len;

    while (*s == '\\' || *s == '/')
      s++;

    if (*s == '.'
        && (s[1] == '\0' || s[1] == '\\' || s[1] == '/')) {
      s++;
      continue;
    }

    start = s;
    while (*s && *s != '\\' && *s != '/')
      s++;

    len = (int)(s - start);
    if (len <= 0)
      continue;

    if (len > 255)
      len = 255;

    if (p + 1 + len >= buf + 0x138)
      break;

    *p++ = (uint8)len;
    memcpy(p, start, len);
    p += len;
    count++;
  }

  *countp = (uint8)count;

  used = (UI)(p - buf);
  tool_put_word_lh(buf + 0x13c, used);
  return(used);
}


/*
 * Current verified Client32 path for mars-nwe DOS utilities:
 *
 *   ncp_mapvar_request(4,0)           -> connRefLocal FFFF:FFFE
 *   ncp_openref_request(connRefLocal) -> Client32 handle, e.g. 0101:0001
 *
 * ncp_mapvar_request currently contains the confirmed Mars server-name scan
 * shape.  It is intentionally kept small and isolated here so FLAG and later
 * tools do not carry the old exploratory tests.
 */
/*
 * ncp_get_requester_handle
 *
 * Purpose:
 *   Resolves the active MARS/NetWare connection into the Client32 NCP handle
 *   used by the raw requester path.
 *
 * Requester path:
 *   ncp_mapvar_request followed by ncp_openref_request.
 *
 * Returns:
 *   0 on success.  Non-zero values indicate that the connection reference or
 *   Client32 NCP handle could not be obtained.
 */
int ncp_get_requester_handle(uint16 *handle_lo, uint16 *handle_hi)
{
  uint8 mapout[32];
  uint8 openout[32];
  uint16 map_ret_ax, map_ret_dx;
  uint16 cref_lo, cref_hi;
  uint16 open_ret_ax, open_ret_dx;

  if (!handle_lo || !handle_hi)
    return(1);

  *handle_lo = 0;
  *handle_hi = 0;

  memset(mapout, 0, sizeof(mapout));
  ncp_mapvar_request(4, 0, mapout);

  map_ret_ax = tool_get_word_lh(mapout + 14);
  map_ret_dx = tool_get_word_lh(mapout + 16);
  cref_lo    = tool_get_word_lh(mapout + 22);
  cref_hi    = tool_get_word_lh(mapout + 24);

  if (map_ret_ax != 0 || map_ret_dx != 0 || (cref_lo == 0 && cref_hi == 0))
    return(2);

  memset(openout, 0, sizeof(openout));
  ncp_openref_request(cref_lo, cref_hi, openout);

  open_ret_ax = tool_get_word_lh(openout + 14);
  open_ret_dx = tool_get_word_lh(openout + 16);
  *handle_lo  = tool_get_word_lh(openout + 18);
  *handle_hi  = tool_get_word_lh(openout + 20);

  if (open_ret_ax != 0 || open_ret_dx != 0 || (*handle_lo == 0 && *handle_hi == 0))
    return(3);

  return(0);
}


