https://gitlab.synchro.net/main/sbbs/-/work_items/872#note_10809
Use case from 2026-11-06: a user reading a GitLab "Reset password instructions" email in a BBS terminal session could not reset their password. The reset link is 88 characters (`
https://gitlab.synchro.net/users/password/edit?reset_password_token=` is 68, plus a 20-character token). The message display word-wraps at `cols - 1` = 79, so the last 9 characters of the token land on the next line. Every click opened a 79-character URL with an 11-character token, and GitLab reports any token it does not recognize as "expired", which the user read as the tokens timing out. The GitLab account-confirmation link has the same problem at 85 characters. Any URL longer than 79 characters in any message is affected.
This is a case the design above does not cover: nobody wrote a script or menu file. The URL is in message text that `show_msg`/`putmsg` displays with `P_WORDWRAP`. To help here, the terminal server needs to link URLs it finds in message text automatically, not only where a script or @-code asks for it.
Notes for that automatic case:
- The visible text should stay the full URL, wrapped exactly as today. OSC 8 only adds the out-of-band URI around it, so terminals without OSC 8 see no change, and copy/paste still works. The short-label form ("[click here]") from the design above belongs to the explicit `hyperlink(uri, text)` case only.
- Because the hyperlink is a state applied to subsequent cells, one OSC 8 open before the URL and one close after it covers both wrapped fragments; the CRLF between them does not end the region (`src/conio/cterm.adoc`, "OSC 8"). No `id=` parameter is needed.
- `src/sbbs3/wordwrap.c` skips Ctrl-A codes and `ESC [` CSI sequences as zero-width but has no handling for OSC (`ESC ]` ... `ESC \`). An OSC 8 sequence inserted before wrapping would count toward the column and could be split. Either teach `wordwrap.c` to skip OSC strings, or apply the linking to the wrapped output. The output-side column tracking in the Terminal class already handles DCS/OSC/PM/APC control strings.
- SyncTERM's own click-to-open URL detection (`detect_url_at()` in `src/syncterm/term.c`) joins a URL across rows only when the previous row's last cell (column 79 of 80) holds a URL character. Synchronet's wrap leaves column 79 blank, so that heuristic does not recover these links either; OSC 8 is the fix on the Synchronet side.
- This would not have helped the user in question, who was in the fTelnet web terminal, unless fTelnet implements OSC 8 (not checked). For GitLab's own links, a short redirect path in GitLab's nginx (e.g. `/pw/<token>`, 50 characters) plus a rewrite of the link in mail delivered to BBS mailboxes reaches every terminal; that is independent of this issue.
*Authored by Claude (Claude Code), on behalf of @rswindell*
--- SBBSecho 3.38-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)