From 86c3bd9d5ae58ae2ca850785ca50296018a30b71 Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Sat, 24 Dec 2022 17:34:42 +0200
Subject: [PATCH 32/32] Use libcurl mime API when available

See osdn #46345

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 INSTALL                          |  6 +++--
 configure.ac                     | 12 ++++++----
 gen_headers/meson_fc_config.h.in |  3 +++
 meson.build                      | 14 ++++++++++--
 utility/netfile.c                | 38 +++++++++++++++++++++++++++++---
 5 files changed, 62 insertions(+), 11 deletions(-)

diff --git a/INSTALL b/INSTALL
index 9445482555..ef196f8be1 100644
--- a/INSTALL
+++ b/INSTALL
@@ -4,7 +4,7 @@ Installing Freeciv:
 
 This file describes how to compile and install Freeciv. Last time we
 made sure this file is up to date was 16-Jul-06.
-Last minor update was 08-Dec-22.
+Last minor update was 24-Dec-22.
 
 There may be a localized version of this file in the ./doc directory,
 named INSTALL.<locale> (e.g., INSTALL.de).
@@ -70,7 +70,9 @@ out whether your system is suitable.  If in doubt, just try it.
 
  - libtool version 2.2 or better
 
- - libcurl version 7.15.4 or better
+ - libcurl;
+   - For autotools based builds version 7.15.4 or better
+   - For meson based builds 7.56.0 or better
 
    Libcurl takes care of http communication with the metaserver, and
    file transfers of modpack installers
diff --git a/configure.ac b/configure.ac
index 96fa0a6d10..b173624688 100644
--- a/configure.ac
+++ b/configure.ac
@@ -683,10 +683,14 @@ if test "x$PKG_CONFIG" = "x" ; then
 fi
 
 if test "x$emscripten" != "xyes" ; then
