error messages, typos/omissions, and it can now actually download the .tar into cache/<GRFID>-<MD5SUM>.tar
authorTero Marttila <terom@fixme.fi>
Tue, 22 Jul 2008 18:29:06 +0300
changeset 11179 fa96e29d7187
parent 11178 aa617a8b4f34
child 11180 982e9f814f97
error messages, typos/omissions, and it can now actually download the .tar into cache/<GRFID>-<MD5SUM>.tar
.hgignore
src/fileio.cpp
src/fileio.h
src/lang/english.txt
src/network/newgrf_download.cpp
--- a/.hgignore	Sat Jul 19 01:38:52 2008 +0300
+++ b/.hgignore	Tue Jul 22 18:29:06 2008 +0300
@@ -1,7 +1,7 @@
 syntax: regexp
 
 ^objs/
-^bin/
+^bin(-server)?/
 ^Makefile(.am)?$
 \.swp$
 ^src/rev\.cpp$
--- a/src/fileio.cpp	Sat Jul 19 01:38:52 2008 +0300
+++ b/src/fileio.cpp	Tue Jul 22 18:29:06 2008 +0300
@@ -216,7 +216,8 @@
 	"scenario" PATHSEP "heightmap" PATHSEP,
 	"gm" PATHSEP,
 	"data" PATHSEP,
-	"lang" PATHSEP
+	"lang" PATHSEP,
+    "cache" PATHSEP
 };
 
 const char *_searchpaths[NUM_SEARCHPATHS];
--- a/src/fileio.h	Sat Jul 19 01:38:52 2008 +0300
+++ b/src/fileio.h	Tue Jul 22 18:29:06 2008 +0300
@@ -32,6 +32,7 @@
 	GM_DIR,        ///< Subdirectory for all music
 	DATA_DIR,      ///< Subdirectory for all data (GRFs, sample.cat, intro game)
 	LANG_DIR,      ///< Subdirectory for all translation files
+    CACHE_DIR,     ///< Subdirectory for all cache data (not user-visible)
 	NUM_SUBDIRS,   ///< Number of subdirectories
 	NO_DIRECTORY,  ///< A path without any base directory
 };
--- a/src/lang/english.txt	Sat Jul 19 01:38:52 2008 +0300
+++ b/src/lang/english.txt	Tue Jul 22 18:29:06 2008 +0300
@@ -3191,9 +3191,12 @@
 STR_NEWGRF_RESCAN_FILES_TIP                                     :{BLACK}Update the list of available NewGRF files
 STR_NEWGRF_DUPLICATE_GRFID                                      :{WHITE}Cannot add file: duplicate GRF ID
 
+STR_NEWGRF_DOWNLOAD_CAPTION                                     :{WHITE}Download NewGRF files
 STR_NEWGRF_DOWNLOAD_LIST_TIP                                    :{BLACK}A list of the NewGRF files that are missing.
 STR_NEWGRF_CHECK_AVAILABLE                                      :{BLACK}Check Available
 STR_NEWGRF_DOWNLOAD_AVAILABLE                                   :{BLACK}Download Available
+STR_NEWGRF_DOWNLOAD_CHECK_FAILED                                :{WHITE}Checking for available NewGRFs failed
+STR_NEWGRF_DOWNLOAD_CHECK_NONE                                  :{WHITE}No NewGRFs available for download
 
 STR_NEWGRF_NOT_FOUND                                            :{RED}Matching file not found
 STR_NEWGRF_DISABLED                                             :{RED}Disabled
--- a/src/network/newgrf_download.cpp	Sat Jul 19 01:38:52 2008 +0300
+++ b/src/network/newgrf_download.cpp	Tue Jul 22 18:29:06 2008 +0300
@@ -20,6 +20,7 @@
 #include "../gfx_func.h"
 #include "../querystring_gui.h"
 #include "../sortlist_type.h"
+#include "../fileio.h"
 #include "../rev.h"
 
 // XXX: ...
