• QWKnet REP pack reports success when recompressing an existing REP fai

    From Rob Swindell@1:103/705 to GitLab issue in main/sbbs on Mon Oct 26 01:02:59 2026
    open https://gitlab.synchro.net/main/sbbs/-/work_items/1305

    When packing a QWKnet hub's outbound REP fails at the compression step while an older, unsent `data/<HUBID>.REP` is still present, `pack_rep()` reports success. Its caller then saves the hub's export pointers, `data/qnet/<hubid>.out/` is emptied and the packed netmail is deleted, so this pass's messages, netmail and outbound files end up in no packet.

    Code references are as of master 3881be3f01 (souls-11-unit, 2026-10-26).

    ## Where

    `sbbs_t::pack_rep()` (`src/sbbs3/pack_rep.cpp`):

    1. If `data/<HUBID>.REP` exists (a previous REP not yet sent, e.g. after a failed call-out), it is extracted into the temp dir to be updated (`:67-87`).
    2. New messages are appended and `subscan[].ptr` is advanced in memory (`:211`).
    3. The packet is recompressed to the same path (`:293-308`): `create_archive()` for a built-in format, otherwise the hub's external `pack` command. A failure is only logged (`libarchive error ...` or `ERR_EXEC`).
    4. The only success check is `if (!fexistcase(str))` (`:309`), which passes when the old REP is still there (or a partial file was left).
    5. Execution continues: `qnet/<hubid>.out/` is emptied (`:314-315`), packed netmail is deleted from the mail base (`:319` onward), and it returns `true`.

    The callers (the event thread's QNET handling in `main.cpp`, and `qwkjob_pack_rep()` in `qwkjob.cpp`) then write the hub's pointer file (`data/qnet/<HUBID>.ptr`).

    The result is one of: the previous REP sent again without this pass's messages, or (if the archiver left a truncated file) a corrupt REP. Either way the new echomail is skipped by the advanced pointers and the netmail is gone from the mail base.

    ## Suggested fix

    Have the compression step itself decide success: treat `create_archive()` < 0 or a non-zero external `pack` exit as failure and return `false` before touching `qnet/<hubid>.out/`, the mail base or the pointers. Better, compress to a temporary name in `data/` and replace-rename it over `<HUBID>.REP` only on success, so a failed pass leaves the previous REP intact and the next pass repeats this one's messages.

    *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.38-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)