----------------------------------------------------------------------------------
@MSGID: 2:5015/46 69a90e2d
@REPLY: 2:5020/2065@FidoNet 5e34603c
@CHRS: CP866 2
@TZUTC: 0300
@TID: hpt/lnx 1.9
Hello, Eugene!
Friday January 31 2020 20:13, from Eugene Palenock -> Stas Mishchenkov:
Не прошло и 6ти лет.
SM>> Пробел в конце второй строчки и перекодированная третья строка.
SM>> Сам файл, который был заююкан:
SM>> https://brorabbit.g0x.ru/uue/scorpions_blackout.mp3
EP> У меня тоже баг. GoldED+/W32-MSVC 1.1.5-b20180707
EP> Заююкал - разююкал - файл не совпадает с оригиналом...
ПочиНИЛ.
From e521d0b4e9c38a092c10d637ff40cc9264059066 Mon Sep 17 00:00:00 2001
From: Nil Alexandrov <
nil.alexandrov@gmail.com>
Date: Wed, 4 Mar 2026 23:53:08 -0500
Subject: [PATCH 2/3] Fix: Prevent UUE line corruption by quote/wrap logic
- Add robust is_uue_line() detection to identify UUE-encoded lines.
- Update is_quote(), is_quote2(), and setlinetype() to never treat
UUE lines as quotes.
- Update MakeLineIndex/put_on_new_line() to prevent paragraph joining
of UUE lines.
- This prevents GoldEd+ from corrupting UUE-encoded data during
editing, import, export, or display.
- Resolves issue where UUE lines containing `>` or similar quote
patterns were misidentified and joined, causing data loss.
-+-
golded3/geedit.cpp | 7 ++++-
golded3/geline.cpp | 4 +++
golded3/geprot.h | 1 +
golded3/geutil.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 78 insertions(+), 1 deletion(-)
diff --git a/golded3/geedit.cpp b/golded3/geedit.cpp
index 0850847..83399c3 100644
--- a/golded3/geedit.cpp
+++ b/golded3/geedit.cpp
@@ -114,7 +114,12 @@ void IEclass::setlinetype(Line* __line)
__line->type &= ~(GLINE_ALL|GLINE_TEAR|GLINE_ORIG|GLINE_TAGL);
- if (is_quote(__line->txt.c_str()) &&
+ // Treat UUE Encoded Payload as strict un-wrappable hard lines
unconditionally
+ if (is_uue_line(__line->txt.c_str()))
+ {
+ __line->type |= GLINE_HARD;
+ }
+ else if (is_quote(__line->txt.c_str()) &&
is_quote2(__line, __line->txt.c_str()))
{
__line->type |= GLINE_QUOT;
diff --git a/golded3/geline.cpp b/golded3/geline.cpp
index 762e6bc..8db89d4 100644
--- a/golded3/geline.cpp
+++ b/golded3/geline.cpp
@@ -2167,6 +2167,10 @@ static bool check_multipart(const char* ptr,
char* boundary)
inline bool put_on_new_line(const char *ptr)
{
+ // Never allow UUE encodings to be concatenated behind unwrapped strings
+ if (is_uue_line(ptr))
+ return true;
+
if((*ptr == CR) or
(*ptr == CTRL_A) or
is_quote(ptr) or
diff --git a/golded3/geprot.h b/golded3/geprot.h
index d348e26..7395111 100644
--- a/golded3/geprot.h
+++ b/golded3/geprot.h
@@ -467,6 +467,7 @@ bool edit_pathname(char* buf, int buf_size, char*
title, int helpcat);
int GetAkaNo(const ftn_addr& __aka);
int GetQuotestr(const char* ptr, char* qbuf, uint* qlen);
int cmp_quotes(char* q1, char* q2);
+bool is_uue_line(const char* ptr);
int is_quote(const char* ptr);
bool is_quote2(Line* line, const char* ptr);
int IsQuoteChar(const char* s);
diff --git a/golded3/geutil.cpp b/golded3/geutil.cpp
index 466f91d..d429367 100644
--- a/golded3/geutil.cpp
+++ b/golded3/geutil.cpp
@@ -373,6 +373,65 @@ void title_shadow()
w_shadow();
}
+// ------------------------------------------------------------------
+// UUE character decode: maps ASCII to 6-bit value, -1 = invalid.
+static int uu_xlat(unsigned char c)
+{
+ if (c >= ` ` && c < (` ` + 64)) return c - ` `;
+ if (c >= ``` && c < (``` + 32)) return c - ```; // lowercase alias
+ return -1;
+}
+
+// UUE Detection Heuristic
+bool is_uue_line(const char* ptr)
+{
+ if (!ptr || !*ptr) return false;
+
+ const unsigned char* s = (const unsigned char*)ptr;
+ int linelen = 0;
+ while (s[linelen] && s[linelen] != `
` && s[linelen] != `
`) {
+ linelen++;
+ }
+
+ if (linelen == 0) return false;
+
+ int decoded_bytes = uu_xlat(s[0]);
+ if (decoded_bytes < 0 || decoded_bytes > 45) return false;
+
+ // An empty line encoding 0 bytes (e.g. at the end of UUE blocks)
+ if (decoded_bytes == 0) return (linelen <= 2);
+
+ int expected = 1 + ((decoded_bytes + 2) / 3) * 4;
+ int datalen = linelen;
+
+ // Tolerate one trailing checksum character
+ if (datalen == expected + 1) datalen = expected;
+
+ bool length_ok = false;
+ if (datalen == expected) {
+ length_ok = true;
+ } else {
+ int max_expected = 61; // 1 + ceil(45/3)*4
+ if (datalen > expected && datalen <= max_expected) {
+ length_ok = true;
+ } else {
+ // Padding variance handling
+ switch (decoded_bytes % 3) {
+ case 1: if (expected - 2 == datalen) length_ok = true; break;
+ case 2: if (expected - 1 == datalen) length_ok = true; break;
+ }
+ }
+ }
+
+ if (!length_ok) return false;
+
+ // Validate overall data stream
+ for (int i = 0; i < datalen; i++) {
+ if (uu_xlat(s[i]) < 0) return false;
+ }
+
+ return true;
+}
// ------------------------------------------------------------------
@@ -395,6 +454,8 @@ int IsQuoteChar(const char* s)
int is_quote(const char* ptr)
{
+ // Prevent corrupting UUE Lines
+ if (is_uue_line(ptr)) return false;
const char* endptr = ptr + 11;
@@ -402,6 +463,9 @@ int is_quote(const char* ptr)
while((*ptr == ` `) or (*ptr == LF) or issoftcr(*ptr))
ptr++;
+ // Prevent corrupting UUE Lines with accidental leading whitespace
+ if (is_uue_line(ptr)) return false;
+
// Check for empty string
if((*ptr == NUL) or (ptr >= endptr))
return false;
@@ -453,6 +517,9 @@ int is_quote(const char* ptr)
bool is_quote2(Line* line, const char* ptr)
{
+ // Prevent treating UUE lines as quotes
+ if (is_uue_line(ptr)) return false;
+
if (!CFG->quoteusenewai) return true;
char *head = (char *)ptr;
--
2.53.0
Best Regards, Nil
--- GoldED+/LNX 1.1.5-b20260305
* Origin: Gemini can make mistakes, so double-check it (2:5015/46)
SEEN-BY: 46/49 50/109 104/117 221/6 240/1120 301/1
341/66 451/31 452/28 166
SEEN-BY: 455/19 460/58 463/68 4500/1 5000/111
5015/42 46 255 519 5019/40 400
SEEN-BY: 5020/101 113 545 620 715 830 846 848
1042 2992 4441 12000 5022/128
SEEN-BY: 5029/32 5030/49 115 1081 1474 5049/1 3
5050/151 5053/51 58 5054/89
SEEN-BY: 5058/104 5060/900 5061/133 5068/45 5083/1
444 6078/80 6090/1
@PATH: 5015/46 5020/1042 4441