@@ -81,7 +82,7 @@
 /** Ask the master database about the availablity of the given NewGRFs, and update
  * the GRFConfigs that are avilable to GCS_AVAILABLE
  * @param config pointer to a linked-list of grfconfig's needed */
-static void CheckAvailableNewGRFs(GRFConfig *list)
+static int CheckAvailableNewGRFs(GRFConfig *list)
 {
     GRFConfig *c;
     int i;
@@ -93,6 +94,8 @@
     long http_code;
     char *buf_ptr;
     CURLcode err;
+    int ret = -1;
+    int found = 0;
 
     // initialize to a safe state for error handling
     curl = write_ctx.buf = NULL;
@@ -153,7 +156,7 @@
             curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, XXX)
     */            
         ||  (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1)))             // no progress meter on stdout, thx
-        ||  (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf)))  // human-readable error messages
+        ||  (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf)))  // XXX: human-readable error messages
         ||  (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_URL, api_url)))              // the URL to retrieve
         ||  (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_USERAGENT, useragent)))      // the User-agent to use
         ||  (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, query_buf)))     // the POST data
@@ -231,6 +234,9 @@
 
                 c->filename = url;
                 c->status = GCS_AVAILABLE;
+
+                found++;
+
                 break;
             } 
         }
@@ -243,6 +249,9 @@
         // move on to the next line
         buf_ptr = nl + 1;
     }
+    
+    // return number of NewGRFs found, defaults to -1 for errors
+    ret = found;    
 
 error :
     // cleanup
@@ -250,6 +259,117 @@
 
     if (curl)
         curl_easy_cleanup(curl);
+    
+    // return as defined by ret
+    return ret;
+}
+
+/** Download the NewGRFs that are listed as GCS_AVAILABLE
+ * @param config pointer to a linked-list of grfconfig's to be downloaded */
+static int DownloadAvailableNewGRFs(GRFConfig *list)
+{
+    GRFConfig *c;
+    CURL *curl = NULL;
+    CURLcode err;
+    FILE *fh = NULL;
+    char md5buf[64], filename[256], useragent[512];
+    long http_code;
+    int ret = -1;
+
+    // set up curl
+    if ((err = do_init_curl())) {
+        DEBUG(grfdl, 0, "curl_global_init failed: %s", curl_easy_strerror(err));
+        goto error;
+    }
+    
+    // allocate a new curl_easy
+    if ((curl = curl_easy_init()) == NULL) {
+        DEBUG(grfdl, 0, "curl_easy_init failed");
+        goto error;
+    }
+    
+    // our useragent
+    assert(snprintf(useragent, sizeof(useragent), NETWORK_HTTP_USER_AGENT, _openttd_revision) < 512);
+
+    // let's set some options...
+    if (
+            (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_VERBOSE, 1)))        // XXX: tie this in with OpenTTD's debug stuff
+    /*            
+            curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, XXX)
+    */            
+        ||  (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1)))             // no progress meter on stdout, thx
+//        ||  (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf)))  // human-readable error messages
+
+        ||  (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_USERAGENT, useragent)))      // the User-agent to use
+
+/*       
+        ||  (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, query_buf)))     // the POST data
+        ||  (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &check_available_write_cb)))
+*/        
+    ) {
+        DEBUG(grfdl, 0, "curl_easy_setopt failed: %s", curl_easy_strerror(err));
+        goto error;
+    }
+    
+    // then start looping through the NewGRFs to download
+    for (c = list; c != NULL; c = c->next) {
+        // skip the ones that are not available
+        if (c->status != GCS_AVAILABLE) 
+            continue;
+        
+        // format the md5sum
+        md5sumToString(md5buf, lastof(md5buf), c->md5sum);
+
+        // snprintf the entry into the query buffer
+        assert(snprintf(filename, sizeof(filename), "%08X-%32s.tar", BSWAP32(c->grfid), md5buf) < 256);
+
+        // open the file
+        if ((fh = FioFOpenFile(filename, "wb", CACHE_DIR)) == NULL) {
+            DEBUG(grfdl, 0, "Opening local GRF file failed: %s", filename);
+            goto error;
+        }
+        
+        // set up curl
+        if (
+                (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_URL, c->filename)))              // the URL to retrieve
+            ||  (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_WRITEDATA, fh)))                 // XXX: need to fwrite() ourself
+        ) {
+            DEBUG(grfdl, 0, "curl_easy_setopt failed: %s", curl_easy_strerror(err));
+            goto error;
+        }
+        
+        // XXX: currently this freezes the UI..
+        if ((err = curl_easy_perform(curl))) {
+            DEBUG(grfdl, 0, "the curl request failed: %s", curl_easy_strerror(err));
+            goto error;
+        }
+        
+        // get the HTTP return code
+        if ((err = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code))) {
+            DEBUG(grfdl, 0, "curl_easy_getinfo failed: %s", curl_easy_strerror(err));
+            goto error;
+        }
+
+        if (http_code != 200) {
+            DEBUG(grfdl, 0, "Bad HTTP response code: %d", http_code);
+            goto error;
+        }
+
+        // OK, great
+        c->status = GCS_UNKNOWN;
+    }
+
+    // success
+    ret = 0;
+
+error:
+    if (fh)
+        fclose(fh);
+    
+    if (curl)
+        curl_easy_cleanup(curl);
+
+    return ret;    
 }
 
 // XXX: copy-pasted from newgrf_gui.cpp
