• [PATCH 2/3] Fix: Prevent UUE line corruption by quote/wrap logic

    From Nil A@2:5015/46 to Eugene Palenock on Thu Mar 5 07:59:18 2026
    Hello, Eugene!

    Friday January 31 2020 20:13, from Eugene Palenock -> Stas Mishchenkov:

    е прошло и 6ти лет.

    Пробел в конце второй строчки и перекодированная третья строка.
    Сам файл, который был заююкан:
    https://brorabbit.g0x.ru/uue/scorpions_blackout.mp3

    У меня тоже баг. GoldED+/W32-MSVC 1.1.5-b20180707
    Заююкал - разююкал - файл не совпадает с оригиналом...

    ПочиИЛ.

    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] != '\r' && s[linelen] != '\n') {
    + 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)
  • From Semen Panevin@2:5025/121 to Nil A on Thu Mar 5 09:06:10 2026
    Доброго здоровьица тебе, Nil!

    Thursday March 05 2026 07:59, Nil A писал Eugene Palenock:

    У меня тоже баг. GoldED+/W32-MSVC 1.1.5-b20180707
    Заююкал - разююкал - файл не совпадает с оригиналом...

    ПочиИЛ.

    srcdate и вот это всё...

    С наилучшими пожеланиями, Семён.

    ... В гостях хорошо, а дома хуже...
    --- GoldED+/LNX 1.1.5-b20250409 (Linux 6.18.12-gentoo iF6M10)
    * Origin: IceLAN (2:5025/121)
  • From Nil A@2:5015/46 to Semen Panevin on Thu Mar 5 09:17:42 2026
    Hello, Semen!

    Thursday March 05 2026 09:06, from Semen Panevin -> Nil A:

    У меня тоже баг. GoldED+/W32-MSVC 1.1.5-b20180707
    Заююкал - разююкал - файл не совпадает с оригиналом...
    ПочиИЛ.
    srcdate и вот это всё...

    Отдельным коммитом я отправляю Виталию. Он зальёт может быть завтра. srcdate обновлять в самом патче закрывающем баг было бы совсем никамильфо.

    Best Regards, Nil
    --- GoldED+/LNX 1.1.5-b20260305
    * Origin: Gemini can make mistakes, so double-check it (2:5015/46)
  • From Stas Mishchenkov@2:460/5858 to Nil A on Thu Mar 5 14:16:08 2026
    Hi Nil!

    05 Mar 26 07:59, Nil A -> Eugene Palenock:

    е прошло и 6ти лет.

    Пробел в конце второй строчки и перекодированная третья строка.
    Сам файл, который был заююкан:
    https://brorabbit.g0x.ru/uue/scorpions_blackout.mp3

    У меня тоже баг. GoldED+/W32-MSVC 1.1.5-b20180707
    Заююкал - разююкал - файл не совпадает с оригиналом...

    ПочиИЛ.

    +//
    ------------------------------------------------------------------
    +// UUE character decode: maps ASCII to 6-bit value, -1 = invalid.
    +static int uu_xlat(unsigned char c)
    +{
    + if (c >= ' ' && c < (' ' + 64)) return c - ' ';

    Точно c >= ' '? В улюлюке же пробелов быть не должно.

    Have nice nights.
    Stas Mishchenkov.

    --- Я понимаю, что сейчас в это трудно поверить, но всё будет хорошо.
    * Origin: Lame Users Breeding. Simferopol, Crimea. (2:460/5858)
  • From Nil A@2:5015/46 to Stas Mishchenkov on Thu Mar 5 18:20:04 2026
    Hello, Stas!

    Thursday March 05 2026 14:16, from Stas Mishchenkov -> Nil A:

    - +// UUE character decode: maps ASCII to 6-bit value, -1 =
    invalid.
    +static int uu_xlat(unsigned char c)
    +{
    + if (c >= ' ' && c < (' ' + 64)) return c - ' ';
    Точно c >= ' '? В улюлюке же пробелов быть не должно.

    Прикол в том, что в оригинальном "стандарте", хотя нет RFC, но есть просто man uuencode(5), как раз пробелы есть.

    https://ru.wikipedia.org/wiki/UUE
    При кодировании из файла берутся данные по три байта (в случае, если
    осталось меньше 3 байт, недостающие заменяются нулями). 24 бита,
    образующие эти три байта, делятся на четыре группы по 6 бит. Каждая шестибитная группа интерпретируется как число (от 0 до 2^6-1=63), к
    которому добавляется 32. Получившееся число в диапазоне от 32 до 95 трактуется как код символа в ASCII таблице (получаются символы от пробела (32) до знака подчёркивания (95)

    Т.е. нули кодируются пробелами в "стандарте". Понятное дело, что постепенно пришло понимание, что пробелы в письмах про@бываются, их не особо видно, и придумали их заменять на обратную-ковычку `, код которой 96, как раз за последним символом подчёркивания (95).

    === Тестируем ===
    % echo -n -e '\0\0\0' | uuencode test
    begin 644 test
    #````
    `
    end
    ====

    Код функции uu_xlat как раз оба варианта хавают.

    Best Regards, Nil
    --- GoldED+/LNX 1.1.5-b20260305
    * Origin: Gemini can make mistakes, so double-check it (2:5015/46)
  • From Stas Mishchenkov@2:460/5858 to Nil A on Fri Mar 6 11:31:00 2026
    Hi Nil!

    05 Mar 26 18:20, Nil A -> Stas Mishchenkov:

    - +// UUE character decode: maps ASCII to 6-bit value, -1 =
    invalid.
    +static int uu_xlat(unsigned char c)
    +{
    + if (c >= ' ' && c < (' ' + 64)) return c - ' ';
    Точно c >= ' '? В улюлюке же пробелов быть не должно.

    Прикол в том, что в оригинальном "стандарте", хотя нет RFC, но есть просто man uuencode(5), как раз пробелы есть.

    https://ru.wikipedia.org/wiki/UUE

    При кодировании из файла берутся данные по три байта (в случае, если
    осталось меньше 3 байт, недостающие заменяются нулями). 24 бита,
    образующие эти три байта, делятся на четыре группы по 6 бит. Каждая
    шестибитная группа интерпретируется как число (от 0 до 2^6-1=63), к
    которому добавляется 32. Получившееся число в диапазоне от 32 до 95
    трактуется как код символа в ASCII таблице (получаются символы от пробела
    (32) до знака подчёркивания (95)

    Т.е. нули кодируются пробелами в "стандарте". Понятное дело, что постепенно пришло понимание, что пробелы в письмах про@бываются, их не особо видно, и придумали их заменять на обратную-ковычку `, код которой 96, как раз за последним символом подчёркивания (95).

    === Тестируем ===
    % echo -n -e '\0\0\0' | uuencode test
    begin 644 test
    #````
    `
    end
    ====

    Код функции uu_xlat как раз оба варианта хавают.

    Ага. Вона оно как? А я только про текущий вариант прочитал. Кстати, хотдогед с пробелами ююки делает.

    Have nice nights.
    Stas Mishchenkov.

    --- Вообще-то, волка голова кормит. А ноги, это так - удачный гаджет.
    * Origin: Lame Users Breeding. Simferopol, Crimea. (2:460/5858)