diff --git a/acinclude.m4 b/acinclude.m4
index f52897a1..c3b893ec 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -915,3 +915,280 @@ AC_DEFUN([AX_CFLAGS_GCC_OPTION],[ifelse(m4_bregexp([$2],[-]),-1,
 
 AC_DEFUN([AX_CXXFLAGS_GCC_OPTION],[ifelse(m4_bregexp([$2],[-]),-1,
 [AX_CXXFLAGS_GCC_OPTION_NEW($@)],[AX_CXXFLAGS_GCC_OPTION_OLD($@)])])
+
+# taken from https://github.com/curl/curl/blob/master/docs/libcurl/libcurl.m4 :
+
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) David Shaw <dshaw@jabberwocky.com>
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION],
+#                       [ACTION-IF-YES], [ACTION-IF-NO])
+# ----------------------------------------------------------
+#      David Shaw <dshaw@jabberwocky.com>   May-09-2006
+#
+# Checks for libcurl.  DEFAULT-ACTION is the string yes or no to
+# specify whether to default to --with-libcurl or --without-libcurl.
+# If not supplied, DEFAULT-ACTION is yes.  MINIMUM-VERSION is the
+# minimum version of libcurl to accept.  Pass the version as a regular
+# version number like 7.10.1. If not supplied, any version is
+# accepted.  ACTION-IF-YES is a list of shell commands to run if
+# libcurl was successfully found and passed the various tests.
+# ACTION-IF-NO is a list of shell commands that are run otherwise.
+# Note that using --without-libcurl does run ACTION-IF-NO.
+#
+# This macro #defines HAVE_LIBCURL if a working libcurl setup is
+# found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary
+# values.  Other useful defines are LIBCURL_FEATURE_xxx where xxx are
+# the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy
+# where yyy are the various protocols supported by libcurl.  Both xxx
+# and yyy are capitalized.  See the list of AH_TEMPLATEs at the top of
+# the macro for the complete list of possible defines.  Shell
+# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also
+# defined to 'yes' for those features and protocols that were found.
+# Note that xxx and yyy keep the same capitalization as in the
+# curl-config list (e.g. it's "HTTP" and not "http").
+#
+# Users may override the detected values by doing something like:
+# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure
+#
+# For the sake of sanity, this macro assumes that any libcurl that is found is
+# after version 7.7.2, the first version that included the curl-config script.
+# Note that it is important for people packaging binary versions of libcurl to
+# include this script!  Without curl-config, we can only guess what protocols
+# are available, or use curl_version_info to figure it out at runtime.
+
+AC_DEFUN([LIBCURL_CHECK_CONFIG],
+[
+  AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL])
+  AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4])
+  AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6])
+  AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz])
+  AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS])
+  AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN])
+  AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI])
+  AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM])
+
+  AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP])
+
+  AC_ARG_WITH(libcurl,
+AS_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]),
+     [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])])
+
+  if test "$_libcurl_with" != "no" ; then
+
+     AC_PROG_AWK
+
+     _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'"
+
+     _libcurl_try_link=yes
+
+     if test -d "$_libcurl_with" ; then
+        LIBCURL_CPPFLAGS="-I$withval/include"
+        _libcurl_ldflags="-L$withval/lib"
+        AC_PATH_PROG([_libcurl_config],[curl-config],[],
+                     ["$withval/bin"])
+     else
+        AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH])
+     fi
+
+     if test x$_libcurl_config != "x" ; then
+        AC_CACHE_CHECK([for the version of libcurl],
+           [libcurl_cv_lib_curl_version],
+           [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`])
+
+        _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
+        _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse`
+
+        if test $_libcurl_wanted -gt 0 ; then
+           AC_CACHE_CHECK([for libcurl >= version $2],
+              [libcurl_cv_lib_version_ok],
+              [
+              if test $_libcurl_version -ge $_libcurl_wanted ; then
+                 libcurl_cv_lib_version_ok=yes
+              else
+                 libcurl_cv_lib_version_ok=no
+              fi
+              ])
+        fi
+
+        if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
+           if test x"$LIBCURL_CPPFLAGS" = "x" ; then
+              LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
+           fi
+           if test x"$LIBCURL" = "x" ; then
+              LIBCURL=`$_libcurl_config --libs`
+
+              # This is so silly, but Apple actually has a bug in their
+              # curl-config script.  Fixed in Tiger, but there are still
+              # lots of Panther installs around.
+              case "${host}" in
+                 powerpc-apple-darwin7*)
+                    LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'`
+                 ;;
+              esac
+           fi
+
+           # All curl-config scripts support --feature
+           _libcurl_features=`$_libcurl_config --feature`
+
+           # Is it modern enough to have --protocols? (7.12.4)
+           if test $_libcurl_version -ge 461828 ; then
+              _libcurl_protocols=`$_libcurl_config --protocols`
+           fi
+        else
+           _libcurl_try_link=no
+        fi
+
+        unset _libcurl_wanted
+     fi
+
+     if test $_libcurl_try_link = yes ; then
+
+        # we did not find curl-config, so let's see if the user-supplied
+        # link line (or failing that, "-lcurl") is enough.
+        LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"}
+
+        AC_CACHE_CHECK([whether libcurl is usable],
+           [libcurl_cv_lib_curl_usable],
+           [
+           _libcurl_save_cppflags=$CPPFLAGS
+           CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS"
+           _libcurl_save_libs=$LIBS
+           LIBS="$LIBCURL $LIBS"
+
+           AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <curl/curl.h>]],[[
+/* Try to use a few common options to force a failure if we are
+   missing symbols or cannot link. */
+int x;
+curl_easy_setopt(NULL,CURLOPT_URL,NULL);
+x=CURL_ERROR_SIZE;
+x=CURLOPT_WRITEFUNCTION;
+x=CURLOPT_WRITEDATA;
+x=CURLOPT_ERRORBUFFER;
+x=CURLOPT_STDERR;
+x=CURLOPT_VERBOSE;
+if (x) {;}
+]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no)
+
+           CPPFLAGS=$_libcurl_save_cppflags
+           LIBS=$_libcurl_save_libs
+           unset _libcurl_save_cppflags
+           unset _libcurl_save_libs
+           ])
+
+        if test $libcurl_cv_lib_curl_usable = yes ; then
+
+           # Does curl_free() exist in this version of libcurl?
+           # If not, fake it with free()
+
+           _libcurl_save_cppflags=$CPPFLAGS
+           CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
+           _libcurl_save_libs=$LIBS
+           LIBS="$LIBS $LIBCURL"
+
+           AC_CHECK_DECL([curl_free],[],
+              [AC_DEFINE([curl_free],[free],
+                [Define curl_free() as free() if our version of curl lacks curl_free.])],
+              [[#include <curl/curl.h>]])
+
+           CPPFLAGS=$_libcurl_save_cppflags
+           LIBS=$_libcurl_save_libs
+           unset _libcurl_save_cppflags
+           unset _libcurl_save_libs
+
+           AC_DEFINE(HAVE_LIBCURL,1,
+             [Define to 1 if you have a functional curl library.])
+           AC_SUBST(LIBCURL_CPPFLAGS)
+           AC_SUBST(LIBCURL)
+
+           for _libcurl_feature in $_libcurl_features ; do
+              AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
+              eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
+           done
+
+           if test "x$_libcurl_protocols" = "x" ; then
+
+              # We do not have --protocols, so just assume that all
+              # protocols are available
+              _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP"
+
+              if test x$libcurl_feature_SSL = xyes ; then
+                 _libcurl_protocols="$_libcurl_protocols HTTPS"
+
+                 # FTPS was not standards-compliant until version
+                 # 7.11.0 (0x070b00 == 461568)
+                 if test $_libcurl_version -ge 461568; then
+                    _libcurl_protocols="$_libcurl_protocols FTPS"
+                 fi
+              fi
+
+              # RTSP, IMAP, POP3 and SMTP were added in
+              # 7.20.0 (0x071400 == 463872)
+              if test $_libcurl_version -ge 463872; then
+                 _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
+              fi
+           fi
+
+           for _libcurl_protocol in $_libcurl_protocols ; do
+              AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1])
+              eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes
+           done
+        else
+           unset LIBCURL
+           unset LIBCURL_CPPFLAGS
+        fi
+     fi
+
+     unset _libcurl_try_link
+     unset _libcurl_version_parse
+     unset _libcurl_config
+     unset _libcurl_feature
+     unset _libcurl_features
+     unset _libcurl_protocol
+     unset _libcurl_protocols
+     unset _libcurl_version
+     unset _libcurl_ldflags
+  fi
+
+  if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then
+     # This is the IF-NO path
+     ifelse([$4],,:,[$4])
+  else
+     # This is the IF-YES path
+     ifelse([$3],,:,[$3])
+  fi
+
+  unset _libcurl_with
+])
diff --git a/configure.ac b/configure.ac
index de231cd6..9f5495bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -610,6 +610,14 @@ if test x$armamain = xtrue; then
   LIBS="$LIBS $XML2_LIBS"
   AC_DEFINE(HAVE_LIBXML2, 1, [Define if you have the libxml2 library])
 
