[Git][debian-gis-team/mapserver][master] 5 commits: New upstream version 8.6.4

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Mon Jun 1 19:23:08 BST 2026



Bas Couwenberg pushed to branch master at Debian GIS Project / mapserver


Commits:
b17252be by Bas Couwenberg at 2026-06-01T20:10:24+02:00
New upstream version 8.6.4
- - - - -
ec25cebb by Bas Couwenberg at 2026-06-01T20:10:39+02:00
Update upstream source from tag 'upstream/8.6.4'

Update to upstream version '8.6.4'
with Debian dir f95e9e8a710d7fce333bcb506d520f235fa9117b
- - - - -
cbc2019f by Bas Couwenberg at 2026-06-01T20:11:23+02:00
New upstream release.

- - - - -
675dbd05 by Bas Couwenberg at 2026-06-01T20:18:05+02:00
Update symbols for 8.6.4.

- - - - -
9c49374f by Bas Couwenberg at 2026-06-01T20:18:05+02:00
Set distribution to unstable.

- - - - -


20 changed files:

- .github/workflows/start.sh
- CITATION.cff
- CMakeLists.txt
- HISTORY.md
- SECURITY.md
- debian/changelog
- debian/libmapserver2t64.symbols
- src/apps/mapserv.c
- src/cgiutil.c
- src/cgiutil.h
- src/mapogcapi.cpp
- src/mapows.c
- src/mapows.h
- src/mappostgis.cpp
- src/maprasterquery.c
- src/mapscale.c
- src/mapserv-index.cpp
- src/mapserver.h
- src/mapstring.cpp
- src/maptemplate.c


Changes:

=====================================
.github/workflows/start.sh
=====================================
@@ -190,4 +190,11 @@ EOF
 MAPSERVER_CONFIG_FILE=/tmp/mapserver.conf mapserv QUERY_STRING="MAP=wfs_simple.map&SERVICE=WFS&REQUEST=GetCapabilities" > /tmp/res.txt
 cat /tmp/res.txt | grep "Web application error" >/dev/null || (cat /tmp/res.txt && /bin/false)
 
+# Check https://github.com/MapServer/MapServer/security/advisories/GHSA-xqj6-vjqr-33vv
+MAPSERVER_CONFIG_FILE=${WORK_DIR}/msautotest/etc/mapserv.conf SCRIPT_NAME=mapserv SERVER_PORT=80 HTTP_X_FORWARDED_HOST="with'single'quote" mapserv QUERY_STRING="MAP=wms_simple_no_onlineresource.map&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-67.5725,42.3683,-58.9275,48.13&FORMAT=application/openlayers&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road" > /tmp/res.txt
+# We need to escape backslash once for the grep regexp, and once for the shell...
+# Hence 4 backslashes for one in the actual output
+cat /tmp/res.txt | grep "with\\\\'single\\\\'quote" >/dev/null || (cat /tmp/res.txt && /bin/false)
+
+
 echo "Done !"


=====================================
CITATION.cff
=====================================
@@ -1,8 +1,8 @@
 cff-version: 1.2.0
 title: MapServer
 message: If you use this software, please cite it using the metadata from this file.
-version: 8.6.3
-date-released: 2026-05-07
+version: 8.6.4
+date-released: 2026-06-01
 abstract: MapServer is an Open Source platform for publishing spatial data and interactive mapping applications to the web.
 type: software
 authors:


=====================================
CMakeLists.txt
=====================================
@@ -17,7 +17,7 @@ include(CheckCSourceCompiles)
 
 set (MapServer_VERSION_MAJOR 8)
 set (MapServer_VERSION_MINOR 6)
-set (MapServer_VERSION_REVISION 3)
+set (MapServer_VERSION_REVISION 4)
 set (MapServer_VERSION_SUFFIX "")
 
 # Set C++ version


=====================================
HISTORY.md
=====================================
@@ -13,6 +13,13 @@ https://mapserver.org/development/changelog/
 
 The online Migration Guide can be found at https://mapserver.org/MIGRATION_GUIDE.html
 
