]> sjero.net Git - wget/blob - src/recur.c
[svn] New function schemes_are_similar_p to test enumerated scheme codes for
[wget] / src / recur.c
1 /* Handling of recursive HTTP retrieving.
2    Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 GNU Wget 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
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #ifdef HAVE_STRING_H
25 # include <string.h>
26 #else
27 # include <strings.h>
28 #endif /* HAVE_STRING_H */
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif /* HAVE_UNISTD_H */
32 #include <errno.h>
33 #include <assert.h>
34 #include <sys/types.h>
35
36 #include "wget.h"
37 #include "url.h"
38 #include "recur.h"
39 #include "utils.h"
40 #include "retr.h"
41 #include "ftp.h"
42 #include "fnmatch.h"
43 #include "host.h"
44 #include "hash.h"
45 #include "res.h"
46
47 #ifndef errno
48 extern int errno;
49 #endif
50
51 extern char *version_string;
52
53 static struct hash_table *dl_file_url_map;
54 static struct hash_table *dl_url_file_map;
55
56 /* List of HTML files downloaded in this Wget run, used for link
57    conversion after Wget is done.  The list and the set contain the
58    same information, except the list maintains the order.  Perhaps I
59    should get rid of the list, it's there for historical reasons.  */
60 static slist *downloaded_html_list;
61 static struct hash_table *downloaded_html_set;
62
63 static void register_delete_file PARAMS ((const char *));
64 \f
65 /* Functions for maintaining the URL queue.  */
66
67 struct queue_element {
68   const char *url;
69   const char *referer;
70   int depth;
71   struct queue_element *next;
72 };
73
74 struct url_queue {
75   struct queue_element *head;
76   struct queue_element *tail;
77   int count, maxcount;
78 };
79
80 /* Create a URL queue. */
81
82 static struct url_queue *
83 url_queue_new (void)
84 {
85   struct url_queue *queue = xmalloc (sizeof (*queue));
86   memset (queue, '\0', sizeof (*queue));
87   return queue;
88 }
89
90 /* Delete a URL queue. */
91
92 static void
93 url_queue_delete (struct url_queue *queue)
94 {
95   xfree (queue);
96 }
97
98 /* Enqueue a URL in the queue.  The queue is FIFO: the items will be
99    retrieved ("dequeued") from the queue in the order they were placed
100    into it.  */
101
102 static void
103 url_enqueue (struct url_queue *queue,
104              const char *url, const char *referer, int depth)
105 {
106   struct queue_element *qel = xmalloc (sizeof (*qel));
107   qel->url = url;
108   qel->referer = referer;
109   qel->depth = depth;
110   qel->next = NULL;
111
112   ++queue->count;
113   if (queue->count > queue->maxcount)
114     queue->maxcount = queue->count;
115
116   DEBUGP (("Enqueuing %s at depth %d\n", url, depth));
117   DEBUGP (("Queue count %d, maxcount %d.\n", queue->count, queue->maxcount));
118
119   if (queue->tail)
120     queue->tail->next = qel;
121   queue->tail = qel;
122
123   if (!queue->head)
124     queue->head = queue->tail;
125 }
126
127 /* Take a URL out of the queue.  Return 1 if this operation succeeded,
128    or 0 if the queue is empty.  */
129
130 static int
131 url_dequeue (struct url_queue *queue,
132              const char **url, const char **referer, int *depth)
133 {
134   struct queue_element *qel = queue->head;
135
136   if (!qel)
137     return 0;
138
139   queue->head = queue->head->next;
140   if (!queue->head)
141     queue->tail = NULL;
142
143   *url = qel->url;
144   *referer = qel->referer;
145   *depth = qel->depth;
146
147   --queue->count;
148
149   DEBUGP (("Dequeuing %s at depth %d\n", qel->url, qel->depth));
150   DEBUGP (("Queue count %d, maxcount %d.\n", queue->count, queue->maxcount));
151
152   xfree (qel);
153   return 1;
154 }
155 \f
156 static int download_child_p PARAMS ((const struct urlpos *, struct url *, int,
157                                      struct url *, struct hash_table *));
158 static int descend_redirect_p PARAMS ((const char *, const char *, int,
159                                        struct url *, struct hash_table *));
160
161
162 /* Retrieve a part of the web beginning with START_URL.  This used to
163    be called "recursive retrieval", because the old function was
164    recursive and implemented depth-first search.  retrieve_tree on the
165    other hand implements breadth-search traversal of the tree, which
166    results in much nicer ordering of downloads.
167
168    The algorithm this function uses is simple:
169
170    1. put START_URL in the queue.
171    2. while there are URLs in the queue:
172
173      3. get next URL from the queue.
174      4. download it.
175      5. if the URL is HTML and its depth does not exceed maximum depth,
176         get the list of URLs embedded therein.
177      6. for each of those URLs do the following:
178
179        7. if the URL is not one of those downloaded before, and if it
180           satisfies the criteria specified by the various command-line
181           options, add it to the queue. */
182
183 uerr_t
184 retrieve_tree (const char *start_url)
185 {
186   uerr_t status = RETROK;
187
188   /* The queue of URLs we need to load. */
189   struct url_queue *queue;
190
191   /* The URLs we do not wish to enqueue, because they are already in
192      the queue, but haven't been downloaded yet.  */
193   struct hash_table *blacklist;
194
195   int up_error_code;
196   struct url *start_url_parsed = url_parse (start_url, &up_error_code);
197
198   if (!start_url_parsed)
199     {
200       logprintf (LOG_NOTQUIET, "%s: %s.\n", start_url,
201                  url_error (up_error_code));
202       return URLERROR;
203     }
204
205   queue = url_queue_new ();
206   blacklist = make_string_hash_table (0);
207
208   /* Enqueue the starting URL.  Use start_url_parsed->url rather than
209      just URL so we enqueue the canonical form of the URL.  */
210   url_enqueue (queue, xstrdup (start_url_parsed->url), NULL, 0);
211   string_set_add (blacklist, start_url_parsed->url);
212
213   while (1)
214     {
215       int descend = 0;
216       char *url, *referer, *file = NULL;
217       int depth;
218       boolean dash_p_leaf_HTML = FALSE;
219
220       if (downloaded_exceeds_quota ())
221         break;
222       if (status == FWRITEERR)
223         break;
224
225       /* Get the next URL from the queue... */
226
227       if (!url_dequeue (queue,
228                         (const char **)&url, (const char **)&referer,
229                         &depth))
230         break;
231
232       /* ...and download it.  Note that this download is in most cases
233          unconditional, as download_child_p already makes sure a file
234          doesn't get enqueued twice -- and yet this check is here, and
235          not in download_child_p.  This is so that if you run `wget -r
236          URL1 URL2', and a random URL is encountered once under URL1
237          and again under URL2, but at a different (possibly smaller)
238          depth, we want the URL's children to be taken into account
239          the second time.  */
240       if (dl_url_file_map && hash_table_contains (dl_url_file_map, url))
241         {
242           file = xstrdup (hash_table_get (dl_url_file_map, url));
243
244           DEBUGP (("Already downloaded \"%s\", reusing it from \"%s\".\n",
245                    url, file));
246
247           if (string_set_contains (downloaded_html_set, file))
248             descend = 1;
249         }
250       else
251         {
252           int dt = 0;
253           char *redirected = NULL;
254           int oldrec = opt.recursive;
255
256           opt.recursive = 0;
257           status = retrieve_url (url, &file, &redirected, referer, &dt);
258           opt.recursive = oldrec;
259
260           if (file && status == RETROK
261               && (dt & RETROKF) && (dt & TEXTHTML))
262             descend = 1;
263
264           if (redirected)
265             {
266               /* We have been redirected, possibly to another host, or
267                  different path, or wherever.  Check whether we really
268                  want to follow it.  */
269               if (descend)
270                 {
271                   if (!descend_redirect_p (redirected, url, depth,
272                                            start_url_parsed, blacklist))
273                     descend = 0;
274                   else
275                     /* Make sure that the old pre-redirect form gets
276                        blacklisted. */
277                     string_set_add (blacklist, url);
278                 }
279
280               xfree (url);
281               url = redirected;
282             }
283         }
284
285       if (descend
286           && depth >= opt.reclevel && opt.reclevel != INFINITE_RECURSION)
287         {
288           if (opt.page_requisites
289               && (depth == opt.reclevel || depth == opt.reclevel + 1))
290             {
291               /* When -p is specified, we are allowed to exceed the
292                  maximum depth, but only for the "inline" links,
293                  i.e. those that are needed to display the page.
294                  Originally this could exceed the depth at most by
295                  one, but we allow one more level so that the leaf
296                  pages that contain frames can be loaded
297                  correctly.  */
298               dash_p_leaf_HTML = TRUE;
299             }
300           else
301             {
302               /* Either -p wasn't specified or it was and we've
303                  already spent the two extra (pseudo-)levels that it
304                  affords us, so we need to bail out. */
305               DEBUGP (("Not descending further; at depth %d, max. %d.\n",
306                        depth, opt.reclevel));
307               descend = 0;
308             }
309         }
310
311       /* If the downloaded document was HTML, parse it and enqueue the
312          links it contains. */
313
314       if (descend)
315         {
316           int meta_disallow_follow = 0;
317           struct urlpos *children
318             = get_urls_html (file, url, &meta_disallow_follow);
319
320           if (opt.use_robots && meta_disallow_follow)
321             {
322               free_urlpos (children);
323               children = NULL;
324             }
325
326           if (children)
327             {
328               struct urlpos *child = children;
329               struct url *url_parsed = url_parsed = url_parse (url, NULL);
330               assert (url_parsed != NULL);
331
332               for (; child; child = child->next)
333                 {
334                   if (child->ignore_when_downloading)
335                     continue;
336                   if (dash_p_leaf_HTML && !child->link_inline_p)
337                     continue;
338                   if (download_child_p (child, url_parsed, depth, start_url_parsed,
339                                         blacklist))
340                     {
341                       url_enqueue (queue, xstrdup (child->url->url),
342                                    xstrdup (url), depth + 1);
343                       /* We blacklist the URL we have enqueued, because we
344                          don't want to enqueue (and hence download) the
345                          same URL twice.  */
346                       string_set_add (blacklist, child->url->url);
347                     }
348                 }
349
350               url_free (url_parsed);
351               free_urlpos (children);
352             }
353         }
354
355       if (opt.delete_after || (file && !acceptable (file)))
356         {
357           /* Either --delete-after was specified, or we loaded this
358              otherwise rejected (e.g. by -R) HTML file just so we
359              could harvest its hyperlinks -- in either case, delete
360              the local file. */
361           DEBUGP (("Removing file due to %s in recursive_retrieve():\n",
362                    opt.delete_after ? "--delete-after" :
363                    "recursive rejection criteria"));
364           logprintf (LOG_VERBOSE,
365                      (opt.delete_after
366                       ? _("Removing %s.\n")
367                       : _("Removing %s since it should be rejected.\n")),
368                      file);
369           if (unlink (file))
370             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
371           register_delete_file (file);
372         }
373
374       xfree (url);
375       FREE_MAYBE (referer);
376       FREE_MAYBE (file);
377     }
378
379   /* If anything is left of the queue due to a premature exit, free it
380      now.  */
381   {
382     char *d1, *d2;
383     int d3;
384     while (url_dequeue (queue, (const char **)&d1, (const char **)&d2, &d3))
385       {
386         xfree (d1);
387         FREE_MAYBE (d2);
388       }
389   }
390   url_queue_delete (queue);
391
392   if (start_url_parsed)
393     url_free (start_url_parsed);
394   string_set_free (blacklist);
395
396   if (downloaded_exceeds_quota ())
397     return QUOTEXC;
398   else if (status == FWRITEERR)
399     return FWRITEERR;
400   else
401     return RETROK;
402 }
403
404 /* Based on the context provided by retrieve_tree, decide whether a
405    URL is to be descended to.  This is only ever called from
406    retrieve_tree, but is in a separate function for clarity.
407
408    The most expensive checks (such as those for robots) are memoized
409    by storing these URLs to BLACKLIST.  This may or may not help.  It
410    will help if those URLs are encountered many times.  */
411
412 static int
413 download_child_p (const struct urlpos *upos, struct url *parent, int depth,
414                   struct url *start_url_parsed, struct hash_table *blacklist)
415 {
416   struct url *u = upos->url;
417   const char *url = u->url;
418   int u_scheme_like_http;
419
420   DEBUGP (("Deciding whether to enqueue \"%s\".\n", url));
421
422   if (string_set_contains (blacklist, url))
423     {
424       DEBUGP (("Already on the black list.\n"));
425       goto out;
426     }
427
428   /* Several things to check for:
429      1. if scheme is not http, and we don't load it
430      2. check for relative links (if relative_only is set)
431      3. check for domain
432      4. check for no-parent
433      5. check for excludes && includes
434      6. check for suffix
435      7. check for same host (if spanhost is unset), with possible
436      gethostbyname baggage
437      8. check for robots.txt
438
439      Addendum: If the URL is FTP, and it is to be loaded, only the
440      domain and suffix settings are "stronger".
441
442      Note that .html files will get loaded regardless of suffix rules
443      (but that is remedied later with unlink) unless the depth equals
444      the maximum depth.
445
446      More time- and memory- consuming tests should be put later on
447      the list.  */
448
449   /* Determine whether URL under consideration has a HTTP-like scheme. */
450   u_scheme_like_http = schemes_are_similar_p (u->scheme, SCHEME_HTTP);
451
452   /* 1. Schemes other than HTTP are normally not recursed into. */
453   if (!u_scheme_like_http && !(u->scheme == SCHEME_FTP && opt.follow_ftp))
454     {
455       DEBUGP (("Not following non-HTTP schemes.\n"));
456       goto out;
457     }
458
459   /* 2. If it is an absolute link and they are not followed, throw it
460      out.  */
461   if (schemes_are_similar_p (u->scheme, SCHEME_HTTP))
462     if (opt.relative_only && !upos->link_relative_p)
463       {
464         DEBUGP (("It doesn't really look like a relative link.\n"));
465         goto out;
466       }
467
468   /* 3. If its domain is not to be accepted/looked-up, chuck it
469      out.  */
470   if (!accept_domain (u))
471     {
472       DEBUGP (("The domain was not accepted.\n"));
473       goto out;
474     }
475
476   /* 4. Check for parent directory.
477
478      If we descended to a different host or changed the scheme, ignore
479      opt.no_parent.  Also ignore it for documents needed to display
480      the parent page when in -p mode.  */
481   if (opt.no_parent
482       && schemes_are_similar_p (u->scheme, start_url_parsed->scheme)
483       && 0 == strcasecmp (u->host, start_url_parsed->host)
484       && u->port == start_url_parsed->port
485       && !(opt.page_requisites && upos->link_inline_p))
486     {
487       if (!frontcmp (start_url_parsed->dir, u->dir))
488         {
489           DEBUGP (("Going to \"%s\" would escape \"%s\" with no_parent on.\n",
490                    u->dir, start_url_parsed->dir));
491           goto out;
492         }
493     }
494
495   /* 5. If the file does not match the acceptance list, or is on the
496      rejection list, chuck it out.  The same goes for the directory
497      exclusion and inclusion lists.  */
498   if (opt.includes || opt.excludes)
499     {
500       if (!accdir (u->dir, ALLABS))
501         {
502           DEBUGP (("%s (%s) is excluded/not-included.\n", url, u->dir));
503           goto out;
504         }
505     }
506
507   /* 6. Check for acceptance/rejection rules.  We ignore these rules
508      for directories (no file name to match) and for HTML documents,
509      which might lead to other files that do need to be downloaded.
510      That is, unless we've exhausted the recursion depth anyway.  */
511   if (u->file[0] != '\0'
512       && !(has_html_suffix_p (u->file)
513            && depth != INFINITE_RECURSION
514            && depth < opt.reclevel - 1))
515     {
516       if (!acceptable (u->file))
517         {
518           DEBUGP (("%s (%s) does not match acc/rej rules.\n",
519                    url, u->file));
520           goto out;
521         }
522     }
523
524   /* 7. */
525   if (schemes_are_similar_p (u->scheme, parent->scheme))
526     if (!opt.spanhost && 0 != strcasecmp (parent->host, u->host))
527       {
528         DEBUGP (("This is not the same hostname as the parent's (%s and %s).\n",
529                  u->host, parent->host));
530         goto out;
531       }
532
533   /* 8. */
534   if (opt.use_robots && u_scheme_like_http)
535     {
536       struct robot_specs *specs = res_get_specs (u->host, u->port);
537       if (!specs)
538         {
539           char *rfile;
540           if (res_retrieve_file (url, &rfile))
541             {
542               specs = res_parse_from_file (rfile);
543               xfree (rfile);
544             }
545           else
546             {
547               /* If we cannot get real specs, at least produce
548                  dummy ones so that we can register them and stop
549                  trying to retrieve them.  */
550               specs = res_parse ("", 0);
551             }
552           res_register_specs (u->host, u->port, specs);
553         }
554
555       /* Now that we have (or don't have) robots.txt specs, we can
556          check what they say.  */
557       if (!res_match_path (specs, u->path))
558         {
559           DEBUGP (("Not following %s because robots.txt forbids it.\n", url));
560           string_set_add (blacklist, url);
561           goto out;
562         }
563     }
564
565   /* The URL has passed all the tests.  It can be placed in the
566      download queue. */
567   DEBUGP (("Decided to load it.\n"));
568
569   return 1;
570
571  out:
572   DEBUGP (("Decided NOT to load it.\n"));
573
574   return 0;
575 }
576
577 /* This function determines whether we will consider downloading the
578    children of a URL whose download resulted in a redirection,
579    possibly to another host, etc.  It is needed very rarely, and thus
580    it is merely a simple-minded wrapper around download_child_p.  */
581
582 static int
583 descend_redirect_p (const char *redirected, const char *original, int depth,
584                     struct url *start_url_parsed, struct hash_table *blacklist)
585 {
586   struct url *orig_parsed, *new_parsed;
587   struct urlpos *upos;
588   int success;
589
590   orig_parsed = url_parse (original, NULL);
591   assert (orig_parsed != NULL);
592
593   new_parsed = url_parse (redirected, NULL);
594   assert (new_parsed != NULL);
595
596   upos = xmalloc (sizeof (struct urlpos));
597   memset (upos, 0, sizeof (*upos));
598   upos->url = new_parsed;
599
600   success = download_child_p (upos, orig_parsed, depth,
601                               start_url_parsed, blacklist);
602
603   url_free (orig_parsed);
604   url_free (new_parsed);
605   xfree (upos);
606
607   if (!success)
608     DEBUGP (("Redirection \"%s\" failed the test.\n", redirected));
609
610   return success;
611 }
612
613 \f
614 #define ENSURE_TABLES_EXIST do {                        \
615   if (!dl_file_url_map)                                 \
616     dl_file_url_map = make_string_hash_table (0);       \
617   if (!dl_url_file_map)                                 \
618     dl_url_file_map = make_string_hash_table (0);       \
619 } while (0)
620
621 /* Return 1 if S1 and S2 are the same, except for "/index.html".  The
622    three cases in which it returns one are (substitute any substring
623    for "foo"):
624
625    m("foo/index.html", "foo/")  ==> 1
626    m("foo/", "foo/index.html")  ==> 1
627    m("foo", "foo/index.html")   ==> 1
628    m("foo", "foo/"              ==> 1
629    m("foo", "foo")              ==> 1  */
630
631 static int
632 match_except_index (const char *s1, const char *s2)
633 {
634   int i;
635   const char *lng;
636
637   /* Skip common substring. */
638   for (i = 0; *s1 && *s2 && *s1 == *s2; s1++, s2++, i++)
639     ;
640   if (i == 0)
641     /* Strings differ at the very beginning -- bail out.  We need to
642        check this explicitly to avoid `lng - 1' reading outside the
643        array.  */
644     return 0;
645
646   if (!*s1 && !*s2)
647     /* Both strings hit EOF -- strings are equal. */
648     return 1;
649   else if (*s1 && *s2)
650     /* Strings are randomly different, e.g. "/foo/bar" and "/foo/qux". */
651     return 0;
652   else if (*s1)
653     /* S1 is the longer one. */
654     lng = s1;
655   else
656     /* S2 is the longer one. */
657     lng = s2;
658
659   /* foo            */            /* foo/           */
660   /* foo/index.html */  /* or */  /* foo/index.html */
661   /*    ^           */            /*     ^          */
662
663   if (*lng != '/')
664     /* The right-hand case. */
665     --lng;
666
667   if (*lng == '/' && *(lng + 1) == '\0')
668     /* foo  */
669     /* foo/ */
670     return 1;
671
672   return 0 == strcmp (lng, "/index.html");
673 }
674
675 static int
676 dissociate_urls_from_file_mapper (void *key, void *value, void *arg)
677 {
678   char *mapping_url = (char *)key;
679   char *mapping_file = (char *)value;
680   char *file = (char *)arg;
681
682   if (0 == strcmp (mapping_file, file))
683     {
684       hash_table_remove (dl_url_file_map, mapping_url);
685       xfree (mapping_url);
686       xfree (mapping_file);
687     }
688
689   /* Continue mapping. */
690   return 0;
691 }
692
693 /* Remove all associations from various URLs to FILE from dl_url_file_map. */
694
695 static void
696 dissociate_urls_from_file (const char *file)
697 {
698   hash_table_map (dl_url_file_map, dissociate_urls_from_file_mapper,
699                   (char *)file);
700 }
701
702 /* Register that URL has been successfully downloaded to FILE.  This
703    is used by the link conversion code to convert references to URLs
704    to references to local files.  It is also being used to check if a
705    URL has already been downloaded.  */
706
707 void
708 register_download (const char *url, const char *file)
709 {
710   char *old_file, *old_url;
711
712   ENSURE_TABLES_EXIST;
713
714   /* With some forms of retrieval, it is possible, although not likely
715      or particularly desirable.  If both are downloaded, the second
716      download will override the first one.  When that happens,
717      dissociate the old file name from the URL.  */
718
719   if (hash_table_get_pair (dl_file_url_map, file, &old_file, &old_url))
720     {
721       if (0 == strcmp (url, old_url))
722         /* We have somehow managed to download the same URL twice.
723            Nothing to do.  */
724         return;
725
726       if (match_except_index (url, old_url)
727           && !hash_table_contains (dl_url_file_map, url))
728         /* The two URLs differ only in the "index.html" ending.  For
729            example, one is "http://www.server.com/", and the other is
730            "http://www.server.com/index.html".  Don't remove the old
731            one, just add the new one as a non-canonical entry.  */
732         goto url_only;
733
734       hash_table_remove (dl_file_url_map, file);
735       xfree (old_file);
736       xfree (old_url);
737
738       /* Remove all the URLs that point to this file.  Yes, there can
739          be more than one such URL, because we store redirections as
740          multiple entries in dl_url_file_map.  For example, if URL1
741          redirects to URL2 which gets downloaded to FILE, we map both
742          URL1 and URL2 to FILE in dl_url_file_map.  (dl_file_url_map
743          only points to URL2.)  When another URL gets loaded to FILE,
744          we want both URL1 and URL2 dissociated from it.
745
746          This is a relatively expensive operation because it performs
747          a linear search of the whole hash table, but it should be
748          called very rarely, only when two URLs resolve to the same
749          file name, *and* the "<file>.1" extensions are turned off.
750          In other words, almost never.  */
751       dissociate_urls_from_file (file);
752     }
753
754   hash_table_put (dl_file_url_map, xstrdup (file), xstrdup (url));
755
756  url_only:
757   /* A URL->FILE mapping is not possible without a FILE->URL mapping.
758      If the latter were present, it should have been removed by the
759      above `if'.  So we could write:
760
761          assert (!hash_table_contains (dl_url_file_map, url));
762
763      The above is correct when running in recursive mode where the
764      same URL always resolves to the same file.  But if you do
765      something like:
766
767          wget URL URL
768
769      then the first URL will resolve to "FILE", and the other to
770      "FILE.1".  In that case, FILE.1 will not be found in
771      dl_file_url_map, but URL will still point to FILE in
772      dl_url_file_map.  */
773   if (hash_table_get_pair (dl_url_file_map, url, &old_url, &old_file))
774     {
775       hash_table_remove (dl_url_file_map, url);
776       xfree (old_url);
777       xfree (old_file);
778     }
779
780   hash_table_put (dl_url_file_map, xstrdup (url), xstrdup (file));
781 }
782
783 /* Register that FROM has been redirected to TO.  This assumes that TO
784    is successfully downloaded and already registered using
785    register_download() above.  */
786
787 void
788 register_redirection (const char *from, const char *to)
789 {
790   char *file;
791
792   ENSURE_TABLES_EXIST;
793
794   file = hash_table_get (dl_url_file_map, to);
795   assert (file != NULL);
796   if (!hash_table_contains (dl_url_file_map, from))
797     hash_table_put (dl_url_file_map, xstrdup (from), xstrdup (file));
798 }
799
800 /* Register that the file has been deleted. */
801
802 static void
803 register_delete_file (const char *file)
804 {
805   char *old_url, *old_file;
806
807   ENSURE_TABLES_EXIST;
808
809   if (!hash_table_get_pair (dl_file_url_map, file, &old_file, &old_url))
810     return;
811
812   hash_table_remove (dl_file_url_map, file);
813   xfree (old_file);
814   xfree (old_url);
815   dissociate_urls_from_file (file);
816 }
817
818 /* Register that FILE is an HTML file that has been downloaded. */
819
820 void
821 register_html (const char *url, const char *file)
822 {
823   if (!downloaded_html_set)
824     downloaded_html_set = make_string_hash_table (0);
825   else if (hash_table_contains (downloaded_html_set, file))
826     return;
827
828   /* The set and the list should use the same copy of FILE, but the
829      slist interface insists on strduping the string it gets.  Oh
830      well. */
831   string_set_add (downloaded_html_set, file);
832   downloaded_html_list = slist_prepend (downloaded_html_list, file);
833 }
834
835 /* This function is called when the retrieval is done to convert the
836    links that have been downloaded.  It has to be called at the end of
837    the retrieval, because only then does Wget know conclusively which
838    URLs have been downloaded, and which not, so it can tell which
839    direction to convert to.
840
841    The "direction" means that the URLs to the files that have been
842    downloaded get converted to the relative URL which will point to
843    that file.  And the other URLs get converted to the remote URL on
844    the server.
845
846    All the downloaded HTMLs are kept in downloaded_html_files, and
847    downloaded URLs in urls_downloaded.  All the information is
848    extracted from these two lists.  */
849
850 void
851 convert_all_links (void)
852 {
853   slist *html;
854   long msecs;
855   int file_count = 0;
856
857   struct wget_timer *timer = wtimer_new ();
858
859   /* Destructively reverse downloaded_html_files to get it in the right order.
860      recursive_retrieve() used slist_prepend() consistently.  */
861   downloaded_html_list = slist_nreverse (downloaded_html_list);
862
863   for (html = downloaded_html_list; html; html = html->next)
864     {
865       struct urlpos *urls, *cur_url;
866       char *url;
867       char *file = html->string;
868
869       /* Determine the URL of the HTML file.  get_urls_html will need
870          it.  */
871       url = hash_table_get (dl_file_url_map, file);
872       if (!url)
873         {
874           DEBUGP (("Apparently %s has been removed.\n", file));
875           continue;
876         }
877
878       DEBUGP (("Scanning %s (from %s)\n", file, url));
879
880       /* Parse the HTML file...  */
881       urls = get_urls_html (file, url, NULL);
882
883       /* We don't respect meta_disallow_follow here because, even if
884          the file is not followed, we might still want to convert the
885          links that have been followed from other files.  */
886
887       for (cur_url = urls; cur_url; cur_url = cur_url->next)
888         {
889           char *local_name;
890           struct url *u = cur_url->url;
891
892           if (cur_url->link_base_p)
893             {
894               /* Base references have been resolved by our parser, so
895                  we turn the base URL into an empty string.  (Perhaps
896                  we should remove the tag entirely?)  */
897               cur_url->convert = CO_NULLIFY_BASE;
898               continue;
899             }
900
901           /* We decide the direction of conversion according to whether
902              a URL was downloaded.  Downloaded URLs will be converted
903              ABS2REL, whereas non-downloaded will be converted REL2ABS.  */
904           local_name = hash_table_get (dl_url_file_map, u->url);
905
906           /* Decide on the conversion type.  */
907           if (local_name)
908             {
909               /* We've downloaded this URL.  Convert it to relative
910                  form.  We do this even if the URL already is in
911                  relative form, because our directory structure may
912                  not be identical to that on the server (think `-nd',
913                  `--cut-dirs', etc.)  */
914               cur_url->convert = CO_CONVERT_TO_RELATIVE;
915               cur_url->local_name = xstrdup (local_name);
916               DEBUGP (("will convert url %s to local %s\n", u->url, local_name));
917             }
918           else
919             {
920               /* We haven't downloaded this URL.  If it's not already
921                  complete (including a full host name), convert it to
922                  that form, so it can be reached while browsing this
923                  HTML locally.  */
924               if (!cur_url->link_complete_p)
925                 cur_url->convert = CO_CONVERT_TO_COMPLETE;
926               cur_url->local_name = NULL;
927               DEBUGP (("will convert url %s to complete\n", u->url));
928             }
929         }
930
931       /* Convert the links in the file.  */
932       convert_links (file, urls);
933       ++file_count;
934
935       /* Free the data.  */
936       free_urlpos (urls);
937     }
938
939   msecs = wtimer_elapsed (timer);
940   wtimer_delete (timer);
941   logprintf (LOG_VERBOSE, _("Converted %d files in %.2f seconds.\n"),
942              file_count, (double)msecs / 1000);
943 }
944
945 /* Cleanup the data structures associated with recursive retrieving
946    (the variables above).  */
947 void
948 recursive_cleanup (void)
949 {
950   if (dl_file_url_map)
951     {
952       free_keys_and_values (dl_file_url_map);
953       hash_table_destroy (dl_file_url_map);
954       dl_file_url_map = NULL;
955     }
956   if (dl_url_file_map)
957     {
958       free_keys_and_values (dl_url_file_map);
959       hash_table_destroy (dl_url_file_map);
960       dl_url_file_map = NULL;
961     }
962   if (downloaded_html_set)
963     string_set_free (downloaded_html_set);
964   slist_free (downloaded_html_list);
965   downloaded_html_list = NULL;
966 }