+dnl *************************************************
+dnl         curl
+dnl *************************************************
+
+LIBCURL_CHECK_CONFIG()
+CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
+LIBS=$"$LIBS $LIBCURL"
+
 dnl *************************************************
 dnl         Armathentication Threading
 dnl *************************************************
-- 
GitLab


From 70a65268beea7ace1f53c9676dccbc219f894277 Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Sat, 1 Mar 2025 21:10:01 +0100
Subject: [PATCH 03/27] First draft of impelementing downloading using curl

---
 src/network/nKrawall.h          |   2 +-
 src/network/nKrawallPrivate.cpp |  31 ++-----
 src/tools/tResourceManager.cpp  | 160 +++++++++++++++++++++++++-------
 src/tools/tResourceManager.h    |  12 +++
 4 files changed, 149 insertions(+), 56 deletions(-)

diff --git a/src/network/nKrawall.h b/src/network/nKrawall.h
index a73328dd..363bee0c 100644
--- a/src/network/nKrawall.h
+++ b/src/network/nKrawall.h
@@ -262,7 +262,7 @@ public:
                                         nPasswordCheckData const & data );
 
     // fetches an URL content, return http return code (-1 if total failure), fill result stream.
-    static int FetchURL( tString const & authority, char const * query, std::ostream & target, int maxlen = 10000 );
+    static int FetchURL(tString const& authority, char const* query, std::ostream& target);
 
 #ifdef KRAWALL_SERVER_LEAGUE
     // secret key to encrypt server->master server league transfer
diff --git a/src/network/nKrawallPrivate.cpp b/src/network/nKrawallPrivate.cpp
index bfaabeee..a0d6a37e 100644
--- a/src/network/nKrawallPrivate.cpp
+++ b/src/network/nKrawallPrivate.cpp
@@ -37,6 +37,7 @@ the executable is not distributed).
 #include "tConsole.h"
 #include "nNetwork.h"
 #include "tConfiguration.h"
+#include "tResourceManager.h"
 #include "tArray.h"
 
 #include <string>
@@ -447,7 +448,7 @@ void nKrawall::CheckScrambledPassword( nCheckResultBase & result,
     }
 }
 
