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