• src/syncterm/sftp_wait.c sftp_wait.hsrc/sftp/sftp.h sftp_client.c sftp

    From Deuc¨@VERT to Git commit to main/sbbs/master on Tue Apr 28 13:12:34 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/d046117460fa604cd5980b5a
    Added Files:
    src/syncterm/sftp_wait.c sftp_wait.h
    Modified Files:
    src/sftp/sftp.h sftp_client.c sftp_outcome.c src/syncterm/CMakeLists.txt GNUmakefile sftp_browser.c sftp_queue.c ssh.c
    Log Message:
    sftp: invert the client API to send-then-callback

    Each sftpc_<op>(state, args, cb, cbdata) builds + sends the request
    packet, registers a typed pending entry, and returns immediately.
    The recv thread (sftpc_recv) demuxes by request-ID, parses the
    reply into the typed pending's fields, and invokes the callback.
    No more send_and_wait inside the library Ä the wait belongs to the
    caller that wants it.

    Pending shape: a common struct sftpc_pending base (req_id, list
    links, parse + free_self function pointers, reply ptr, delivered/
    aborted flags, callback + cbdata) plus per-op typed extensions
    that embed the base as their first field Ä sftpc_realpath_pending, sftpc_open_pending, sftpc_read_pending, sftpc_stat_pending, sftpc_readdir_pending, sftpc_descs_pending. Ops with no extra
    result data (close, write, setstat) use the base directly.

    Outcome lives on the pending: err, result, estr. estr is heap-
    allocated and grown via realloc as records accumulate (errors
    aren't a hot path) so there's no fixed-size cap on diagnostic
    text Ä important because parts of estr come straight from the
    remote (SSH_FXP_STATUS message + lang). struct sftpc_outcome and SFTPC_OUTCOME_DECL are gone from the client side; the server side
    keeps its existing flex-array struct sftps_outcome.

    SyncTERM scaffolding (throwaway, deletes when the Wren UI lands):

    - New sftp_wait.[ch] with sftp_wait_cb (signals an event from
    cbdata) plus sftp_sync_<op> blocking wrappers per op. The
    existing C-side SFTP UI (sftp_browser, sftp_queue, ssh.c's
    sftpc_init / authorized_keys read+write loop) all use these.
    - Migration is verbose but mechanical Ä each old call site
    becomes "front half + check err/result + read typed field +
    sftpc_pending_free". Fine for the alpha-level prototype.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net