+8.6.4 release (2026-06-01)
+--------------------------
+
+- security: properly escape mapserv_onlineresource in OpenLayers viewer with WMS (#7517)
+
+- security: PostGIS: make sure identifier value is numeric when the declared type is numeric too (#7516)
+
 8.6.3 release (2026-05-07)
 --------------------------
 


=====================================
SECURITY.md
=====================================
@@ -10,6 +10,13 @@ option link at the top of this page, or send your report to the email address:
 Please follow the general guidelines for bug 
 submissions, when describing the vulnerability (see https://mapserver.org/development/bugs.html).
 
+## Note about use of AI/LLM/automated scanners
+
+While reporters are free to use any tool of their choice to detect issues, they
+must *manually* confirm the findings of those tools with an actual reproducing
+test case, not just a theoretical analysis.
+The report must also be humanly checked and be kept as succint as possible.
+
 ## Supported Versions
 
 The MapServer PSC (Project Steering Committee) will release patches for security vulnerabilities 


=====================================
debian/changelog
=====================================
@@ -1,3 +1,10 @@
+mapserver (8.6.4-1) unstable; urgency=high
+
+  * New upstream release.
+  * Update symbols for 8.6.4.
+
+ -- Bas Couwenberg <sebastic at debian.org>  Mon, 01 Jun 2026 20:12:31 +0200
+
 mapserver (8.6.3-1) unstable; urgency=high
 
   * New upstream release.


=====================================
debian/libmapserver2t64.symbols
=====================================
@@ -2201,6 +2201,7 @@ libmapserver.so.2 #PACKAGE# #MINVER#
  msEncodeUrlExcept at Base 6.2.1
  msEncryptStringWithKey at Base 6.2.1
  msEndShapeKml at Base 6.4.0
+ msEscapeJSonLikeString at Base 8.6.4
  msEscapeJSonString at Base 7.0.0
  msEvalContext at Base 6.2.1
  msEvalDoubleExpression at Base 7.6.0
@@ -3307,7 +3308,6 @@ libmapserver.so.2 #PACKAGE# #MINVER#
  (c++)"virtual thunk to ClipperLib::Clipper::Reset()@Base" 6.2.1
  (c++)"virtual thunk to ClipperLib::Clipper::~Clipper()@Base" 6.2.1
  writeSymbol at Base 6.2.1
- x2c at Base 6.2.1
  yyerror at Base 6.2.1
  yylex at Base 6.2.1
  yyparse at Base 6.2.1


=====================================
src/apps/mapserv.c
=====================================
@@ -60,6 +60,14 @@ static int finish_process = 0;
 static void msCleanupOnSignal(int nInData) {
   (void)nInData;
   finish_process = 1;
+#ifdef USE_FASTCGI
+  /* Ask libfcgi to stop accepting new requests. This causes a blocked
+   * FCGI_Accept() to return -1, so the main loop can exit promptly
+   * instead of waiting for the next request to arrive. Safe to call
+   * from a signal handler: it just sets an internal flag (declared in
+   * fcgiapp.h, which is pulled in via fcgi_stdio.h above). */
+  FCGX_ShutdownPending();
+#endif
 }
 #endif
 
@@ -242,8 +250,22 @@ int main(int argc, char *argv[]) {
   /*      Setup cleanup magic, mainly for FastCGI case.                   */
   /* -------------------------------------------------------------------- */
 #ifndef _WIN32
-  signal(SIGUSR1, msCleanupOnSignal);
-  signal(SIGTERM, msCleanupOnSignal);
+  {
+    /* Install via sigaction without SA_RESTART so that a blocking
+     * accept()/select() inside FCGI_Accept() returns EINTR when the
+     * signal arrives while the process is idle. Combined with
+     * FCGX_ShutdownPending() in the handler, this lets the FastCGI
+     * loop exit on SIGTERM instead of waiting for the next request. */
+    struct sigaction sa;
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_handler = msCleanupOnSignal;
+    sigemptyset(&sa.sa_mask);
+    sigaddset(&sa.sa_mask, SIGUSR1);
+    sigaddset(&sa.sa_mask, SIGTERM);
+    sa.sa_flags = 0; /* deliberately no SA_RESTART */
+    sigaction(SIGUSR1, &sa, NULL);
+    sigaction(SIGTERM, &sa, NULL);
+  }
 #endif
 
 #ifdef USE_FASTCGI


=====================================
src/cgiutil.c
=====================================
@@ -396,22 +396,37 @@ char *fmakeword(FILE *f, char stop, int *cl) {
   }
 }
 
-char x2c(char *what) {
-  register char digit;
-
-  digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
-  digit *= 16;
-  digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
-  return (digit);
+static int hex_to_integer(char c) {
+  if (c >= '0' && c <= '9')
+    return c - '0';
+  if (c >= 'A' && c <= 'F')
+    return c - 'A' + 10;
+  if (c >= 'a' && c <= 'f')
+    return c - 'a' + 10;
+  return -1;
 }
 
 void unescape_url(char *url) {
-  register int x, y;
+  register int x, y, hi, lo;
 
   for (x = 0, y = 0; url[y]; ++x, ++y) {
-    if ((url[x] = url[y]) == '%') {
-      url[x] = x2c(&url[y + 1]);
+    if (url[y] == '%') {
+      hi = hex_to_integer(url[y + 1]);
+      if (hi < 0) {
+        /* %-encoding is malformed, leave as-is */
+        url[x] = '%';
+        continue;
+      }
+      lo = hex_to_integer(url[y + 2]);
+      if (lo < 0) {
+        /* %-encoding is malformed, leave as-is */
+        url[x] = '%';
+        continue;
+      }
+      url[x] = (char)(hi * 16 + lo);
       y += 2;
+    } else {
+      url[x] = url[y];
     }
   }
   url[x] = '\0';


=====================================
src/cgiutil.h
=====================================
@@ -93,7 +93,6 @@ MS_DLL_EXPORT void getword(char *, char *, char);
 MS_DLL_EXPORT char *makeword_skip(char *, char, char);
 MS_DLL_EXPORT char *makeword(char *, char);
 MS_DLL_EXPORT char *fmakeword(FILE *, char, int *);
-MS_DLL_EXPORT char x2c(char *);
 MS_DLL_EXPORT void unescape_url(char *);
 MS_DLL_EXPORT void plustospace(char *);
 MS_DLL_EXPORT int rind(char *, char);


=====================================
src/mapogcapi.cpp
=====================================
@@ -2023,9 +2023,6 @@ OGCAPIFormat msOGCAPIGetOutputFormat(cgiRequestObj *request) {
                    strstr(p, OGCAPI_MIMETYPE_HTML) != nullptr)) {
     format = OGCAPIFormat::HTML;
   } else if (p) {
-    std::string errorMsg("Unsupported format requested: ");
-    errorMsg += p;
-    msOGCAPIOutputError(OGCAPI_PARAM_ERROR, errorMsg.c_str());
     format = OGCAPIFormat::Invalid;
   } else {
     format = OGCAPIFormat::HTML; // default for now
@@ -2060,6 +2057,7 @@ int msOGCAPIDispatchRequest(mapObj *map, cgiRequestObj *request) {
   const OGCAPIFormat format = msOGCAPIGetOutputFormat(request);
 
   if (format == OGCAPIFormat::Invalid) {
+    msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested.");
     return MS_SUCCESS; // avoid any downstream MapServer processing
   }
 


=====================================
src/mapows.c
=====================================
@@ -1468,7 +1468,7 @@ const char *msOWSGetInspireSchemasLocation(mapObj *map) {
   schemas_location =
       msLookupHashTable(&(map->web.metadata), "inspire_schemas_location");
   if (schemas_location == NULL)
-    schemas_location = "http://inspire.ec.europa.eu/schemas";
+    schemas_location = INSPIRE_DEFAULT_SCHEMAS_LOCATION;
 
   return schemas_location;
 }


=====================================
src/mapows.h
=====================================
@@ -40,6 +40,13 @@
  */
 #define OWS_DEFAULT_SCHEMAS_LOCATION "http://schemas.opengis.net"
 
+/* Likewise, this is the URL to the official INSPIRE Schema Repository. Used by
+ * default for INSPIRE services (i.e. services that define
+ * ows_inspire_capabilities) unless the inspire_schemas_location web
+ * metadata is set in the mapfile.
+ */
+#define INSPIRE_DEFAULT_SCHEMAS_LOCATION "https://inspire.ec.europa.eu/schemas"
+
 #if defined USE_LIBXML2 && defined USE_WFS_SVR
 #include <libxml/tree.h>
 #endif


=====================================
src/mappostgis.cpp
=====================================
@@ -2024,18 +2024,16 @@ static std::string msPostGISBuildSQLWhere(layerObj *layer, const rectObj *rect,
       }
     }
   }
-  bool insert_and = false;
+
   std::string strWhere;
   if (bIsValidRect && !strRect.empty()) {
     strWhere += strRect;
-    insert_and = true;
   }
 
   /* Handle a translated filter (RFC91). */
   if (layer->filter.native_string) {
-    if (insert_and) {
+    if (!strWhere.empty()) {
       strWhere += " AND ";
-      insert_and = true;
     }
     strWhere += '(';
     strWhere += layer->filter.native_string;
@@ -2045,17 +2043,17 @@ static std::string msPostGISBuildSQLWhere(layerObj *layer, const rectObj *rect,
   /* Handle a native filter set as a PROCESSING option (#5001). */
   const char *native_filter = msLayerGetProcessingKey(layer, "NATIVE_FILTER");
   if (native_filter) {
-    if (insert_and) {
+    if (!strWhere.empty()) {
       strWhere += " AND ";
-      insert_and = true;
     }
+
     strWhere += '(';
     strWhere += native_filter;
     strWhere += ')';
   }
 
   if (uid) {
-    if (insert_and) {
+    if (!strWhere.empty()) {
       strWhere += " AND ";
     }
 
@@ -3736,6 +3734,17 @@ static int msPostGISLayerTranslateFilter(layerObj *layer, expressionObj *filter,
       native_string += stresc;
       native_string += '\'';
     } else {
+      char *endptr = nullptr;
+      std::strtod(stresc, &endptr);
+      if (endptr != stresc + strlen(stresc)) {
+        if (layer->debug >= 2) {
+          msDebug(
+              "msPostGISLayerTranslateFilter. '%s' is not a numeric value.\n",
+              filter->string);
+        }
+        msFree(stresc);
+        return MS_FAILURE;
+      }
       native_string += stresc;
     }
     msFree(stresc);


=====================================
src/maprasterquery.c
=====================================
@@ -1205,7 +1205,10 @@ int msRASTERLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record) {
 
         switch (rlinfo->eDataType) {
         case GDT_Byte:
+#if GDAL_VERSION_MAJOR > 3 ||                                                  \
+    (GDAL_VERSION_MAJOR == 3 && GDAL_VERSION_MINOR >= 7)
         case GDT_Int8:
+#endif
         case GDT_UInt16:
         case GDT_Int16:
         case GDT_Int32:


=====================================
src/mapscale.c
=====================================
@@ -309,7 +309,7 @@ imageObj *msDrawScalebar(mapObj *map) {
         }
       }
 
-      sprintf(label, "%g", j * i);
+      snprintf(label, sizeof(label), "%g", j * i);
       map->scalebar.label.position = MS_CC;
       p.x = ox + j * isx; /* + MS_NINT(fontPtr->w/2); */
       p.y = oy + map->scalebar.height + MS_NINT(VSPACING * fontHeight);
@@ -320,9 +320,10 @@ imageObj *msDrawScalebar(mapObj *map) {
       }
       state = -state;
     }
-    sprintf(label, "%g", j * i);
+    snprintf(label, sizeof(label), "%g", j * i);
     ox = ox + j * isx - MS_NINT((strlen(label) * fontWidth) / 2.0);
-    sprintf(label, "%g %s", j * i, unitText[map->scalebar.units]);
+    snprintf(label, sizeof(label), "%g %s", j * i,
+             unitText[map->scalebar.units]);
     map->scalebar.label.position = MS_CR;
     p.x = ox; /* + MS_NINT(fontPtr->w/2); */
     p.y = oy + map->scalebar.height + MS_NINT(VSPACING * fontHeight);
@@ -361,12 +362,13 @@ imageObj *msDrawScalebar(mapObj *map) {
         goto scale_cleanup;
       }
 
-      sprintf(label, "%g", j * i);
+      snprintf(label, sizeof(label), "%g", j * i);
       if (j != map->scalebar.intervals) {
         map->scalebar.label.position = MS_CC;
         p.x = ox + j * isx; /* + MS_NINT(fontPtr->w/2); */
       } else {
-        sprintf(label, "%g %s", j * i, unitText[map->scalebar.units]);
+        snprintf(label, sizeof(label), "%g %s", j * i,
+                 unitText[map->scalebar.units]);
         map->scalebar.label.position = MS_CR;
         p.x = ox + j * isx - MS_NINT((strlen(label) * fontWidth) / 2.0);
       }


=====================================
src/mapserv-index.cpp
=====================================
@@ -425,7 +425,7 @@ static int createHTMLOutput(json response, const char *templateName) {
 int msOGCAPIDispatchMapIndexRequest(mapservObj *mapserv, configObj *config) {
 #ifdef USE_OGCAPI_SVR
   if (!mapserv || !config)
-    return -1; // Handle null pointers
+    return MS_FAILURE; // Handle null pointers
 
   cgiRequestObj *request = mapserv->request;
 
@@ -437,6 +437,12 @@ int msOGCAPIDispatchMapIndexRequest(mapservObj *mapserv, configObj *config) {
   }
 
   OGCAPIFormat format = msOGCAPIGetOutputFormat(request);
+
+  if (format == OGCAPIFormat::Invalid) {
+    msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested.");
+    return MS_FAILURE;
+  }
+
   const char *key = request->api_path[0];
 
   mapObj *map = getMapFromConfig(config, key);
@@ -479,11 +485,16 @@ int msOGCAPIDispatchMapIndexRequest(mapservObj *mapserv, configObj *config) {
 int msOGCAPIDispatchIndexRequest(mapservObj *mapserv, configObj *config) {
 #ifdef USE_OGCAPI_SVR
   if (!mapserv || !config)
-    return -1; // Handle null pointers
+    return MS_FAILURE; // Handle null pointers
 
   cgiRequestObj *request = mapserv->request;
   const OGCAPIFormat format = msOGCAPIGetOutputFormat(request);
 
+  if (format == OGCAPIFormat::Invalid) {
+    msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested.");
+    return MS_FAILURE;
+  }
+
   const char *key = NULL;
   json links = json::array();
 
@@ -504,7 +515,7 @@ int msOGCAPIDispatchIndexRequest(mapservObj *mapserv, configObj *config) {
   } else if (format == OGCAPIFormat::HTML) {
     createHTMLOutput(response, TEMPLATE_HTML_INDEX);
   } else {
-    msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested.");
+    assert(false && "Unhandled OGCAPIFormat value");
   }
 
   return MS_SUCCESS;


=====================================
src/mapserver.h
=====================================
@@ -2889,7 +2889,8 @@ MS_DLL_EXPORT void msStringFirstCap(char *string);
 MS_DLL_EXPORT int msEncodeChar(const char);
 MS_DLL_EXPORT char *msEncodeUrlExcept(const char *, const char);
 MS_DLL_EXPORT char *msEncodeUrl(const char *);
-MS_DLL_EXPORT char *msEscapeJSonString(const char *pszJSonString);
+MS_DLL_EXPORT char *msEscapeJSonString(const char *pszString);
+MS_DLL_EXPORT char *msEscapeJSonLikeString(const char *pszString, char chQuote);
 MS_DLL_EXPORT char *msEncodeHTMLEntities(const char *string);
 MS_DLL_EXPORT void msDecodeHTMLEntities(const char *string);
 MS_DLL_EXPORT int msIsXMLTagValid(const char *string);


=====================================
src/mapstring.cpp
=====================================
@@ -1205,18 +1205,18 @@ char *msEncodeUrlExcept(const char *data, const char except) {
 /*                            msEscapeJSonString()                      */
 /************************************************************************/
 
-/* The input (and output) string are not supposed to start/end with double */
-/* quote characters. It is the responsibility of the caller to do that. */
-char *msEscapeJSonString(const char *pszJSonString) {
+/* The input (and output) string are not supposed to start/end with chQuote
+ * characters. It is the responsibility of the caller to do that. */
+char *msEscapeJSonLikeString(const char *pszString, char chQuote) {
   /* Worst case is one character to become \uABCD so 6 characters */
   char *pszRet;
   int i = 0, j = 0;
   static const char *pszHex = "0123456789ABCDEF";
 
-  pszRet = (char *)msSmallMalloc(strlen(pszJSonString) * 6 + 1);
+  pszRet = (char *)msSmallMalloc(strlen(pszString) * 6 + 1);
   /* From http://www.json.org/ */
-  for (i = 0; pszJSonString[i] != '\0'; i++) {
-    unsigned char ch = pszJSonString[i];
+  for (i = 0; pszString[i] != '\0'; i++) {
+    unsigned char ch = pszString[i];
     if (ch == '\b') {
       pszRet[j++] = '\\';
       pszRet[j++] = 'b';
@@ -1239,9 +1239,9 @@ char *msEscapeJSonString(const char *pszJSonString) {
       pszRet[j++] = '0';
       pszRet[j++] = pszHex[ch / 16];
       pszRet[j++] = pszHex[ch % 16];
-    } else if (ch == '"') {
+    } else if (ch == chQuote) {
       pszRet[j++] = '\\';
-      pszRet[j++] = '"';
+      pszRet[j++] = chQuote;
     } else if (ch == '\\') {
       pszRet[j++] = '\\';
       pszRet[j++] = '\\';
@@ -1253,6 +1253,12 @@ char *msEscapeJSonString(const char *pszJSonString) {
   return pszRet;
 }
 
+/* The input (and output) string are not supposed to start/end with double
+ * quote characters. It is the responsibility of the caller to do that. */
+char *msEscapeJSonString(const char *pszString) {
+  return msEscapeJSonLikeString(pszString, '"');
+}
+
 /* msEncodeHTMLEntities()
 **
 ** Return a copy of string after replacing some problematic chars with their


=====================================
src/maptemplate.c
=====================================
@@ -4097,7 +4097,21 @@ static char *processLine(mapservObj *mapserv, const char *instr, FILE *stream,
 #else
     ol = msBuildOnlineResource(mapserv->map, mapserv->request);
 #endif
-    outstr = msReplaceSubstring(outstr, "[mapserv_onlineresource]", ol);
+
+    if (strstr(outstr, "'[mapserv_onlineresource]'")) {
+      // Fix
+      // https://github.com/MapServer/MapServer/security/advisories/GHSA-xqj6-vjqr-33vv
+      char *pszEscaped = msEscapeJSonLikeString(ol, '\'');
+      const size_t nLen = 1 + strlen(pszEscaped) + 1 + 1;
+      char *pszEscapedWithSingleQuotes = (char *)msSmallMalloc(nLen);
+      snprintf(pszEscapedWithSingleQuotes, nLen, "'%s'", pszEscaped);
+      outstr = msReplaceSubstring(outstr, "'[mapserv_onlineresource]'",
+                                  pszEscapedWithSingleQuotes);
+      msFree(pszEscapedWithSingleQuotes);
+      msFree(pszEscaped);
+    } else {
+      outstr = msReplaceSubstring(outstr, "[mapserv_onlineresource]", ol);
+    }
     msFree(ol);
   }
 



View it on GitLab: https://salsa.debian.org/debian-gis-team/mapserver/-/compare/fae9ca68878a6b8f5d1801b67b5cd150ee3aa623...9c49374f98a2640deefb354ce87701210bb336e6

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/mapserver/-/compare/fae9ca68878a6b8f5d1801b67b5cd150ee3aa623...9c49374f98a2640deefb354ce87701210bb336e6
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20260601/cead7cd4/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list