Commit Graph

17888 Commits

Author SHA1 Message Date
csoler
e43d23f1af
Merge pull request #3314 from thunder2/get-main-executable-path
Moved Windows specific code for getting main executable path from ret…
2026-09-11 20:09:55 +02:00
csoler
360da46e96
Merge pull request #3290 from defnax/account-creation-service
⚙️Added account creation for retroshare service - v2
2026-09-11 20:09:27 +02:00
thunder2
419bac9eb0 Moved Windows specific code for getting main executable path from retroshare-service.cc to an own file as function getMainExecutablePath 2026-09-11 14:23:05 +02:00
defnax
f1db29079a Fix terminal prompts and formatting
- Left-pad profile indices with leading zeros to align with node list
- Clarify prompts: use "profile name" instead of "Username" and "node to that profile" instead of "of it"
- Update terms to use "Node ID" and "Profile ID"
- Initialize webui_pass2 to empty string
- Report unexpected error in switches for CreateAccountResult::Unknown
2026-09-10 21:38:45 +02:00
defnax
3a7b465321 define explicit enum values for CreateAccountResult 2026-09-10 21:20:54 +02:00
csoler
01bc50edb3
Merge pull request #3306 from jolavillette/fix/gui-applicationfilepath-non-windows
gui/main: fix non-Windows build, applicationFilePath declared under WINDOWS_SYS only
2026-09-05 13:40:11 +02:00
jolavillette
52cefc693e gui/main: fix Linux/macOS build, applicationFilePath was declared under WINDOWS_SYS only
Commit e63584843 declared applicationFilePath inside the WINDOWS_SYS
block but uses it unconditionally to fill conf.main_executable_path,
so every non-Windows GUI build fails with 'applicationFilePath was
not declared in this scope'. Declare it at function scope, seeded
from argv[0] (the previous non-Windows behaviour); Windows still
overrides it with QCoreApplication::applicationFilePath().

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-04 07:53:07 +02:00
csoler
799d4c9197
Merge pull request #3281 from thunder2/fix-tor
Fix tor
2026-09-03 22:32:07 +02:00
csoler
03daec3e2a
Merge pull request #3297 from jolavillette/fix/distant-chat-locally-closed-event
Distant chat window: close it when the conversation is closed from another client
2026-09-03 18:48:09 +02:00
csoler
21c981a430
Merge pull request #3299 from jolavillette/fix/sharemanager-friend-event-reset
ShareManager: stop discarding pending edits on every friend-list event
2026-08-31 10:12:45 +02:00
jolavillette
040d19c946 ShareManager: stop discarding pending edits on every friend-list event
The "Configure shared directories" dialog edits a local copy of the
shared directories and only commits it when Apply is pressed. Since
0ce2dd848 it reloads that copy from the core on *any* FRIEND_LIST event,
while the intent was only to follow friend-group changes. NODE_CONNECTED,
NODE_STATUS_CHANGED, NODE_STATE_STRING_CHANGED... fire every few seconds
as soon as a friend is online, so a directory added or removed in the
dialog reverts to the saved state before the user can press Apply.

Only react to GROUP_ADDED/REMOVED/CHANGED, and on those refresh the group
names column (dropping groups that no longer exist) instead of reloading
everything. Also do not reload when showYourself() is called while the
dialog is already open, for the same reason.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 05:47:37 +02:00
jolavillette
ea97a7437d Distant chat window: close it when the conversation is closed from another client
A distant chat started from the web UI pops the desktop chat window for
its tunnel (the core sends itself a "[Starting distant chat" message).
Leaving that conversation from the web UI then left the window as it was:
green LED, "You can talk", and on close the offer to end a conversation
the core no longer had -- closeEvent() ignored the false answer of
getDistantChatStatus() and read a default-initialised status.

On the new RsDistantChatEventCode::TUNNEL_STATUS_LOCALLY_CLOSED
(libretroshare fix/distant-chat-locally-closed-event) the window closes,
as it does when the conversation is ended from the window itself. And
closeEvent() asks no confirmation and calls no close for a tunnel the
core does not know any more.
2026-08-30 09:20:37 +02:00
jolavillette
6622cb9526 service: harden the terminal account creation
Follow-up to "Added account creation for retroshare service", touching
only that feature's own paths.

