Revert changes relative to lib/*.[ch] recent renaming
[platform/upstream/curl.git] / src / tool_metalink.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 #include "tool_setup.h"
23
24 #ifdef USE_METALINK
25
26 #include <sys/stat.h>
27
28 #ifdef HAVE_FCNTL_H
29 #  include <fcntl.h>
30 #endif
31
32 #ifdef USE_SSLEAY
33 #  ifdef USE_OPENSSL
34 #    include <openssl/md5.h>
35 #    include <openssl/sha.h>
36 #  else
37 #    include <md5.h>
38 #    include <sha.h>
39 #  endif
40 #elif defined(USE_GNUTLS_NETTLE)
41 #  include <nettle/md5.h>
42 #  include <nettle/sha.h>
43 #  define MD5_CTX    struct md5_ctx
44 #  define SHA_CTX    struct sha1_ctx
45 #  define SHA256_CTX struct sha256_ctx
46 #elif defined(USE_GNUTLS)
47 #  include <gcrypt.h>
48 #  define MD5_CTX    gcry_md_hd_t
49 #  define SHA_CTX    gcry_md_hd_t
50 #  define SHA256_CTX gcry_md_hd_t
51 #elif defined(USE_NSS)
52 #  include <nss.h>
53 #  include <pk11pub.h>
54 #  define MD5_CTX    void *
55 #  define SHA_CTX    void *
56 #  define SHA256_CTX void *
57 #  ifdef HAVE_NSS_INITCONTEXT
58      static NSSInitContext *nss_context;
59 #  endif
60 #elif defined(__MAC_10_4) || defined(__IPHONE_5_0)
61 /* For Apple operating systems: CommonCrypto has the functions we need.
62    The library's headers are even backward-compatible with OpenSSL's
63    headers as long as we define COMMON_DIGEST_FOR_OPENSSL first.
64
65    These functions are available on Tiger and later, as well as iOS 5.0
66    and later. If you're building for an older cat, well, sorry. */
67 #  define COMMON_DIGEST_FOR_OPENSSL
68 #  include <CommonCrypto/CommonDigest.h>
69 #elif defined(_WIN32)
70 /* For Windows: If no other crypto library is provided, we fallback
71    to the hash functions provided within the Microsoft Windows CryptoAPI */
72 #  include <wincrypt.h>
73 /* Custom structure in order to store the required provider and hash handle */
74 struct win32_crypto_hash {
75   HCRYPTPROV hCryptProv;
76   HCRYPTHASH hHash;
77 };
78 /* Custom Microsoft AES Cryptographic Provider defines required for MinGW */
79 #  ifndef ALG_SID_SHA_256
80 #    define ALG_SID_SHA_256  12
81 #  endif
82 #  ifndef CALG_SHA_256
83 #    define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
84 #  endif
85 #  define MD5_CTX    struct win32_crypto_hash
86 #  define SHA_CTX    struct win32_crypto_hash
87 #  define SHA256_CTX struct win32_crypto_hash
88 #else
89 #  error "Can't compile METALINK support without a crypto library."
90 #endif
91
92 #include "rawstr.h"
93
94 #define ENABLE_CURLX_PRINTF
95 /* use our own printf() functions */
96 #include "curlx.h"
97
98 #include "tool_getparam.h"
99 #include "tool_paramhlp.h"
100 #include "tool_cfgable.h"
101 #include "tool_metalink.h"
102 #include "tool_msgs.h"
103
104 #include "memdebug.h" /* keep this as LAST include */
105
106 /* Copied from tool_getparam.c */
107 #define GetStr(str,val) do { \
108   if(*(str)) { \
109     free(*(str)); \
110     *(str) = NULL; \
111   } \
112   if((val)) \
113     *(str) = strdup((val)); \
114   if(!(val)) \
115     return PARAM_NO_MEM; \
116 } WHILE_FALSE
117
118 #ifdef USE_GNUTLS_NETTLE
119
120 static int MD5_Init(MD5_CTX *ctx)
121 {
122   md5_init(ctx);
123   return 1;
124 }
125
126 static void MD5_Update(MD5_CTX *ctx,
127                        const unsigned char *input,
128                        unsigned int inputLen)
129 {
130   md5_update(ctx, inputLen, input);
131 }
132
133 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
134 {
135   md5_digest(ctx, 16, digest);
136 }
137
138 static int SHA1_Init(SHA_CTX *ctx)
139 {
140   sha1_init(ctx);
141   return 1;
142 }
143
144 static void SHA1_Update(SHA_CTX *ctx,
145                         const unsigned char *input,
146                         unsigned int inputLen)
147 {
148   sha1_update(ctx, inputLen, input);
149 }
150
151 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
152 {
153   sha1_digest(ctx, 20, digest);
154 }
155
156 static int SHA256_Init(SHA256_CTX *ctx)
157 {
158   sha256_init(ctx);
159   return 1;
160 }
161
162 static void SHA256_Update(SHA256_CTX *ctx,
163                           const unsigned char *input,
164                           unsigned int inputLen)
165 {
166   sha256_update(ctx, inputLen, input);
167 }
168
169 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
170 {
171   sha256_digest(ctx, 32, digest);
172 }
173
174 #elif defined(USE_GNUTLS)
175
176 static int MD5_Init(MD5_CTX *ctx)
177 {
178   gcry_md_open(ctx, GCRY_MD_MD5, 0);
179   return 1;
180 }
181
182 static void MD5_Update(MD5_CTX *ctx,
183                        const unsigned char *input,
184                        unsigned int inputLen)
185 {
186   gcry_md_write(*ctx, input, inputLen);
187 }
188
189 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
190 {
191   memcpy(digest, gcry_md_read(*ctx, 0), 16);
192   gcry_md_close(*ctx);
193 }
194
195 static int SHA1_Init(SHA_CTX *ctx)
196 {
197   gcry_md_open(ctx, GCRY_MD_SHA1, 0);
198   return 1;
199 }
200
201 static void SHA1_Update(SHA_CTX *ctx,
202                         const unsigned char *input,
203                         unsigned int inputLen)
204 {
205   gcry_md_write(*ctx, input, inputLen);
206 }
207
208 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
209 {
210   memcpy(digest, gcry_md_read(*ctx, 0), 20);
211   gcry_md_close(*ctx);
212 }
213
214 static int SHA256_Init(SHA256_CTX *ctx)
215 {
216   gcry_md_open(ctx, GCRY_MD_SHA256, 0);
217   return 1;
218 }
219
220 static void SHA256_Update(SHA256_CTX *ctx,
221                           const unsigned char *input,
222                           unsigned int inputLen)
223 {
224   gcry_md_write(*ctx, input, inputLen);
225 }
226
227 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
228 {
229   memcpy(digest, gcry_md_read(*ctx, 0), 32);
230   gcry_md_close(*ctx);
231 }
232
233 #elif defined(USE_NSS)
234
235 static int nss_hash_init(void **pctx, SECOidTag hash_alg)
236 {
237   PK11Context *ctx;
238
239   /* we have to initialize NSS if not initialized alraedy */
240 #ifdef HAVE_NSS_INITCONTEXT
241   if(!NSS_IsInitialized() && !nss_context) {
242     static NSSInitParameters params;
243     params.length = sizeof params;
244     nss_context = NSS_InitContext("", "", "", "", &params, NSS_INIT_READONLY
245         | NSS_INIT_NOCERTDB   | NSS_INIT_NOMODDB       | NSS_INIT_FORCEOPEN
246         | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
247   }
248 #endif
249
250   ctx = PK11_CreateDigestContext(hash_alg);
251   if(!ctx)
252     return /* failure */ 0;
253
254   if(PK11_DigestBegin(ctx) != SECSuccess) {
255     PK11_DestroyContext(ctx, PR_TRUE);
256     return /* failure */ 0;
257   }
258
259   *pctx = ctx;
260   return /* success */ 1;
261 }
262
263 static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len)
264 {
265   PK11Context *ctx = *pctx;
266   unsigned int outlen;
267   PK11_DigestFinal(ctx, out, &outlen, len);
268   PK11_DestroyContext(ctx, PR_TRUE);
269 }
270
271 static int MD5_Init(MD5_CTX *pctx)
272 {
273   return nss_hash_init(pctx, SEC_OID_MD5);
274 }
275
276 static void MD5_Update(MD5_CTX *pctx,
277                        const unsigned char *input,
278                        unsigned int input_len)
279 {
280   PK11_DigestOp(*pctx, input, input_len);
281 }
282
283 static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
284 {
285   nss_hash_final(pctx, digest, 16);
286 }
287
288 static int SHA1_Init(SHA_CTX *pctx)
289 {
290   return nss_hash_init(pctx, SEC_OID_SHA1);
291 }
292
293 static void SHA1_Update(SHA_CTX *pctx,
294                         const unsigned char *input,
295                         unsigned int input_len)
296 {
297   PK11_DigestOp(*pctx, input, input_len);
298 }
299
300 static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
301 {
302   nss_hash_final(pctx, digest, 20);
303 }
304
305 static int SHA256_Init(SHA256_CTX *pctx)
306 {
307   return nss_hash_init(pctx, SEC_OID_SHA256);
308 }
309
310 static void SHA256_Update(SHA256_CTX *pctx,
311                           const unsigned char *input,
312                           unsigned int input_len)
313 {
314   PK11_DigestOp(*pctx, input, input_len);
315 }
316
317 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx)
318 {
319   nss_hash_final(pctx, digest, 32);
320 }
321
322 #elif defined(_WIN32) && !defined(USE_SSLEAY)
323
324 static void win32_crypto_final(struct win32_crypto_hash *ctx,
325                                unsigned char *digest,
326                                unsigned int digestLen)
327 {
328   unsigned long length;
329   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
330   if(length == digestLen)
331     CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
332   if(ctx->hHash)
333     CryptDestroyHash(ctx->hHash);
334   if(ctx->hCryptProv)
335     CryptReleaseContext(ctx->hCryptProv, 0);
336 }
337
338 static int MD5_Init(MD5_CTX *ctx)
339 {
340   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
341                          PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
342     CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
343   }
344   return 1;
345 }
346
347 static void MD5_Update(MD5_CTX *ctx,
348                        const unsigned char *input,
349                        unsigned int inputLen)
350 {
351   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
352 }
353
354 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
355 {
356   win32_crypto_final(ctx, digest, 16);
357 }
358
359 static int SHA1_Init(SHA_CTX *ctx)
360 {
361   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
362                          PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
363     CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
364   }
365   return 1;
366 }
367
368 static void SHA1_Update(SHA_CTX *ctx,
369                         const unsigned char *input,
370                         unsigned int inputLen)
371 {
372   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
373 }
374
375 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
376 {
377   win32_crypto_final(ctx, digest, 20);
378 }
379
380 static int SHA256_Init(SHA256_CTX *ctx)
381 {
382   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
383                          PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
384     CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
385   }
386   return 1;
387 }
388
389 static void SHA256_Update(SHA256_CTX *ctx,
390                           const unsigned char *input,
391                           unsigned int inputLen)
392 {
393   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
394 }
395
396 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
397 {
398   win32_crypto_final(ctx, digest, 32);
399 }
400
401 #endif /* CRYPTO LIBS */
402
403 const digest_params MD5_DIGEST_PARAMS[] = {
404   {
405     (Curl_digest_init_func) MD5_Init,
406     (Curl_digest_update_func) MD5_Update,
407     (Curl_digest_final_func) MD5_Final,
408     sizeof(MD5_CTX),
409     16
410   }
411 };
412
413 const digest_params SHA1_DIGEST_PARAMS[] = {
414   {
415     (Curl_digest_init_func) SHA1_Init,
416     (Curl_digest_update_func) SHA1_Update,
417     (Curl_digest_final_func) SHA1_Final,
418     sizeof(SHA_CTX),
419     20
420   }
421 };
422
423 const digest_params SHA256_DIGEST_PARAMS[] = {
424   {
425     (Curl_digest_init_func) SHA256_Init,
426     (Curl_digest_update_func) SHA256_Update,
427     (Curl_digest_final_func) SHA256_Final,
428     sizeof(SHA256_CTX),
429     32
430   }
431 };
432
433 static const metalink_digest_def SHA256_DIGEST_DEF[] = {
434   {"sha-256", SHA256_DIGEST_PARAMS}
435 };
436
437 static const metalink_digest_def SHA1_DIGEST_DEF[] = {
438   {"sha-1", SHA1_DIGEST_PARAMS}
439 };
440
441 static const metalink_digest_def MD5_DIGEST_DEF[] = {
442   {"md5", MD5_DIGEST_PARAMS}
443 };
444
445 /*
446  * The alias of supported hash functions in the order by preference
447  * (basically stronger hash comes first). We included "sha-256" and
448  * "sha256". The former is the name defined in the IANA registry named
449  * "Hash Function Textual Names". The latter is widely (and
450  * historically) used in Metalink version 3.
451  */
452 static const metalink_digest_alias digest_aliases[] = {
453   {"sha-256", SHA256_DIGEST_DEF},
454   {"sha256", SHA256_DIGEST_DEF},
455   {"sha-1", SHA1_DIGEST_DEF},
456   {"sha1", SHA1_DIGEST_DEF},
457   {"md5", MD5_DIGEST_DEF},
458   {NULL, NULL}
459 };
460
461 digest_context *Curl_digest_init(const digest_params *dparams)
462 {
463   digest_context *ctxt;
464
465   /* Create digest context */
466   ctxt = malloc(sizeof *ctxt);
467
468   if(!ctxt)
469     return ctxt;
470
471   ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize);
472
473   if(!ctxt->digest_hashctx) {
474     free(ctxt);
475     return NULL;
476   }
477
478   ctxt->digest_hash = dparams;
479
480   if(dparams->digest_init(ctxt->digest_hashctx) != 1) {
481     free(ctxt);
482     return NULL;
483   }
484
485   return ctxt;
486 }
487
488 int Curl_digest_update(digest_context *context,
489                        const unsigned char *data,
490                        unsigned int len)
491 {
492   (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
493
494   return 0;
495 }
496
497 int Curl_digest_final(digest_context *context, unsigned char *result)
498 {
499   (*context->digest_hash->digest_final)(result, context->digest_hashctx);
500
501   free(context->digest_hashctx);
502   free(context);
503
504   return 0;
505 }
506
507 static unsigned char hex_to_uint(const char *s)
508 {
509   int v[2];
510   int i;
511   for(i = 0; i < 2; ++i) {
512     v[i] = Curl_raw_toupper(s[i]);
513     if('0' <= v[i] && v[i] <= '9') {
514       v[i] -= '0';
515     }
516     else if('A' <= v[i] && v[i] <= 'Z') {
517       v[i] -= 'A'-10;
518     }
519   }
520   return (unsigned char)((v[0] << 4) | v[1]);
521 }
522
523 /*
524  * Check checksum of file denoted by filename. The expected hash value
525  * is given in hex_hash which is hex-encoded string.
526  *
527  * This function returns 1 if it succeeds or one of the following
528  * integers:
529  *
530  * 0:
531  *   Checksum didn't match.
532  * -1:
533  *   Could not open file; or could not read data from file.
534  * -2:
535  *   Hash algorithm not available.
536  */
537 static int check_hash(const char *filename,
538                       const metalink_digest_def *digest_def,
539                       const unsigned char *digest, FILE *error)
540 {
541   unsigned char *result;
542   digest_context *dctx;
543   int check_ok, flags, fd;
544
545   flags = O_RDONLY;
546 #ifdef O_BINARY
547   /* O_BINARY is required in order to avoid binary EOF in text mode */
548   flags |= O_BINARY;
549 #endif
550
551   fd = open(filename, flags);
552   if(fd == -1) {
553     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
554             digest_def->hash_name, strerror(errno));
555     return -1;
556   }
557
558   dctx = Curl_digest_init(digest_def->dparams);
559   if(!dctx) {
560     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
561             digest_def->hash_name, "failed to initialize hash algorithm");
562     close(fd);
563     return -2;
564   }
565
566   result = malloc(digest_def->dparams->digest_resultlen);
567   while(1) {
568     unsigned char buf[4096];
569     ssize_t len = read(fd, buf, sizeof(buf));
570     if(len == 0) {
571       break;
572     }
573     else if(len == -1) {
574       fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
575               digest_def->hash_name, strerror(errno));
576       Curl_digest_final(dctx, result);
577       close(fd);
578       return -1;
579     }
580     Curl_digest_update(dctx, buf, (unsigned int)len);
581   }
582   Curl_digest_final(dctx, result);
583   check_ok = memcmp(result, digest,
584                     digest_def->dparams->digest_resultlen) == 0;
585   /* sha*sum style verdict output */
586   if(check_ok)
587     fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
588             digest_def->hash_name);
589   else
590     fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
591             filename, digest_def->hash_name);
592
593   free(result);
594   close(fd);
595   return check_ok;
596 }
597
598 int metalink_check_hash(struct Configurable *config,
599                         metalinkfile *mlfile,
600                         const char *filename)
601 {
602   int rv;
603   fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
604   if(mlfile->checksum == NULL) {
605     fprintf(config->errors,
606             "Metalink: validating (%s) FAILED (digest missing)\n",
607             filename);
608     return -2;
609   }
610   rv = check_hash(filename, mlfile->checksum->digest_def,
611                   mlfile->checksum->digest, config->errors);
612   return rv;
613 }
614
615 static metalink_checksum *new_metalink_checksum_from_hex_digest
616 (const metalink_digest_def *digest_def, const char *hex_digest)
617 {
618   metalink_checksum *chksum;
619   unsigned char *digest;
620   size_t i;
621   size_t len = strlen(hex_digest);
622   digest = malloc(len/2);
623   for(i = 0; i < len; i += 2) {
624     digest[i/2] = hex_to_uint(hex_digest+i);
625   }
626   chksum = malloc(sizeof(metalink_checksum));
627   chksum->digest_def = digest_def;
628   chksum->digest = digest;
629   return chksum;
630 }
631
632 static metalink_resource *new_metalink_resource(const char *url)
633 {
634   metalink_resource *res;
635   res = malloc(sizeof(metalink_resource));
636   res->next = NULL;
637   res->url = strdup(url);
638   return res;
639 }
640
641 /* Returns nonzero if hex_digest is properly formatted; that is each
642    letter is in [0-9A-Za-z] and the length of the string equals to the
643    result length of digest * 2. */
644 static int check_hex_digest(const char *hex_digest,
645                             const metalink_digest_def *digest_def)
646 {
647   size_t i;
648   for(i = 0; hex_digest[i]; ++i) {
649     char c = hex_digest[i];
650     if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
651          ('A' <= c && c <= 'Z'))) {
652       return 0;
653     }
654   }
655   return digest_def->dparams->digest_resultlen * 2 == i;
656 }
657
658 static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
659 {
660   metalinkfile *f;
661   f = (metalinkfile*)malloc(sizeof(metalinkfile));
662   f->next = NULL;
663   f->filename = strdup(fileinfo->name);
664   f->checksum = NULL;
665   f->resource = NULL;
666   if(fileinfo->checksums) {
667     const metalink_digest_alias *digest_alias;
668     for(digest_alias = digest_aliases; digest_alias->alias_name;
669         ++digest_alias) {
670       metalink_checksum_t **p;
671       for(p = fileinfo->checksums; *p; ++p) {
672         if(Curl_raw_equal(digest_alias->alias_name, (*p)->type) &&
673            check_hex_digest((*p)->hash, digest_alias->digest_def)) {
674           f->checksum =
675             new_metalink_checksum_from_hex_digest(digest_alias->digest_def,
676                                                   (*p)->hash);
677           break;
678         }
679       }
680       if(f->checksum) {
681         break;
682       }
683     }
684   }
685   if(fileinfo->resources) {
686     metalink_resource_t **p;
687     metalink_resource root, *tail;
688     root.next = NULL;
689     tail = &root;
690     for(p = fileinfo->resources; *p; ++p) {
691       metalink_resource *res;
692       /* Filter by type if it is non-NULL. In Metalink v3, type
693          includes the type of the resource. In curl, we are only
694          interested in HTTP, HTTPS and FTP. In addition to them,
695          Metalink v3 file may contain bittorrent type URL, which
696          points to the BitTorrent metainfo file. We ignore it here.
697          In Metalink v4, type was deprecated and all
698          fileinfo->resources point to the target file. BitTorrent
699          metainfo file URL may be appeared in fileinfo->metaurls.
700       */
701       if((*p)->type == NULL ||
702          Curl_raw_equal((*p)->type, "http") ||
703          Curl_raw_equal((*p)->type, "https") ||
704          Curl_raw_equal((*p)->type, "ftp") ||
705          Curl_raw_equal((*p)->type, "ftps")) {
706         res = new_metalink_resource((*p)->url);
707         tail->next = res;
708         tail = res;
709       }
710     }
711     f->resource = root.next;
712   }
713   return f;
714 }
715
716 int parse_metalink(struct Configurable *config, struct OutStruct *outs,
717                    const char *metalink_url)
718 {
719   metalink_error_t r;
720   metalink_t* metalink;
721   metalink_file_t **files;
722   bool warnings = FALSE;
723
724   /* metlaink_parse_final deletes outs->metalink_parser */
725   r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
726   outs->metalink_parser = NULL;
727   if(r != 0) {
728     return -1;
729   }
730   if(metalink->files == NULL) {
731     fprintf(config->errors, "Metalink: parsing (%s) WARNING "
732             "(missing or invalid file name)\n",
733             metalink_url);
734     metalink_delete(metalink);
735     return -1;
736   }
737   for(files = metalink->files; *files; ++files) {
738     struct getout *url;
739     /* Skip an entry which has no resource. */
740     if(!(*files)->resources) {
741       fprintf(config->errors, "Metalink: parsing (%s) WARNING "
742               "(missing or invalid resource)\n",
743               metalink_url, (*files)->name);
744       continue;
745     }
746     if(config->url_get ||
747        ((config->url_get = config->url_list) != NULL)) {
748       /* there's a node here, if it already is filled-in continue to
749          find an "empty" node */
750       while(config->url_get && (config->url_get->flags & GETOUT_URL))
751         config->url_get = config->url_get->next;
752     }
753
754     /* now there might or might not be an available node to fill in! */
755
756     if(config->url_get)
757       /* existing node */
758       url = config->url_get;
759     else
760       /* there was no free node, create one! */
761       url = new_getout(config);
762
763     if(url) {
764       metalinkfile *mlfile;
765       mlfile = new_metalinkfile(*files);
766       if(!mlfile->checksum) {
767         warnings = TRUE;
768         fprintf(config->errors, "Metalink: parsing (%s) WARNING "
769                 "(digest missing)\n",
770                 metalink_url);
771       }
772       /* Set name as url */
773       GetStr(&url->url, mlfile->filename);
774
775       /* set flag metalink here */
776       url->flags |= GETOUT_URL | GETOUT_METALINK;
777
778       if(config->metalinkfile_list) {
779         config->metalinkfile_last->next = mlfile;
780         config->metalinkfile_last = mlfile;
781       }
782       else {
783         config->metalinkfile_list = config->metalinkfile_last = mlfile;
784       }
785     }
786   }
787   metalink_delete(metalink);
788   return (warnings) ? -2 : 0;
789 }
790
791 size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
792                          void *userdata)
793 {
794   struct OutStruct *outs = userdata;
795   struct Configurable *config = outs->config;
796   int rv;
797
798   /*
799    * Once that libcurl has called back tool_write_cb() the returned value
800    * is checked against the amount that was intended to be written, if
801    * it does not match then it fails with CURLE_WRITE_ERROR. So at this
802    * point returning a value different from sz*nmemb indicates failure.
803    */
804   const size_t failure = (sz * nmemb) ? 0 : 1;
805
806   if(!config)
807     return failure;
808
809   rv = metalink_parse_update(outs->metalink_parser, buffer, sz *nmemb);
810   if(rv == 0)
811     return sz * nmemb;
812   else {
813     fprintf(config->errors, "Metalink: parsing FAILED\n");
814     return failure;
815   }
816 }
817
818 /*
819  * Returns nonzero if content_type includes mediatype.
820  */
821 static int check_content_type(const char *content_type, const char *media_type)
822 {
823   const char *ptr = content_type;
824   size_t media_type_len = strlen(media_type);
825   for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
826   if(!*ptr) {
827     return 0;
828   }
829   return Curl_raw_nequal(ptr, media_type, media_type_len) &&
830     (*(ptr+media_type_len) == '\0' || *(ptr+media_type_len) == ' ' ||
831      *(ptr+media_type_len) == '\t' || *(ptr+media_type_len) == ';');
832 }
833
834 int check_metalink_content_type(const char *content_type)
835 {
836   return check_content_type(content_type, "application/metalink+xml");
837 }
838
839 int count_next_metalink_resource(metalinkfile *mlfile)
840 {
841   int count = 0;
842   metalink_resource *res;
843   for(res = mlfile->resource; res; res = res->next, ++count);
844   return count;
845 }
846
847 static void delete_metalink_checksum(metalink_checksum *chksum)
848 {
849   if(chksum == NULL) {
850     return;
851   }
852   Curl_safefree(chksum->digest);
853   Curl_safefree(chksum);
854 }
855
856 static void delete_metalink_resource(metalink_resource *res)
857 {
858   if(res == NULL) {
859     return;
860   }
861   Curl_safefree(res->url);
862   Curl_safefree(res);
863 }
864
865 static void delete_metalinkfile(metalinkfile *mlfile)
866 {
867   metalink_resource *res;
868   if(mlfile == NULL) {
869     return;
870   }
871   Curl_safefree(mlfile->filename);
872   delete_metalink_checksum(mlfile->checksum);
873   for(res = mlfile->resource; res;) {
874     metalink_resource *next;
875     next = res->next;
876     delete_metalink_resource(res);
877     res = next;
878   }
879   Curl_safefree(mlfile);
880 }
881
882 void clean_metalink(struct Configurable *config)
883 {
884   while(config->metalinkfile_list) {
885     metalinkfile *mlfile = config->metalinkfile_list;
886     config->metalinkfile_list = config->metalinkfile_list->next;
887     delete_metalinkfile(mlfile);
888   }
889   config->metalinkfile_last = 0;
890 }
891
892 void metalink_cleanup(void)
893 {
894 #if defined(USE_NSS) && defined(HAVE_NSS_INITCONTEXT)
895   if(nss_context) {
896     NSS_ShutdownContext(nss_context);
897     nss_context = NULL;
898   }
899 #endif
900 }
901
902 #endif /* USE_METALINK */