/* sqWin32DnsInfo.c: Gathers DNS information on Windows */
#include <windows.h>
#include "sq.h"

extern struct VirtualMachine *interpreterProxy;
#define vm interpreterProxy

/* Large enough since we only use 3 entries with 1k bytes max */
#define RESULTBUFSIZE 20000
static char *buf = 0;

#define LOOKUPBUFSIZ 1000

static void
lookup(HKEY hk, char *key, char lkupbuf[LOOKUPBUFSIZ]) {
  DWORD dwLength = LOOKUPBUFSIZ - 1;
  lkupbuf[0] = 0;
  (void)RegQueryValueExA(hk, key, NULL, NULL, (BYTE *)lkupbuf, &dwLength);
  lkupbuf[dwLength] = 0;
}

/* Print base registry info. Return true if DNS info was provided. */
static int
printBaseInfo(char *hkeyName) {
  HKEY hkey;
  DWORD ret;
  int result = 0;
  char value[LOOKUPBUFSIZ];

  ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, hkeyName, 0, KEY_READ, &hkey);
  if(ret != ERROR_SUCCESS) {
    printf("RegOpenKeyExA failed\n");
    return vm->primitiveFail();
  }

  /* Provide Hostname info if present */
  lookup(hkey, "Hostname", value);
  if(value[0]) {
    strcat(buf, "\nhostname ");
    strcat(buf, value);
  }

  /* The list of suffixes to search */
  lookup(hkey, "SearchList", value);
  if(value[0]) {
    strcat(buf, "\nsearch ");
    strcat(buf, value);
  }

  /* The (static or dhcp) domain */
  lookup(hkey, "Domain", value);
  if(value[0]) {
    strcat(buf, "\ndomain ");
    strcat(buf, value);
    strcat(buf, " # static");
  } else {
    lookup(hkey, "DhcpDomain", value);
    if(value[0]) {
      strcat(buf, "\ndomain ");
      strcat(buf, value);
      strcat(buf, " # dhcp");
    }
  }

  /* And the (static or dhcp) configured name servers */
  lookup(hkey, "NameServer", value);
  if(value[0]) {
    strcat(buf, "\nnameserver ");
    strcat(buf, value);
    strcat(buf, " # static");
    result = 1;
  } else {
    lookup(hkey, "DhcpNameServer", value);
    if(value[0]) {
      strcat(buf, "\nnameserver ");
      strcat(buf, value);
      strcat(buf, " # dhcp");
      result = 1;
    }
  }
  RegCloseKey(hkey);
  return result;
}

static int
printAdapterInfo(char *hkeyName) {
  HKEY hkey;
  DWORD ret;
  int result = 0;
  char value[LOOKUPBUFSIZ];

  ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, hkeyName, 0, KEY_READ, &hkey);
  if(ret != ERROR_SUCCESS) {
    printf("RegOpenKeyExA failed\n");
    return vm->primitiveFail();
  }

  /* Provide interface address if present */
  lookup(hkey, "IPAddress", value);
  if(value[0] && strcmp(value, "0.0.0.0")) {
    /* Skip interface info since we can't currently determine
       if the information is correct or a dead adapter */
#if 0
    strcat(buf, "\ninterface ");
    strcat(buf, value);
    strcat(buf, " # static");
#endif
  } else {
    lookup(hkey, "DhcpIPAddress", value);
    if(value[0] && strcmp(value, "0.0.0.0")) {
#if 0
      strcat(buf, "\ninterface ");
      strcat(buf, value);
      strcat(buf, " # dhcp ");
#endif
    } else {
      /* Don't bother printing DNS for an adapter w/o IP */
      goto done;
    }
  }

  /* Print the (static or dhcp) configured name servers */
  lookup(hkey, "NameServer", value);
  if(value[0]) {
    strcat(buf, "\nnameserver ");
    strcat(buf, value);
    strcat(buf, " # static");
    result = 1;
  } else {
    lookup(hkey, "DhcpNameServer", value);
    if(value[0]) {
      strcat(buf, "\nnameserver ");
      strcat(buf, value);
      strcat(buf, " # dhcp");
      result = 1;
    }
  }

 done:
  RegCloseKey(hkey);
  return result;
}

#define BASE_KEY \
  "SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces"

EXPORT(int) primitiveDnsInfo(void) {
  HKEY hkey;
  sqInt sz, stroop;
  DWORD dwLength, ret, index;
  char adapter[1024];

  if (!buf) {
	buf = malloc(RESULTBUFSIZE);
	if (!buf) {
	  vm->primitiveFailFor(PrimErrNoCMemory);
	  return 0;
	}
  }
  *buf = 0;
  strcat(buf, "# Global config settings");

  /* Print the global options */
  if(printBaseInfo("SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters"))
    /* If we have DNS entries globally, skip enumerating all interfaces */
    goto done;

  /* Enumerate the available interfaces */
  ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, BASE_KEY, 0, KEY_READ, &hkey);
  for(index=0;;index++) {
    char keyName[1024];
    dwLength = sizeof(adapter);
    ret = RegEnumKeyExA(hkey, index, adapter, &dwLength, NULL, NULL, NULL, NULL);
    if(ret != ERROR_SUCCESS) break;
    strcpy(keyName, BASE_KEY);
    strcat(keyName, "\\");
    strcat(keyName, adapter);
    /* Should look up and print the adapter name */
    printAdapterInfo(keyName);
  }

 done:
  sz = strlen(buf);
  stroop = vm->instantiateClassindexableSize(vm->classString(), sz);
  if(!vm->failed()) {
    memcpy(vm->firstIndexableField(stroop), buf, sz);
    vm->popthenPush(vm->methodArgumentCount()+1, stroop);
  }
  return 1;
}