-int nKrawall::FetchURL( tString const & authority, char const * query, std::ostream & target, int maxlen )
+int nKrawall::FetchURL(tString const& authority, char const* query, std::ostream& target)
 {
     // compose real URL
     std::ostringstream fullURL;
@@ -458,31 +459,15 @@ int nKrawall::FetchURL( tString const & authority, char const * query, std::ostr
     // con << "Fetching authentication URL " << fullURL.str() << "\n";
 
     // fetch URL
-    void * ctxt = xmlNanoHTTPOpen( fullURL.str().c_str(), NULL);
-    if (ctxt == NULL)
-    {
-        return -1;
-    }
-
-    int rc = xmlNanoHTTPReturnCode(ctxt);
+    tResourceManager::Result ret = tResourceManager::FetchURI(fullURL.str().c_str(), target);
 
-    // read content
-    char buf[1000];
-    buf[0] = 0;
-    unsigned int len = 1;
-    while ( len > 0 && maxlen > 0 )
+    switch (ret)
     {
-        int max = sizeof(buf);
-        if ( max > maxlen )
-            max = maxlen;
-        len = xmlNanoHTTPRead( ctxt, &buf, max );
-        target.write( buf, len );
-        maxlen -= len;
+    case tResourceManager::Result::OK:
+        return 200;
+    default:
+        return -1;
     }
-
-    xmlNanoHTTPClose(ctxt);
-
-    return rc;
 }
 
 #ifdef KRAWALL_SERVER_LEAGUE
diff --git a/src/tools/tResourceManager.cpp b/src/tools/tResourceManager.cpp
index 60d9a92e..6f689a0a 100644
--- a/src/tools/tResourceManager.cpp
+++ b/src/tools/tResourceManager.cpp
@@ -5,6 +5,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <fstream>
 #include <sys/types.h>
 
 #include <libxml/nanohttp.h>
@@ -14,6 +15,50 @@
 #include "tResourceManager.h"
 #include "tString.h"
 
+#ifndef LIBXML_HTTP_ENABLED
+#ifdef LIBCURL_PROTOCOL_HTTP
+#include <curl/curl.h>
+
+class tCurlGlobal
+{
+public:
+    tCurlGlobal()
+    {
+        curl_global_init(CURL_GLOBAL_DEFAULT);
+    };
+
+    ~tCurlGlobal()
+    {
+        curl_global_cleanup();
+    }
+};
+
+class tCurlLocal
+{
+private:
+    CURL* _handle;
+
+public:
+    tCurlLocal()
+    {
+        static tCurlGlobal curlGlobal;
+        _handle = curl_easy_init();
+    };
+
+    ~tCurlLocal()
+    {
+        curl_easy_cleanup(_handle);
+    }
+
+    operator CURL*()
+    {
+        return _handle;
+    }
+};
+
+#endif
+#endif
+
 // server determined resource repository
 tString tResourceManager::resRepoServer("http://resource.armagetronad.net/resource/");
 // the nSettingItem is in gStuff.cpp
@@ -22,47 +67,98 @@ tString tResourceManager::resRepoServer("http://resource.armagetronad.net/resour
 tString tResourceManager::resRepoClient("http://resource.armagetronad.net/resource/");
 static tSettingItem<tString> conf_res_repo("RESOURCE_REPOSITORY_CLIENT", tResourceManager::resRepoClient);
 
-static int myHTTPFetch(const char *URI, const char *filename, const char *savepath)
+tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostream& o, int maxLen)
 {
-    void *ctxt = NULL;
-    char *buf = NULL;
-    FILE* fd;
-    int len, rc;
-
-    con << tOutput( "$resource_downloading", URI );
-    // con << "Downloading " << URI << "...\n";
+#ifdef LIBXML_HTTP_ENABLED
+    {
+        void* ctxt = NULL;
+        int len, rc;
+
+        ctxt = xmlNanoHTTPOpen(URI, NULL);
+        if (ctxt == NULL)
+        {
+            con << tOutput("$resource_fetcherror_noconnect", URI);
+            return ERROR_URI;
+        }
 
-    ctxt = xmlNanoHTTPOpen(URI, NULL);
-    if (ctxt == NULL) {
-        con << tOutput( "$resource_fetcherror_noconnect", URI );
-        return 1;
-    }
+        if ((rc = xmlNanoHTTPReturnCode(ctxt)) != 200)
+        {
+            con << tOutput(rc == 404 ? "$resource_fetcherror_404" : "$resource_fetcherror", rc);
+            return rc == 404 ? ERROR_NOACCESS : ERROR_NOTFOUND;
+        }
 
-    if ( (rc = xmlNanoHTTPReturnCode(ctxt)) != 200 ) {
-        con << tOutput( rc == 404 ? "$resource_fetcherror_404" : "$resource_fetcherror", rc );
-        return 2;
-    }
+        // xmlNanoHTTPFetchContent( ctxt, &buf, &len );
+        char buf[10000];
+        while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0)
+        {
+            if (maxLen >= 0)
+            {
+                if (maxLen == 0)
+                    break;
+                len = std::min(len, maxLen);
+                maxLen -= len;
+            }
+            o.write(buf, len);
+        }
 
-    fd = fopen(savepath, "w");
-    if (fd == NULL) {
         xmlNanoHTTPClose(ctxt);
-        con << tOutput( "$resource_no_write", savepath );
-        return 3;
     }
-
-    //xmlNanoHTTPFetchContent( ctxt, &buf, &len );
-    int maxlen = 10000;
-    buf = (char*)malloc(maxlen);
-    while( (len = xmlNanoHTTPRead(ctxt, buf, maxlen)) > 0 ) {
-        Ignore( fwrite(buf, len, 1, fd) );
+#else
+#ifdef LIBCURL_PROTOCOL_HTTP
+    {
+        tCurlLocal handle;
+
+        // Set the URL to request
+        curl_easy_setopt(handle, CURLOPT_URL, "https://www.example.com");
+        // Set the callback function to handle the response
+        curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, [](char* data, size_t size, size_t nmemb, void* userp) {
+            // Cast the user pointer to an ostream and write the data to it
+            static_cast<std::ostream*>(userp)->write(data, size);
+            // Return the number of bytes processed
+            return size * nmemb;
+        });
+        // Set the user pointer to be an ostream to which the response will be written
+        std::ostringstream response;
+        curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response);
+        // Perform the request
+        CURLcode result = curl_easy_perform(handle);
+        // Check the result
+        if (result != CURLE_OK)
+        {
+            // If the request failed, print an error message
+            std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(result) << std::endl;
+        }
+        else
+        {
+            // If the request was successful, print the response
+            std::cout << response.str() << std::endl;
+        }
+        // Clean up
+        curl_easy_cleanup(handle);
     }
-    free(buf);
-
-    xmlNanoHTTPClose(ctxt);
-    fclose(fd);
+#else
+    con << "FAILED libcurl or libxml's nanohttp required";
+    return ERROR_UNKNOWN;
+#endif
+#endif
+    con << "OK\n";
+    return Result::OK;
+}
 
