]> err.no Git - mapper/blobdiff - src/map-download.c
Path: misc adjustments
[mapper] / src / map-download.c
index 14763497e61e2e78881bbd36def100226422bb15..d1505403cd0e93684d2bd72a6eb7f8d120cda9be 100644 (file)
@@ -1,6 +1,29 @@
-#include "config.h"
+/*
+ * This file is part of mapper
+ *
+ * Copyright (C) 2007 Kaj-Michael Lang
+ * Copyright (C) 2006-2007 John Costigan.
+ *
+ * POI and GPS-Info code originally written by Cezary Jackiewicz.
+ *
+ * Default map data provided by http://www.openstreetmap.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
 
-#define _GNU_SOURCE
+#include "config.h"
 
 #include <unistd.h>
 #include <stdlib.h>
 #include "hildon-mapper.h"
 
 #include "utils.h"
-#include "map.h"
 #include "osm.h"
 #include "db.h"
 #include "osm-db.h"
 #include "poi.h"
 #include "route.h"
 #include "gps.h"
-#include "bt.h"
 #include "mapper-types.h"
 #include "ui-common.h"
 #include "settings.h"
 #include "latlon.h"
-#include "gpx.h"
 #include "map-download.h"
+#include "iap.h"
+#include "map-repo.h"
+#include "gtkmap.h"
 
 static guint _num_downloads=0;
 static guint _curr_download=0;
 
+static GQueue *curl_easy_queue=NULL;
+static GTree *pui_tree=NULL;
+static GTree *downloading_tree=NULL;
+static GHashTable *pui_by_easy=NULL;
+
 static gchar *map_construct_url(guint tilex, guint tiley, guint zoom);
 
 static gboolean 
@@ -47,6 +75,33 @@ get_next_pui(gpointer key, gpointer value, ProgressUpdateInfo ** data)
 return TRUE;
 }
 
+static gint
+download_comparefunc(const ProgressUpdateInfo * a, const ProgressUpdateInfo * b, gpointer user_data)
+{
+gint diff = (a->priority - b->priority);
+if (diff)
+       return diff;
+diff = (a->tilex - b->tilex);
+if (diff)
+       return diff;
+diff = (a->tiley - b->tiley);
+if (diff)
+       return diff;
+diff = (a->zoom - b->zoom);
+if (diff)
+       return diff;
+diff = (a->repo - b->repo);
+if (diff)
+       return diff;
+/* Otherwise, deletes are "greatest" (least priority). */
+if (!a->retries)
+       return (b->retries ? -1 : 0);
+else if (!b->retries)
+       return (a->retries ? 1 : 0);
+/* Do updates after non-updates (because they'll both be done anyway). */
+return (a->retries - b->retries);
+}
+
 /**
  * Free a ProgressUpdateInfo data structure that was allocated during the
  * auto-map-download process.
@@ -75,18 +130,15 @@ while (_curl_multi && (msg = curl_multi_info_read(_curl_multi, &num_msgs))) {
                if (msg->easy_handle == _autoroute_data.curl_easy) {
                        /* This is the autoroute download. */
                        /* Now, parse the autoroute and update the display. */