@@ -473,16 +593,42 @@
 
 	virtual void OnClick(Point pt, int widget)
 	{
+        int found;
+
 		switch (widget) {
             case DNGRFS_CHECK_AVAILABLE:
-                CheckAvailableNewGRFs(this->list);
+                // do the HTTP request etc.
+                found = CheckAvailableNewGRFs(this->list);
+
+                if (found < 0) {
+                    // failed
+                    ShowErrorMessage(INVALID_STRING_ID, STR_NEWGRF_DOWNLOAD_CHECK_FAILED, 0, 0);
+
+                } else if (found == 0) {
+                    // no NewGRFs found
+                    ShowErrorMessage(INVALID_STRING_ID, STR_NEWGRF_DOWNLOAD_CHECK_NONE, 0, 0);
+
+                } else {
+                    // success, flip the button enabled states
+                    this->SetWidgetDisabledState(DNGRFS_CHECK_AVAILABLE, 1);
+                    this->SetWidgetDisabledState(DNGRFS_DOWNLOAD_AVAILABLE, 0);
+                    
+                    // redraw with new status
+                    this->SetDirty();
+                }
 				
-                this->SetDirty();
 
                 break;
 
             case DNGRFS_DOWNLOAD_AVAILABLE:
-                // XXX: implement
+                // do a bunch of HTTP requests
+                found = DownloadAvailableNewGRFs(this->list);
+                
+                // disable the button, not useful anymore
+                this->SetWidgetDisabledState(DNGRFS_DOWNLOAD_AVAILABLE, 1);
+                
+                // redraw with new status
+                this->SetDirty();
 
                 break;
 
@@ -520,7 +666,7 @@
 /* Widget definition of the download newgrfs window */
 static const Widget _newgrf_download_widgets[] = {
 {   WWT_CLOSEBOX,  RESIZE_NONE, 10,   0,  10,   0,  13, STR_00C5,                    STR_018B_CLOSE_WINDOW },            // DNGRFS_CLOSEBOX
-{    WWT_CAPTION, RESIZE_RIGHT, 10,  11, 299,   0,  13, STR_NEWGRF_SETTINGS_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS },  // DNGRFS_CAPTION
+{    WWT_CAPTION, RESIZE_RIGHT, 10,  11, 299,   0,  13, STR_NEWGRF_DOWNLOAD_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS },  // DNGRFS_CAPTION
 {      WWT_PANEL, RESIZE_RIGHT, 10,   0, 299,  14,  29, STR_NULL,                    STR_NULL },                         // DNGRFS_BACKGROUND
 
     /*