/* getlogin for OS/2 */

/* NetWare code by Frank Whaley */
/* further hacking by Paul Eggert and Kai Uwe Rommel */
/* LAN Server/Manager and 32-bit code by Kai Uwe Rommel */

/* $Id: loginos2.c,v 1.2 1992/01/06 03:18:26 eggert Exp $ */

#define INCL_NOPM
#define INCL_DOS
#include <os2.h>
#include <string.h>

#pragma pack(1)

/* Compilation is supported with emx (gcc) for OS/2 32-bit and with MS
 * C 6.00A for OS/2 16-bit targets. If compiling for emx (32-bit),
 * version 0.8h with at least fix level 7 is absolutely required. */

/* Because importing network API functions directly would prevent the
 * executables from loading on systems without the corresponding
 * network software, me must link them in during runtime manually with
 * DosLoadModule/DosGetProcAddress/DosFreeModule. This gets even more
 * difficult and ugly in 32-bit mode, since we have to call the same
 * old 16-bit API's and thunking from gcc (emx) is a bit difficult. */

#ifdef __386__
#ifndef __32BIT__
#define __32BIT__ 1
#endif
#endif

#ifndef __32BIT__
#define DosQueryProcAddr(handle, ord, name, funcptr) \
	DosGetProcAddr(handle, name, funcptr)
#endif

/* ----- Novell NetWare ----- */

struct info 
{
  USHORT connectionID;
  USHORT connectFlags;
  USHORT sessionID;
  USHORT connectionNumber;
  CHAR serverAddr[12];
  USHORT serverType;
  CHAR serverName[48];
  USHORT clientType;
  CHAR clientName[48];
};

typedef struct info FAR *PINFO;

#ifdef __EMX__

USHORT (APIENTRY *NWGDCID16)(PUSHORT pID);
USHORT (APIENTRY *NWGCS16)(USHORT nID, PINFO pInfo, USHORT nSize);

USHORT NWGetDefaultConnectionID(PUSHORT pID)
{
  return (USHORT)
          (_THUNK_PROLOG (4);
           _THUNK_FLAT (pID);
           _THUNK_CALLI (_emx_32to16(NWGDCID16)));
}

USHORT NWGetConnectionStatus(USHORT nID, PINFO pInfo, USHORT nSize)
{
  return (USHORT)
          (_THUNK_PROLOG (2+4+2);
           _THUNK_SHORT (nID);
           _THUNK_FLAT (pInfo);
           _THUNK_SHORT (nSize);
           _THUNK_CALLI (_emx_32to16(NWGCS16)));
}

#else

#ifdef __32BIT__

USHORT (* APIENTRY16 NWGetDefaultConnectionID)(PVOID16 pID);
USHORT (* APIENTRY16 NWGetConnectionStatus)(USHORT nID, PVOID16 pInfo, USHORT nSize);

#else

USHORT (APIENTRY * NWGetDefaultConnectionID)(PUSHORT pID);
USHORT (APIENTRY * NWGetConnectionStatus)(USHORT nID, PINFO pInfo, USHORT nSize);

#endif

#define NWGDCID16 NWGetDefaultConnectionID
#define NWGCS16 NWGetConnectionStatus

#endif

char *nw_getlogin()
{
  static struct info ci;

  HMODULE NWCalls;
  USHORT id;
  char buf[256], *res = NULL;

  if (DosLoadModule(buf, sizeof(buf), "NWCALLS", &NWCalls) == 0) 
  {
    if (DosQueryProcAddr(NWCalls, 0, "NWGETDEFAULTCONNECTIONID", 
			 (PVOID) &NWGDCID16) == 0 &&
        DosQueryProcAddr(NWCalls, 0, "NWGETCONNECTIONSTATUS", 
			 (PVOID) &NWGCS16) == 0)
    {
#if defined(__WATCOMC__) && defined(__386__)
      NWGDCID16 = (PVOID) (ULONG) (PVOID16) NWGDCID16;
      NWGCS16 = (PVOID) (ULONG) (PVOID16) NWGCS16;
#endif

      if (NWGetDefaultConnectionID(&id) == 0 && 
	  NWGetConnectionStatus(id, &ci, sizeof(ci)) == 0)
      {
	strlwr(ci.clientName);
	if (ci.clientName[0])
	  res = ci.clientName;
      }
    }

    DosFreeModule(NWCalls);
  }

  return res;
}

/* ----- Microsoft LAN Manager, IBM LAN Server ----- */

#ifdef __EMX__

#define PSTR _far16ptr
#define _fstrcpy(d, s) strcpy(d, _emx_16to32(s))

USHORT (APIENTRY *NWGI16)(PSTR pszServer, USHORT sLevel, 
  PVOID pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail);

USHORT NetWkstaGetInfo(PSZ pszServer, USHORT sLevel, PVOID pbBuffer, 
		       USHORT cbBuffer, PUSHORT pcbTotalAvail)
{
  return (USHORT)
          (_THUNK_PROLOG (4+2+4+2+4);
           _THUNK_FLAT (pszServer);
           _THUNK_SHORT (sLevel);
           _THUNK_FLAT (pbBuffer);
           _THUNK_SHORT (cbBuffer);
           _THUNK_FLAT (pcbTotalAvail);
           _THUNK_CALLI (_emx_32to16(NWGI16)));
}

#else

#ifdef __32BIT__

#define PSTR PCHAR16

#ifdef __WATCOMC__
#define _fstrcpy(d, s) {char *t = s; strcpy(d, t);}
#else
#define _fstrcpy(d, s) strcpy(d, s)
#endif

USHORT (* APIENTRY16 NetWkstaGetInfo)(PSTR pszServer, USHORT sLevel, 
  PVOID16 pbBuffer, USHORT cbBuffer, PVOID16 pcbTotalAvail);

#else

#define PSTR PSZ

USHORT (APIENTRY *NetWkstaGetInfo)(PSTR pszServer, USHORT sLevel, 
  PVOID pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail);

#endif

#define NWGI16 NetWkstaGetInfo

#endif

struct wksta_info_10
{
  PSTR computername;
  PSTR username;
  PSTR langroup;
  BYTE ver_major;
  BYTE ver_minor;
  PSTR logon_domain;
  PSTR oth_domains;
  BYTE filler[32];
};

char *lan_getlogin()
{
  struct wksta_info_10 wksta;
  static char name[32];

  HMODULE NETAPI;
  USHORT total;
  char buf[256], *res = NULL;

  if (DosLoadModule(buf, sizeof(buf), "NETAPI", &NETAPI) == 0) 
  {
    if (DosQueryProcAddr(NETAPI, 0, "NETWKSTAGETINFO", (PVOID) &NWGI16) == 0)
    {
#if defined(__WATCOMC__) && defined(__386__)
      NWGI16 = (PVOID) (ULONG) (PVOID16) NWGI16;
#endif

      if (NetWkstaGetInfo(0, 10, &wksta, sizeof(wksta), &total) == 0)
      {
	_fstrcpy(name, wksta.username);
	strlwr(name);
	if (name[0])
	  res = name;
      }
    }

    DosFreeModule(NETAPI);
  }

  return res;
}

#ifdef TEST

/* ----- testing code ----- */

void main(void)
{
  printf("NetWare: <%s>\nLAN Manager: <%s>\n", 
	 nw_getlogin(), lan_getlogin());
}

#else

/* ----- main entry point ----- */

char *getlogin()
{
  char *lm = lan_getlogin();
  char *nw = nw_getlogin();
  return lm ? lm : nw ? nw : (char *) 0;
}

#endif