-  PKG_CHECK_MODULES([CURL], [libcurl >= 7.15.4],,
-      [AC_MSG_ERROR([libcurl development files required])])
-  UTILITY_CFLAGS="${UTILITY_CFLAGS} ${CURL_CFLAGS}"
-  UTILITY_LIBS="${UTILITY_LIBS} ${CURL_LIBS}"
+  PKG_CHECK_MODULES([CURL_MIME_API], [libcurl > 7.56.0],
+    [UTILITY_CFLAGS="${UTILITY_CFLAGS} ${CURL_MIME_API_CFLAGS}"
+     UTILITY_LIBS="${UTILITY_LIBS} ${CURL_MIME_API_LIBS}"
+     AC_DEFINE([HAVE_CURL_MIME_API], [1], [libcurl has the mime api])],
+    [PKG_CHECK_MODULES([CURL], [libcurl >= 7.15.4],
+      [UTILITY_CFLAGS="${UTILITY_CFLAGS} ${CURL_CFLAGS}"
+       UTILITY_LIBS="${UTILITY_LIBS} ${CURL_LIBS}"],
+      [AC_MSG_ERROR([libcurl development files required])])])
 fi
 
 AC_ARG_ENABLE([xml-registry],
diff --git a/gen_headers/meson_fc_config.h.in b/gen_headers/meson_fc_config.h.in
index e0b309e5da..a7b18e211b 100644
--- a/gen_headers/meson_fc_config.h.in
+++ b/gen_headers/meson_fc_config.h.in
@@ -392,5 +392,8 @@
 #define NONBLOCKING_SOCKETS 1
 #endif
 
+/* Libcurl has the mime API */
+#mesondefine HAVE_CURL_MIME_API
+
 /* Custom path to CA cert bundle */
 #mesondefine CUSTOM_CACERT_PATH
diff --git a/meson.build b/meson.build
index b728951731..f8574314c3 100644
--- a/meson.build
+++ b/meson.build
@@ -596,6 +596,17 @@ endif
 sqlite3_dep = c_compiler.find_library('sqlite3', dirs: cross_lib_path)
 m_dep = c_compiler.find_library('m', dirs: cross_lib_path)
 
+curl_dep = c_compiler.find_library('curl', dirs: cross_lib_path)
+
+if c_compiler.compiles(net_incl + '''
+#include <stddef.h>
+#include <curl/curl.h>
+int main(void) { curl_mime *mime = curl_mime_init(NULL); }''')
+  priv_conf_data.set('HAVE_CURL_MIME_API', 1)
+else
+  error('Too old libcurl version - does not support mime API')
+endif
+
 if get_option('gitrev')
   priv_conf_data.set('GITREV', 1)
 endif
@@ -910,8 +921,7 @@ common_lib = library('freeciv',
             tolua_com_a, tolua_com_z, tolua_game, tolua_signal],
   link_whole: fc_deps,
   dependencies: [c_compiler.find_library('z', dirs: cross_lib_path),
-                 c_compiler.find_library('curl', dirs: cross_lib_path),
-                 m_dep, sqlite3_dep, icu_dep,
+                 curl_dep, m_dep, sqlite3_dep, icu_dep,
                  net_dep, jansson_dep, lua_dep, lzma_dep, zstd_dep,
                  bcrypt_lib_dep, iconv_lib_dep,
                  gettext_dep, charset_dep, mw_dep,
diff --git a/utility/netfile.c b/utility/netfile.c
index b8dce3c2b7..6d46561527 100644
--- a/utility/netfile.c
+++ b/utility/netfile.c
@@ -33,8 +33,12 @@
 #include "netfile.h"
 
 struct netfile_post {
+#ifdef HAVE_CURL_MIME_API
+  curl_mime *mime;
+#else  /* HAVE_CURL_MIME_API */
   struct curl_httppost *first;
   struct curl_httppost *last;
+#endif /* HAVE_CURL_MIME_API */
 };
 
 typedef size_t (*netfile_write_cb)(char *ptr, size_t size, size_t nmemb, void *userdata);
@@ -188,7 +192,13 @@ bool netfile_download_file(const char *URL, const char *filename,
 ***********************************************************************/
 struct netfile_post *netfile_start_post(void)
 {
-  return fc_calloc(1, sizeof(struct netfile_post));
+  struct netfile_post *post = fc_calloc(1, sizeof(struct netfile_post));
+
+#ifdef HAVE_CURL_MIME_API
+  post->mime = curl_mime_init(chandle);
+#endif
+
+  return post;
 }
 
 /*******************************************************************//** 
@@ -197,10 +207,19 @@ struct netfile_post *netfile_start_post(void)
 void netfile_add_form_str(struct netfile_post *post,
                           const char *name, const char *val)
 {
+#ifdef HAVE_CURL_MIME_API
+  curl_mimepart *part;
+
+  part = curl_mime_addpart(post->mime);
+
+  curl_mime_data(part, val, CURL_ZERO_TERMINATED);
+  curl_mime_name(part, name);
+#else  /* HAVE_CURL_MIME_API */
   curl_formadd(&post->first, &post->last,
                CURLFORM_COPYNAME, name,
                CURLFORM_COPYCONTENTS, val,
                CURLFORM_END);
+#endif /* HAVE_CURL_MIME_API */
 }
 
 /*******************************************************************//** 
@@ -220,7 +239,12 @@ void netfile_add_form_int(struct netfile_post *post,
 ***********************************************************************/
 void netfile_close_post(struct netfile_post *post)
 {
+#ifdef HAVE_CURL_MIME_API
+  curl_mime_free(post->mime);
+#else  /* HAVE_CURL_MIME_API */
   curl_formfree(post->first);
+#endif /* HAVE_CURL_MIME_API */
+
   FC_FREE(post);
 }
 
@@ -228,7 +252,8 @@ void netfile_close_post(struct netfile_post *post)
   Dummy write callback used only to make sure curl's default write
   function does not get used as we don't want reply to stdout
 ***********************************************************************/
-static size_t dummy_write(void *buffer, size_t size, size_t nmemb, void *userp)
+static size_t dummy_write(void *buffer, size_t size, size_t nmemb,
+                          void *userp)
 {
   return size * nmemb;
 }
@@ -237,7 +262,8 @@ static size_t dummy_write(void *buffer, size_t size, size_t nmemb, void *userp)
   Send HTTP POST
 ***********************************************************************/
 bool netfile_send_post(const char *URL, struct netfile_post *post,
-                       FILE *reply_fp, struct netfile_write_cb_data *mem_data,
+                       FILE *reply_fp,
+                       struct netfile_write_cb_data *mem_data,
                        const char *addr)
 {
   CURLcode curlret;
@@ -250,7 +276,13 @@ bool netfile_send_post(const char *URL, struct netfile_post *post,
   headers = curl_slist_append(headers, "User-Agent: Freeciv/" VERSION_STRING);
 
   curl_easy_setopt(handle, CURLOPT_URL, URL);
+
+#ifdef HAVE_CURL_MIME_API
+  curl_easy_setopt(handle, CURLOPT_MIMEPOST, post->mime);
+#else  /* HAVE_CURL_MIME_API */
   curl_easy_setopt(handle, CURLOPT_HTTPPOST, post->first);
+#endif /* HAVE_CURL_MIME_API */
+
   if (mem_data != NULL) {
     mem_data->mem = NULL;
     mem_data->size = 0;
-- 
2.35.1