**-U create could only mint a brand-new PGP profile.** A null RsPgpId was
always passed to createLocationV2(), so a user who already has a profile,
sees it in the -U list output and picks [c] silently got a second
identity: their friends no longer recognise them and every certificate
has to be exchanged again. createLocationV2() takes pgpId as in/out and
reuses it when non-null (rsinit.cc:2247), and it explicitly accepts an
empty pgpName in that case (rsinit.cc:2243), so the profiles known to
RsAccounts::GetPGPLogins() are now listed first and reusing one just adds
this machine as another node. The prompt spells out what a new profile
costs.

**Ctrl-C at a prompt reported the wrong thing.** On glibc signal()
installs the handler with SA_RESTART, so the read blocked behind getline
is restarted and keepRunning is only seen once the user also presses
Enter. Control then fell out of the selector with prefUserString still
"list", RsPeerId("list") null, and the user who had just cancelled was
told their location id was invalid, with exit -EINVAL. Cancelling now
returns 0. doTerminalCreateAccount() returns a three-state result so a
deliberate abort is no longer reported as a failure, and the failure
paths use -RsInit::ERR_* instead of a bare -1 (exit 255).

**-U list failed on a non-tty even when accounts existed.** It returned
ERR_NO_AVAILABLE_ACCOUNT whenever stdin was not a terminal, while the
option is documented as a way to list accounts and retroshare-webui's
README puts it in the first-start flow. It now prints the list and
returns 0, keeping the error for the case it names: nothing to list. The
[c] line moved below that check, so a non-interactive run no longer
advertises an option it then refuses.

**Every prompt is bounded.** A terminal dying mid-prompt -- an ssh
session dropping, a container losing its tty -- turns each following read
into an immediate EOF, and all these loops re-ask on empty or mismatched
input. Three attempts then a clear message. This also covers the -W web
interface password loop, which had the same shape before this feature
existed.

**A passphrase is no longer asked of an absent terminal.** The
PASSWORD_REQUESTED handler now checks for an interactive stdin first, so
-U <hexid> under systemd or docker fails with a readable message instead
of prompting nothing.

Selections are trimmed, so "1 " and a CRLF line are no longer rejected as
invalid, and MAX_PROMPT_ATTEMPTS sits outside the terminal-login guard
because the web interface password prompt has its own build option.
Compile-checked in all four RS_SERVICE_TERMINAL_LOGIN /
RS_SERVICE_TERMINAL_WEBUI_PASSWORD combinations, warning-free.

Note that the underlying spin is a libretroshare bug: rs_getpass() stored
getchar()'s EOF in an unsigned char, where -1 becomes 0xFF and never ends
the loop. Fixed separately in libretroshare; the bounds here are useful
on their own and do not depend on it.
2026-08-28 13:50:32 +02:00
defnax
411ef267ad Added fallback option when no account available 2026-08-28 13:50:32 +02:00
defnax
be884ded91 Added account creation for retroshare service 2026-08-28 13:50:31 +02:00
csoler
f8553d2fd9
Merge pull request #3276 from csoler/v0.6-IdentityDialog3
fixed warning message about identities with insecure fingerprint
2026-08-28 12:21:25 +02:00
csoler
5bbe63e4d4
Merge pull request #3292 from jolavillette/fix/eliditemdelegate-font-inherit
gui: let RSElidedItemDelegate inherit the view font from the model font
2026-08-28 11:14:46 +02:00
csoler
5a4c943b96
Merge pull request #3272 from jolavillette/fix/securityitem-sslonly-accept-button
Fix "Accept friend request" button persisting after SSL-only friend added
2026-08-28 10:45:40 +02:00
csoler
fd69cff8d7
Merge pull request #3263 from jolavillette/fix/voip-preview-aspect-ratio
fix(voip): keep aspect ratio in camera preview
2026-08-28 10:42:50 +02:00
jolavillette
4a1799db76 fix(voip): keep aspect ratio in camera preview
The self-view preview in Preferences/VOIP scaled camera frames into the
display widget with Qt::IgnoreAspectRatio, forcing them into a 4:3 box.
Non-4:3 cameras (e.g. 16:9) were therefore stretched vertically.

Use Qt::KeepAspectRatio, matching the sibling showFrameOff() which
already scales the placeholder icon correctly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-16 18:24:46 +02:00
jolavillette
f0a5a4687f Fix "Accept friend request" button persisting after SSL-only friend added
In the Activity feed, accepting an unknown peer (no PGP key in keyring)
adds it as an SSL-only friend via addSslOnlyFriend(), which sets
skip_pgp_signature_validation instead of the PGP-keyring accept_connection
flag. SecurityItem::updateItem() only tested details.accept_connection to
decide button visibility, so for an accepted SSL-only friend the condition
stayed false and the "Accept friend request" button kept being shown (and
"Remove friend" stayed hidden), even though the peer was already a friend.

