ws2_32: Return the right value for SO_CONNECT_TIME if the socket is not connected.
[wine] / dlls / dnsapi / record.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
39 #include "windef.h"
40 #include "winbase.h"
41 #include "winnls.h"
42 #include "windns.h"
43
44 #include "dnsapi.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
47
48 const char *dns_type_to_str( unsigned short type )
49 {
50     switch (type)
51     {
52 #define X(x)    case (x): return #x;
53     X(DNS_TYPE_ZERO)
54     X(DNS_TYPE_A)
55     X(DNS_TYPE_NS)
56     X(DNS_TYPE_MD)
57     X(DNS_TYPE_MF)
58     X(DNS_TYPE_CNAME)
59     X(DNS_TYPE_SOA)
60     X(DNS_TYPE_MB)
61     X(DNS_TYPE_MG)
62     X(DNS_TYPE_MR)
63     X(DNS_TYPE_NULL)
64     X(DNS_TYPE_WKS)
65     X(DNS_TYPE_PTR)
66     X(DNS_TYPE_HINFO)
67     X(DNS_TYPE_MINFO)
68     X(DNS_TYPE_MX)
69     X(DNS_TYPE_TEXT)
70     X(DNS_TYPE_RP)
71     X(DNS_TYPE_AFSDB)
72     X(DNS_TYPE_X25)
73     X(DNS_TYPE_ISDN)
74     X(DNS_TYPE_RT)
75     X(DNS_TYPE_NSAP)
76     X(DNS_TYPE_NSAPPTR)
77     X(DNS_TYPE_SIG)
78     X(DNS_TYPE_KEY)
79     X(DNS_TYPE_PX)
80     X(DNS_TYPE_GPOS)
81     X(DNS_TYPE_AAAA)
82     X(DNS_TYPE_LOC)
83     X(DNS_TYPE_NXT)
84     X(DNS_TYPE_EID)
85     X(DNS_TYPE_NIMLOC)
86     X(DNS_TYPE_SRV)
87     X(DNS_TYPE_ATMA)
88     X(DNS_TYPE_NAPTR)
89     X(DNS_TYPE_KX)
90     X(DNS_TYPE_CERT)
91     X(DNS_TYPE_A6)
92     X(DNS_TYPE_DNAME)
93     X(DNS_TYPE_SINK)
94     X(DNS_TYPE_OPT)
95     X(DNS_TYPE_UINFO)
96     X(DNS_TYPE_UID)
97     X(DNS_TYPE_GID)
98     X(DNS_TYPE_UNSPEC)
99     X(DNS_TYPE_ADDRS)
100     X(DNS_TYPE_TKEY)
101     X(DNS_TYPE_TSIG)
102     X(DNS_TYPE_IXFR)
103     X(DNS_TYPE_AXFR)
104     X(DNS_TYPE_MAILB)
105     X(DNS_TYPE_MAILA)
106     X(DNS_TYPE_ANY)
107     X(DNS_TYPE_WINS)
108     X(DNS_TYPE_WINSR)
109 #undef X
110     default: { static char tmp[7]; sprintf( tmp, "0x%04x", type ); return tmp; }
111     }
112 }
113
114 static int dns_strcmpX( LPCVOID str1, LPCVOID str2, BOOL wide )
115 {
116     if (wide)
117         return lstrcmpiW( str1, str2 );
118     else
119         return lstrcmpiA( str1, str2 );
120 }
121
122 /******************************************************************************
123  * DnsRecordCompare                        [DNSAPI.@]
124  *
125  */
126 BOOL WINAPI DnsRecordCompare( PDNS_RECORD r1, PDNS_RECORD r2 )
127 {
128     BOOL wide;
129     unsigned int i;
130
131     TRACE( "(%p,%p)\n", r1, r2 );
132
133     if (r1->wType       != r2->wType       ||
134         r1->wDataLength != r2->wDataLength ||
135         r1->Flags.DW    != r2->Flags.DW    ||
136         r1->dwReserved  != r2->dwReserved) return FALSE;
137
138     wide = (r1->Flags.S.CharSet == DnsCharSetUnicode) ? TRUE : FALSE;
139     if (dns_strcmpX( r1->pName, r2->pName, wide )) return FALSE;
140
141     switch (r1->wType)
142     {
143     case DNS_TYPE_A:
144     {
145         if (r1->Data.A.IpAddress != r2->Data.A.IpAddress) return FALSE;
146         break;
147     }
148     case DNS_TYPE_SOA:
149     {
150         if (r1->Data.SOA.dwSerialNo   != r2->Data.SOA.dwSerialNo ||
151             r1->Data.SOA.dwRefresh    != r2->Data.SOA.dwRefresh  ||
152             r1->Data.SOA.dwRetry      != r2->Data.SOA.dwRetry    ||
153             r1->Data.SOA.dwExpire     != r2->Data.SOA.dwExpire   ||
154             r1->Data.SOA.dwDefaultTtl != r2->Data.SOA.dwDefaultTtl)
155             return FALSE;
156         if (dns_strcmpX( r1->Data.SOA.pNamePrimaryServer,
157                          r2->Data.SOA.pNamePrimaryServer, wide ) ||
158             dns_strcmpX( r1->Data.SOA.pNameAdministrator,
159                          r2->Data.SOA.pNameAdministrator, wide ))
160             return FALSE;
161         break;
162     }
163     case DNS_TYPE_PTR:
164     case DNS_TYPE_NS:
165     case DNS_TYPE_CNAME:
166     case DNS_TYPE_MB:
167     case DNS_TYPE_MD:
168     case DNS_TYPE_MF:
169     case DNS_TYPE_MG:
170     case DNS_TYPE_MR:
171     {
172         if (dns_strcmpX( r1->Data.PTR.pNameHost,
173                          r2->Data.PTR.pNameHost, wide )) return FALSE;
174         break;
175     }
176     case DNS_TYPE_MINFO:
177     case DNS_TYPE_RP:
178     {
179         if (dns_strcmpX( r1->Data.MINFO.pNameMailbox,
180                          r2->Data.MINFO.pNameMailbox, wide ) ||
181             dns_strcmpX( r1->Data.MINFO.pNameErrorsMailbox,
182                          r2->Data.MINFO.pNameErrorsMailbox, wide ))
183             return FALSE;
184         break;
185     }
186     case DNS_TYPE_MX:
187     case DNS_TYPE_AFSDB:
188     case DNS_TYPE_RT:
189     {
190         if (r1->Data.MX.wPreference != r2->Data.MX.wPreference)
191             return FALSE;
192         if (dns_strcmpX( r1->Data.MX.pNameExchange,
193                          r2->Data.MX.pNameExchange, wide ))
194             return FALSE;
195         break;
196     }
197     case DNS_TYPE_HINFO:
198     case DNS_TYPE_ISDN:
199     case DNS_TYPE_TEXT:
200     case DNS_TYPE_X25:
201     {
202         if (r1->Data.TXT.dwStringCount != r2->Data.TXT.dwStringCount)
203             return FALSE;
204         for (i = 0; i < r1->Data.TXT.dwStringCount; i++)
205         {
206             if (dns_strcmpX( r1->Data.TXT.pStringArray[i],
207                              r2->Data.TXT.pStringArray[i], wide ))
208                 return FALSE;
209         }
210         break;
211     }
212     case DNS_TYPE_NULL:
213     {
214         if (r1->Data.Null.dwByteCount != r2->Data.Null.dwByteCount)
215             return FALSE;
216         if (memcmp( r1->Data.Null.Data,
217                     r2->Data.Null.Data, r1->Data.Null.dwByteCount ))
218             return FALSE;
219         break;
220     }
221     case DNS_TYPE_AAAA:
222     {
223         for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
224         {
225             if (r1->Data.AAAA.Ip6Address.IP6Dword[i] !=
226                 r2->Data.AAAA.Ip6Address.IP6Dword[i]) return FALSE;
227         }
228         break;
229     }
230     case DNS_TYPE_KEY:
231     {
232         if (r1->Data.KEY.wFlags      != r2->Data.KEY.wFlags      ||
233             r1->Data.KEY.chProtocol  != r2->Data.KEY.chProtocol  ||
234             r1->Data.KEY.chAlgorithm != r2->Data.KEY.chAlgorithm)
235             return FALSE;
236         if (memcmp( r1->Data.KEY.Key, r2->Data.KEY.Key,
237                     r1->wDataLength - sizeof(DNS_KEY_DATA) + 1 ))
238             return FALSE;
239         break;
240     }
241     case DNS_TYPE_SIG:
242     {
243         if (dns_strcmpX( r1->Data.SIG.pNameSigner,
244                          r2->Data.SIG.pNameSigner, wide ))
245             return FALSE;
246         if (r1->Data.SIG.wTypeCovered  != r2->Data.SIG.wTypeCovered  ||
247             r1->Data.SIG.chAlgorithm   != r2->Data.SIG.chAlgorithm   ||
248             r1->Data.SIG.chLabelCount  != r2->Data.SIG.chLabelCount  ||
249             r1->Data.SIG.dwOriginalTtl != r2->Data.SIG.dwOriginalTtl ||
250             r1->Data.SIG.dwExpiration  != r2->Data.SIG.dwExpiration  ||
251             r1->Data.SIG.dwTimeSigned  != r2->Data.SIG.dwTimeSigned  ||
252             r1->Data.SIG.wKeyTag       != r2->Data.SIG.wKeyTag)
253             return FALSE;
254         if (memcmp( r1->Data.SIG.Signature, r2->Data.SIG.Signature,
255                     r1->wDataLength - sizeof(DNS_SIG_DATAA) + 1 ))
256             return FALSE;
257         break;
258     }
259     case DNS_TYPE_ATMA:
260     {
261         if (r1->Data.ATMA.AddressType != r2->Data.ATMA.AddressType)
262             return FALSE;
263         for (i = 0; i < DNS_ATMA_MAX_ADDR_LENGTH; i++)
264         {
265             if (r1->Data.ATMA.Address[i] != r2->Data.ATMA.Address[i])
266                 return FALSE;
267         }
268         break;
269     }
270     case DNS_TYPE_NXT:
271     {
272         if (dns_strcmpX( r1->Data.NXT.pNameNext,
273                          r2->Data.NXT.pNameNext, wide )) return FALSE;
274         if (r1->Data.NXT.wNumTypes != r2->Data.NXT.wNumTypes) return FALSE;
275         if (memcmp( r1->Data.NXT.wTypes, r2->Data.NXT.wTypes,
276                     r1->wDataLength - sizeof(DNS_NXT_DATAA) + sizeof(WORD) ))
277             return FALSE;
278         break;
279     }
280     case DNS_TYPE_SRV:
281     {
282         if (dns_strcmpX( r1->Data.SRV.pNameTarget,
283                          r2->Data.SRV.pNameTarget, wide )) return FALSE;
284         if (r1->Data.SRV.wPriority != r2->Data.SRV.wPriority ||
285             r1->Data.SRV.wWeight   != r2->Data.SRV.wWeight   ||
286             r1->Data.SRV.wPort     != r2->Data.SRV.wPort)
287             return FALSE;
288         break;
289     }
290     case DNS_TYPE_TKEY:
291     {
292         if (dns_strcmpX( r1->Data.TKEY.pNameAlgorithm,
293                          r2->Data.TKEY.pNameAlgorithm, wide ))
294             return FALSE;
295         if (r1->Data.TKEY.dwCreateTime    != r2->Data.TKEY.dwCreateTime     ||
296             r1->Data.TKEY.dwExpireTime    != r2->Data.TKEY.dwExpireTime     ||
297             r1->Data.TKEY.wMode           != r2->Data.TKEY.wMode            ||
298             r1->Data.TKEY.wError          != r2->Data.TKEY.wError           ||
299             r1->Data.TKEY.wKeyLength      != r2->Data.TKEY.wKeyLength       ||
300             r1->Data.TKEY.wOtherLength    != r2->Data.TKEY.wOtherLength     ||
301             r1->Data.TKEY.cAlgNameLength  != r2->Data.TKEY.cAlgNameLength   ||
302             r1->Data.TKEY.bPacketPointers != r2->Data.TKEY.bPacketPointers)
303             return FALSE;
304
305         /* FIXME: ignoring pAlgorithmPacket field */
306         if (memcmp( r1->Data.TKEY.pKey, r2->Data.TKEY.pKey,
307                     r1->Data.TKEY.wKeyLength ) ||
308             memcmp( r1->Data.TKEY.pOtherData, r2->Data.TKEY.pOtherData,
309                     r1->Data.TKEY.wOtherLength )) return FALSE;
310         break;
311     }
312     case DNS_TYPE_TSIG:
313     {
314         if (dns_strcmpX( r1->Data.TSIG.pNameAlgorithm,
315                          r2->Data.TSIG.pNameAlgorithm, wide ))
316             return FALSE;
317         if (r1->Data.TSIG.i64CreateTime   != r2->Data.TSIG.i64CreateTime    ||
318             r1->Data.TSIG.wFudgeTime      != r2->Data.TSIG.wFudgeTime       ||
319             r1->Data.TSIG.wOriginalXid    != r2->Data.TSIG.wOriginalXid     ||
320             r1->Data.TSIG.wError          != r2->Data.TSIG.wError           ||
321             r1->Data.TSIG.wSigLength      != r2->Data.TSIG.wSigLength       ||
322             r1->Data.TSIG.wOtherLength    != r2->Data.TSIG.wOtherLength     ||
323             r1->Data.TSIG.cAlgNameLength  != r2->Data.TSIG.cAlgNameLength   ||
324             r1->Data.TSIG.bPacketPointers != r2->Data.TSIG.bPacketPointers)
325             return FALSE;
326
327         /* FIXME: ignoring pAlgorithmPacket field */
328         if (memcmp( r1->Data.TSIG.pSignature, r2->Data.TSIG.pSignature,
329                     r1->Data.TSIG.wSigLength ) ||
330             memcmp( r1->Data.TSIG.pOtherData, r2->Data.TSIG.pOtherData,
331                     r1->Data.TSIG.wOtherLength )) return FALSE;
332         break;
333     }
334     case DNS_TYPE_WINS:
335     {
336         if (r1->Data.WINS.dwMappingFlag    != r2->Data.WINS.dwMappingFlag   ||
337             r1->Data.WINS.dwLookupTimeout  != r2->Data.WINS.dwLookupTimeout ||
338             r1->Data.WINS.dwCacheTimeout   != r2->Data.WINS.dwCacheTimeout  ||
339             r1->Data.WINS.cWinsServerCount != r2->Data.WINS.cWinsServerCount)
340             return FALSE;
341         if (memcmp( r1->Data.WINS.WinsServers, r2->Data.WINS.WinsServers,
342                     r1->wDataLength - sizeof(DNS_WINS_DATA) + sizeof(IP4_ADDRESS) ))
343             return FALSE;
344         break;
345     }
346     case DNS_TYPE_WINSR:
347     {
348         if (r1->Data.WINSR.dwMappingFlag   != r2->Data.WINSR.dwMappingFlag   ||
349             r1->Data.WINSR.dwLookupTimeout != r2->Data.WINSR.dwLookupTimeout ||
350             r1->Data.WINSR.dwCacheTimeout  != r2->Data.WINSR.dwCacheTimeout)
351             return FALSE;
352         if (dns_strcmpX( r1->Data.WINSR.pNameResultDomain,
353                          r2->Data.WINSR.pNameResultDomain, wide ))
354             return FALSE;
355         break;
356     }
357     default:
358         FIXME( "unknown type: %s\n", dns_type_to_str( r1->wType ) );
359         return FALSE;
360     }
361     return TRUE;
362 }
363
364 static LPVOID dns_strcpyX( LPCVOID src, DNS_CHARSET in, DNS_CHARSET out )
365 {
366     switch (in)
367     {
368     case DnsCharSetUnicode:
369     {
370         switch (out)
371         {
372         case DnsCharSetUnicode: return dns_strdup_w( src );
373         case DnsCharSetUtf8:    return dns_strdup_wu( src );
374         case DnsCharSetAnsi:    return dns_strdup_wa( src );
375         default:
376             WARN( "unhandled target charset: %d\n", out );
377             break;
378         }
379         break;
380     }
381     case DnsCharSetUtf8:
382         switch (out)
383         {
384         case DnsCharSetUnicode: return dns_strdup_uw( src );
385         case DnsCharSetUtf8:    return dns_strdup_u( src );
386         case DnsCharSetAnsi:    return dns_strdup_ua( src );
387         default:
388             WARN( "unhandled target charset: %d\n", out );
389             break;
390         }
391         break;
392     case DnsCharSetAnsi:
393         switch (out)
394         {
395         case DnsCharSetUnicode: return dns_strdup_aw( src );
396         case DnsCharSetUtf8:    return dns_strdup_au( src );
397         case DnsCharSetAnsi:    return dns_strdup_a( src );
398         default:
399             WARN( "unhandled target charset: %d\n", out );
400             break;
401         }
402         break;
403     default:
404         WARN( "unhandled source charset: %d\n", in );
405         break;
406     }
407     return NULL;
408 }
409
410 /******************************************************************************
411  * DnsRecordCopyEx                         [DNSAPI.@]
412  *
413  */
414 PDNS_RECORD WINAPI DnsRecordCopyEx( PDNS_RECORD src, DNS_CHARSET in, DNS_CHARSET out )
415 {
416     DNS_RECORD *dst;
417     unsigned int i, size;
418
419     TRACE( "(%p,%d,%d)\n", src, in, out );
420
421     size = FIELD_OFFSET(DNS_RECORD, Data) + src->wDataLength;
422     dst = heap_alloc_zero( size );
423     if (!dst) return NULL;
424
425     memcpy( dst, src, size );
426
427     if (src->Flags.S.CharSet == DnsCharSetUtf8 ||
428         src->Flags.S.CharSet == DnsCharSetAnsi ||
429         src->Flags.S.CharSet == DnsCharSetUnicode) in = src->Flags.S.CharSet;
430
431     dst->Flags.S.CharSet = out;
432     dst->pName = dns_strcpyX( src->pName, in, out );
433     if (!dst->pName) goto error;
434
435     switch (src->wType)
436     {
437     case DNS_TYPE_HINFO:
438     case DNS_TYPE_ISDN:
439     case DNS_TYPE_TEXT:
440     case DNS_TYPE_X25:
441     {
442         for (i = 0; i < src->Data.TXT.dwStringCount; i++)
443         {
444             dst->Data.TXT.pStringArray[i] =
445                 dns_strcpyX( src->Data.TXT.pStringArray[i], in, out );
446
447             if (!dst->Data.TXT.pStringArray[i])
448             {
449                 while (i > 0) heap_free( dst->Data.TXT.pStringArray[--i] );
450                 goto error;
451             }
452         }
453         break;
454     }
455     case DNS_TYPE_MINFO:
456     case DNS_TYPE_RP:
457     {
458         dst->Data.MINFO.pNameMailbox =
459             dns_strcpyX( src->Data.MINFO.pNameMailbox, in, out );
460         if (!dst->Data.MINFO.pNameMailbox) goto error;
461
462         dst->Data.MINFO.pNameErrorsMailbox =
463             dns_strcpyX( src->Data.MINFO.pNameErrorsMailbox, in, out );
464         if (!dst->Data.MINFO.pNameErrorsMailbox)
465         {
466             heap_free( dst->Data.MINFO.pNameMailbox );
467             goto error;
468         }
469         break;
470     }
471     case DNS_TYPE_AFSDB:
472     case DNS_TYPE_RT:
473     case DNS_TYPE_MX:
474     {
475         dst->Data.MX.pNameExchange =
476             dns_strcpyX( src->Data.MX.pNameExchange, in, out );
477         if (!dst->Data.MX.pNameExchange) goto error;
478         break;
479     }
480     case DNS_TYPE_NXT:
481     {
482         dst->Data.NXT.pNameNext =
483             dns_strcpyX( src->Data.NXT.pNameNext, in, out );
484         if (!dst->Data.NXT.pNameNext) goto error;
485         break;
486     }
487     case DNS_TYPE_CNAME:
488     case DNS_TYPE_MB:
489     case DNS_TYPE_MD:
490     case DNS_TYPE_MF:
491     case DNS_TYPE_MG:
492     case DNS_TYPE_MR:
493     case DNS_TYPE_NS:
494     case DNS_TYPE_PTR:
495     {
496         dst->Data.PTR.pNameHost =
497             dns_strcpyX( src->Data.PTR.pNameHost, in, out );
498         if (!dst->Data.PTR.pNameHost) goto error;
499         break;
500     }
501     case DNS_TYPE_SIG:
502     {
503         dst->Data.SIG.pNameSigner =
504             dns_strcpyX( src->Data.SIG.pNameSigner, in, out );
505         if (!dst->Data.SIG.pNameSigner) goto error;
506         break;
507     }
508     case DNS_TYPE_SOA:
509     {
510         dst->Data.SOA.pNamePrimaryServer =
511             dns_strcpyX( src->Data.SOA.pNamePrimaryServer, in, out );
512         if (!dst->Data.SOA.pNamePrimaryServer) goto error;
513
514         dst->Data.SOA.pNameAdministrator =
515             dns_strcpyX( src->Data.SOA.pNameAdministrator, in, out );
516         if (!dst->Data.SOA.pNameAdministrator)
517         {
518             heap_free( dst->Data.SOA.pNamePrimaryServer );
519             goto error;
520         }
521         break;
522     }
523     case DNS_TYPE_SRV:
524     {
525         dst->Data.SRV.pNameTarget =
526             dns_strcpyX( src->Data.SRV.pNameTarget, in, out );
527         if (!dst->Data.SRV.pNameTarget) goto error;
528         break;
529     }
530     default:
531         break;
532     }
533     return dst;
534
535 error:
536     heap_free( dst->pName );
537     heap_free( dst );
538     return NULL;
539 }
540
541 /******************************************************************************
542  * DnsRecordListFree                       [DNSAPI.@]
543  *
544  */
545 VOID WINAPI DnsRecordListFree( PDNS_RECORD list, DNS_FREE_TYPE type )
546 {
547     DNS_RECORD *r, *next;
548     unsigned int i;
549
550     TRACE( "(%p,%d)\n", list, type );
551
552     if (!list) return;
553
554     switch (type)
555     {
556     case DnsFreeRecordList:
557     {
558         for (r = list; (list = r); r = next)
559         {
560             heap_free( r->pName );
561
562             switch (r->wType)
563             {
564             case DNS_TYPE_HINFO:
565             case DNS_TYPE_ISDN:
566             case DNS_TYPE_TEXT:
567             case DNS_TYPE_X25:
568             {
569                 for (i = 0; i < r->Data.TXT.dwStringCount; i++)
570                     heap_free( r->Data.TXT.pStringArray[i] );
571
572                 break;
573             }
574             case DNS_TYPE_MINFO:
575             case DNS_TYPE_RP:
576             {
577                 heap_free( r->Data.MINFO.pNameMailbox );
578                 heap_free( r->Data.MINFO.pNameErrorsMailbox );
579                 break;
580             }
581             case DNS_TYPE_AFSDB:
582             case DNS_TYPE_RT:
583             case DNS_TYPE_MX:
584             {
585                 heap_free( r->Data.MX.pNameExchange );
586                 break;
587             }
588             case DNS_TYPE_NXT:
589             {
590                 heap_free( r->Data.NXT.pNameNext );
591                 break;
592             }
593             case DNS_TYPE_CNAME:
594             case DNS_TYPE_MB:
595             case DNS_TYPE_MD:
596             case DNS_TYPE_MF:
597             case DNS_TYPE_MG:
598             case DNS_TYPE_MR:
599             case DNS_TYPE_NS:
600             case DNS_TYPE_PTR:
601             {
602                 heap_free( r->Data.PTR.pNameHost );
603                 break;
604             }
605             case DNS_TYPE_SIG:
606             {
607                 heap_free( r->Data.SIG.pNameSigner );
608                 break;
609             }
610             case DNS_TYPE_SOA:
611             {
612                 heap_free( r->Data.SOA.pNamePrimaryServer );
613                 heap_free( r->Data.SOA.pNameAdministrator );
614                 break;
615             }
616             case DNS_TYPE_SRV:
617             {
618                 heap_free( r->Data.SRV.pNameTarget );
619                 break;
620             }
621             default:
622                 break;
623             }
624
625             next = r->pNext;
626             heap_free( r );
627         }
628         break;
629     }
630     case DnsFreeFlat:
631     case DnsFreeParsedMessageFields:
632     {
633         FIXME( "unhandled free type: %d\n", type );
634         break;
635     }
636     default:
637         WARN( "unknown free type: %d\n", type );
638         break;
639     }
640 }
641
642 /******************************************************************************
643  * DnsFree                     [DNSAPI.@]
644  *
645  */
646 void WINAPI DnsFree( PVOID data, DNS_FREE_TYPE type )
647 {
648     DnsRecordListFree( data, type );
649 }
650
651 /******************************************************************************
652  * DnsRecordSetCompare                     [DNSAPI.@]
653  *
654  */
655 BOOL WINAPI DnsRecordSetCompare( PDNS_RECORD set1, PDNS_RECORD set2,
656                                  PDNS_RECORD *diff1, PDNS_RECORD *diff2 )
657 {
658     BOOL ret = TRUE;
659     DNS_RECORD *r, *t, *u;
660     DNS_RRSET rr1, rr2;
661
662     TRACE( "(%p,%p,%p,%p)\n", set1, set2, diff1, diff2 );
663
664     if (!set1 && !set2) return FALSE;
665
666     if (diff1) *diff1 = NULL;
667     if (diff2) *diff2 = NULL;
668
669     if (set1 && !set2)
670     {
671         if (diff1) *diff1 = DnsRecordSetCopyEx( set1, 0, set1->Flags.S.CharSet );
672         return FALSE;
673     }
674     if (!set1 && set2)
675     {
676         if (diff2) *diff2 = DnsRecordSetCopyEx( set2, 0, set2->Flags.S.CharSet );
677         return FALSE;
678     }
679
680     DNS_RRSET_INIT( rr1 );
681     DNS_RRSET_INIT( rr2 );
682
683     for (r = set1; r; r = r->pNext)
684     {
685         for (t = set2; t; t = t->pNext)
686         {
687             u = DnsRecordCopyEx( r, r->Flags.S.CharSet, t->Flags.S.CharSet );
688             if (!u) goto error;
689
690             if (!DnsRecordCompare( t, u ))
691             {
692                 DNS_RRSET_ADD( rr1, u );
693                 ret = FALSE;
694             }
695             else DnsRecordListFree( u, DnsFreeRecordList );
696         }
697     }
698
699     for (t = set2; t; t = t->pNext)
700     {
701         for (r = set1; r; r = r->pNext)
702         {
703             u = DnsRecordCopyEx( t, t->Flags.S.CharSet, r->Flags.S.CharSet );
704             if (!u) goto error;
705
706             if (!DnsRecordCompare( r, u ))
707             {
708                 DNS_RRSET_ADD( rr2, u );
709                 ret = FALSE;
710             }
711             else DnsRecordListFree( u, DnsFreeRecordList );
712         }
713     }
714
715     DNS_RRSET_TERMINATE( rr1 );
716     DNS_RRSET_TERMINATE( rr2 );
717     
718     if (diff1) *diff1 = rr1.pFirstRR;
719     else DnsRecordListFree( rr1.pFirstRR, DnsFreeRecordList );
720
721     if (diff2) *diff2 = rr2.pFirstRR;
722     else DnsRecordListFree( rr2.pFirstRR, DnsFreeRecordList );
723
724     return ret;
725
726 error:
727     DNS_RRSET_TERMINATE( rr1 );
728     DNS_RRSET_TERMINATE( rr2 );
729
730     DnsRecordListFree( rr1.pFirstRR, DnsFreeRecordList );
731     DnsRecordListFree( rr2.pFirstRR, DnsFreeRecordList );
732     
733     return FALSE;
734 }
735
736 /******************************************************************************
737  * DnsRecordSetCopyEx                      [DNSAPI.@]
738  *
739  */
740 PDNS_RECORD WINAPI DnsRecordSetCopyEx( PDNS_RECORD src_set, DNS_CHARSET in, DNS_CHARSET out )
741 {
742     DNS_RRSET dst_set;
743     DNS_RECORD *src, *dst;
744
745     TRACE( "(%p,%d,%d)\n", src_set, in, out );
746
747     DNS_RRSET_INIT( dst_set );
748
749     for (src = src_set; (src_set = src); src = src_set->pNext)
750     {
751         dst = DnsRecordCopyEx( src, in, out );
752         if (!dst)
753         {
754             DNS_RRSET_TERMINATE( dst_set );
755             DnsRecordListFree( dst_set.pFirstRR, DnsFreeRecordList );
756             return NULL;
757         }
758         DNS_RRSET_ADD( dst_set, dst );
759     }
760
761     DNS_RRSET_TERMINATE( dst_set );
762     return dst_set.pFirstRR;
763 }
764
765 /******************************************************************************
766  * DnsRecordSetDetach                      [DNSAPI.@]
767  *
768  */
769 PDNS_RECORD WINAPI DnsRecordSetDetach( PDNS_RECORD set )
770 {
771     DNS_RECORD *r, *s;
772
773     TRACE( "(%p)\n", set );
774
775     for (r = set; (set = r); r = set->pNext)
776     {
777         if (r->pNext && !r->pNext->pNext)
778         {
779             s = r->pNext;
780             r->pNext = NULL;
781             return s;
782         }
783     }
784     return NULL;
785 }