Initial dnsapi sources.
authorArt Yerkes <art.yerkes@gmail.com>
Thu, 18 Dec 2003 10:54:02 +0000 (10:54 +0000)
committerArt Yerkes <art.yerkes@gmail.com>
Thu, 18 Dec 2003 10:54:02 +0000 (10:54 +0000)
svn path=/trunk/; revision=7112

reactos/lib/dnsapi/dnsapi/adns.c [new file with mode: 0644]
reactos/lib/dnsapi/dnsapi/context.c [new file with mode: 0644]
reactos/lib/dnsapi/dnsapi/free.c [new file with mode: 0644]
reactos/lib/dnsapi/dnsapi/names.c [new file with mode: 0644]
reactos/lib/dnsapi/dnsapi/query.c [new file with mode: 0644]

diff --git a/reactos/lib/dnsapi/dnsapi/adns.c b/reactos/lib/dnsapi/dnsapi/adns.c
new file mode 100644 (file)
index 0000000..c148fc1
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS system libraries
+ * FILE:        lib/dnsapi/dnsapi/context.c
+ * PURPOSE:     ADNS translation.
+ * PROGRAMER:   Art Yerkes
+ * UPDATE HISTORY:
+ *              12/15/03 -- Created
+ */
+
+#include <windows.h>
+#include <WinError.h>
+#include <WinDNS.h>
+#include <internal/windns.h>
+
+DNS_STATUS DnsIntTranslateAdnsToDNS_STATUS( int Status ) {
+  switch( Status ) {
+  case adns_s_ok:
+    return ERROR_SUCCESS;
+  case adns_s_nomemory:
+  case adns_s_systemfail:
+  default: /* There really aren't any general errors in the dns part. */
+    return DNS_ERROR_NO_MEMORY;
+  }
+}
+
diff --git a/reactos/lib/dnsapi/dnsapi/context.c b/reactos/lib/dnsapi/dnsapi/context.c
new file mode 100644 (file)
index 0000000..855bab0
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS system libraries
+ * FILE:        lib/dnsapi/dnsapi/context.c
+ * PURPOSE:     DNSAPI functions built on the ADNS library.
+ * PROGRAMER:   Art Yerkes
+ * UPDATE HISTORY:
+ *              12/15/03 -- Created
+ */
+
+#include <windows.h>
+#include <WinError.h>
+#include <WinDNS.h>
+#include <internal/windns.h>
+
+/* DnsAcquireContextHandle *************
+ * Create a context handle that will allow us to open and retrieve queries.
+ *
+ * DWORD CredentialsFlags --            TRUE  -- Unicode
+ *                                      FALSE -- Ansi or UTF-8?
+ *
+ * PVOID Credentials      --            Pointer to a SEC_WINNT_AUTH_IDENTITY
+ *                                      TODO: Use it.
+ *
+ * PHANDLE ContextHandle  --            Pointer to a HANDLE that will receive
+ *                                      our context pointer.
+ *
+ * RETURNS:
+ * ERROR_SUCCESS or a failure code.
+ * TODO: Which ones area allowed?
+ */
+
+extern DNS_STATUS WINAPI DnsAcquireContextHandle_UTF8
+( DWORD CredentialsFlags,
+  PVOID Credentials,
+  HANDLE *ContextHandle );
+
+DNS_STATUS WINAPI DnsAcquireContextHandle_W
+( DWORD CredentialsFlags,
+  PVOID Credentials,
+  HANDLE *ContextHandle ) {
+  if( CredentialsFlags ) {
+    PWINDNS_CONTEXT Context;
+    int adns_status;
+
+    /* For now, don't worry about the user's identity. */
+    Context = (PWINDNS_CONTEXT)RtlAllocateHeap( RtlGetProcessHeap(), 0, 
+                                               sizeof( WINDNS_CONTEXT ) );
+    /* The real work here is to create an adns_state that will help us
+     * do what we want to later. */
+    adns_status = adns_init( &Context->State, 
+                            adns_if_noenv | 
+                            adns_if_noerrprint |
+                            adns_if_noserverwarn,
+                            0 );
+    if( adns_status != adns_s_ok ) {
+      *ContextHandle = 0;
+      return DnsIntTranslateAdnsToDNS_STATUS( adns_status );
+    } else {
+      *ContextHandle = (HANDLE)Context;
+      return ERROR_SUCCESS;
+    }
+  } else {
+    return DnsAcquireContextHandle_UTF8( CredentialsFlags, 
+                                        Credentials,
+                                        ContextHandle );
+  }
+}
+
+DNS_STATUS WINAPI DnsAcquireContextHandle_UTF8
+( DWORD CredentialsFlags,
+  PVOID Credentials,
+  HANDLE *ContextHandle ) {
+  if( CredentialsFlags ) {
+    return DnsAcquireContextHandle_W( CredentialsFlags,
+                                     Credentials,
+                                     ContextHandle );
+  } else {
+    /* Convert to unicode, then call the _W version 
+     * For now, there is no conversion */
+    DNS_STATUS Status;
+    
+    Status = DnsAcquireContextHandle_W( TRUE,
+                                       Credentials, /* XXX arty */
+                                       ContextHandle );
+    
+    /* Free the unicode credentials when they exist. */
+
+    return Status;
+  }
+}
+
+DNS_STATUS WINAPI DnsAcquireContextHandle_A
+( DWORD CredentialFlags,
+  PVOID Credentials,
+  HANDLE *ContextHandle ) {
+  if( CredentialFlags ) {
+    return DnsAcquireContextHandle_W( CredentialFlags,
+                                     Credentials,
+                                     ContextHandle );
+  } else {
+    return DnsAcquireContextHandle_UTF8( CredentialFlags,
+                                        Credentials,
+                                        ContextHandle );
+  }
+}
+/* DnsReleaseContextHandle *************
+ * Release a context handle, freeing all resources.
+ */
+
+void WINAPI DnsReleaseContextHandle
+( HANDLE ContextHandle ) {
+  PWINDNS_CONTEXT Context = (PWINDNS_CONTEXT)ContextHandle;
+  adns_finish( Context->State );
+  RtlFreeHeap( RtlGetProcessHeap(), 0, Context );
+}
diff --git a/reactos/lib/dnsapi/dnsapi/free.c b/reactos/lib/dnsapi/dnsapi/free.c
new file mode 100644 (file)
index 0000000..fabb343
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS system libraries
+ * FILE:        lib/dnsapi/dnsapi/free.c
+ * PURPOSE:     DNSAPI functions built on the ADNS library.
+ * PROGRAMER:   Art Yerkes
+ * UPDATE HISTORY:
+ *              12/15/03 -- Created
+ */
+
+#include <windows.h>
+#include <WinError.h>
+#include <WinDNS.h>
+#include <internal/windns.h>
+
+VOID WINAPI DnsFree
+( PVOID Data, DNS_FREE_TYPE FreeType ) {
+  switch( FreeType ) {
+  case DnsFreeFlat:
+    RtlFreeHeap( RtlGetProcessHeap(), 0, Data );
+    break;
+
+  case DnsFreeRecordList:
+    DnsIntFreeRecordList( (PDNS_RECORDA)Data );
+    break;
+
+  case DnsFreeParsedMessageFields:
+    /* assert( FALSE ); XXX arty not yet implemented. */
+    break;
+  }
+}
+
+VOID WINAPI DnsRecordListFree
+( PVOID Data, DNS_FREE_TYPE FreeType ) {
+  DnsFree( Data, FreeType );
+}
diff --git a/reactos/lib/dnsapi/dnsapi/names.c b/reactos/lib/dnsapi/dnsapi/names.c
new file mode 100644 (file)
index 0000000..0cd5f22
--- /dev/null
@@ -0,0 +1,199 @@
+#include <windows.h>
+#include <WinError.h>
+#include <WinDNS.h>
+#include <internal/windns.h>
+#include <wchar.h>
+#include <string.h>
+#include <ctype.h>
+
+static BOOL DnsIntNameContainsDots( LPCWSTR Name ) {
+  return wcschr( Name, '.' ) ? TRUE : FALSE;
+}
+
+static BOOL DnsIntTwoConsecutiveDots( LPCWSTR Name ) {
+  return wcsstr( Name, L".." ) ? TRUE : FALSE;
+}
+
+static BOOL DnsIntContainsUnderscore( LPCWSTR Name ) {
+  return wcschr( Name, '_' ) ? TRUE : FALSE;
+}
+
+/* DnsValidateName *********************
+ * Use some different algorithms to validate the given name as suitable for
+ * use with DNS.
+ *
+ * Name      -- The name to evaluate.
+ * Format    -- Format to use:
+ *               DnsNameDomain
+ *               DnsNameDomainLabel
+ *               DnsNameHostnameFull
+ *               DnsNameHostnameLabel
+ *               DnsNameWildcard
+ *               DnsNameSrvRecord
+ * RETURNS:
+ * ERROR_SUCCESS                -- All good
+ * ERROR_INVALID_NAME           --
+ *  Name greater than 255 chars.
+ *  Label greater than 63 chars.
+ *  Two consecutive dots, or starts with dot.
+ *  Contains a dot, but a Label check was specified.
+ * DNS_ERROR_INVALID_NAME_CHAR
+ *  Contains any invalid char: " {|}~[\]^':;<=>?@!"#$%^`()+/,"
+ *  Contains an *, except when it is the first label and Wildcard was
+ *  specified.
+ * DNS_ERROR_NUMERIC_NAME
+ *  Set if the name contains only numerics, unless Domain is specified.
+ * DNS_ERROR_NON_RFC_NAME
+ *  If the name contains underscore.
+ *  If there is an underscore in any position but the first in the SrvRecord
+ *   case.
+ *  If the name contains a non-ascii character.
+ */
+
+DNS_STATUS WINAPI DnsValidateName_W
+( LPCWSTR Name,
+  DNS_NAME_FORMAT Format )  {
+  BOOL AllowDot = FALSE;
+  BOOL AllowLeadingAst = FALSE;
+  BOOL AllowLeadingUnderscore = FALSE;
+  BOOL AllowAllDigits = FALSE;
+  const WCHAR *NextLabel, *CurrentLabel, *CurrentChar;
+  
+  switch( Format ) {
+  case DnsNameDomain:
+    AllowAllDigits = TRUE;
+    AllowDot = TRUE;
+    break;
+  case DnsNameDomainLabel:
+    AllowAllDigits = TRUE;
+    break;
+  case DnsNameHostnameFull:
+    AllowDot = TRUE;
+    break;
+  case DnsNameHostnameLabel:
+    break;
+  case DnsNameWildcard:
+    AllowLeadingAst = TRUE;
+    AllowDot = TRUE;
+    break;
+  case DnsNameSrvRecord:
+    AllowLeadingUnderscore = TRUE;
+    break;
+  default:
+    break;
+  }
+
+  /* Preliminary checks */
+  if( Name[0] == 0 ) return ERROR_INVALID_NAME; /* XXX arty: Check this */
+
+  /* Name too long */
+  if( wcslen( Name ) > 255 ) {
+    return ERROR_INVALID_NAME;
+  }
+  
+  /* Violations about dots */
+  if( (!AllowDot && DnsIntNameContainsDots( Name )) ||
+      Name[0] == '.' || DnsIntTwoConsecutiveDots( Name ) ) 
+    return ERROR_INVALID_NAME;
+  
+  /* Check component sizes */
+  CurrentLabel = Name;
+  do {
+    NextLabel = CurrentLabel;
+    while( *NextLabel && *NextLabel != '.' ) NextLabel++;
+
+    if( NextLabel - CurrentLabel > 63 ) 
+      return ERROR_INVALID_NAME;
+
+    CurrentLabel = NextLabel;
+  } while( *CurrentLabel );
+
+  CurrentChar = Name;
+
+  while( *CurrentChar ) {
+    if( wcschr(L" {|}~[\\]^':;<=>?@!\"#$%^`()+/,",*CurrentChar) )
+      return DNS_ERROR_INVALID_NAME_CHAR;
+    CurrentChar++;
+  }
+
+  if( (!AllowLeadingAst && Name[0] == '*') ||
+      (AllowLeadingAst && Name[0] == '*' && Name[1] && Name[1] != '.') )
+    return DNS_ERROR_INVALID_NAME_CHAR;
+
+  if( wcschr( Name + 1, '*' ) ) 
+    return DNS_ERROR_INVALID_NAME_CHAR;
+
+  CurrentChar = Name;
+  while( !AllowAllDigits && *CurrentChar ) {
+    if( *CurrentChar == '.' || (*CurrentChar >= '0' && *CurrentChar <= '9') )
+      return DNS_ERROR_NUMERIC_NAME;
+  }
+
+  if( ((AllowLeadingUnderscore && Name[0] == '_') || Name[0] != '_') &&
+      !DnsIntContainsUnderscore( Name + 1 ) ) 
+    return DNS_ERROR_NON_RFC_NAME;
+
+  return ERROR_SUCCESS;
+}
+
+DNS_STATUS WINAPI DnsValidateName_UTF8
+( LPCSTR Name,
+  DNS_NAME_FORMAT Format ) {
+  PWCHAR Buffer;
+  int StrLenWc;
+  DNS_STATUS Status;
+
+  StrLenWc = mbstowcs( NULL, Name, 0 );
+  Buffer = RtlAllocateHeap( GetProcessHeap(), 0, 
+                           sizeof( WCHAR ) * (StrLenWc + 1) );
+  mbstowcs( Buffer, Name, StrLenWc + 1 );
+  Status = DnsValidateName_W( Buffer, Format );
+  RtlFreeHeap( GetProcessHeap(), 0, Buffer );
+  
+  return Status;
+}
+
+DNS_STATUS WINAPI DnsValidateName_A
+( LPCSTR Name,
+  DNS_NAME_FORMAT Format ) {
+  return DnsValidateName_UTF8( Name, Format );
+}
+
+/* DnsNameCompare **********************
+ * Return TRUE if the names are identical.
+ *
+ * Name1 & Name2 -- Names.
+ */
+
+BOOL WINAPI DnsNameCompare_W
+( LPWSTR Name1,
+  LPWSTR Name2 ) {
+  int offset = 0;
+
+  while( Name1[offset] && Name2[offset] && 
+        towupper( Name1[offset] ) == towupper( Name2[offset] ) ) offset++;
+  return 
+    (!Name1[offset] && !Name2[offset]) ||
+    (!Name1[offset] && !wcscmp( Name2 + offset, L"." )) ||
+    (!Name2[offset] && !wcscmp( Name1 + offset, L"." ));
+}
+
+BOOL WINAPI DnsNameCompare_UTF8
+( LPCSTR Name1,
+  LPCSTR Name2 ) {
+  int offset = 0;
+  
+  while( Name1[offset] && Name2[offset] &&
+        toupper( Name1[offset] ) == toupper( Name2[offset] ) ) offset++;
+  return
+    (!Name1[offset] && !Name2[offset]) ||
+    (!Name1[offset] && !strcmp( Name2 + offset, ".")) ||
+    (!Name2[offset] && !strcmp( Name1 + offset, "."));
+}
+
+BOOL WINAPI DnsNameCompare_A
+( LPCSTR Name1,
+  LPCSTR Name2 ) {
+  return DnsNameCompare_UTF8( Name1, Name2 );
+}
+
diff --git a/reactos/lib/dnsapi/dnsapi/query.c b/reactos/lib/dnsapi/dnsapi/query.c
new file mode 100644 (file)
index 0000000..8271903
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS system libraries
+ * FILE:        lib/dnsapi/dnsapi/query.c
+ * PURPOSE:     DNSAPI functions built on the ADNS library.
+ * PROGRAMER:   Art Yerkes
+ * UPDATE HISTORY:
+ *              12/15/03 -- Created
+ */
+
+#include <windows.h>
+#include <WinError.h>
+#include <WinDNS.h>
+#include <internal/windns.h>
+#include <string.h>
+
+/* DnsQuery ****************************
+ * Begin a DNS query, and allow the result to be placed in the application
+ * supplied result pointer.  The result can be manipulated with the record
+ * functions.  
+ *
+ * Name                 -- The DNS object to be queried.
+ * Type                 -- The type of records to be returned.  These are 
+ *                          listed in windns.h
+ * Options              -- Query options.  DNS_QUERY_STANDARD is the base
+ *                          state, and every other option takes precedence.
+ *                          multiple options can be combined.  Listed in
+ *                          windns.h
+ * Servers              -- List of alternate servers (optional)
+ * QueryResultSet       -- Pointer to the result pointer that will be filled
+ *                          when the response is available.
+ * Reserved             -- Response as it appears on the wire.  Optional.
+ */
+
+char *xstrsave(const char *str) {
+  char *p;
+  
+  p= RtlAllocateHeap( RtlGetProcessHeap(), 0, strlen(str)+1 );
+  strcpy(p,str);
+  return p;
+}
+
+DNS_STATUS WINAPI DnsQuery_A
+( LPCSTR Name,
+  WORD Type,
+  DWORD Options,
+  PIP4_ARRAY Servers,
+  PDNS_RECORDA *QueryResultSet,
+  PVOID *Reserved ) {
+  adns_state astate;
+  int quflags = 0;
+  int adns_error;
+  adns_answer *answer;
+
+  *QueryResultSet = 0;
+
+  switch( Type ) {
+  case DNS_TYPE_A:
+    adns_error = adns_init( &astate,
+                           adns_if_noenv |
+                           adns_if_noerrprint |
+                           adns_if_noserverwarn,
+                           0 );
+    if( adns_error != adns_s_ok ) {
+      adns_finish( astate );
+      return DnsIntTranslateAdnsToDNS_STATUS( adns_error );
+    }
+
+    adns_error = adns_synchronous( astate, 
+                                  Name, 
+                                  adns_r_addr, 
+                                  quflags, 
+                                  &answer );
+                                  
+    if( adns_error != adns_s_ok ) {
+      adns_finish( astate );
+      return DnsIntTranslateAdnsToDNS_STATUS( adns_error );
+    }
+
+    *QueryResultSet = (PDNS_RECORDA)RtlAllocateHeap( RtlGetProcessHeap(), 0, 
+                                                    sizeof( DNS_RECORDA ) );
+    (*QueryResultSet)->wType = Type;
+    (*QueryResultSet)->pName = xstrsave( Name );
+    (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
+    (*QueryResultSet)->Data.A.IpAddress = 
+      ntohl( answer->rrs.addr->addr.inet.sin_addr.s_addr );
+    adns_finish( astate );
+    return ERROR_SUCCESS;
+    
+  default:
+    return DNS_ERROR_NO_MEMORY; /* XXX arty: find a better error code. */
+  }
+}
+
+static PCHAR DnsWToC( const WCHAR *WideString ) {
+  int chars = wcstombs( NULL, WideString, 0 );
+  PCHAR out = RtlAllocateHeap( RtlGetProcessHeap(), 0, chars + 1 );
+  wcstombs( out, WideString, chars + 1 );
+  return out;
+}
+
+static PWCHAR DnsCToW( const CHAR *NarrowString ) {
+  int chars = mbstowcs( NULL, NarrowString, 0 );
+  PWCHAR out = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
+                               (chars + 1) * sizeof(WCHAR) );
+  mbstowcs( out, NarrowString, chars + 1 );
+  return out;
+}
+
+DNS_STATUS WINAPI DnsQuery_W
+( LPCWSTR Name,
+  WORD Type,
+  DWORD Options,
+  PIP4_ARRAY Servers,
+  PDNS_RECORDW *QueryResultSet,
+  PVOID *Reserved ) {
+  int i;
+  PCHAR Buffer;
+  DNS_STATUS Status;
+  PDNS_RECORDA QueryResultWide;
+  PDNS_RECORDW ConvertedRecord = 0, LastRecord = 0;
+
+  Buffer = DnsWToC( Name );
+
+  Status = DnsQuery_A( Buffer, Type, Options, Servers, &QueryResultWide,
+                      Reserved );
+
+  while( Status == ERROR_SUCCESS && QueryResultWide ) {
+    switch( QueryResultWide->wType ) {
+    case DNS_TYPE_A:
+    case DNS_TYPE_WKS:
+    case DNS_TYPE_AAAA:
+    case DNS_TYPE_KEY:
+      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
+                                        sizeof(DNS_RECORDA) );
+      ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
+      ConvertedRecord->wType = QueryResultWide->wType;
+      ConvertedRecord->wDataLength = QueryResultWide->wDataLength;
+      memcpy( ConvertedRecord, QueryResultWide, 
+             QueryResultWide->wDataLength );
+      break;
+
+    case DNS_TYPE_CNAME:
+    case DNS_TYPE_PTR:
+    case DNS_TYPE_NS:
+    case DNS_TYPE_MB:
+    case DNS_TYPE_MD:
+    case DNS_TYPE_MF:
+    case DNS_TYPE_MG:
+    case DNS_TYPE_MR:
+      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
+                                        sizeof(DNS_RECORDA) );
+      ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
+      ConvertedRecord->wType = QueryResultWide->wType;
+      ConvertedRecord->wDataLength = sizeof(DNS_PTR_DATAA);
+      ConvertedRecord->Data.PTR.pNameHost = 
+       DnsCToW( QueryResultWide->Data.PTR.pNameHost );
+      break;
+    case DNS_TYPE_MINFO:
+    case DNS_TYPE_RP:
+      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
+                                        sizeof(DNS_RECORDA) );
+      ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
+      ConvertedRecord->wType = QueryResultWide->wType;
+      ConvertedRecord->wDataLength = sizeof(DNS_MINFO_DATAA);
+      ConvertedRecord->Data.MINFO.pNameMailbox =
+       DnsCToW( QueryResultWide->Data.MINFO.pNameMailbox );
+      ConvertedRecord->Data.MINFO.pNameErrorsMailbox =
+       DnsCToW( QueryResultWide->Data.MINFO.pNameErrorsMailbox );
+      break;
+
+    case DNS_TYPE_MX:
+    case DNS_TYPE_AFSDB:
+    case DNS_TYPE_RT:
+      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
+                                        sizeof(DNS_RECORDA) );
+      ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
+      ConvertedRecord->wType = QueryResultWide->wType;
+      ConvertedRecord->wDataLength = sizeof(DNS_MX_DATAW);
+      ConvertedRecord->Data.MX.pNameExchange = 
+       DnsCToW( QueryResultWide->Data.MX.pNameExchange );
+      ConvertedRecord->Data.MX.wPreference =
+       QueryResultWide->Data.MX.wPreference;
+      break;
+
+    case DNS_TYPE_TXT:
+    case DNS_TYPE_HINFO:
+    case DNS_TYPE_ISDN:
+      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
+                                        sizeof(DNS_TXT_DATAW) + 
+                                        QueryResultWide->
+                                        Data.TXT.dwStringCount );
+      ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
+      ConvertedRecord->wType = QueryResultWide->wType;
+      ConvertedRecord->wDataLength = 
+       sizeof(DNS_TXT_DATAW) + 
+       (sizeof(PWCHAR) * QueryResultWide->Data.TXT.dwStringCount);
+      ConvertedRecord->Data.TXT.dwStringCount = 
+       QueryResultWide->Data.TXT.dwStringCount;
+      for( i = 0; i < ConvertedRecord->Data.TXT.dwStringCount; i++ ) {
+       ConvertedRecord->Data.TXT.pStringArray[i] = 
+         DnsCToW( QueryResultWide->Data.TXT.pStringArray[i] );
+      }
+      break;
+
+    case DNS_TYPE_NULL:
+      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
+                                        sizeof(DNS_NULL_DATA) + 
+                                        QueryResultWide->
+                                        Data.Null.dwByteCount );
+      ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
+      ConvertedRecord->wType = QueryResultWide->wType;
+      ConvertedRecord->wDataLength =
+       sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount;
+      ConvertedRecord->Data.Null.dwByteCount = 
+       QueryResultWide->Data.Null.dwByteCount;
+      memcpy( &ConvertedRecord->Data.Null.Data, 
+             &QueryResultWide->Data.Null.Data,
+             QueryResultWide->Data.Null.dwByteCount );
+      break;
+
+    case DNS_TYPE_SIG:
+      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
+                                        sizeof(DNS_RECORDA) );
+      ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
+      ConvertedRecord->wType = QueryResultWide->wType;
+      ConvertedRecord->wDataLength = sizeof(DNS_SIG_DATAA);
+      memcpy( &ConvertedRecord->Data.SIG,
+             &QueryResultWide->Data.SIG,
+             sizeof(QueryResultWide->Data.SIG) );
+      ConvertedRecord->Data.SIG.pNameSigner =
+       DnsCToW( QueryResultWide->Data.SIG.pNameSigner );
+      break;
+
+    case DNS_TYPE_NXT:
+      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
+                                        sizeof(DNS_RECORDA) );
+      ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
+      ConvertedRecord->wType = QueryResultWide->wType;
+      ConvertedRecord->wDataLength = sizeof(DNS_NXT_DATAA);
+      memcpy( &ConvertedRecord->Data.NXT,
+             &QueryResultWide->Data.NXT,
+             sizeof(QueryResultWide->Data.NXT) );
+      ConvertedRecord->Data.NXT.pNameNext =
+       DnsCToW( QueryResultWide->Data.NXT.pNameNext );
+      break;
+
+    case DNS_TYPE_SRV:
+      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
+                                        sizeof(DNS_RECORDA) );
+      ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
+      ConvertedRecord->wType = QueryResultWide->wType;
+      ConvertedRecord->wDataLength = sizeof(DNS_SRV_DATAA);
+      memcpy( &ConvertedRecord->Data.SRV,
+             &QueryResultWide->Data.SRV,
+             sizeof(QueryResultWide->Data.SRV) );
+      ConvertedRecord->Data.SRV.pNameTarget =
+       DnsCToW( QueryResultWide->Data.SRV.pNameTarget );
+      break;
+    }
+
+    if( LastRecord ) {
+      LastRecord->pNext = ConvertedRecord;
+      LastRecord = LastRecord->pNext;
+    } else {
+      LastRecord = *QueryResultSet = ConvertedRecord;
+    }
+  }
+
+  LastRecord->pNext = 0;
+
+  /* The name */
+  RtlFreeHeap( RtlGetProcessHeap(), 0, Buffer );
+
+  return Status;
+}
+
+DNS_STATUS WINAPI DnsQuery_UTF8
+( LPCSTR Name,
+  WORD Type,
+  DWORD Options,
+  PIP4_ARRAY Servers,
+  PDNS_RECORDA *QueryResultSet,
+  PVOID *Reserved ) {
+  return DnsQuery_UTF8( Name, Type, Options, Servers, QueryResultSet, 
+                       Reserved );
+}
+
+void DnsIntFreeRecordList( PDNS_RECORDA ToDelete ) {
+  int i;
+  PDNS_RECORDA next = 0;
+
+  while( ToDelete ) {
+    if( ToDelete->pName ) 
+      RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->pName );
+    switch( ToDelete->wType ) {
+    case DNS_TYPE_CNAME:
+    case DNS_TYPE_PTR:
+    case DNS_TYPE_NS:
+    case DNS_TYPE_MB:
+    case DNS_TYPE_MD:
+    case DNS_TYPE_MF:
+    case DNS_TYPE_MG:
+    case DNS_TYPE_MR:
+      RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.PTR.pNameHost );
+      break;
+    case DNS_TYPE_MINFO:
+    case DNS_TYPE_RP:
+      RtlFreeHeap( RtlGetProcessHeap(), 0, 
+                  ToDelete->Data.MINFO.pNameMailbox );
+      RtlFreeHeap( RtlGetProcessHeap(), 0,
+                  ToDelete->Data.MINFO.pNameErrorsMailbox );
+      break;
+
+    case DNS_TYPE_MX:
+    case DNS_TYPE_AFSDB:
+    case DNS_TYPE_RT:
+      RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.MX.pNameExchange );
+      break;
+
+    case DNS_TYPE_TXT:
+    case DNS_TYPE_HINFO:
+    case DNS_TYPE_ISDN:
+      for( i = 0; i < ToDelete->Data.TXT.dwStringCount; i++ ) {
+       RtlFreeHeap( RtlGetProcessHeap(), 0, 
+                    ToDelete->Data.TXT.pStringArray[i] );
+      }
+      RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray );
+      break;
+
+    case DNS_TYPE_SIG:
+      RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.SIG.pNameSigner );
+      break;
+
+    case DNS_TYPE_NXT:
+      RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.NXT.pNameNext );
+      break;
+
+    case DNS_TYPE_SRV:
+      RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.SRV.pNameTarget );
+      break;
+    }
+
+    next = ToDelete->pNext;
+    RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete );
+    ToDelete = next;
+  }
+}