+static int myHTTPFetch(const char* URI, const char* filename, const char* savepath)
+{
+    con << tOutput("$resource_downloading", URI);
+    // con << "Downloading " << URI << "...\n";
 
-    con << "OK\n";
+    try
+    {
+        std::ofstream o{savepath};
+        return tResourceManager::FetchURI(URI, o);
+    }
+    catch (...)
+    {
+        return 4;
+    }
 
     return 0;
 }
diff --git a/src/tools/tResourceManager.h b/src/tools/tResourceManager.h
index 192c3758..0421bff6 100644
--- a/src/tools/tResourceManager.h
+++ b/src/tools/tResourceManager.h
@@ -6,6 +6,18 @@
 //! resource manager: fetches and caches resources from repositories or arbitrary URIs
 class tResourceManager {
 public:
+    enum Result
+    {
+        OK = 0,
+        ERROR_UNKNOWN = 1,
+        ERROR_URI = 2,      // URI not well formed
+        ERROR_NOTFOUND = 3, // URI not found
+        ERROR_NOACCESS = 4  // Access denied
+    };
+
+    // fetches an URI and stores it in the provided stream, up to maxLen bytes
+    static Result FetchURI(const char* URI, std::ostream& o, int maxLen = -1);
+
     //! Return the position of the resource in the cache
     static tString locateResource(const char *uri, const char *file);
     //! opens a resource
-- 
GitLab


From 9e7a9d3e08308821bc2e26397586d6b1e50fb0fd Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Sat, 1 Mar 2025 23:31:46 +0100
Subject: [PATCH 04/27] Complete basic CURL implementation

Use real URI
Use real output stream
Use standalone receiver function
Activate error handing
---
 src/tools/tResourceManager.cpp | 36 ++++++++++++++++++++--------------
 1 file changed, 21 insertions(+), 15 deletions(-)

diff --git a/src/tools/tResourceManager.cpp b/src/tools/tResourceManager.cpp
index 6f689a0a..983881c6 100644
--- a/src/tools/tResourceManager.cpp
+++ b/src/tools/tResourceManager.cpp
@@ -54,6 +54,14 @@ public:
     {
         return _handle;
     }
+
+    static size_t write_to_ostream(char* data, size_t size, size_t nmemb, void* ostream)
+    {
+        // Cast the user pointer to an ostream and write the data to it
+        static_cast<std::ostream*>(ostream)->write(data, size * nmemb);
+        // Return the number of bytes processed
+        return size * nmemb;
+    }
 };
 
 #endif
@@ -107,32 +115,29 @@ tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostrea
 #ifdef LIBCURL_PROTOCOL_HTTP
     {
         tCurlLocal handle;
+        if (nullptr == handle)
+            return Result::ERROR_UNKNOWN;
 
         // Set the URL to request
-        curl_easy_setopt(handle, CURLOPT_URL, "https://www.example.com");
+        curl_easy_setopt(handle, CURLOPT_URL, URI);
         // Set the callback function to handle the response
-        curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, [](char* data, size_t size, size_t nmemb, void* userp) {
-            // Cast the user pointer to an ostream and write the data to it
-            static_cast<std::ostream*>(userp)->write(data, size);
-            // Return the number of bytes processed
-            return size * nmemb;
-        });
+        curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &tCurlLocal::write_to_ostream);
         // Set the user pointer to be an ostream to which the response will be written
-        std::ostringstream response;
-        curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response);
+        curl_easy_setopt(handle, CURLOPT_WRITEDATA, &o);
+        // activate failure on HTTP errors
+        curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1L);
         // Perform the request
         CURLcode result = curl_easy_perform(handle);
         // Check the result
         if (result != CURLE_OK)
         {
+            long http_code = 0;
+            curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_code);
             // If the request failed, print an error message
             std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(result) << std::endl;
+            return Result::ERROR_UNKNOWN;
         }
-        else
-        {
-            // If the request was successful, print the response
-            std::cout << response.str() << std::endl;
-        }
+
         // Clean up
         curl_easy_cleanup(handle);
     }