Treat skip_pgp_signature_validation == true as accepted too, since that
flag is only set for a peer already present in the friend list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-16 18:24:35 +02:00
jolavillette
61e647081c gui: let RSElidedItemDelegate inherit the view font from the model font
The delegate took the Qt::FontRole of the model and assigned it to the style option as
is, replacing the font of the view instead of merging into it. A font stored in a model
usually only carries the one attribute the caller wanted to change — most of the time
bold — and expects family and size to keep coming from the view. Assigning it whole
dropped those items back to the application font, ignoring the font size configured in
the settings, which FontSizeHandler puts on the view.

That is easy to trigger: QTreeWidgetItem::font() returns a default constructed font when
the item has no Qt::FontRole yet, so the familiar "read the font, set it bold, write it
back" turned the whole list into the application font. On a remote X display where the
desktop font is 9pt and the RetroShare font size is 11pt, the list visibly shrank.

Merge with QFont::resolve() instead, which keeps only the attributes the model really
set and takes the rest from the view — the same merge QStyledItemDelegate::initStyleOption()
performs. Same change in the tooltip path of editorEvent(), which recomputes the elision
with that font. sizeHint() was already using the merged font from initStyleOption(), so
rows were being measured with one font and painted with another.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 18:23:58 +02:00
csoler
6160b39dab
Merge pull request #3271 from defnax/distantchat-popup-fix
💬 Fixed to not popup distant chat on incoming chat
2026-08-16 14:16:35 +02:00
csoler
48c60e1cdb
Merge pull request #3210 from jolavillette/FixSearchColumnWidthPersistence
GUI: persist search results column widths across restarts
2026-08-13 18:13:47 +02:00
jolavillette
9119058c48 GUI: persist search results column widths across restarts 2026-08-07 01:12:19 +02:00
csoler
682cde9fbd
Merge pull request #3274 from jolavillette/fix/gxs-mark-all-read-nofreeze
Fix UI freeze on "mark all as read/unread" for forums, channels and boards
2026-08-06 21:46:57 +02:00
jolavillette
1b99beebc5 Address review: pointer hand-off to the workers, event-driven board update
- GxsForumModel / PostedPostsModel: hand the id list to the background
  worker through a pointer deleted after the call, so the lambda capture
  does not deep copy it.
- PostedPostsModel: setAllMsgReadStatus() no longer updates the model
  directly. The batched READ_STATUS_CHANGED event now carries the
  affected ids and their new state (libretroshare side), and the event
  handler applies them locally — so a batch initiated by another
  frontend (e.g. webUI) updates the board view exactly the same way,
  and no post is re-read from the database.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
ebac1481f0 Revert "gui(forums): opt-in latency probes on the read/unread and loading path"
Profiling code removed from the PR, as requested in review of the sibling
PRs. This reverts commit 8845aa4636e630977f4a6817e8a267735e128e28.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
dea2f28dd9 gui(forums): opt-in latency probes on the read/unread and loading path
Set RS_GUI_PROFILE to a threshold in milliseconds (0 reports
everything) to get one line per measured operation on stderr, plus a
50 ms watchdog on the GUI thread that reports every stall of the event
loop wherever the blocking code lives, naming the last probed
operation. This is what located the actual freeze of the read/unread
path (a whole-model dataChanged() measured at 1072 ms) after several
plausible-from-code-reading fixes had failed to: the numbers say where
the time goes instead of a story explaining where it might go.

