richedit: Avoid strlen in traces.
[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     }
380     case DnsCharSetUtf8:
381         switch (out)
382         {
383         case DnsCharSetUnicode: return dns_strdup_uw( src );
384         case DnsCharSetUtf8:    return dns_strdup_u( src );
385         case DnsCharSetAnsi:    return dns_strdup_ua( src );
386         default:
387             WARN( "unhandled target charset: %d\n", out );
388             break;
389         }
390     case DnsCharSetAnsi:
391         switch (out)
392         {
393         case DnsCharSetUnicode: return dns_strdup_aw( src );
394         case DnsCharSetUtf8:    return dns_strdup_au( src );
395         case DnsCharSetAnsi:    return dns_strdup_a( src );
396         default:
397             WARN( "unhandled target charset: %d\n", out );
398             break;
399         }
400     default:
401         WARN( "unhandled source charset: %d\n", in );
402         break;
403     }
404     return NULL;
405 }
406
407 /******************************************************************************
408  * DnsRecordCopyEx                         [DNSAPI.@]
409  *
410  */
411 PDNS_RECORD WINAPI DnsRecordCopyEx( PDNS_RECORD src, DNS_CHARSET in, DNS_CHARSET out )
412 {
413     DNS_RECORD *dst;
414     unsigned int i, size;
415
416     TRACE( "(%p,%d,%d)\n", src, in, out );
417
418     size = FIELD_OFFSET(DNS_RECORD, Data) + src->wDataLength;
419     dst = heap_alloc_zero( size );
420     if (!dst) return NULL;
421
422     memcpy( dst, src, size );
423
424     if (src->Flags.S.CharSet == DnsCharSetUtf8 ||
425         src->Flags.S.CharSet == DnsCharSetAnsi ||
426         src->Flags.S.CharSet == DnsCharSetUnicode) in = src->Flags.S.CharSet;
427
428     dst->Flags.S.CharSet = out;
429     dst->pName = dns_strcpyX( src->pName, in, out );
430     if (!dst->pName) goto error;
431
432     switch (src->wType)
433     {
434     case DNS_TYPE_HINFO:
435     case DNS_TYPE_ISDN:
436     case DNS_TYPE_TEXT:
437     case DNS_TYPE_X25:
438     {
439         for (i = 0; i < src->Data.TXT.dwStringCount; i++)
440         {
441             dst->Data.TXT.pStringArray[i] =
442                 dns_strcpyX( src->Data.TXT.pStringArray[i], in, out );
443
444             if (!dst->Data.TXT.pStringArray[i])
445             {
446                 while (i > 0) heap_free( dst->Data.TXT.pStringArray[--i] );
447                 goto error;
448             }
449         }
450         break;
451     }
452     case DNS_TYPE_MINFO:
453     case DNS_TYPE_RP:
454     {
455         dst->Data.MINFO.pNameMailbox =
456             dns_strcpyX( src->Data.MINFO.pNameMailbox, in, out );
457         if (!dst->Data.MINFO.pNameMailbox) goto error;
458
459         dst->Data.MINFO.pNameErrorsMailbox =
460             dns_strcpyX( src->Data.MINFO.pNameErrorsMailbox, in, out );
461         if (!dst->Data.MINFO.pNameErrorsMailbox)
462         {
463             heap_free( dst->Data.MINFO.pNameMailbox );
464             goto error;
465         }
466         break;
467     }
468     case DNS_TYPE_AFSDB:
469     case DNS_TYPE_RT:
470     case DNS_TYPE_MX:
471     {
472         dst->Data.MX.pNameExchange =
473             dns_strcpyX( src->Data.MX.pNameExchange, in, out );
474         if (!dst->Data.MX.pNameExchange) goto error;
475         break;
476     }
477     case DNS_TYPE_NXT:
478     {
479         dst->Data.NXT.pNameNext =
480             dns_strcpyX( src->Data.NXT.pNameNext, in, out );
481         if (!dst->Data.NXT.pNameNext) goto error;
482         break;
483     }
484     case DNS_TYPE_CNAME:
485     case DNS_TYPE_MB:
486     case DNS_TYPE_MD:
487     case DNS_TYPE_MF:
488     case DNS_TYPE_MG:
489     case DNS_TYPE_MR:
490     case DNS_TYPE_NS:
491     case DNS_TYPE_PTR:
492     {
493         dst->Data.PTR.pNameHost =
494             dns_strcpyX( src->Data.PTR.pNameHost, in, out );
495         if (!dst->Data.PTR.pNameHost) goto error;
496         break;
497     }
498     case DNS_TYPE_SIG:
499     {
500         dst->Data.SIG.pNameSigner =
501             dns_strcpyX( src->Data.SIG.pNameSigner, in, out );
502         if (!dst->Data.SIG.pNameSigner) goto error;
503         break;
504     }
505     case DNS_TYPE_SOA:
506     {
507         dst->Data.SOA.pNamePrimaryServer =
508             dns_strcpyX( src->Data.SOA.pNamePrimaryServer, in, out );
509         if (!dst->Data.SOA.pNamePrimaryServer) goto error;
510
511         dst->Data.SOA.pNameAdministrator =
512             dns_strcpyX( src->Data.SOA.pNameAdministrator, in, out );
513         if (!dst->Data.SOA.pNameAdministrator)
514         {
515             heap_free( dst->Data.SOA.pNamePrimaryServer );
516             goto error;
517         }
518         break;
519     }
520     case DNS_TYPE_SRV:
521     {
522         dst->Data.SRV.pNameTarget =
523             dns_strcpyX( src->Data.SRV.pNameTarget, in, out );
524         if (!dst->Data.SRV.pNameTarget) goto error;
525         break;
526     }
527     default:
528         break;
529     }
530     return dst;
531
532 error:
533     heap_free( dst->pName );
534     heap_free( dst );
535     return NULL;
536 }
537
538 /******************************************************************************
539  * DnsRecordListFree                       [DNSAPI.@]
540  *
541  */
542 VOID WINAPI DnsRecordListFree( PDNS_RECORD list, DNS_FREE_TYPE type )
543 {
544     DNS_RECORD *r, *next;
545     unsigned int i;
546
547     TRACE( "(%p,%d)\n", list, type );
548
549     if (!list) return;
550
551     switch (type)
552     {
553     case DnsFreeRecordList:
554     {
555         for (r = list; (list = r); r = next)
556         {
557             heap_free( r->pName );
558
559             switch (r->wType)
560             {
561             case DNS_TYPE_HINFO:
562             case DNS_TYPE_ISDN:
563             case DNS_TYPE_TEXT:
564             case DNS_TYPE_X25:
565             {
566                 for (i = 0; i < r->Data.TXT.dwStringCount; i++)
567                     heap_free( r->Data.TXT.pStringArray[i] );
568
569                 break;
570             }
571             case DNS_TYPE_MINFO:
572             case DNS_TYPE_RP:
573             {
574                 heap_free( r->Data.MINFO.pNameMailbox );
575                 heap_free( r->Data.MINFO.pNameErrorsMailbox );
576                 break;
577             }
578             case DNS_TYPE_AFSDB:
579             case DNS_TYPE_RT:
580             case DNS_TYPE_MX:
581             {
582                 heap_free( r->Data.MX.pNameExchange );
583                 break;
584             }
585             case DNS_TYPE_NXT:
586             {
587                 heap_free( r->Data.NXT.pNameNext );
588                 break;
589             }
590             case DNS_TYPE_CNAME:
591             case DNS_TYPE_MB:
592             case DNS_TYPE_MD:
593             case DNS_TYPE_MF:
594             case DNS_TYPE_MG:
595             case DNS_TYPE_MR:
596             case DNS_TYPE_NS:
597             case DNS_TYPE_PTR:
598             {
599                 heap_free( r->Data.PTR.pNameHost );
600                 break;
601             }
602             case DNS_TYPE_SIG:
603             {
604                 heap_free( r->Data.SIG.pNameSigner );
605                 break;
606             }
607             case DNS_TYPE_SOA:
608             {
609                 heap_free( r->Data.SOA.pNamePrimaryServer );
610                 heap_free( r->Data.SOA.pNameAdministrator );
611                 break;
612             }
613             case DNS_TYPE_SRV:
614             {
615                 heap_free( r->Data.SRV.pNameTarget );
616                 break;
617             }
618             default:
619                 break;
620             }
621
622             next = r->pNext;
623             heap_free( r );
624         }
625         break;
626     }
627     case DnsFreeFlat:
628     case DnsFreeParsedMessageFields:
629     {
630         FIXME( "unhandled free type: %d\n", type );
631         break;
632     }
633     default:
634         WARN( "unknown free type: %d\n", type );
635         break;
636     }
637 }
638
639 /******************************************************************************
640  * DnsRecordSetCompare                     [DNSAPI.@]
641  *
642  */
643 BOOL WINAPI DnsRecordSetCompare( PDNS_RECORD set1, PDNS_RECORD set2,
644                                  PDNS_RECORD *diff1, PDNS_RECORD *diff2 )
645 {
646     BOOL ret = TRUE;
647     DNS_RECORD *r, *t, *u;
648     DNS_RRSET rr1, rr2;
649
650     TRACE( "(%p,%p,%p,%p)\n", set1, set2, diff1, diff2 );
651
652     if (!set1 && !set2) return FALSE;
653
654     if (diff1) *diff1 = NULL;
655     if (diff2) *diff2 = NULL;
656
657     if (set1 && !set2)
658     {
659         if (diff1) *diff1 = DnsRecordSetCopyEx( set1, 0, set1->Flags.S.CharSet );
660         return FALSE;
661     }
662     if (!set1 && set2)
663     {
664         if (diff2) *diff2 = DnsRecordSetCopyEx( set2, 0, set2->Flags.S.CharSet );
665         return FALSE;
666     }
667
668     DNS_RRSET_INIT( rr1 );
669     DNS_RRSET_INIT( rr2 );
670
671     for (r = set1; r; r = r->pNext)
672     {
673         for (t = set2; t; t = t->pNext)
674         {
675             u = DnsRecordCopyEx( r, r->Flags.S.CharSet, t->Flags.S.CharSet );
676             if (!u) goto error;
677
678             if (!DnsRecordCompare( t, u ))
679             {
680                 DNS_RRSET_ADD( rr1, u );
681                 ret = FALSE;
682             }
683             else heap_free( u );
684         }
685     }
686
687     for (t = set2; t; t = t->pNext)
688     {
689         for (r = set1; r; r = r->pNext)
690         {
691             u = DnsRecordCopyEx( t, t->Flags.S.CharSet, r->Flags.S.CharSet );
692             if (!u) goto error;
693
694             if (!DnsRecordCompare( r, u ))
695             {
696                 DNS_RRSET_ADD( rr2, u );
697                 ret = FALSE;
698             }
699             else heap_free( u );
700         }
701     }
702
703     DNS_RRSET_TERMINATE( rr1 );
704     DNS_RRSET_TERMINATE( rr2 );
705     
706     if (diff1) *diff1 = rr1.pFirstRR;
707     if (diff2) *diff2 = rr2.pFirstRR;
708
709     return ret;
710
711 error:
712     DNS_RRSET_TERMINATE( rr1 );
713     DNS_RRSET_TERMINATE( rr2 );
714
715     DnsRecordListFree( rr1.pFirstRR, DnsFreeRecordList );
716     DnsRecordListFree( rr2.pFirstRR, DnsFreeRecordList );
717     
718     return FALSE;
719 }
720
721 /******************************************************************************
722  * DnsRecordSetCopyEx                      [DNSAPI.@]
723  *
724  */
725 PDNS_RECORD WINAPI DnsRecordSetCopyEx( PDNS_RECORD src_set, DNS_CHARSET in, DNS_CHARSET out )
726 {
727     DNS_RRSET dst_set;
728     DNS_RECORD *src, *dst;
729
730     TRACE( "(%p,%d,%d)\n", src_set, in, out );
731
732     DNS_RRSET_INIT( dst_set );
733
734     for (src = src_set; (src_set = src); src = src_set->pNext)
735     {
736         dst = DnsRecordCopyEx( src, in, out );
737         if (!dst)
738         {
739             DNS_RRSET_TERMINATE( dst_set );
740             DnsRecordListFree( dst_set.pFirstRR, DnsFreeRecordList );
741             return NULL;
742         }
743         DNS_RRSET_ADD( dst_set, dst );
744     }
745
746     DNS_RRSET_TERMINATE( dst_set );
747     return dst_set.pFirstRR;
748 }
749
750 /******************************************************************************
751  * DnsRecordSetDetach                      [DNSAPI.@]
752  *
753  */
754 PDNS_RECORD WINAPI DnsRecordSetDetach( PDNS_RECORD set )
755 {
756     DNS_RECORD *r, *s;
757
758     TRACE( "(%p)\n", set );
759
760     for (r = set; (set = r); r = set->pNext)
761     {
762         if (r->pNext && !r->pNext->pNext)
763         {
764             s = r->pNext;
765             r->pNext = NULL;
766             return s;
767         }
768     }
769     return NULL;
770 }