@@ -153,7 +158,8 @@ static int myHTTPFetch(const char* URI, const char* filename, const char* savepa
     try
     {
         std::ofstream o{savepath};
-        return tResourceManager::FetchURI(URI, o);
+        tResourceManager::Result ret = tResourceManager::FetchURI(URI, o);
+        return ret;
     }
     catch (...)
     {
-- 
GitLab


From f99e605a7207305df977033735324a162a638737 Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Sat, 1 Mar 2025 23:45:34 +0100
Subject: [PATCH 05/27] Delete target file on error

---
 src/tools/tResourceManager.cpp | 14 ++++++--------
 src/tools/tResourceManager.h   |  4 ++--
 2 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/src/tools/tResourceManager.cpp b/src/tools/tResourceManager.cpp
index 983881c6..fc6626b9 100644
--- a/src/tools/tResourceManager.cpp
+++ b/src/tools/tResourceManager.cpp
@@ -75,7 +75,7 @@ tString tResourceManager::resRepoServer("http://resource.armagetronad.net/resour
 tString tResourceManager::resRepoClient("http://resource.armagetronad.net/resource/");
 static tSettingItem<tString> conf_res_repo("RESOURCE_REPOSITORY_CLIENT", tResourceManager::resRepoClient);
 
-tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostream& o, int maxLen)
+tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostream& o)
 {
 #ifdef LIBXML_HTTP_ENABLED
     {
@@ -99,13 +99,6 @@ tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostrea
         char buf[10000];
         while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0)
         {
-            if (maxLen >= 0)
-            {
-                if (maxLen == 0)
-                    break;
-                len = std::min(len, maxLen);
-                maxLen -= len;
-            }
             o.write(buf, len);
         }
 
@@ -159,10 +152,15 @@ static int myHTTPFetch(const char* URI, const char* filename, const char* savepa
     {
         std::ofstream o{savepath};
         tResourceManager::Result ret = tResourceManager::FetchURI(URI, o);
+        o.close();
+        if (ret != tResourceManager::Result::OK)
+            remove(savepath);
         return ret;
     }
     catch (...)
     {
+        remove(savepath);
+
         return 4;
     }
 
diff --git a/src/tools/tResourceManager.h b/src/tools/tResourceManager.h
index 0421bff6..4734fb32 100644
--- a/src/tools/tResourceManager.h
+++ b/src/tools/tResourceManager.h
@@ -15,8 +15,8 @@ public:
         ERROR_NOACCESS = 4  // Access denied
     };
 
-    // fetches an URI and stores it in the provided stream, up to maxLen bytes
-    static Result FetchURI(const char* URI, std::ostream& o, int maxLen = -1);
+    // fetches an URI and stores it in the provided stream
+    static Result FetchURI(const char* URI, std::ostream& o);
 
     //! Return the position of the resource in the cache
     static tString locateResource(const char *uri, const char *file);
-- 
GitLab


From 3539390a36fbb8db56685a38cf65c0a8f02bc67d Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Sun, 2 Mar 2025 00:01:13 +0100
Subject: [PATCH 06/27] Document future possibility of more negative error
 return codes

---
 src/network/nKrawall.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/network/nKrawall.h b/src/network/nKrawall.h
index 363bee0c..d475697e 100644
--- a/src/network/nKrawall.h
+++ b/src/network/nKrawall.h
@@ -261,7 +261,7 @@ public:
     static void CheckScrambledPassword( nCheckResultBase & result,
                                         nPasswordCheckData const & data );
 
-    // fetches an URL content, return http return code (-1 if total failure), fill result stream.
+    // fetches an URL content, return http return code (negative values if total failure), fill result stream.
     static int FetchURL(tString const& authority, char const* query, std::ostream& target);
 
 #ifdef KRAWALL_SERVER_LEAGUE
-- 
GitLab


From 972772a558ee444ef35f4c4af0fcc67a2cca7ae5 Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Sun, 2 Mar 2025 00:01:38 +0100
Subject: [PATCH 07/27] Change values of URI fetch return codes to match HTTP
 return codes

---
 src/tools/tResourceManager.h | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/tools/tResourceManager.h b/src/tools/tResourceManager.h
index 4734fb32..c5087164 100644
--- a/src/tools/tResourceManager.h
+++ b/src/tools/tResourceManager.h
@@ -8,11 +8,12 @@ class tResourceManager {
 public:
     enum Result
     {
-        OK = 0,
-        ERROR_UNKNOWN = 1,
-        ERROR_URI = 2,      // URI not well formed
-        ERROR_NOTFOUND = 3, // URI not found
-        ERROR_NOACCESS = 4  // Access denied
+        OK = 200,               // all fine
+        ERROR_UNKNOWN = -1,     // unknown error
+        ERROR_URI = -2,         // URI not well formed
+        ERROR_FILE_ACCESS = -3, // target file not writable
+        ERROR_NOTFOUND = 404,   // URI not found
+        ERROR_NOACCESS = 401    // Access denied
     };
 
     // fetches an URI and stores it in the provided stream
-- 
GitLab


From e89e8f9b9b4b278b7ffa3d489bb661c959f25609 Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Sun, 2 Mar 2025 00:01:58 +0100
Subject: [PATCH 08/27] Use new return code

---
 src/tools/tResourceManager.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/tResourceManager.cpp b/src/tools/tResourceManager.cpp
index fc6626b9..ad98f2f5 100644
--- a/src/tools/tResourceManager.cpp
+++ b/src/tools/tResourceManager.cpp
@@ -161,7 +161,7 @@ static int myHTTPFetch(const char* URI, const char* filename, const char* savepa
     {
         remove(savepath);
 
-        return 4;
+        return tResourceManager::Result::ERROR_FILE_ACCESS;
     }
 
     return 0;
-- 
GitLab


From ab0d22fe74dc90c13ea4c94c48fdb0d1a9730b94 Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Sun, 2 Mar 2025 00:04:32 +0100
Subject: [PATCH 09/27] Adapt to future changed return code of
 nKrawall::FetchURL

More fully map actual URI fetching return codes to FetchURL return codes
---
 src/network/nAuthentication.cpp |  4 ++--
 src/network/nKrawallPrivate.cpp | 13 ++++---------
 2 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/src/network/nAuthentication.cpp b/src/network/nAuthentication.cpp
index 0e3625c2..16b0028a 100644
--- a/src/network/nAuthentication.cpp
+++ b/src/network/nAuthentication.cpp
@@ -788,7 +788,7 @@ bool nLoginProcess::FetchInfoFromAuthorityRemote()
         std::stringstream answer;
         int rc = nKrawall::FetchURL( fullAuthority, "?query=methods", answer );
 
-        if ( rc == -1 )
+        if (rc < 0)
         {
             return ReportAuthorityError( tOutput( "$login_error_invalidurl_notfound", authority ) );
         }
@@ -835,7 +835,7 @@ bool nLoginProcess::FetchInfoFromAuthorityRemote()
         
         if ( rc != 200 )
         {
-            if ( rc == -1 )
+            if (rc < 0)
             {
                 return ReportAuthorityError( tOutput( "$login_error_invalidurl_notfound", authority ) );
             }
diff --git a/src/network/nKrawallPrivate.cpp b/src/network/nKrawallPrivate.cpp
index a0d6a37e..fd717d80 100644
--- a/src/network/nKrawallPrivate.cpp
+++ b/src/network/nKrawallPrivate.cpp
@@ -334,7 +334,7 @@ void nKrawall::CheckScrambledPassword( nCheckResultBase & result,
         std::stringstream content;
         int rc = FetchURL( data.fullAuthority, request.str().c_str(), content );
 
-        if (rc == -1)
+        if (rc < 0)
         {
             result.error = tOutput( "$login_error_invalidurl_notfound", result.authority );
             result.success = false;
@@ -459,15 +459,10 @@ int nKrawall::FetchURL(tString const& authority, char const* query, std::ostream
     // con << "Fetching authentication URL " << fullURL.str() << "\n";
 
     // fetch URL
-    tResourceManager::Result ret = tResourceManager::FetchURI(fullURL.str().c_str(), target);
-
-    switch (ret)
-    {
-    case tResourceManager::Result::OK:
-        return 200;
-    default:
+    int ret = tResourceManager::FetchURI(fullURL.str().c_str(), target);
+    if (ret < 0)
         return -1;
-    }
+    return ret;
 }
 
 #ifdef KRAWALL_SERVER_LEAGUE
-- 
GitLab


From 13923dd97077c9b1e17bdaa3702514948823c873 Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Sun, 2 Mar 2025 00:27:05 +0100
Subject: [PATCH 10/27] Error code propagation

Sometimes, only 0 means OK...
---
 src/tools/tResourceManager.cpp | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/tools/tResourceManager.cpp b/src/tools/tResourceManager.cpp
index ad98f2f5..941781e0 100644
--- a/src/tools/tResourceManager.cpp
+++ b/src/tools/tResourceManager.cpp
@@ -92,7 +92,7 @@ tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostrea
         if ((rc = xmlNanoHTTPReturnCode(ctxt)) != 200)
         {
             con << tOutput(rc == 404 ? "$resource_fetcherror_404" : "$resource_fetcherror", rc);
-            return rc == 404 ? ERROR_NOACCESS : ERROR_NOTFOUND;
+            return static_cast<tResourceManager::Result>(rc);
         }
 
         // xmlNanoHTTPFetchContent( ctxt, &buf, &len );
@@ -153,8 +153,11 @@ static int myHTTPFetch(const char* URI, const char* filename, const char* savepa
         std::ofstream o{savepath};
         tResourceManager::Result ret = tResourceManager::FetchURI(URI, o);
         o.close();
-        if (ret != tResourceManager::Result::OK)
-            remove(savepath);
+        if (ret == tResourceManager::Result::OK)
+            return 0;
+
+        // some error
+        remove(savepath);
         return ret;
     }
     catch (...)
@@ -184,7 +187,8 @@ static int myFetch(const char *URIs, const char *filename, const char *savepath)
         // NOTE: skip semicolons, *NOT* nulls
         while (p[-1] == ' ') --p;			// skip spaces at the end of the item
         len = (size_t)(p - r);
-        if (len > 0) {						// skip this for null-length items
+        if (len > 0)
+        { // skip this for null-length items
             u = (char*)malloc((len + 1) * sizeof(char));
             strncpy(u, r, len);
             u[len] = '\0';					// u now contains the individual URI
-- 
GitLab


From f6b62102dbccf1c5f4970652af428990aa558215 Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Sun, 2 Mar 2025 00:39:29 +0100
Subject: [PATCH 11/27] Rename enum values, Windows has one of them as a macro

---
 src/tools/tResourceManager.cpp | 12 ++++++------
 src/tools/tResourceManager.h   | 12 ++++++------
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/tools/tResourceManager.cpp b/src/tools/tResourceManager.cpp
index 941781e0..29f3ddda 100644
--- a/src/tools/tResourceManager.cpp
+++ b/src/tools/tResourceManager.cpp
@@ -86,7 +86,7 @@ tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostrea
         if (ctxt == NULL)
         {
             con << tOutput("$resource_fetcherror_noconnect", URI);
-            return ERROR_URI;
+            return ERROR_Uri;
         }
 
         if ((rc = xmlNanoHTTPReturnCode(ctxt)) != 200)
@@ -109,7 +109,7 @@ tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostrea
     {
         tCurlLocal handle;
         if (nullptr == handle)
-            return Result::ERROR_UNKNOWN;
+            return Result::ERROR_Unknown;
 
         // Set the URL to request
         curl_easy_setopt(handle, CURLOPT_URL, URI);
@@ -128,7 +128,7 @@ tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostrea
             curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_code);
             // If the request failed, print an error message
             std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(result) << std::endl;
-            return Result::ERROR_UNKNOWN;
+            return Result::ERROR_Unknown;
         }
 
         // Clean up
@@ -140,7 +140,7 @@ tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostrea
 #endif
 #endif
     con << "OK\n";
-    return Result::OK;
+    return Result::RESULT_Ok;
 }
 
 static int myHTTPFetch(const char* URI, const char* filename, const char* savepath)
@@ -153,7 +153,7 @@ static int myHTTPFetch(const char* URI, const char* filename, const char* savepa
         std::ofstream o{savepath};
         tResourceManager::Result ret = tResourceManager::FetchURI(URI, o);
         o.close();
-        if (ret == tResourceManager::Result::OK)
+        if (ret == tResourceManager::Result::RESULT_Ok)
             return 0;
 
         // some error
@@ -164,7 +164,7 @@ static int myHTTPFetch(const char* URI, const char* filename, const char* savepa
     {
         remove(savepath);
 
-        return tResourceManager::Result::ERROR_FILE_ACCESS;
+        return tResourceManager::Result::ERROR_FileAccess;
     }
 
     return 0;
diff --git a/src/tools/tResourceManager.h b/src/tools/tResourceManager.h
index c5087164..7a0116b9 100644
--- a/src/tools/tResourceManager.h
+++ b/src/tools/tResourceManager.h
@@ -8,12 +8,12 @@ class tResourceManager {
 public:
     enum Result
     {
-        OK = 200,               // all fine
-        ERROR_UNKNOWN = -1,     // unknown error
-        ERROR_URI = -2,         // URI not well formed
-        ERROR_FILE_ACCESS = -3, // target file not writable
-        ERROR_NOTFOUND = 404,   // URI not found
-        ERROR_NOACCESS = 401    // Access denied
+        RESULT_Ok = 200,       // all fine
+        ERROR_Unknown = -1,    // unknown error
+        ERROR_Uri = -2,        // URI not well formed
+        ERROR_FileAccess = -3, // target file not writable
+        ERROR_NotFound = 404,  // URI not found
+        ERROR_NoAccess = 401   // Access denied
     };
 
     // fetches an URI and stores it in the provided stream
-- 
GitLab


From 8637ea7dea79e9aefe32c4f320ae23cb9a08eb59 Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Sun, 2 Mar 2025 00:43:38 +0100
Subject: [PATCH 12/27] Follow redirects

---
 src/tools/tResourceManager.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/tools/tResourceManager.cpp b/src/tools/tResourceManager.cpp
index 29f3ddda..e33de2bf 100644
--- a/src/tools/tResourceManager.cpp
+++ b/src/tools/tResourceManager.cpp
@@ -119,6 +119,8 @@ tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostrea
         curl_easy_setopt(handle, CURLOPT_WRITEDATA, &o);
         // activate failure on HTTP errors
         curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1L);
+        // activate automatic redirection following
+        curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);
         // Perform the request
         CURLcode result = curl_easy_perform(handle);
         // Check the result
-- 
GitLab


From dd13ef27ed7a5360ae4d70baf055b3c3cb6f88e1 Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Sun, 2 Mar 2025 00:54:06 +0100
Subject: [PATCH 13/27] Set other recommended options to libcurl

---
 src/tools/tResourceManager.cpp | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/src/tools/tResourceManager.cpp b/src/tools/tResourceManager.cpp
index e33de2bf..3df7bc1c 100644
--- a/src/tools/tResourceManager.cpp
+++ b/src/tools/tResourceManager.cpp
@@ -121,6 +121,20 @@ tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostrea
         curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1L);
         // activate automatic redirection following
         curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);
+        // activate SSL verification
+        curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 1L);
+        curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 2L);
+        // shorten timeouts (10s connect, 30s total)
+        curl_easy_setopt(handle, CURLOPT_TIMEOUT, 30L);
+        curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, 10L);
+        // set user agent
+        curl_easy_setopt(handle, CURLOPT_USERAGENT, "Armagetron Advanced"); // using that instead of the variable progtitle so servers always know what to expect
+#ifdef DEBUG
+        // more detailed error reporting
+        char errbuf[CURL_ERROR_SIZE];
+        curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errbuf);
+        curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
+#endif
         // Perform the request
         CURLcode result = curl_easy_perform(handle);
         // Check the result
-- 
GitLab


From 58d001d2a0844d945c46918c89363168f1c05630 Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Sun, 2 Mar 2025 12:21:35 +0100
Subject: [PATCH 14/27] Explain why we always check for libcurl

---
 configure.ac | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/configure.ac b/configure.ac
index 9f5495bd..e7d1f0bf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -614,6 +614,11 @@ dnl *************************************************
 dnl         curl
 dnl *************************************************
 
+dnl We unconditionally check for curl even though on older systems,
+dnl libxml's nanoHTTP would suffice for fetching; we want our binary
+dnl builds to be future compatible with systems where nanoHTTP has
+dnl been removed.
+
 LIBCURL_CHECK_CONFIG()
 CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
 LIBS=$"$LIBS $LIBCURL"
-- 
GitLab


From 82d0bacb52725cd080af70738aa8ba410aef0d66 Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Mon, 3 Mar 2025 00:58:34 +0100
Subject: [PATCH 15/27] Add --enable-curl configure option

We don't want to silently enforce linking with curl even if we need it,
it should be a conscious decision. But we do detect if it would be
required and complain about it.
---
 configure.ac                   | 32 ++++++++++++++++++++++++--------
 src/tools/tResourceManager.cpp |  2 +-
 2 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/configure.ac b/configure.ac
index e7d1f0bf..e53758ae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -136,6 +136,17 @@ AC_ARG_ENABLE(glout,
        *) AC_MSG_ERROR(bad value ${enableval} for --enable-glout) ;;
      esac],)
 
