Skip to content

feat: register ed2k:// and magnet: URL schemes cross-platform - #324

Merged
got3nks merged 2 commits into
amule-org:masterfrom
got3nks:feat/protocol-handler-manager
Jul 6, 2026
Merged

feat: register ed2k:// and magnet: URL schemes cross-platform#324
got3nks merged 2 commits into
amule-org:masterfrom
got3nks:feat/protocol-handler-manager

Conversation

@got3nks

@got3nks got3nks commented Jul 6, 2026

Copy link
Copy Markdown

Summary

Wraps OS-level scheme registration behind a cross-platform ProtocolHandlerManager (mirroring AutostartManager from #744) so a browser click on ed2k:// or magnet: reaches aMule directly - no more .reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Closes amule-project#793.

Related: #233 - complementary; this PR fixes the OS-level side, #233's browser-extension route addresses Chromium's active blocking of ed2k:// clicks that this PR cannot solve at the registration layer.

Backends

OS Store Notes
Windows HKCU\Software\Classes\<scheme> (URL Protocol keys) Per-user, no elevation
Linux $XDG_CONFIG_HOME/mimeapps.list [Default Applications] xdg-mime-compatible ini write, no dep on xdg-utils
macOS LSSetDefaultHandlerForURLScheme + CFBundleURLTypes in Info.plist LaunchServices-native

Surfaces

Four consistent entry points, all routing through the same manager:

  • Preferences → General: two checkboxes below the autostart toggle, live OS state on open, with an "Another app is currently the default handler for these links, replace with aMule?" confirm dialog before overwriting a third-party registration. Magnet-specific variant of the dialog spells out the BitTorrent limitation.
  • First-run wizard: new Integrations page between Bootstrap and Folders. Folds in the existing autostart toggle plus the two URL-scheme toggles. Strings shared verbatim with Preferences so translators only see them once. The magnet checkbox carries an explicit hint that BitTorrent magnets are not supported.
  • --configure-protocols on|off CLI: one-shot, no prompt, mirrors --configure-autostart. Invoked by the Windows installer.
  • Windows installer: new SecProtocols section, default checked, description mentions the BitTorrent limitation. Uninstall symmetry only wipes registry keys if they still point inside $INSTDIR (protects a user's hand-set third-party registration from being clobbered).

Per-binary identity: amule.exe and amulegui.exe (or .app on macOS, .desktop id on Linux) each track their own registration state. The Preferences checkbox in amulegui correctly reads unchecked when amule.exe holds the registration, and toggling on prompts before replacing it.

macOS specifics

  • Info.plist gets CFBundleURLTypes for both schemes via a plutil post-build step (both aMule.app and aMuleGUI.app).
  • Runtime scheme delivery uses a kAEGetURL Apple Event handler registered in __attribute__((constructor)) at dylib-load time - this is required because macOS dispatches cold-launch scheme URLs between applicationWillFinishLaunching: and applicationDidFinishLaunching:, before any wxApp OnInit runs.
  • On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks explicitly after the poll timer starts so a URL queued pre-EC-connect reaches the daemon immediately post-connect rather than waiting ~1s for the first poll tick.
  • LaunchServices has no "clear default handler" call, so Disable() is a no-op on macOS - the Prefs checkbox is hidden while we're the current handler (Linux/Windows Disable works, boxes stay visible there).

Magnet handling

Kept scoped to eD2k-compatible magnets (existing CMagnetED2KConverter contract). BitTorrent-only magnets are ignored - and every surface where the toggle can be enabled now spells out that limitation to the user (installer description, prefs tooltip, wizard hint, confirm-dialog magnet-specific text).

SelfHeal

SelfHealOnStartup() rewrites the registered path if it drifted (user moved AppImage / .app / install dir) - only when we're already the current handler, never when a third-party handler owns the scheme. Mirrors AutostartManager::SelfHealOnStartup.

Test plan

Verified end-to-end on:

  • macOS (aMule.app + aMuleGUI.app): cold-launch click, warm-launch click, prefs toggle, confirm dialog for third-party overrides.
  • Ubuntu (amule-dev-vm, source install): .desktop MimeType= advertises both schemes, xdg-mime picks aMule automatically, mimeapps.list runtime toggle works.
  • Windows (amule-dev-windows, portable install): HKCU\Software\Classes\{ed2k,magnet} populated by Prefs toggle; Firefox/Edge click delivery verified.

Not yet exercised

  • Windows NSIS installer: SecProtocols default-checked section + uninstall symmetry (only tested the portable build's runtime path).
  • Linux Flatpak: sandboxed mimeapps.list semantics.
  • Linux AppImage: portable-integration variant with the new %u Exec substitution.

Leaving as draft until those three packaging paths are verified.

Known limitation

Chrome on Windows blocks ed2k:// clicks with about:blank#blocked regardless of registration - Chromium's ExternalProtocolHandler doesn't allow-list ed2k:. magnet: works because it's on the allow-list. Firefox works. See #233 for background; the practical mitigation is the Chrome extension route.

Commits

  1. feat: register ed2k:// and magnet: URL schemes cross-platform - the feature.
  2. po: regenerate catalogs after ProtocolHandlerManager string additions - required by the App-catalogs-in-sync CI check per scripts/update-po.sh.

@ngosang

ngosang commented Jul 6, 2026

Copy link
Copy Markdown
Member

I'm thinking that maybe we should allow users to configure the two protocols separately. The magnet protocol is used in BitTorrent applications, and it's common for some users to have both a BitTorrent client and Amule installed at the same time. BitTorrent is more popular, so users will likely want to associate magnet with BitTorrent and ed2k with aMule.

Update: I think I didn't explain myself clearly. Amule should be registered as an application that supports both protocols, but it shouldn't be set as the default application for both protocols at the same time.

@got3nks

got3nks commented Jul 6, 2026

Copy link
Copy Markdown
Author

Yes it’s already a separate checkbox in the preferences. But I’ll have to make the same for the Windows installer, there it’s a single checkbox to bind to both protocols atm.

@ngosang

ngosang commented Jul 6, 2026

Copy link
Copy Markdown
Member

Update: I think I didn't explain myself clearly. Amule should be registered as an application that supports both protocols, but it shouldn't be set as the default application for both protocols at the same time.

@got3nks
got3nks force-pushed the feat/protocol-handler-manager branch from 6e18e24 to 93b70b9 Compare July 6, 2026 19:01
@got3nks

got3nks commented Jul 6, 2026

Copy link
Copy Markdown
Author

Update: refined the default state to be less aggressive about the magnet scheme, since aMule only handles the eD2k-compatible subset and would otherwise silently steal BitTorrent magnet clicks from a user's BT client.

  • Windows installer: the SecProtocols section is split into two - SecProtoEd2k (default checked) and SecProtoMagnet (default unchecked). Users who want both can tick both; users who only want ed2k get it out of the box; users on a shared-with-a-BT-client machine keep their magnet handler untouched.
  • First-run wizard: the ed2k checkbox defaults to true (opt-in to the common case), the magnet checkbox defaults to false. Previously both mirrored live OS state, which meant both were unchecked on fresh install.
  • CLI: --configure-protocols now accepts per-scheme values as well as the legacy bare form. The Windows installer's two new sections use ed2k:on / magnet:on respectively; on / off still toggle both schemes for back-compat.
  • PO catalogs: regenerated in the second commit as usual.

Also fired a `workflow_dispatch` on the fork's Packaging workflow to validate the AppImage, Flatpak, macOS Universal2, and Windows installer builds against the branch: https://github.com/got3nks/amule/actions/runs/28816136839

@got3nks
got3nks force-pushed the feat/protocol-handler-manager branch from 93b70b9 to a289959 Compare July 6, 2026 20:09
@got3nks

got3nks commented Jul 6, 2026

Copy link
Copy Markdown
Author

This is what it looks like during install:

immagine

New setup wizard page:

immagine

And preferences:

immagine

@got3nks
got3nks force-pushed the feat/protocol-handler-manager branch 2 times, most recently from ebc0d6a to 0cb0ca9 Compare July 6, 2026 20:28
got3nks added a commit that referenced this pull request Jul 6, 2026
)

* feat(AppImage): install amulegui launcher + shell shortcuts, fix em-dashes

Two related integration gaps + one string-encoding cleanup in the same
change:

1. amulegui first-class integration
   Previously the first-launch AppImage integration prompt only wrote
   org.amule.aMule.desktop (the monolithic amule variant). Users who
   invoked the AppImage via a `amulegui`-named symlink got amulegui
   running fine (AppRun's argv[0]-dispatch handled it), but no
   dedicated menu entry and no icon binding.

   Extended to also install org.amule.aMule.gui.desktop with Exec=
   pointing at ~/.local/bin/amulegui (the symlink from point 2 below),
   so AppRun's basename dispatch picks amulegui rather than the
   default amule. This also fixes the "amulegui registered as ed2k
   scheme handler opens amule" bug surfaced by #324:
   ProtocolHandlerManager writes the correct .desktop id to
   mimeapps.list, but xdg-mime couldn't find the .gui .desktop and
   silently fell back to amule.

2. Shell command shortcuts
   New InstallCommandSymlinks() iterates the AppRun-recognized names
   (amule, amuled, amulegui, amulecmd, amuleweb, amuleapi, ed2k, cas,
   wxcas, alc, alcc) and creates ~/.local/bin/<name> symlinks for
   each one the AppImage actually bundles. Users can now `amulecmd`,
   `amuled`, etc. straight from a terminal without knowing the
   AppImage path. Skips names that are pre-existing regular files
   (protects a user's distro-packaged binary if they somehow ended
   up under ~/.local/bin); replaces existing symlinks so a re-run
   with a newer AppImage refreshes the target.

3. Fix two user-visible em-dashes that mojibake on Windows
   Same class of bug as #326:
     - src/AppImageIntegration.cpp:222 (the integration prompt itself,
       reported by @got3nks during Ubuntu AppImage testing)
     - src/webapi/App.cpp:342 (amuleapi startup error when bound to a
       non-loopback address with no password set)
   Replaced the em-dashes with hyphens - identical rendering on Linux
   and macOS, no mojibake on Windows.

The integration prompt string is also expanded to mention
~/.local/bin so users know what's being touched.

Related: #324 (URL scheme handler PR that surfaced the amulegui gap).

* po: regenerate catalogs after AppImageIntegration text changes

Picks up the two revised msgids from the feat commit above:
  * the integration-prompt body (now mentions shell shortcuts and
    ~/.local/bin, and the em-dash was replaced with a hyphen)
  * the amuleapi startup-error message (em-dash → hyphen)
  * the log line summarising integration outcome (new %d counter for
    installed shell shortcuts)

Required by the App-catalogs-in-sync CI check per scripts/update-po.sh.
@got3nks
got3nks force-pushed the feat/protocol-handler-manager branch 2 times, most recently from 69883a4 to 7ce63fc Compare July 6, 2026 21:02
@got3nks
got3nks marked this pull request as ready for review July 6, 2026 21:06
@got3nks
got3nks force-pushed the feat/protocol-handler-manager branch from 7ce63fc to 59d23d2 Compare July 6, 2026 22:38
got3nks added 2 commits July 7, 2026 01:18
Wraps OS-level scheme registration behind a cross-platform
ProtocolHandlerManager (mirroring AutostartManager from amule-project#744) so a
browser click on ed2k:// or magnet: reaches aMule directly — no more
.reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Backends:
  Windows  HKCU\Software\Classes\<scheme> (per-user URL Protocol keys)
  Linux    $XDG_CONFIG_HOME/mimeapps.list [Default Applications]
  macOS    LSSetDefaultHandlerForURLScheme + CFBundleURLTypes plist decl

Four surfaces expose the toggle, all going through the same manager:

  * Preferences → General: two checkboxes below the autostart toggle,
    live OS state on open, with an "Another app is currently the default
    handler for these links, replace with aMule?" confirm dialog before
    overwriting a third-party registration.

  * First-run wizard: new Integrations page between Bootstrap and
    Folders. Folds in the existing autostart toggle plus the two
    URL-scheme toggles. Strings shared verbatim with Preferences so
    translators only see them once.

  * --configure-protocols on|off CLI: one-shot, no prompt, mirrors
    --configure-autostart. Invoked by the Windows installer.

  * Windows installer: new SecProtocols section, default checked.
    Uninstall symmetry only wipes registry keys if they still point
    inside \$INSTDIR (protects a user's hand-set third-party
    registration from being clobbered).

Identity is per-binary (basename on Windows/Linux, bundle id on macOS),
so amule.exe and amulegui.exe each track their own registration state.
The Preferences checkbox in amulegui correctly reads unchecked when
amule.exe holds the registration, and toggling on prompts before
replacing it.

macOS specifics:

  * Info.plist gets CFBundleURLTypes for both schemes via a plutil
    post-build step (both aMule.app and aMuleGUI.app).

  * Runtime scheme delivery uses a kAEGetURL Apple Event handler
    registered in __attribute__((constructor)) at dylib-load time —
    required because macOS dispatches cold-launch scheme URLs between
    applicationWillFinishLaunching: and applicationDidFinishLaunching:,
    before any wxApp OnInit runs.

  * On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks
    explicitly after the poll timer starts so a URL queued pre-EC-
    connect reaches the daemon immediately post-connect rather than
    waiting ~1s for the first poll tick.

  * LaunchServices has no "clear default handler" call, so Disable()
    is a no-op on macOS — the Prefs checkbox is hidden while we're
    the current handler (Linux/Windows Disable works, boxes stay
    visible there).

Magnet handling stays scoped to eD2k-compatible magnets (existing
CMagnetED2KConverter contract). BitTorrent-only magnets are ignored.

SelfHealOnStartup rewrites the registered path if it drifted (user
moved AppImage / .app / install dir) — only when we're already the
current handler, never when a third-party handler owns the scheme.
Mirrors AutostartManager::SelfHealOnStartup.

Closes amule-project#793.
Picks up the msgids added by the feature commit above (Preferences +
Wizard checkbox labels, tooltips, magnet-specific confirm dialog text,
wizard BitTorrent-limitation hint, and the two new installer section
names / descriptions from the ed2k / magnet split).

Required by the App-catalogs-in-sync CI check per scripts/update-po.sh.
@got3nks
got3nks force-pushed the feat/protocol-handler-manager branch from 59d23d2 to e60fa19 Compare July 6, 2026 23:18
@got3nks
got3nks merged commit f029cef into amule-org:master Jul 6, 2026
12 checks passed
@got3nks
got3nks deleted the feat/protocol-handler-manager branch July 6, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Register ed2k:// and magnet: URI schemes automatically

2 participants