dbghelp: Base and symbols.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "winerror.h"
42 #include "winnls.h"
43 #include "windns.h"
44
45 #include "dnsapi.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
48
49 const char *dns_type_to_str( unsigned short type )
50 {
51     switch (type)
52     {
53 #define X(x)    case (x): return #x;
54     X(DNS_TYPE_ZERO)
55     X(DNS_TYPE_A)
56     X(DNS_TYPE_NS)
57     X(DNS_TYPE_MD)
58     X(DNS_TYPE_MF)
59     X(DNS_TYPE_CNAME)
60     X(DNS_TYPE_SOA)
61     X(DNS_TYPE_MB)
62     X(DNS_TYPE_MG)
63     X(DNS_TYPE_MR)
64     X(DNS_TYPE_NULL)
65     X(DNS_TYPE_WKS)
66     X(DNS_TYPE_PTR)
67     X(DNS_TYPE_HINFO)
68     X(DNS_TYPE_MINFO)
69     X(DNS_TYPE_MX)
70     X(DNS_TYPE_TEXT)
71     X(DNS_TYPE_RP)
72     X(DNS_TYPE_AFSDB)
73     X(DNS_TYPE_X25)
74     X(DNS_TYPE_ISDN)
75     X(DNS_TYPE_RT)
76     X(DNS_TYPE_NSAP)
77     X(DNS_TYPE_NSAPPTR)
78     X(DNS_TYPE_SIG)
79     X(DNS_TYPE_KEY)
80     X(DNS_TYPE_PX)
81     X(DNS_TYPE_GPOS)
82     X(DNS_TYPE_AAAA)
83     X(DNS_TYPE_LOC)
84     X(DNS_TYPE_NXT)
85     X(DNS_TYPE_EID)
86     X(DNS_TYPE_NIMLOC)
87     X(DNS_TYPE_SRV)
88     X(DNS_TYPE_ATMA)
89     X(DNS_TYPE_NAPTR)
90     X(DNS_TYPE_KX)
91     X(DNS_TYPE_CERT)
92     X(DNS_TYPE_A6)
93     X(DNS_TYPE_DNAME)
94     X(DNS_TYPE_SINK)
95     X(DNS_TYPE_OPT)
96     X(DNS_TYPE_UINFO)
97     X(DNS_TYPE_UID)
98     X(DNS_TYPE_GID)
99     X(DNS_TYPE_UNSPEC)
100     X(DNS_TYPE_ADDRS)
101     X(DNS_TYPE_TKEY)
102     X(DNS_TYPE_TSIG)
103     X(DNS_TYPE_IXFR)
104     X(DNS_TYPE_AXFR)
105     X(DNS_TYPE_MAILB)
106     X(DNS_TYPE_MAILA)
107     X(DNS_TYPE_ANY)
108     X(DNS_TYPE_WINS)
109     X(DNS_TYPE_WINSR)
110 #undef X
111     default: { static char tmp[7]; sprintf( tmp, "0x%04x", type ); return tmp; }
112     }
113 }
114
115 static int dns_strcmpX( LPCVOID str1, LPCVOID str2, BOOL wide )
116 {
117     if (wide)
118         return lstrcmpiW( (LPCWSTR)str1, (LPCWSTR)str2 );
119     else
120         return lstrcmpiA( (LPCSTR)str1, (LPCSTR)str2 );
121 }
122
123 /******************************************************************************
124  * DnsRecordCompare                        [DNSAPI.@]
125  *
126  */
127 BOOL WINAPI DnsRecordCompare( PDNS_RECORD r1, PDNS_RECORD r2 )
128 {
129     BOOL wide;
130     unsigned int i;
131
132     TRACE( "(%p,%p)\n", r1, r2 );
133
134     if (r1->wType       != r2->wType       ||
135         r1->wDataLength != r2->wDataLength ||
136         r1->Flags.DW    != r2->Flags.DW    ||
137         r1->dwTtl       != r2->dwTtl       ||
138         r1->dwReserved  != r2->dwReserved) return FALSE;
139
140     wide = (r1->Flags.S.CharSet == DnsCharSetUnicode) ? TRUE : FALSE;
141     if (dns_strcmpX( r1->pName, r2->pName, wide )) return FALSE;
142
143     switch (r1->wType)
144     {
145     case DNS_TYPE_A:
146     {
147         if (r1->Data.A.IpAddress != r2->Data.A.IpAddress) return FALSE;
148         break;
149     }
150     case DNS_TYPE_SOA:
151     {
152         if (r1->Data.SOA.dwSerialNo   != r2->Data.SOA.dwSerialNo ||
153             r1->Data.SOA.dwRefresh    != r2->Data.SOA.dwRefresh  ||
154             r1->Data.SOA.dwRetry      != r2->Data.SOA.dwRetry    ||
155             r1->Data.SOA.dwExpire     != r2->Data.SOA.dwExpire   ||
156             r1->Data.SOA.dwDefaultTtl != r2->Data.SOA.dwDefaultTtl)
157             return FALSE;
158         if (dns_strcmpX( r1->Data.SOA.pNamePrimaryServer,
159                          r2->Data.SOA.pNamePrimaryServer, wide ) ||
160             dns_strcmpX( r1->Data.SOA.pNameAdministrator,
161                          r2->Data.SOA.pNameAdministrator, wide ))
162             return FALSE;
163         break;
164     }
165     case DNS_TYPE_PTR:
166     case DNS_TYPE_NS:
167     case DNS_TYPE_CNAME:
168     case DNS_TYPE_MB:
169     case DNS_TYPE_MD:
170     case DNS_TYPE_MF:
171     case DNS_TYPE_MG:
172     case DNS_TYPE_MR:
173     {
174         if (dns_strcmpX( r1->Data.PTR.pNameHost,
175                          r2->Data.PTR.pNameHost, wide )) return FALSE;
176         break;
177     }
178     case DNS_TYPE_MINFO:
179     case DNS_TYPE_RP:
180     {
181         if (dns_strcmpX( r1->Data.MINFO.pNameMailbox,
182                          r2->Data.MINFO.pNameMailbox, wide ) ||
183             dns_strcmpX( r1->Data.MINFO.pNameErrorsMailbox,
184                          r2->Data.MINFO.pNameErrorsMailbox, wide ))
185             return FALSE;
186         break;
187     }
188     case DNS_TYPE_MX:
189     case DNS_TYPE_AFSDB:
190     case DNS_TYPE_RT:
191     {
192         if (r1->Data.MX.wPreference != r2->Data.MX.wPreference)
193             return FALSE;
194         if (dns_strcmpX( r1->Data.MX.pNameExchange,
195                          r2->Data.MX.pNameExchange, wide ))
196             return FALSE;
197         break;
198     }
199     case DNS_TYPE_HINFO:
200     case DNS_TYPE_ISDN:
201     case DNS_TYPE_TEXT:
202     case DNS_TYPE_X25:
203     {
204         if (r1->Data.TXT.dwStringCount != r2->Data.TXT.dwStringCount)
205             return FALSE;
206         for (i = 0; i < r1->Data.TXT.dwStringCount; i++)
207         {
208             if (dns_strcmpX( r1->Data.TXT.pStringArray[i],
209                              r2->Data.TXT.pStringArray[i], wide ))
210                 return FALSE;
211         }
212         break;
213     }
214     case DNS_TYPE_NULL:
215     {
216         if (r1->Data.Null.dwByteCount != r2->Data.Null.dwByteCount)
217             return FALSE;
218         if (memcmp( r1->Data.Null.Data,
219                     r2->Data.Null.Data, r1->Data.Null.dwByteCount ))
220             return FALSE;
221         break;
222     }
223     case DNS_TYPE_AAAA:
224     {
225         for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
226         {
227             if (r1->Data.AAAA.Ip6Address.IP6Dword[i] !=
228                 r2->Data.AAAA.Ip6Address.IP6Dword[i]) return FALSE;
229         }
230         break;
231     }
232     case DNS_TYPE_KEY:
233     {
234         if (r1->Data.KEY.wFlags      != r2->Data.KEY.wFlags      ||
235             r1->Data.KEY.chProtocol  != r2->Data.KEY.chProtocol  ||
236             r1->Data.KEY.chAlgorithm != r2->Data.KEY.chAlgorithm)
237             return FALSE;
238         if (memcmp( r1->Data.KEY.Key, r2->Data.KEY.Key,
239                     r1->wDataLength - sizeof(DNS_KEY_DATA) + 1 ))
240             return FALSE;
241         break;
242     }
243     case DNS_TYPE_SIG:
244     {
245         if (dns_strcmpX( r1->Data.SIG.pNameSigner,
246                          r2->Data.SIG.pNameSigner, wide ))
247             return FALSE;
248         if (r1->Data.SIG.wTypeCovered  != r2->Data.SIG.wTypeCovered  ||
249             r1->Data.SIG.chAlgorithm   != r2->Data.SIG.chAlgorithm   ||
250             r1->Data.SIG.chLabelCount  != r2->Data.SIG.chLabelCount  ||
251             r1->Data.SIG.dwOriginalTtl != r2->Data.SIG.dwOriginalTtl ||
252             r1->Data.SIG.dwExpiration  != r2->Data.SIG.dwExpiration  ||
253             r1->Data.SIG.dwTimeSigned  != r2->Data.SIG.dwTimeSigned  ||
254             r1->Data.SIG.wKeyTag       != r2->Data.SIG.wKeyTag)
255             return FALSE;
256         if (memcmp( r1->Data.SIG.Signature, r2->Data.SIG.Signature,
257                     r1->wDataLength - sizeof(DNS_SIG_DATAA) + 1 ))
258             return FALSE;
259         break;
260     }
261     case DNS_TYPE_ATMA:
262     {
263         if (r1->Data.ATMA.AddressType != r2->Data.ATMA.AddressType)
264             return FALSE;
265         for (i = 0; i < DNS_ATMA_MAX_ADDR_LENGTH; i++)
266         {
267             if (r1->Data.ATMA.Address[i] != r2->Data.ATMA.Address[i])
268                 return FALSE;
269         }
270         break;
271     }
272     case DNS_TYPE_NXT:
273     {
274         if (dns_strcmpX( r1->Data.NXT.pNameNext,
275                          r2->Data.NXT.pNameNext, wide )) return FALSE;
276         if (r1->Data.NXT.wNumTypes != r2->Data.NXT.wNumTypes) return FALSE;
277         if (memcmp( r1->Data.NXT.wTypes, r2->Data.NXT.wTypes,
278                     r1->wDataLength - sizeof(DNS_NXT_DATAA) + sizeof(WORD) ))
279             return FALSE;
280         break;
281     }
282     case DNS_TYPE_SRV:
283     {
284         if (dns_strcmpX( r1->Data.SRV.pNameTarget,
285                          r2->Data.SRV.pNameTarget, wide )) return FALSE;
286         if (r1->Data.SRV.wPriority != r2->Data.SRV.wPriority ||
287             r1->Data.SRV.wWeight   != r2->Data.SRV.wWeight   ||
288             r1->Data.SRV.wPort     != r2->Data.SRV.wPort)
289             return FALSE;
290         break;
291     }
292     case DNS_TYPE_TKEY:
293     {
294         if (dns_strcmpX( r1->Data.TKEY.pNameAlgorithm,
295                          r2->Data.TKEY.pNameAlgorithm, wide ))
296             return FALSE;
297         if (r1->Data.TKEY.dwCreateTime    != r2->Data.TKEY.dwCreateTime     ||
298             r1->Data.TKEY.dwExpireTime    != r2->Data.TKEY.dwExpireTime     ||
299             r1->Data.TKEY.wMode           != r2->Data.TKEY.wMode            ||
300             r1->Data.TKEY.wError          != r2->Data.TKEY.wError           ||
301             r1->Data.TKEY.wKeyLength      != r2->Data.TKEY.wKeyLength       ||
302             r1->Data.TKEY.wOtherLength    != r2->Data.TKEY.wOtherLength     ||
303             r1->Data.TKEY.cAlgNameLength  != r2->Data.TKEY.cAlgNameLength   ||
304             r1->Data.TKEY.bPacketPointers != r2->Data.TKEY.bPacketPointers)
305             return FALSE;
306
307         /* FIXME: ignoring pAlgorithmPacket field */
308         if (memcmp( r1->Data.TKEY.pKey, r2->Data.TKEY.pKey,
309                     r1->Data.TKEY.wKeyLength ) ||
310             memcmp( r1->Data.TKEY.pOtherData, r2->Data.TKEY.pOtherData,
311                     r1->Data.TKEY.wOtherLength )) return FALSE;
312         break;
313     }
314     case DNS_TYPE_TSIG:
315     {
316         if (dns_strcmpX( r1->Data.TSIG.pNameAlgorithm,
317                          r2->Data.TSIG.pNameAlgorithm, wide ))
318             return FALSE;
319         if (r1->Data.TSIG.i64CreateTime   != r2->Data.TSIG.i64CreateTime    ||
320             r1->Data.TSIG.wFudgeTime      != r2->Data.TSIG.wFudgeTime       ||
321             r1->Data.TSIG.wOriginalXid    != r2->Data.TSIG.wOriginalXid     ||
322             r1->Data.TSIG.wError          != r2->Data.TSIG.wError           ||
323             r1->Data.TSIG.wSigLength      != r2->Data.TSIG.wSigLength       ||
324             r1->Data.TSIG.wOtherLength    != r2->Data.TSIG.wOtherLength     ||
325             r1->Data.TSIG.cAlgNameLength  != r2->Data.TSIG.cAlgNameLength   ||
326             r1->Data.TSIG.bPacketPointers != r2->Data.TSIG.bPacketPointers)
327             return FALSE;
328
329         /* FIXME: ignoring pAlgorithmPacket field */
330         if (memcmp( r1->Data.TSIG.pSignature, r2->Data.TSIG.pSignature,
331                     r1->Data.TSIG.wSigLength ) ||
332             memcmp( r1->Data.TSIG.pOtherData, r2->Data.TSIG.pOtherData,
333                     r1->Data.TSIG.wOtherLength )) return FALSE;
334         break;
335     }
336     case DNS_TYPE_WINS:
337     {
338         if (r1->Data.WINS.dwMappingFlag    != r2->Data.WINS.dwMappingFlag   ||
339             r1->Data.WINS.dwLookupTimeout  != r2->Data.WINS.dwLookupTimeout ||
340             r1->Data.WINS.dwCacheTimeout   != r2->Data.WINS.dwCacheTimeout  ||
341             r1->Data.WINS.cWinsServerCount != r2->Data.WINS.cWinsServerCount)
342             return FALSE;
343         if (memcmp( r1->Data.WINS.WinsServers, r2->Data.WINS.WinsServers,
344                     r1->wDataLength - sizeof(DNS_WINS_DATA) + sizeof(IP4_ADDRESS) ))
345             return FALSE;
346         break;
347     }
348     case DNS_TYPE_WINSR:
349     {
350         if (r1->Data.WINSR.dwMappingFlag   != r2->Data.WINSR.dwMappingFlag   ||
351             r1->Data.WINSR.dwLookupTimeout != r2->Data.WINSR.dwLookupTimeout ||
352             r1->Data.WINSR.dwCacheTimeout  != r2->Data.WINSR.dwCacheTimeout)
353             return FALSE;
354         if (dns_strcmpX( r1->Data.WINSR.pNameResultDomain,
355                          r2->Data.WINSR.pNameResultDomain, wide ))
356             return FALSE;
357         break;
358     }
359     default:
360         FIXME( "unknown type: %s\n", dns_type_to_str( r1->wType ) );
361         return FALSE;
362     }
363     return TRUE;
364 }
365
366 static LPVOID dns_strcpyX( LPCVOID src, DNS_CHARSET in, DNS_CHARSET out )
367 {
368     switch (in)
369     {
370     case DnsCharSetUnicode:
371     {
372         switch (out)
373         {
374         case DnsCharSetUnicode: return dns_strdup_w( src );
375         case DnsCharSetUtf8:    return dns_strdup_wu( src );
376         case DnsCharSetAnsi:    return dns_strdup_wa( src );
377         default:
378             WARN( "unhandled target charset: %d\n", out );
379             break;
380         }
381     }
382     case DnsCharSetUtf8:
383         switch (out)
384         {
385         case DnsCharSetUnicode: return dns_strdup_uw( src );
386         case DnsCharSetUtf8:    return dns_strdup_u( src );
387         case DnsCharSetAnsi:    return dns_strdup_ua( src );
388         default:
389             WARN( "unhandled target charset: %d\n", out );
390             break;
391         }
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     default:
403         WARN( "unhandled source charset: %d\n", in );
404         break;
405     }
406     return NULL;
407 }
408
409 /******************************************************************************
410  * DnsRecordCopyEx                         [DNSAPI.@]
411  *
412  */
413 PDNS_RECORD WINAPI DnsRecordCopyEx( PDNS_RECORD src, DNS_CHARSET in, DNS_CHARSET out )
414 {
415     DNS_RECORD *dst;
416     unsigned int i, size;
417
418     TRACE( "(%p,%d,%d)\n", src, in, out );
419
420     size = FIELD_OFFSET(DNS_RECORD, Data) + src->wDataLength;
421     dst = dns_zero_alloc( size );
422     if (!dst) return NULL;
423
424     memcpy( dst, src, size );
425
426     if (src->Flags.S.CharSet == DnsCharSetUtf8 ||
427         src->Flags.S.CharSet == DnsCharSetAnsi ||
428         src->Flags.S.CharSet == DnsCharSetUnicode) in = src->Flags.S.CharSet;
429
430     dst->Flags.S.CharSet = out;
431     dst->pName = dns_strcpyX( src->pName, in, out );
432     if (!dst->pName) goto error;
433
434     switch (src->wType)
435     {
436     case DNS_TYPE_HINFO:
437     case DNS_TYPE_ISDN:
438     case DNS_TYPE_TEXT:
439     case DNS_TYPE_X25:
440     {
441         for (i = 0; i < src->Data.TXT.dwStringCount; i++)
442         {
443             dst->Data.TXT.pStringArray[i] =
444                 dns_strcpyX( src->Data.TXT.pStringArray[i], in, out );
445
446             if (!dst->Data.TXT.pStringArray[i])
447             {
448                 for (--i; i >= 0; i--)
449                     dns_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             dns_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             dns_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     dns_free( dst->pName );
537     dns_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             dns_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                     dns_free( r->Data.TXT.pStringArray[i] );
571
572                 break;
573             }
574             case DNS_TYPE_MINFO:
575             case DNS_TYPE_RP:
576             {
577                 dns_free( r->Data.MINFO.pNameMailbox );
578                 dns_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                 dns_free( r->Data.MX.pNameExchange );
586                 break;
587             }
588             case DNS_TYPE_NXT:
589             {
590                 dns_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                 dns_free( r->Data.PTR.pNameHost );
603                 break;
604             }
605             case DNS_TYPE_SIG:
606             {
607                 dns_free( r->Data.SIG.pNameSigner );
608                 break;
609             }
610             case DNS_TYPE_SOA:
611             {
612                 dns_free( r->Data.SOA.pNamePrimaryServer );
613                 dns_free( r->Data.SOA.pNameAdministrator );
614                 break;
615             }
616             case DNS_TYPE_SRV:
617             {
618                 dns_free( r->Data.SRV.pNameTarget );
619                 break;
620             }
621             default:
622                 break;
623             }
624
625             next = r->pNext;
626             dns_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  * DnsRecordSetCopyEx                      [DNSAPI.@]
644  *
645  */
646 PDNS_RECORD WINAPI DnsRecordSetCopyEx( PDNS_RECORD src_set, DNS_CHARSET in, DNS_CHARSET out )
647 {
648     DNS_RRSET dst_set;
649     DNS_RECORD *src, *dst;
650
651     TRACE( "(%p,%d,%d)\n", src_set, in, out );
652
653     DNS_RRSET_INIT( dst_set );
654
655     for (src = src_set; (src_set = src); src = src_set->pNext)
656     {
657         dst = DnsRecordCopyEx( src, in, out );
658         if (!dst)
659         {
660             DNS_RRSET_TERMINATE( dst_set );
661             DnsRecordListFree( dst_set.pFirstRR, DnsFreeRecordList );
662             return NULL;
663         }
664         DNS_RRSET_ADD( dst_set, dst );
665     }
666
667     DNS_RRSET_TERMINATE( dst_set );
668     return dst_set.pFirstRR;
669 }