+use_curl=false
+AC_ARG_ENABLE(curl,
+     AC_HELP_STRING([--enable-curl],
+        [Use libcurl for http requests]),
+     [case "${enableval}" in
+       yes) use_curl=true ;;
+       no)  use_curl=false ;;
+       *) AC_MSG_ERROR(bad value ${enableval} for --enable-main) ;;
+     esac],[use_curl=false])
+
+
 # consistency check of the three build flags	 
 test x$armamain = xfalse && build_dedicated=false build_regular=false
 test x$build_dedicated = xfalse && test x$build_regular = xfalse && armamain=false
@@ -610,18 +621,23 @@ if test x$armamain = xtrue; then
   LIBS="$LIBS $XML2_LIBS"
   AC_DEFINE(HAVE_LIBXML2, 1, [Define if you have the libxml2 library])
 
+
+
 dnl *************************************************
 dnl         curl
 dnl *************************************************
 
-dnl We unconditionally check for curl even though on older systems,
-dnl libxml's nanoHTTP would suffice for fetching; we want our binary
-dnl builds to be future compatible with systems where nanoHTTP has
-dnl been removed.
-
-LIBCURL_CHECK_CONFIG()
-CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
-LIBS=$"$LIBS $LIBCURL"
+if test x$use_curl = xtrue; then
+    LIBCURL_CHECK_CONFIG(,,
+    CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
+    LIBS=$"$LIBS $LIBCURL",
+    AC_MSG_ERROR([libcurl not found. Either provide it or disable it (with `configure --disable-curl`)])
+    )
+else
+  AC_CHECK_DECL(LIBXML_HTTP_ENABLED,,
+                AC_MSG_ERROR([libxml2 does not have the http client compiled in. Rerun with curl enabled (`configure --enable-curl`)]),
+                [[#include "libxml/nanohttp.h"]])
+fi
 
 dnl *************************************************
 dnl         Armathentication Threading
diff --git a/src/tools/tResourceManager.cpp b/src/tools/tResourceManager.cpp
index 3df7bc1c..56cc70a5 100644
--- a/src/tools/tResourceManager.cpp
+++ b/src/tools/tResourceManager.cpp
@@ -151,7 +151,7 @@ tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostrea
         curl_easy_cleanup(handle);
     }
 #else
-    con << "FAILED libcurl or libxml's nanohttp required";
+    #error libcurl or libxml's nanohttp required; configure should have told you. Please file a bug.
     return ERROR_UNKNOWN;
 #endif
 #endif
-- 
GitLab


From 5d84e17b58aef6db39f9bd6ca0914225c437931e Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Mon, 3 Mar 2025 22:56:22 +0100
Subject: [PATCH 16/27] Automatically activate libcurl if needed

---
 configure.ac | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/configure.ac b/configure.ac
index e53758ae..899661d0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -136,7 +136,7 @@ AC_ARG_ENABLE(glout,
        *) AC_MSG_ERROR(bad value ${enableval} for --enable-glout) ;;
      esac],)
 
