msxml3: Callback only if state really changed.
[wine] / dlls / dnsapi / query.c
1 /*
2  * DNS support
3  *
4  * Copyright (C) 2006 Hans Leidekker
5  * 
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23 #include "wine/debug.h"
24
25 #include <stdarg.h>
26 #include <string.h>
27 #include <sys/types.h>
28
29 #ifdef HAVE_NETINET_IN_H
30 # include <netinet/in.h>
31 #endif
32 #ifdef HAVE_ARPA_NAMESER_H
33 # include <arpa/nameser.h>
34 #endif
35 #ifdef HAVE_RESOLV_H
36 # include <resolv.h>
37 #endif
38 #ifdef HAVE_NETDB_H
39 # include <netdb.h>
40 #endif
41
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winerror.h"
45 #include "winnls.h"
46 #include "windns.h"
47 #include "nb30.h"
48
49 #include "dnsapi.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
52
53 #ifdef HAVE_RESOLV
54
55 /* call res_init() just once because of a bug in Mac OS X 10.4 */
56 /* call once per thread on systems that have per-thread _res */
57 static void initialise_resolver( void )
58 {
59     if ((_res.options & RES_INIT) == 0)
60         res_init();
61 }
62
63 static const char *dns_section_to_str( ns_sect section )
64 {
65     switch (section)
66     {
67     case ns_s_qd:   return "Question";
68     case ns_s_an:   return "Answer";
69     case ns_s_ns:   return "Authority";
70     case ns_s_ar:   return "Additional";
71     default:
72     {
73         static char tmp[5];
74         FIXME( "unknown section: 0x%02x\n", section );
75         sprintf( tmp, "0x%02x", section );
76         return tmp;
77     }
78     }
79 }
80
81 static unsigned long dns_map_options( DWORD options )
82 {
83     unsigned long ret = 0;
84             
85     if (options == DNS_QUERY_STANDARD)
86         return RES_DEFAULT;
87
88     if (options & DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE)
89         ret |= RES_IGNTC;
90     if (options & DNS_QUERY_USE_TCP_ONLY)
91         ret |= RES_USEVC;
92     if (options & DNS_QUERY_NO_RECURSION)
93         ret &= ~RES_RECURSE;
94     if (options & DNS_QUERY_NO_LOCAL_NAME)
95         ret &= ~RES_DNSRCH;
96     if (options & DNS_QUERY_NO_HOSTS_FILE)
97         ret |= RES_NOALIASES;
98     if (options & DNS_QUERY_TREAT_AS_FQDN)
99         ret &= ~RES_DEFNAMES;
100
101     if (options & DNS_QUERY_DONT_RESET_TTL_VALUES)
102         FIXME( "option DNS_QUERY_DONT_RESET_TTL_VALUES not implemented\n" );
103     if (options & DNS_QUERY_RESERVED)
104         FIXME( "option DNS_QUERY_RESERVED not implemented\n" );
105     if (options & DNS_QUERY_WIRE_ONLY)
106         FIXME( "option DNS_QUERY_WIRE_ONLY not implemented\n" );
107     if (options & DNS_QUERY_NO_WIRE_QUERY)
108         FIXME( "option DNS_QUERY_NO_WIRE_QUERY not implemented\n" );
109     if (options & DNS_QUERY_BYPASS_CACHE)
110         FIXME( "option DNS_QUERY_BYPASS_CACHE not implemented\n" );
111     if (options & DNS_QUERY_RETURN_MESSAGE)
112         FIXME( "option DNS_QUERY_RETURN_MESSAGE not implemented\n" );
113
114     if (options & DNS_QUERY_NO_NETBT)
115         TRACE( "netbios query disabled\n" );
116
117     return ret;
118 }
119
120 static DNS_STATUS dns_map_error( int error )
121 {
122     switch (error)
123     {
124     case ns_r_noerror:  return ERROR_SUCCESS;
125     case ns_r_formerr:  return DNS_ERROR_RCODE_FORMAT_ERROR;
126     case ns_r_servfail: return DNS_ERROR_RCODE_SERVER_FAILURE;
127     case ns_r_nxdomain: return DNS_ERROR_RCODE_NAME_ERROR;
128     case ns_r_notimpl:  return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
129     case ns_r_refused:  return DNS_ERROR_RCODE_REFUSED;
130     case ns_r_yxdomain: return DNS_ERROR_RCODE_YXDOMAIN;
131     case ns_r_yxrrset:  return DNS_ERROR_RCODE_YXRRSET;
132     case ns_r_nxrrset:  return DNS_ERROR_RCODE_NXRRSET;
133     case ns_r_notauth:  return DNS_ERROR_RCODE_NOTAUTH;
134     case ns_r_notzone:  return DNS_ERROR_RCODE_NOTZONE;
135     default:
136         FIXME( "unmapped error code: %d\n", error );
137         return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
138     }
139 }
140
141 static DNS_STATUS dns_map_h_errno( int error )
142 {
143     switch (error)
144     {
145     case NO_DATA:
146     case HOST_NOT_FOUND: return DNS_ERROR_RCODE_NAME_ERROR;
147     case TRY_AGAIN:      return DNS_ERROR_RCODE_SERVER_FAILURE;
148     case NO_RECOVERY:    return DNS_ERROR_RCODE_REFUSED;
149     case NETDB_INTERNAL: return DNS_ERROR_RCODE;
150     default:
151         FIXME( "unmapped error code: %d\n", error );
152         return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
153     }
154 }
155
156 static char *dns_dname_from_msg( ns_msg msg, const unsigned char *pos )
157 {
158     int len;
159     char *str, dname[NS_MAXDNAME] = ".";
160
161     /* returns *compressed* length, ignore it */
162     len = dns_ns_name_uncompress( ns_msg_base( msg ), ns_msg_end( msg ),
163                                   pos, dname, sizeof(dname) );
164
165     len = strlen( dname );
166     str = heap_alloc( len + 1 );
167     if (str) strcpy( str, dname );
168     return str;
169 }
170
171 static char *dns_str_from_rdata( const unsigned char *rdata )
172 {
173     char *str;
174     unsigned int len = rdata[0];
175
176     str = heap_alloc( len + 1 );
177     if (str)
178     {
179         memcpy( str, ++rdata, len );
180         str[len] = '\0';
181     }
182     return str;
183 }
184
185 static unsigned int dns_get_record_size( const ns_rr *rr )
186 {
187     const unsigned char *pos = rr->rdata;
188     unsigned int num = 0, size = sizeof(DNS_RECORDA);
189
190     switch (rr->type)
191     {
192     case ns_t_key:
193     {
194         pos += sizeof(WORD) + sizeof(BYTE) + sizeof(BYTE);
195         size += rr->rdata + rr->rdlength - pos - 1;
196         break;
197     }
198     case ns_t_sig:
199     {
200         pos += sizeof(PCHAR) + sizeof(WORD) + 2 * sizeof(BYTE);
201         pos += 3 * sizeof(DWORD) + 2 * sizeof(WORD);
202         size += rr->rdata + rr->rdlength - pos - 1;
203         break;
204     }
205     case ns_t_hinfo:
206     case ns_t_isdn:
207     case ns_t_txt:
208     case ns_t_x25:
209     {
210         while (pos[0] && pos < rr->rdata + rr->rdlength)
211         {
212             num++;
213             pos += pos[0] + 1;
214         }
215         size += (num - 1) * sizeof(PCHAR);
216         break;
217     }
218     case ns_t_null:
219     {
220         size += rr->rdlength - 1;
221         break;
222     }
223     case ns_t_nxt:
224     case ns_t_wks:
225     case 0xff01:  /* WINS */
226     {
227         FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
228         break;
229     }
230     default:
231         break;
232     }
233     return size;
234 }
235
236 static DNS_STATUS dns_copy_rdata( ns_msg msg, const ns_rr *rr, DNS_RECORDA *r, WORD *dlen )
237 {
238     DNS_STATUS ret = ERROR_SUCCESS;
239     const unsigned char *pos = rr->rdata;
240     unsigned int i, size;
241
242     switch (rr->type)
243     {
244     case ns_t_a:
245     {
246         r->Data.A.IpAddress = *(const DWORD *)pos;
247         *dlen = sizeof(DNS_A_DATA);
248         break; 
249     }
250     case ns_t_aaaa:
251     {
252         for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
253         {
254             r->Data.AAAA.Ip6Address.IP6Dword[i] = *(const DWORD *)pos;
255             pos += sizeof(DWORD);
256         }
257
258         *dlen = sizeof(DNS_AAAA_DATA);
259         break;
260     }
261     case ns_t_key:
262     {
263         /* FIXME: byte order? */
264         r->Data.KEY.wFlags      = *(const WORD *)pos;   pos += sizeof(WORD);
265         r->Data.KEY.chProtocol  = *pos++;
266         r->Data.KEY.chAlgorithm = *pos++;
267
268         size = rr->rdata + rr->rdlength - pos;
269
270         for (i = 0; i < size; i++)
271             r->Data.KEY.Key[i] = *pos++;
272
273         *dlen = sizeof(DNS_KEY_DATA) + (size - 1) * sizeof(BYTE);
274         break;
275     }
276     case ns_t_rp:
277     case ns_t_minfo:
278     {
279         r->Data.MINFO.pNameMailbox = dns_dname_from_msg( msg, pos );
280         if (!r->Data.MINFO.pNameMailbox) return ERROR_NOT_ENOUGH_MEMORY;
281
282         if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
283             return DNS_ERROR_BAD_PACKET;
284
285         r->Data.MINFO.pNameErrorsMailbox = dns_dname_from_msg( msg, pos );
286         if (!r->Data.MINFO.pNameErrorsMailbox)
287         {
288             heap_free( r->Data.MINFO.pNameMailbox );
289             return ERROR_NOT_ENOUGH_MEMORY;
290         }
291
292         *dlen = sizeof(DNS_MINFO_DATAA);
293         break; 
294     }
295     case ns_t_afsdb:
296     case ns_t_rt:
297     case ns_t_mx:
298     {
299         r->Data.MX.wPreference = ntohs( *(const WORD *)pos );
300         r->Data.MX.pNameExchange = dns_dname_from_msg( msg, pos + sizeof(WORD) );
301         if (!r->Data.MX.pNameExchange) return ERROR_NOT_ENOUGH_MEMORY;
302
303         *dlen = sizeof(DNS_MX_DATAA);
304         break; 
305     }
306     case ns_t_null:
307     {
308         r->Data.Null.dwByteCount = rr->rdlength;
309         memcpy( r->Data.Null.Data, rr->rdata, rr->rdlength );
310
311         *dlen = sizeof(DNS_NULL_DATA) + rr->rdlength - 1;
312         break;
313     }
314     case ns_t_cname:
315     case ns_t_ns:
316     case ns_t_mb:
317     case ns_t_md:
318     case ns_t_mf:
319     case ns_t_mg:
320     case ns_t_mr:
321     case ns_t_ptr:
322     {
323         r->Data.PTR.pNameHost = dns_dname_from_msg( msg, pos );
324         if (!r->Data.PTR.pNameHost) return ERROR_NOT_ENOUGH_MEMORY;
325
326         *dlen = sizeof(DNS_PTR_DATAA);
327         break;
328     }
329     case ns_t_sig:
330     {
331         r->Data.SIG.pNameSigner = dns_dname_from_msg( msg, pos );
332         if (!r->Data.SIG.pNameSigner) return ERROR_NOT_ENOUGH_MEMORY;
333
334         if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
335             return DNS_ERROR_BAD_PACKET;
336
337         /* FIXME: byte order? */
338         r->Data.SIG.wTypeCovered  = *(const WORD *)pos;   pos += sizeof(WORD);
339         r->Data.SIG.chAlgorithm   = *pos++;
340         r->Data.SIG.chLabelCount  = *pos++;
341         r->Data.SIG.dwOriginalTtl = *(const DWORD *)pos;  pos += sizeof(DWORD);
342         r->Data.SIG.dwExpiration  = *(const DWORD *)pos;  pos += sizeof(DWORD);
343         r->Data.SIG.dwTimeSigned  = *(const DWORD *)pos;  pos += sizeof(DWORD);
344         r->Data.SIG.wKeyTag       = *(const WORD *)pos;
345
346         size = rr->rdata + rr->rdlength - pos;
347
348         for (i = 0; i < size; i++)
349             r->Data.SIG.Signature[i] = *pos++;
350
351         *dlen = sizeof(DNS_SIG_DATAA) + (size - 1) * sizeof(BYTE);
352         break; 
353     }
354     case ns_t_soa:
355     {
356         r->Data.SOA.pNamePrimaryServer = dns_dname_from_msg( msg, pos );
357         if (!r->Data.SOA.pNamePrimaryServer) return ERROR_NOT_ENOUGH_MEMORY;
358
359         if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
360             return DNS_ERROR_BAD_PACKET;
361
362         r->Data.SOA.pNameAdministrator = dns_dname_from_msg( msg, pos );
363         if (!r->Data.SOA.pNameAdministrator)
364         {
365             heap_free( r->Data.SOA.pNamePrimaryServer );
366             return ERROR_NOT_ENOUGH_MEMORY;
367         }
368
369         if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
370             return DNS_ERROR_BAD_PACKET;
371
372         r->Data.SOA.dwSerialNo   = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
373         r->Data.SOA.dwRefresh    = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
374         r->Data.SOA.dwRetry      = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
375         r->Data.SOA.dwExpire     = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
376         r->Data.SOA.dwDefaultTtl = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
377
378         *dlen = sizeof(DNS_SOA_DATAA);
379         break; 
380     }
381     case ns_t_srv:
382     {
383         r->Data.SRV.wPriority = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
384         r->Data.SRV.wWeight   = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
385         r->Data.SRV.wPort     = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
386
387         r->Data.SRV.pNameTarget = dns_dname_from_msg( msg, pos );
388         if (!r->Data.SRV.pNameTarget) return ERROR_NOT_ENOUGH_MEMORY;
389
390         *dlen = sizeof(DNS_SRV_DATAA);
391         break; 
392     }
393     case ns_t_hinfo:
394     case ns_t_isdn:
395     case ns_t_x25:
396     case ns_t_txt:
397     {
398         i = 0;
399         while (pos[0] && pos < rr->rdata + rr->rdlength)
400         {
401             r->Data.TXT.pStringArray[i] = dns_str_from_rdata( pos );
402             if (!r->Data.TXT.pStringArray[i])
403             {
404                 while (i > 0) heap_free( r->Data.TXT.pStringArray[--i] );
405                 return ERROR_NOT_ENOUGH_MEMORY;
406             }
407             i++;
408             pos += pos[0] + 1;
409         }
410         r->Data.TXT.dwStringCount = i;
411         *dlen = sizeof(DNS_TXT_DATAA) + (i - 1) * sizeof(PCHAR);
412         break;
413     }
414     case ns_t_atma:
415     case ns_t_loc:
416     case ns_t_nxt:
417     case ns_t_tsig:
418     case ns_t_wks:
419     case 0x00f9:  /* TKEY */
420     case 0xff01:  /* WINS */
421     case 0xff02:  /* WINSR */
422     default:
423         FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
424         return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
425     }
426
427     return ret;
428
429
430 static DNS_STATUS dns_copy_record( ns_msg msg, ns_sect section,
431                                    unsigned short num, DNS_RECORDA **recp )
432 {
433     DNS_STATUS ret;
434     DNS_RECORDA *record;
435     WORD dlen;
436     ns_rr rr;
437
438     if (dns_ns_parserr( &msg, section, num, &rr ) < 0)
439         return DNS_ERROR_BAD_PACKET;
440
441     if (!(record = heap_alloc_zero( dns_get_record_size( &rr ) )))
442         return ERROR_NOT_ENOUGH_MEMORY;
443
444     record->pName = dns_strdup_u( rr.name );
445     if (!record->pName)
446     {
447         heap_free( record );
448         return ERROR_NOT_ENOUGH_MEMORY;
449     }
450
451     record->wType = rr.type;
452     record->Flags.S.Section = section;
453     record->Flags.S.CharSet = DnsCharSetUtf8;
454     record->dwTtl = rr.ttl;
455
456     if ((ret = dns_copy_rdata( msg, &rr, record, &dlen )))
457     {
458         heap_free( record->pName );
459         heap_free( record );
460         return ret;
461     }
462     record->wDataLength = dlen;
463     *recp = record;
464
465     TRACE( "found %s record in %s section\n",
466            dns_type_to_str( rr.type ), dns_section_to_str( section ) );
467     return ERROR_SUCCESS;
468 }
469
470 #define DEFAULT_TTL  1200
471
472 static DNS_STATUS dns_do_query_netbios( PCSTR name, DNS_RECORDA **recp )
473 {
474     NCB ncb;
475     UCHAR ret;
476     DNS_RRSET rrset;
477     FIND_NAME_BUFFER *buffer;
478     FIND_NAME_HEADER *header;
479     DNS_RECORDA *record = NULL;
480     unsigned int i, len;
481     DNS_STATUS status = ERROR_INVALID_NAME;
482
483     len = strlen( name );
484     if (len >= NCBNAMSZ) return DNS_ERROR_RCODE_NAME_ERROR;
485
486     DNS_RRSET_INIT( rrset );
487
488     memset( &ncb, 0, sizeof(ncb) );
489     ncb.ncb_command = NCBFINDNAME;
490
491     memset( ncb.ncb_callname, ' ', sizeof(ncb.ncb_callname) );
492     memcpy( ncb.ncb_callname, name, len );
493     ncb.ncb_callname[NCBNAMSZ - 1] = '\0';
494
495     ret = Netbios( &ncb );
496     if (ret != NRC_GOODRET) return ERROR_INVALID_NAME;
497
498     header = (FIND_NAME_HEADER *)ncb.ncb_buffer;
499     buffer = (FIND_NAME_BUFFER *)((char *)header + sizeof(FIND_NAME_HEADER));
500
501     for (i = 0; i < header->node_count; i++) 
502     {
503         record = heap_alloc_zero( sizeof(DNS_RECORDA) );
504         if (!record)
505         {
506             status = ERROR_NOT_ENOUGH_MEMORY;
507             goto exit;
508         }
509         else
510         {
511             record->pName = dns_strdup_u( name );
512             if (!record->pName)
513             {
514                 status = ERROR_NOT_ENOUGH_MEMORY;
515                 goto exit;
516             }
517
518             record->wType = DNS_TYPE_A;
519             record->Flags.S.Section = DnsSectionAnswer;
520             record->Flags.S.CharSet = DnsCharSetUtf8;
521             record->dwTtl = DEFAULT_TTL;
522
523             /* FIXME: network byte order? */
524             record->Data.A.IpAddress = *(DWORD *)((char *)buffer[i].destination_addr + 2);
525
526             DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
527         }
528     }
529     status = ERROR_SUCCESS;
530
531 exit:
532     DNS_RRSET_TERMINATE( rrset );
533
534     if (status != ERROR_SUCCESS)
535         DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
536     else
537         *recp = (DNS_RECORDA *)rrset.pFirstRR;
538
539     return status;
540 }
541
542 /* res_init() must have been called before calling these three functions.
543  */
544 static DNS_STATUS dns_set_serverlist( const IP4_ARRAY *addrs )
545 {
546     int i;
547
548     if (addrs->AddrCount > MAXNS) 
549     {
550         WARN( "too many servers: %d only using the first: %d\n",
551               addrs->AddrCount, MAXNS );
552         _res.nscount = MAXNS;
553     }
554     else _res.nscount = addrs->AddrCount;
555
556     for (i = 0; i < _res.nscount; i++)
557         _res.nsaddr_list[i].sin_addr.s_addr = addrs->AddrArray[i];
558
559     return ERROR_SUCCESS;
560 }
561
562 static DNS_STATUS dns_get_serverlist( PIP4_ARRAY addrs, PDWORD len )
563 {
564     unsigned int size;
565     int i;
566
567     size = sizeof(IP4_ARRAY) + sizeof(IP4_ADDRESS) * (_res.nscount - 1);
568     if (!addrs || *len < size)
569     {
570         *len = size;
571         return ERROR_INSUFFICIENT_BUFFER;
572     }
573
574     addrs->AddrCount = _res.nscount;
575
576     for (i = 0; i < _res.nscount; i++)
577         addrs->AddrArray[i] = _res.nsaddr_list[i].sin_addr.s_addr;
578
579     return ERROR_SUCCESS;
580 }
581
582 static DNS_STATUS dns_do_query( PCSTR name, WORD type, DWORD options,
583                                 PDNS_RECORDA *result )
584 {
585     DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
586
587     unsigned int i, num;
588     unsigned char answer[NS_PACKETSZ];
589     ns_sect sections[] = { ns_s_an, ns_s_ar };
590     ns_msg msg;
591
592     DNS_RECORDA *record = NULL;
593     DNS_RRSET rrset;
594     int len;
595
596     DNS_RRSET_INIT( rrset );
597
598     len = res_query( name, ns_c_in, type, answer, sizeof(answer) );
599     if (len < 0)
600     {
601         ret = dns_map_h_errno( h_errno );
602         goto exit;
603     }
604
605     if (dns_ns_initparse( answer, len, &msg ) < 0)
606     {
607         ret = DNS_ERROR_BAD_PACKET;
608         goto exit;
609     }
610
611 #define RCODE_MASK 0x0f
612     if ((msg._flags & RCODE_MASK) != ns_r_noerror)
613     {
614         ret = dns_map_error( msg._flags & RCODE_MASK );
615         goto exit;
616     }
617
618     for (i = 0; i < sizeof(sections)/sizeof(sections[0]); i++)
619     {
620         for (num = 0; num < ns_msg_count( msg, sections[i] ); num++)
621         {
622             ret = dns_copy_record( msg, sections[i], num, &record );
623             if (ret != ERROR_SUCCESS) goto exit;
624
625             DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
626         }
627     }
628
629 exit:
630     DNS_RRSET_TERMINATE( rrset );
631
632     if (ret != ERROR_SUCCESS)
633         DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
634     else
635         *result = (DNS_RECORDA *)rrset.pFirstRR;
636
637     return ret;
638 }
639
640 #endif /* HAVE_RESOLV */
641
642 /******************************************************************************
643  * DnsQuery_A           [DNSAPI.@]
644  *
645  */
646 DNS_STATUS WINAPI DnsQuery_A( PCSTR name, WORD type, DWORD options, PVOID servers,
647                               PDNS_RECORDA *result, PVOID *reserved )
648 {
649     WCHAR *nameW;
650     DNS_RECORDW *resultW;
651     DNS_STATUS status;
652
653     TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
654            options, servers, result, reserved );
655
656     if (!name || !result)
657         return ERROR_INVALID_PARAMETER;
658
659     nameW = dns_strdup_aw( name );
660     if (!nameW) return ERROR_NOT_ENOUGH_MEMORY;
661
662     status = DnsQuery_W( nameW, type, options, servers, &resultW, reserved ); 
663
664     if (status == ERROR_SUCCESS)
665     {
666         *result = (DNS_RECORDA *)DnsRecordSetCopyEx(
667              (DNS_RECORD *)resultW, DnsCharSetUnicode, DnsCharSetAnsi );
668
669         if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
670         DnsRecordListFree( (DNS_RECORD *)resultW, DnsFreeRecordList );
671     }
672
673     heap_free( nameW );
674     return status;
675 }
676
677 /******************************************************************************
678  * DnsQuery_UTF8              [DNSAPI.@]
679  *
680  */
681 DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PVOID servers,
682                                  PDNS_RECORDA *result, PVOID *reserved )
683 {
684     DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
685 #ifdef HAVE_RESOLV
686
687     TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
688            options, servers, result, reserved );
689
690     if (!name || !result)
691         return ERROR_INVALID_PARAMETER;
692
693     initialise_resolver();
694     _res.options |= dns_map_options( options );
695
696     if (servers && (ret = dns_set_serverlist( servers )))
697         return ret;
698
699     ret = dns_do_query( name, type, options, result );
700
701     if (ret == DNS_ERROR_RCODE_NAME_ERROR && type == DNS_TYPE_A &&
702         !(options & DNS_QUERY_NO_NETBT))
703     {
704         TRACE( "dns lookup failed, trying netbios query\n" );
705         ret = dns_do_query_netbios( name, result );
706     }
707
708 #endif
709     return ret;
710 }
711
712 /******************************************************************************
713  * DnsQuery_W              [DNSAPI.@]
714  *
715  */
716 DNS_STATUS WINAPI DnsQuery_W( PCWSTR name, WORD type, DWORD options, PVOID servers,
717                               PDNS_RECORDW *result, PVOID *reserved )
718 {
719     char *nameU;
720     DNS_RECORDA *resultA;
721     DNS_STATUS status;
722
723     TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_w(name), dns_type_to_str( type ),
724            options, servers, result, reserved );
725
726     if (!name || !result)
727         return ERROR_INVALID_PARAMETER;
728
729     nameU = dns_strdup_wu( name );
730     if (!nameU) return ERROR_NOT_ENOUGH_MEMORY;
731
732     status = DnsQuery_UTF8( nameU, type, options, servers, &resultA, reserved ); 
733
734     if (status == ERROR_SUCCESS)
735     {
736         *result = (DNS_RECORDW *)DnsRecordSetCopyEx(
737             (DNS_RECORD *)resultA, DnsCharSetUtf8, DnsCharSetUnicode );
738
739         if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
740         DnsRecordListFree( (DNS_RECORD *)resultA, DnsFreeRecordList );
741     }
742
743     heap_free( nameU );
744     return status;
745 }
746
747 static DNS_STATUS dns_get_hostname_a( COMPUTER_NAME_FORMAT format,
748                                       PSTR buffer, PDWORD len )
749 {
750     char name[256];
751     DWORD size = sizeof(name)/sizeof(name[0]);
752
753     if (!GetComputerNameExA( format, name, &size ))
754         return DNS_ERROR_NAME_DOES_NOT_EXIST;
755
756     if (!buffer || (size = lstrlenA( name ) + 1) > *len)
757     {
758         *len = size;
759         return ERROR_INSUFFICIENT_BUFFER;
760     }
761
762     lstrcpyA( buffer, name );
763     return ERROR_SUCCESS;
764 }
765
766 static DNS_STATUS dns_get_hostname_w( COMPUTER_NAME_FORMAT format,
767                                       PWSTR buffer, PDWORD len )
768 {
769     WCHAR name[256];
770     DWORD size = sizeof(name)/sizeof(name[0]);
771
772     if (!GetComputerNameExW( format, name, &size ))
773         return DNS_ERROR_NAME_DOES_NOT_EXIST;
774
775     if (!buffer || (size = lstrlenW( name ) + 1) > *len)
776     {
777         *len = size;
778         return ERROR_INSUFFICIENT_BUFFER;
779     }
780
781     lstrcpyW( buffer, name );
782     return ERROR_SUCCESS;
783 }
784
785 /******************************************************************************
786  * DnsQueryConfig          [DNSAPI.@]
787  *
788  */
789 DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PCWSTR adapter,
790                                   PVOID reserved, PVOID buffer, PDWORD len )
791 {
792     DNS_STATUS ret = ERROR_INVALID_PARAMETER;
793
794     TRACE( "(%d,0x%08x,%s,%p,%p,%p)\n", config, flag, debugstr_w(adapter),
795            reserved, buffer, len );
796
797     if (!len) return ERROR_INVALID_PARAMETER;
798
799     switch (config)
800     {
801     case DnsConfigDnsServerList:
802     {
803 #ifdef HAVE_RESOLV
804         initialise_resolver();
805         ret = dns_get_serverlist( buffer, len );
806         break;
807 #else
808         WARN( "compiled without resolver support\n" );
809         break;
810 #endif
811     }
812     case DnsConfigHostName_A:
813     case DnsConfigHostName_UTF8:
814         return dns_get_hostname_a( ComputerNameDnsHostname, buffer, len );
815
816     case DnsConfigFullHostName_A:
817     case DnsConfigFullHostName_UTF8:
818         return dns_get_hostname_a( ComputerNameDnsFullyQualified, buffer, len );
819
820     case DnsConfigPrimaryDomainName_A:
821     case DnsConfigPrimaryDomainName_UTF8:
822         return dns_get_hostname_a( ComputerNameDnsDomain, buffer, len );
823
824     case DnsConfigHostName_W:
825         return dns_get_hostname_w( ComputerNameDnsHostname, buffer, len );
826
827     case DnsConfigFullHostName_W:
828         return dns_get_hostname_w( ComputerNameDnsFullyQualified, buffer, len );
829
830     case DnsConfigPrimaryDomainName_W:
831         return dns_get_hostname_w( ComputerNameDnsDomain, buffer, len );
832
833     case DnsConfigAdapterDomainName_A:
834     case DnsConfigAdapterDomainName_W:
835     case DnsConfigAdapterDomainName_UTF8:
836     case DnsConfigSearchList:
837     case DnsConfigAdapterInfo:
838     case DnsConfigPrimaryHostNameRegistrationEnabled:
839     case DnsConfigAdapterHostNameRegistrationEnabled:
840     case DnsConfigAddressRegistrationMaxCount:
841         FIXME( "unimplemented config type %d\n", config );
842         break;
843
844     default:
845         WARN( "unknown config type: %d\n", config );
846         break;
847     }
848     return ret;
849 }