All probes are inert unless the environment variable is set.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
5cbcd962dd gui(forums): re-read the group on SUBSCRIBE_STATUS_CHANGED instead of flipping the flag
The event means the subscription status changed, not that it was
toggled: guessing the new value by inverting the current flag goes
wrong as soon as one event is duplicated, lost, or refers to a state
the widget already holds. When the guess lands on 'unsubscribed', the
widget silently refuses to mark posts read or unread (the very first
check of markMsgAsReadUnread) until the next group reload puts the flag
right again. updateGroupData() was already called anyway; let it be the
only writer of the flag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
b0ca91c825 gui(forums): drop the expanded-items save/restore around read-status changes
setMsgReadStatus() only emits dataChanged(); it never resets the model
nor changes its layout, so the expanded items and the current index
survive it untouched. Saving and restoring them on every toggle was
pure overhead, and an expensive one: the restore walks every expanded
item and pays, for each, a linear scan of the post array plus a linear
scan of the view items -- quadratic work on the GUI thread for a single
post marked read or unread on a large forum.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
243c417bfc GxsForumModel: size the read-status view refresh on rows, not message ids
280e51f53 restricted the dataChanged() refresh to the affected post
unless more than 5 messages changed, in which case it refreshes the
whole view. But changed_msgs counts message ids, and a post carries one
id per stored version of itself, all sharing one read status: marking a
single post read or unread on a post edited 46 times queued 47 ids and
triggered the whole-model refresh. Measured on a 8259 post forum: one
click, one row repainted, 1072 ms of frozen GUI in the dataChanged()
handling; with this fix the same click costs about 1 ms.

Count the changed rows separately and size the refresh on that.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
3860f76dc1 gui(forums): create reload timer before setGroupId (fix ctor SIGSEGV)
The coalescing timer was allocated near the end of the constructor, but
setGroupId(forumId) is called earlier and synchronously reaches
groupIdChanged() -> updateDisplay(true) -> mDeferredReloadTimer->stop(),
dereferencing the still-uninitialised pointer and crashing the moment a forum
was opened. Allocate the timer right after setupUi(), before setGroupId().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
839293f84d gui(forums): coalesce full-forum reloads to stop sync-burst UI freezes
handleEvent_main_thread() ran a full updateDisplay(true) (updateForum ->
getForumPostsHierarchy -> setPosts full reset -> proxy re-sort/re-filter ->
tree rebuild) for every incoming GXS event. A sync batch delivers many
NEW_MESSAGE events back to back, so the forum was reloaded once per post,
freezing the UI for seconds and resetting the model out from under the user's
current selection (and racing the async read-status persistence, making a
just-read post pop back to bold).

Route those events through a single-shot QTimer (300 ms) that is restarted on
each event, so a whole burst collapses into one reload once the events settle.
An explicit reload (forum switch) cancels any pending deferred one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
78ff5d66e6 GxsForumModel: fix malformed model reset dropping freshly-arrived posts
setPosts() called beginResetModel()/endResetModel() *before* swapping mPosts,
so endResetModel() fired while the model still exposed the previous hierarchy,
then emitted an extra beginInsertRows()/endInsertRows() on top of the reset.
That double-signalling left the view/proxy row->source mapping stale, so a
post that had just arrived could map to an invalid source index: selecting it
neither displayed its content nor cleared its unread (bold) state.

Bracket the actual data swap with beginResetModel()/endResetModel() and drop
the bogus row-insertion signal; a full reset already tells the views to
re-query everything. Same anti-pattern as the channels grid-empty-on-new-post
fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
8959b45087 gui(forums): keep single-post read latency low via unitary markRead
Routing every read through the batched markRead(grpId, vector, read) also
routed single interactive reads (selecting/opening one post) through its
waitToken(): the READ_STATUS_CHANGED event, and thus the forum-list unread
counter refresh, was only emitted once the DB write completed, adding
~100ms plus one GXS tick of latency versus the previous behaviour.

Send a single changed message through the per-message markRead(pair),
which emits the event immediately, and keep the batched call only for
larger sets (mark-all, with-children, versioned posts) where deferring the
single event until completion is what avoids the freeze.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
2816dfd9f6 gui(forums): fix slow post navigation by restricting dataChanged refresh to affected post and parents 2026-08-01 23:16:08 +02:00
jolavillette
e5ed16c805 Channels/Posted models: never freeze the UI on "mark all as read"
GxsChannelPostsModel and PostedPostsModel spawned one detached std::thread (and
got one event) per post on "mark all as read/unread", freezing the UI on large
channels/boards - the same problem just fixed for forums, and worse here given
the much larger channel/board databases.

Both now collect the affected message ids and issue a single background batch
call (setMessageReadStatus / setPostReadStatus with a vector) plus a single view
refresh. PostedPostsModel additionally updates its local model up front (it
previously relied entirely on the per-message events).

Requires the matching libretroshare bulk overloads.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
f4463dd17f GxsForumModel: never freeze the UI on "mark all as read"
recursSetMsgReadStatus() used to spawn one detached std::thread per changed
post (each blocking up to 5s in markRead) and emit one dataChanged() per post.
On a forum with thousands of unread posts this created thousands of threads
and signals driven from the GUI thread, freezing (and sometimes crashing) the
UI - the reported symptom being an hour-long hourglass on an 8000-post forum.