-use_curl=false
+use_curl=auto
 AC_ARG_ENABLE(curl,
      AC_HELP_STRING([--enable-curl],
         [Use libcurl for http requests]),
@@ -144,7 +144,7 @@ AC_ARG_ENABLE(curl,
        yes) use_curl=true ;;
        no)  use_curl=false ;;
        *) AC_MSG_ERROR(bad value ${enableval} for --enable-main) ;;
-     esac],[use_curl=false])
+     esac],[use_curl=auto])
 
 
 # consistency check of the three build flags	 
@@ -621,22 +621,26 @@ if test x$armamain = xtrue; then
   LIBS="$LIBS $XML2_LIBS"
   AC_DEFINE(HAVE_LIBXML2, 1, [Define if you have the libxml2 library])
 
-
+  AC_CHECK_DECL(LIBXML_HTTP_ENABLED,,
+               dnl no nanoHTTP, auto-enable curl (if not explicitly disabled)
+               if test x$use_curl = xfalse; then
+                   AC_MSG_ERROR([[libxml2 does not have the http client compiled in. Curl replacement needed, do not disable it.]])
+               else
+                   use_curl=true
+               fi
+               ,
+               [[#include "libxml/nanohttp.h"]])
 
 dnl *************************************************
 dnl         curl
 dnl *************************************************
 
 if test x$use_curl = xtrue; then
-    LIBCURL_CHECK_CONFIG(,,
-    CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
-    LIBS=$"$LIBS $LIBCURL",
-    AC_MSG_ERROR([libcurl not found. Either provide it or disable it (with `configure --disable-curl`)])
-    )
-else
-  AC_CHECK_DECL(LIBXML_HTTP_ENABLED,,
-                AC_MSG_ERROR([libxml2 does not have the http client compiled in. Rerun with curl enabled (`configure --enable-curl`)]),
-                [[#include "libxml/nanohttp.h"]])
+   LIBCURL_CHECK_CONFIG(,,
+   CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
+   LIBS=$"$LIBS $LIBCURL",
+   AC_MSG_ERROR([libcurl not found. Either provide it or disable it (with `configure --disable-curl`)])
+   )
 fi
 
 dnl *************************************************
-- 
GitLab


From 13fdb46d1025b652f5857308c78fe1a1c741a939 Mon Sep 17 00:00:00 2001
From: Manuel Moos <z-man@users.sf.net>
Date: Mon, 3 Mar 2025 22:56:54 +0100
Subject: [PATCH 17/27] Prefer libcurl if included

even if nanoHTTP would be available. In that case, libcurl is only
available if the user explicitly requested it.
---
 src/tools/tResourceManager.cpp | 63 ++++++++++++++++------------------
 1 file changed, 30 insertions(+), 33 deletions(-)

diff --git a/src/tools/tResourceManager.cpp b/src/tools/tResourceManager.cpp
index 56cc70a5..672370e4 100644
--- a/src/tools/tResourceManager.cpp
+++ b/src/tools/tResourceManager.cpp
@@ -15,7 +15,6 @@
 #include "tResourceManager.h"
 #include "tString.h"
 
-#ifndef LIBXML_HTTP_ENABLED
 #ifdef LIBCURL_PROTOCOL_HTTP
 #include <curl/curl.h>
 
@@ -63,8 +62,6 @@ public:
         return size * nmemb;
     }
 };
-
-#endif
 #endif
 
 // server determined resource repository
@@ -77,34 +74,6 @@ static tSettingItem<tString> conf_res_repo("RESOURCE_REPOSITORY_CLIENT", tResour
 
 tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostream& o)
 {
-#ifdef LIBXML_HTTP_ENABLED
-    {
-        void* ctxt = NULL;
-        int len, rc;
-
-        ctxt = xmlNanoHTTPOpen(URI, NULL);
-        if (ctxt == NULL)
-        {
-            con << tOutput("$resource_fetcherror_noconnect", URI);
-            return ERROR_Uri;
-        }
-
-        if ((rc = xmlNanoHTTPReturnCode(ctxt)) != 200)
-        {
-            con << tOutput(rc == 404 ? "$resource_fetcherror_404" : "$resource_fetcherror", rc);
-            return static_cast<tResourceManager::Result>(rc);
-        }
-
-        // xmlNanoHTTPFetchContent( ctxt, &buf, &len );
-        char buf[10000];
-        while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0)
-        {
-            o.write(buf, len);
-        }
-
-        xmlNanoHTTPClose(ctxt);
-    }
-#else
 #ifdef LIBCURL_PROTOCOL_HTTP
     {
         tCurlLocal handle;
@@ -151,8 +120,36 @@ tResourceManager::Result tResourceManager::FetchURI(const char* URI, std::ostrea
         curl_easy_cleanup(handle);
     }
 #else
-    #error libcurl or libxml's nanohttp required; configure should have told you. Please file a bug.
-    return ERROR_UNKNOWN;
+#ifdef LIBXML_HTTP_ENABLED
+    {
+        void* ctxt = NULL;
+        int len, rc;
+
+        ctxt = xmlNanoHTTPOpen(URI, NULL);
+        if (ctxt == NULL)
+        {
+            con << tOutput("$resource_fetcherror_noconnect", URI);
+            return ERROR_Uri;
+        }
+
+        if ((rc = xmlNanoHTTPReturnCode(ctxt)) != 200)
+        {
+            con << tOutput(rc == 404 ? "$resource_fetcherror_404" : "$resource_fetcherror", rc);
+            return static_cast<tResourceManager::Result>(rc);
+        }
+
+        // xmlNanoHTTPFetchContent( ctxt, &buf, &len );
+        char buf[10000];
+        while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0)
+        {
+            o.write(buf, len);
+        }
+
+        xmlNanoHTTPClose(ctxt);
+    }
+#else
+#error libcurl or libxml nanohttp required; configure should have told you. Please file a bug.
+    return Result::ERROR_Unknown;
 #endif
 #endif
     con << "OK\n";
-- 
GitLab