-                       if (_autoroute_data.enabled && parse_gpx(&_route,
-                                        _autoroute_data.rdl_data.bytes,
-                                        _autoroute_data.rdl_data.bytes_read, 0)) {
+                       if (_autoroute_data.enabled && path_gpx_parse(_route, _autoroute_data.rdl_data.bytes, _autoroute_data.rdl_data.bytes_read, 0)) {
                                /* Find the nearest route point, if we're connected. */
-                               route_find_nearest_point();
-                               map_force_redraw();
+                               path_find_nearest_point(_route, _gps->data.lat, _gps->data.lon);
                        }
-                       cancel_autoroute(TRUE); /* We're done. Clean up. */
+                       route_cancel_autoroute(_route, TRUE);   /* We're done. Clean up. */
                } else {
-                       ProgressUpdateInfo *pui = g_hash_table_lookup(_pui_by_easy, msg->easy_handle);
-                       g_queue_push_head(_curl_easy_queue, msg->easy_handle);
-                       g_hash_table_remove(_pui_by_easy, msg->easy_handle);
+                       ProgressUpdateInfo *pui = g_hash_table_lookup(pui_by_easy, msg->easy_handle);
+                       g_queue_push_head(curl_easy_queue, msg->easy_handle);
+                       g_hash_table_remove(pui_by_easy, msg->easy_handle);
                        fclose(pui->file);
                        if (msg->data.result != CURLE_OK)
                                g_unlink(pui->dest_str);        /* Delete so we try again. */
@@ -97,27 +149,27 @@ while (_curl_multi && (msg = curl_multi_info_read(_curl_multi, &num_msgs))) {
 }
 
 /* Up to 1 transfer per tile. */
-while (num_transfers < (BUF_WIDTH_TILES * BUF_HEIGHT_TILES) && g_tree_nnodes(_pui_tree)) {
+while (num_transfers < (4*4) && g_tree_nnodes(pui_tree)) {
        ProgressUpdateInfo *pui;
-       g_tree_foreach(_pui_tree, (GTraverseFunc) get_next_pui, &pui);
+       g_tree_foreach(pui_tree, (GTraverseFunc)get_next_pui, &pui);
 
        if (pui->retries) {
                /* This is a download. */
                FILE *f;
-               g_tree_steal(_pui_tree, pui);
-               g_tree_insert(_downloading_tree, pui, pui);
+               g_tree_steal(pui_tree, pui);
+               g_tree_insert(downloading_tree, pui, pui);
 
-               pui->src_str = map_construct_url(pui->tilex, pui->tiley, pui->zoom);
-               pui->dest_str = g_strdup_printf("%s/%u/%u/%u.jpg",
-                                   pui->repo->cache_dir, pui->zoom,
-                                   pui->tilex, pui->tiley);
+               pui->src_str=map_construct_url(pui->tilex, pui->tiley, pui->zoom);
 
                if (!pui->src_str) {
                        /* Failed to generate URL. */
+                       g_debug("Failed to generate tile download URL");
                        g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_download_idle_refresh, pui, NULL);
                        continue;
                }
 
+               pui->dest_str=g_strdup_printf("%s/%u/%u/%u.jpg", pui->repo->cache_dir, pui->zoom, pui->tilex, pui->tiley);
+
                /* Check to see if we need to overwrite. */
                if (pui->retries > 0) {
                        /* We're not updating - check if file already exists. */
@@ -128,39 +180,31 @@ while (num_transfers < (BUF_WIDTH_TILES * BUF_HEIGHT_TILES) && g_tree_nnodes(_pu
                }
 
                /* Attempt to open the file for writing. */
-               if (!(f = g_fopen(pui->dest_str, "w")) && errno == ENOENT) {
+               if (!(f=g_fopen(pui->dest_str, "w")) && errno == ENOENT) {
                        /* Directory doesn't exist yet - create it, then we'll retry */
                        gchar buffer[BUFFER_SIZE];
-                       snprintf(buffer, sizeof(buffer), "%s/%u/%u",
-                                pui->repo->cache_dir, pui->zoom, pui->tilex);
+                       g_snprintf(buffer, sizeof(buffer), "%s/%u/%u", pui->repo->cache_dir, pui->zoom, pui->tilex);
                        g_mkdir_with_parents(buffer, 0775);
-                       f = g_fopen(pui->dest_str, "w");
+                       f=g_fopen(pui->dest_str, "w");
                }
 
                if (f) {
                        CURL *curl_easy;
                        pui->file = f;
-                       curl_easy = g_queue_pop_tail(_curl_easy_queue);
+                       curl_easy = g_queue_pop_tail(curl_easy_queue);
                        if (!curl_easy) {
                                /* Need a new curl_easy. */
                                MACRO_CURL_EASY_INIT(curl_easy);
                        }
                        curl_easy_setopt(curl_easy, CURLOPT_URL, pui->src_str);
                        curl_easy_setopt(curl_easy, CURLOPT_WRITEDATA, f);
-                       g_hash_table_insert(_pui_by_easy, curl_easy, pui);
-                       if (!_curl_multi) {
-                               /* Initialize CURL. */
-                               _curl_multi = curl_multi_init();
-                               /*curl_multi_setopt(_curl_multi, CURLMOPT_PIPELINING, 1); */
-                       }
+                       g_hash_table_insert(pui_by_easy, curl_easy, pui);
                        curl_multi_add_handle(_curl_multi, curl_easy);
                        num_transfers++;
                } else {
                        /* Unable to open tile file for writing. */
                        gchar buffer[BUFFER_SIZE];
-                       snprintf(buffer, sizeof(buffer), "%s:\n%s",
-                                _("Failed to open file for writing"),
-                                pui->dest_str);
+                       g_snprintf(buffer, sizeof(buffer), "%s:\n%s", _("Failed to open file for writing"), pui->dest_str);
                        MACRO_BANNER_SHOW_INFO(_window, buffer);
                        g_idle_add_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)map_download_idle_refresh, pui, NULL);
                        continue;
@@ -168,29 +212,24 @@ while (num_transfers < (BUF_WIDTH_TILES * BUF_HEIGHT_TILES) && g_tree_nnodes(_pu
        } else if (--deletes_left) {
                /* This is a delete. */
                gchar buffer[BUFFER_SIZE];
-               g_tree_steal(_pui_tree, pui);
-               g_tree_insert(_downloading_tree, pui, pui);
+               g_tree_steal(pui_tree, pui);
+               g_tree_insert(downloading_tree, pui, pui);
 
-               snprintf(buffer, sizeof(buffer), "%s/%u/%u/%u.jpg",
-                       pui->repo->cache_dir, pui->zoom, 
-                       pui->tilex,     pui->tiley);
+               g_snprintf(buffer, sizeof(buffer), "%s/%u/%u/%u.jpg", pui->repo->cache_dir, pui->zoom, pui->tilex, pui->tiley);
                g_unlink(buffer);
                g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_download_idle_refresh, pui, NULL);
        } else
                break;
 }
 
-if (!(num_transfers || g_tree_nnodes(_pui_tree))) {
+if (!(num_transfers || g_tree_nnodes(pui_tree))) {
        /* Destroy curl after 50 counts (5 seconds). */
        if (--destroy_counter) {
                /* Clean up curl. */
                CURL *curr;
-               while ((curr = g_queue_pop_tail(_curl_easy_queue)))
+               while ((curr = g_queue_pop_tail(curl_easy_queue)))
                        curl_easy_cleanup(curr);
 
-               curl_multi_cleanup(_curl_multi);
-               _curl_multi = NULL;
-
                _curl_sid = 0;
                return FALSE;
        }
@@ -200,11 +239,15 @@ if (!(num_transfers || g_tree_nnodes(_pui_tree))) {
 return TRUE;
 }
 
+#ifdef MAP_DOWNLOAD_WMS
 /**
  * Given a wms uri pattern, compute the coordinate transformation and
  * trimming.
  * 'proj' is used for the conversion
  */
+
+#define WMS_TILE_SIZE_PIXELS (256)
+
 static gchar *
 map_convert_wms_to_wms(gint tilex, gint tiley, gint zoomlevel, gchar * uri)
 {
@@ -226,22 +269,18 @@ strncpy(srs + 4, srsstr + 8, 256);
 srs[srsstre - srsstr - 4] = 0;
 /* convert to lower, as WMC is EPSG and cs2cs is epsg */
 
-gint dwidth = widthstr ? atoi(widthstr + 6) - TILE_SIZE_PIXELS : 0;
-gint dheight = heightstr ? atoi(heightstr + 7) - TILE_SIZE_PIXELS : 0;
+gint dwidth = widthstr ? atoi(widthstr + 6) - WMS_TILE_SIZE_PIXELS : 0;
+gint dheight = heightstr ? atoi(heightstr + 7) - WMS_TILE_SIZE_PIXELS : 0;
 
-unit2latlon(tile2zunit(tilex, zoomlevel)
-           - pixel2zunit(dwidth / 2, zoomlevel),
-           tile2zunit(tiley + 1, zoomlevel)
-           + pixel2zunit((dheight + 1) / 2, zoomlevel), lat1, lon1);
+unit2latlon(tile2zunit(tilex, zoomlevel) - pixel2zunit(dwidth / 2, zoomlevel),
+           tile2zunit(tiley + 1, zoomlevel) + pixel2zunit((dheight + 1) / 2, zoomlevel), &lat1, &lon1);
 
-unit2latlon(tile2zunit(tilex + 1, zoomlevel)
-           + pixel2zunit((dwidth + 1) / 2, zoomlevel),
-           tile2zunit(tiley, zoomlevel)
-           - pixel2zunit(dheight / 2, zoomlevel), lat2, lon2);
+unit2latlon(tile2zunit(tilex + 1, zoomlevel) + pixel2zunit((dwidth + 1) / 2, zoomlevel), 
+               tile2zunit(tiley, zoomlevel) - pixel2zunit(dheight / 2, zoomlevel), &lat2, &lon2);
 
 setlocale(LC_NUMERIC, "C");
 
-snprintf(cmd, sizeof(cmd),
+g_snprintf(cmd, sizeof(cmd),
         "(echo \"%.6f %.6f\"; echo \"%.6f %.6f\") | "
         "/usr/bin/cs2cs +proj=longlat +datum=WGS84 +to +init=%s -f %%.6f "
         " > /tmp/tmpcs2cs ", lon1, lat1, lon2, lat2, srs);
@@ -264,7 +303,7 @@ setlocale(LC_NUMERIC, "");
 
 return ret;
 }
-
+#endif
 
 /**
  * Given the xyz coordinates of our map coordinate system, write the qrst
@@ -301,63 +340,80 @@ map_construct_url(guint tilex, guint tiley, guint zoom)
 switch (_curr_repo->type) {
 case REPOTYPE_XYZ:
        return g_strdup_printf(_curr_repo->url, tilex, tiley, zoom);
-
 case REPOTYPE_XYZ_INV:
        return g_strdup_printf(_curr_repo->url, 17 - zoom, tilex, tiley);
-
-case REPOTYPE_QUAD_QRST:
-       {
-               gchar location[MAX_ZOOM + 2];
+case REPOTYPE_QUAD_QRST: {
+               gchar location[32];
                map_convert_coords_to_quadtree_string(tilex, tiley, zoom, location, 't', "qrts");
                return g_strdup_printf(_curr_repo->url, location);
        }
-
-case REPOTYPE_QUAD_ZERO:
-       {
+case REPOTYPE_QUAD_ZERO: {
                /* This is a zero-based quadtree URI. */
-               gchar location[MAX_ZOOM + 2];
+               gchar location[32];
                map_convert_coords_to_quadtree_string(tilex, tiley, zoom, location, '\0', "0123");
                return g_strdup_printf(_curr_repo->url, location);
        }
-
+#ifdef MAP_DOWNLOAD_WMD
 case REPOTYPE_WMS:
        return map_convert_wms_to_wms(tilex, tiley, zoom, _curr_repo->url);
-
+#endif
 default:
        return NULL;
 }
 return "";
 }
 
+void 
+map_download_progress_clear(void) 
+{
+g_assert(_progress_item);
+gtk_progress_bar_set_fraction(_progress_item, 0.0);
+gtk_progress_bar_set_text(_progress_item, "");
+}
+
+void 
+map_download_progress_set(gint currd, gint numd)
+{
+gchar buffer[64];
+
+g_assert(_progress_item);
+g_snprintf(buffer, sizeof(buffer), _("Downloading maps (%d/%d)"), currd, numd);
+gtk_progress_bar_set_text(_progress_item, buffer);     
+gtk_progress_bar_set_fraction(_progress_item, currd/(double)numd);
+}
 
 gboolean 
 map_download_idle_refresh(ProgressUpdateInfo * pui)
 {
+guint tmp=0;
 /* Test if download succeeded (only if retries != 0). */
 if (!pui->retries || g_file_test(pui->dest_str, G_FILE_TEST_EXISTS)) {
-       gint zoom_diff = pui->zoom - _zoom;
+       gint zoom_diff = pui->zoom - gtk_map_get_zoom(_map);
+
+#if 0
        /* Only refresh at same or "lower" (more detailed) zoom level. */
        if (zoom_diff >= 0) {
+               guint tilex, tiley, tilex_end, tiley_end;
+
                /* If zoom has changed since we first put in the request for
                 * this tile, then we may have to update more than one tile. */
-               guint tilex, tiley, tilex_end, tiley_end;
                for (tilex = pui->tilex << zoom_diff, tilex_end = tilex + (1 << zoom_diff); tilex < tilex_end; tilex++) {
                        for (tiley = pui->tiley << zoom_diff, tiley_end = tiley + (1 << zoom_diff); tiley < tiley_end; tiley++) {
-                               if ((tilex - _base_tilex) < BUF_WIDTH_TILES && (tiley - _base_tiley) < BUF_HEIGHT_TILES) {
-                                       map_render_tile(tilex, tiley,
-                                                       ((tilex - _base_tilex) << TILE_SIZE_P2),
-                                                       ((tiley - _base_tiley) << TILE_SIZE_P2),
-                                                       TRUE);
+                               tmp++;
+                               if (map_render_tile(tilex, tiley, ((tilex - _base_tilex) << TILE_SIZE_P2), ((tiley - _base_tiley) << TILE_SIZE_P2), TRUE)==TRUE) {
                                        map_render_data();
-                                       gtk_widget_queue_draw_area
-                                           (_map_widget,
+                                       gtk_widget_queue_draw_area(_map_widget,
                                             ((tilex - _base_tilex) << TILE_SIZE_P2) - _offsetx,
                                             ((tiley - _base_tiley) << TILE_SIZE_P2) - _offsety,
                                             TILE_SIZE_PIXELS, TILE_SIZE_PIXELS);
                                }
                        }
                }
+       g_debug("*** MDIR LOOP: %u", tmp);
        }
+#else
+       g_debug("XXX: Add cb or signal or something to inform map widget about fresh tile");
+#endif
 }
 /* Else the download failed. Update retries and maybe try again. */
 else {
@@ -368,13 +424,9 @@ else {
 
        if (pui->retries) {
                /* removal automatically calls progress_update_info_free(). */
-               g_tree_steal(_downloading_tree, pui);
-               g_tree_insert(_pui_tree, pui, pui);
-#ifdef WITH_OSSO
+               g_tree_steal(downloading_tree, pui);
+               g_tree_insert(pui_tree, pui, pui);
                if (iap_is_connected() && !_curl_sid)
-#else
-               if (!_curl_sid)
-#endif
                        _curl_sid = g_timeout_add(100,(GSourceFunc)map_download_timeout, NULL);
                /* Don't do anything else. */
                return FALSE;
@@ -385,16 +437,13 @@ else {
 }
 
 /* removal automatically calls progress_update_info_free(). */
-g_tree_remove(_downloading_tree, pui);
+g_tree_remove(downloading_tree, pui);
 
 if (++_curr_download == _num_downloads) {
-#ifdef WITH_HILDON
-       gtk_widget_destroy(_download_banner);
-       _download_banner = NULL;
-#endif
        _num_downloads = _curr_download = 0;
+       map_download_progress_clear();
 } else {
-       hildon_banner_set_fraction(HILDON_BANNER(_download_banner), _curr_download / (double)_num_downloads);
+       map_download_progress_set(_curr_download, _num_downloads);
 }
 return FALSE;
 }
@@ -409,21 +458,19 @@ map_initiate_download(guint tilex, guint tiley, guint zoom, gint retries)
 {
 ProgressUpdateInfo *pui;
 
-#ifdef WITH_OSSO
 iap_connect();
-#endif
 
 pui = g_slice_new(ProgressUpdateInfo);
 pui->tilex = tilex;
 pui->tiley = tiley;
 pui->zoom = zoom;
-pui->priority = (abs((gint) tilex - unit2tile(_center.unitx)) + abs((gint) tiley - unit2tile(_center.unity)));
+pui->priority = 1;
 if (!retries)
        pui->priority = -pui->priority; /* "Negative" makes them lowest pri. */
 pui->retries = retries;
 pui->repo = _curr_repo;
 
-if (g_tree_lookup(_pui_tree, pui) || g_tree_lookup(_downloading_tree, pui)) {
+if (g_tree_lookup(pui_tree, pui) || g_tree_lookup(downloading_tree, pui)) {
        /* Already downloading. */
        g_slice_free(ProgressUpdateInfo, pui);
        return;
@@ -432,66 +479,93 @@ pui->src_str = NULL;
 pui->dest_str = NULL;
 pui->file = NULL;
 
-g_tree_insert(_pui_tree, pui, pui);
-#ifdef WITH_OSSO
+g_tree_insert(pui_tree, pui, pui);
 if (iap_is_connected() && !_curl_sid)
-#else
-if (!_curl_sid)
-#endif
        _curl_sid = g_timeout_add(100, (GSourceFunc) map_download_timeout, NULL);
 
-if (!_num_downloads++ && !_download_banner) {
-       _download_banner = hildon_banner_show_progress(_window, NULL, _("Downloading maps..."));
-}
+if (!_num_downloads++)
+       gtk_progress_bar_set_text(_progress_item, _("Downloading maps..."));    
 }
 
 void
 map_download_init(void)
 {
-_curl_easy_queue = g_queue_new();
-_pui_tree = g_tree_new_full((GCompareDataFunc) download_comparefunc, NULL, (GDestroyNotify) progress_update_info_free, NULL);
-_downloading_tree = g_tree_new_full((GCompareDataFunc) download_comparefunc, NULL, (GDestroyNotify) progress_update_info_free, NULL);
-_pui_by_easy = g_hash_table_new(g_direct_hash, g_direct_equal);
+curl_easy_queue = g_queue_new();
+pui_tree = g_tree_new_full((GCompareDataFunc)download_comparefunc, NULL, (GDestroyNotify) progress_update_info_free, NULL);
+downloading_tree = g_tree_new_full((GCompareDataFunc)download_comparefunc, NULL, (GDestroyNotify) progress_update_info_free, NULL);
+pui_by_easy = g_hash_table_new(g_direct_hash, g_direct_equal);
+_curl_multi = curl_multi_init();
+/* curl_multi_setopt(_curl_multi, CURLMOPT_PIPELINING, 1); */
 }
 
-void
-map_download_deinit(void) 
+gboolean
+map_download_stop(void)
 {
-/* Clean up CURL. */
 if (_curl_multi) {
        CURL *curr;
        CURLMsg *msg;
-       gint num_transfers, num_msgs;
-
-       /* First, remove all downloads from _pui_tree. */
-       g_tree_destroy(_pui_tree);
+       gint num_msgs;
 
-       /* Finish up all downloads. */
-       while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(_curl_multi, &num_transfers) || num_transfers) {
-               /* XXX: should inform the user why it's taking so damn long... */
+       /* Clear the tree and create it again */
+       if (pui_tree) {
+               g_tree_destroy(pui_tree);
+               pui_tree = g_tree_new_full((GCompareDataFunc)download_comparefunc, NULL, (GDestroyNotify) progress_update_info_free, NULL);
        }
 
        /* Close all finished files. */
        while ((msg = curl_multi_info_read(_curl_multi, &num_msgs))) {
                if (msg->msg == CURLMSG_DONE) {
                        /* This is a map download. */
-                       ProgressUpdateInfo *pui = g_hash_table_lookup(_pui_by_easy, msg->easy_handle);
-                       g_queue_push_head(_curl_easy_queue, msg->easy_handle);
-                       g_hash_table_remove(_pui_by_easy, msg->easy_handle);
-                       fclose(pui->file);
+                       ProgressUpdateInfo *pui = g_hash_table_lookup(pui_by_easy, msg->easy_handle);
+                       g_queue_push_head(curl_easy_queue, msg->easy_handle);
+                       g_hash_table_remove(pui_by_easy, msg->easy_handle);
+                       if (pui->file)
+                               fclose(pui->file);
                        curl_multi_remove_handle(_curl_multi, msg->easy_handle);
                }
        }
 
-       while ((curr = g_queue_pop_tail(_curl_easy_queue)))
+       g_debug("Stopping downloads");
+       while ((curr = g_queue_pop_tail(curl_easy_queue)))
                curl_easy_cleanup(curr);
+       return TRUE;
+}
+g_debug("No downloads to stop");
+return FALSE;
+}
 
+/*
+ * Clean up CURL and structures
+ */
+void
+map_download_deinit(void) 
+{
+if (_curl_multi) {
+       CURL *curr;
+       gint num_transfers;
+
+       /* Finish up all downloads. */
+       while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(_curl_multi, &num_transfers) || num_transfers) {
+               g_debug("NT: %d", num_transfers);
+       }
+
+       /* Stop all transfers and cleanup */
+       map_download_stop();
+
+       if (pui_tree)
+               g_tree_destroy(pui_tree);
+       if (downloading_tree)
+               g_tree_destroy(downloading_tree);
+       if (pui_by_easy)
+               g_hash_table_destroy(pui_by_easy);
+       if (curl_easy_queue)
+               g_queue_free(curl_easy_queue);
        curl_multi_cleanup(_curl_multi);
        _curl_multi = NULL;
-
-       g_queue_free(_curl_easy_queue);
-       g_tree_destroy(_downloading_tree);
-       g_hash_table_destroy(_pui_by_easy);
 }
 
+if (_curl_sid) {
+    g_source_remove(_curl_sid);
+    _curl_sid = 0;
+}
 }