Now the recursion only collects the affected message ids and updates the
in-memory model; setMsgReadStatus() then issues a single background batch call
(rsGxsForums->markRead(group, ids, read)) and a single view refresh. The GUI
thread does O(n) in-memory work plus one thread and one signal, so it stays
responsive no matter how large the forum is.

Requires the matching libretroshare bulk markRead() overload.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
csoler
ec9ab70561
Merge pull request #3280 from jolavillette/perf/gxs-channel-loading
GUI: stop copying and sorting the channel post array in the Qt thread
2026-08-01 21:10:36 +02:00
jolavillette
0e31d5fed0 GUI: remove the profiling probes from the channel post model
Requested in review: the RS_GXS_PROFILE instrumentation of update_posts()
and setPosts() served to measure the freeze and verify the fix, but it
should not stay in the optimised code. The libretroshare profiling header
is no longer included.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 14:31:38 +02:00
jolavillette
28e7f791ff GUI: stop copying and sorting the channel post array in the Qt thread
setPosts() runs in the Qt thread, through postToObject(). It copied the whole
post array a fourth time and then sorted it there, so for a channel with a few
thousand posts the interface was frozen for the duration of both.

Move the sort into the loader thread in update_posts(), where the array is
already sitting after the service call, and have setPosts() take its argument
by rvalue reference so the array is moved in rather than copied. The sort is
kept in setPosts() as a safety net: on an already ordered array it only runs
comparisons and moves nothing.

Combined with the libretroshare side making posts movable, the array is now
handed from the data store to the model without a single deep copy of a
thumbnail.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 22:34:12 +02:00
jolavillette
54d4c791aa GUI: profile the channel post model loading
Complements the GXS side instrumentation (libretroshare, gxs/rsgxsprofiler.h)
with the two phases that happen in the GUI: the service calls made from the
loader thread in update_posts(), and the model update in setPosts(), which
runs in the Qt thread and is what actually freezes the interface.

setPosts() reports its three phases separately (array copy, sort, view update)
since they have very different causes.

Enabled by the same RS_GXS_PROFILE environment variable, off by default.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 22:34:12 +02:00
csoler
2bf991418d
Merge pull request #3284 from jolavillette/fix/feedreader-mark-all-unread
FeedReader: add "Mark all as unread" alongside "Mark all as read"
2026-07-30 14:34:04 +02:00
thunder2
2c9fcd0c57 Moved tor data directory for gui to account directory so that we can run multiple tor instances simultaneously 2026-07-27 19:07:57 +02:00
thunder2
9e92faad7c Use “GetModuleFileName” instead of argv[0] for the name of the executable file on Windows, as argv[0] does not always contain the full path 2026-07-27 19:07:57 +02:00
thunder2
e635848438 Use “QCoreApplication::applicationFilePath” instead of argv[0] for the name of the executable file, as argv[0] does not always contain the full path on Windows 2026-07-27 11:15:16 +02:00
jolavillette
2cd7c21aa6 gui(feedreader): add "Mark all as unread" alongside "Mark all as read"
The FeedReader message widget already offered "Mark all as read"
(toolbar button + context menu) but had no way to mark every visible
message as unread again. Add the symmetric "Mark all as unread" entry
to the message context menu.

Factor the shared iterate-over-visible-items logic out of
markAllAsReadMsg() into setAllMsgAsReadUnread(bool read); the read and
unread slots now just call it. Like the existing "mark all as read", the
action honours the current filter (acts on non-hidden rows only) and
goes through the existing per-message setMessageRead() path, so no
backend change is required.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 13:31:47 +02:00
Gioacchino Mazzurco
086184ad21
Fix GitLab mirror failing on GitHub PR refs
The mirror workflow cloned with --mirror and pushed all refs, including
GitHub's refs/pull/* and upstream/pr/*, which GitLab rejects as hidden
refs ("deny updating a hidden ref" on upstream/pr/3213), failing the
whole push. Clone --bare and push only refs/heads/* and refs/tags/*
with --prune, keeping deletion sync while never touching PR refs.
2026-07-23 18:10:46 +02:00
Gioacchino Mazzurco
76ba160ad1
Merge pull request #3269 from jolavillette/docs/build-cmake
Docs/build cmake
2026-07-23 17:56:14 +02:00