See: transport design | ident & dispatch | file: plugin | webdav design
• wxFilePickerCtrl verdict: cannot cleanly accept URLs. DbSelectionPanel::DoValidation() calls wxFileName(path).FileExists() which is a direct OS call, bypassing our pws_os::FileExists() intercept. Resolution: replace path entry with a plain wxTextCtrl + recent-locations dropdown + a "Browse…" button (Browse opens wxFilePickerCtrl for local files only). See Phase 3.
• Scope: Linux first, Mac next, Windows later. Mac needs file.cpp is a separate file; .so→.dll and /proc/self/exe→GetModuleFileName() differ. Add Windows support later.
• Cache directory: use /home/john/.cache/pwsafe/ (not ~/.pwsafe/cache/). Create on first use.
• WebDAV plugin registers for webdav, http, and https. Bare https://server/file.psafe3 routes to WebDAV plugin without needing the explicit webdav: prefix.
No plugins yet. URLs → "no plugin found" error. Goal: infrastructure compiles and intercepts correctly.
New: src/os/transport.h
• PWSTransport struct (see design)
• PWSTransport_ABI_VERSION constant
• pws_register_transport(), pws_find_transport() declarations
• pws_transport_load_for_scheme(scheme) — lazy loader
New: src/os/transport.cpp
• Transport registry (std::map<std::string, PWSTransport*>)
• Lazy loader: construct pwsafe-<scheme>.so filename, find in app dir (+ cwd if DEVELOPMENT), pre-scan identity string, dlopen, call init, dlclose on failure
• Cache path resolver: ~/.pwsafe/cache/ + sha256 of URL (create dir if absent)
• std::map<FILE*, CacheInfo> bridging FOpen → FClose
• Plugin unload: pws_transport_unload(scheme) — called on database close
Modify: src/os/unix/file.cpp
• FileExists: if URL → call transport exists()
• FOpen: if URL → call transport fetch() to cache, open cache file, register in map
• FClose: if fd in map and write mode → call transport store() from cache, remove from map
• LockFile / UnlockFile: if URL → call transport lock()/unlock()
• URL detection helper: static bool is_url(const stringT&) — checks for scheme: prefix
Modify: CMakeLists.txt — add transport.cpp to core build
Goal: full round-trip working against a local file via the plugin stack. Validates the entire infrastructure before any network code.
New: src/os/plugins/file/transport-file.cpp
• Implements all five PWSTransport functions (fetch/store = file copy, exists = stat, lock/unlock = no-op)
• Embeds identity string: PWS_TRANSPORT_INFO:1:file:Local file transport (testing)
• pws_plugin_init registers for scheme file
Modify: CMakeLists.txt — add MODULE target → pwsafe-file.so
Test: pwsafe file:///tmp/test.psafe3 — open, modify, save, reopen, verify contents
Goal: user can type or paste a local path or URL into the open dialog. wxFilePickerCtrl is replaced for the path entry field.
• Replace wxFilePickerCtrl in DbSelectionPanel with: a wxComboBox (text entry + recent-locations dropdown) alongside a "Browse…" button
• Browse button opens a wxFilePickerCtrl dialog for local files only; selected path is written back into the combo box
• Recent locations list: persist to prefs (capped, e.g. 10 entries); includes both local paths and URLs
• Update DoValidation(): detect URL first; if URL skip wxFileName check entirely; validate via pws_os::FileExists() (which we intercept)
• Error dialog: "No plugin found for scheme 'X'. Install pwsafe-X.so alongside the application."
• Windows UI: defer
Goal: open and save a real .psafe3 file on a WebDAV server.
New: src/os/plugins/webdav/transport-webdav.cpp
• fetch → libcurl GET; store → libcurl PUT; exists → HEAD
• On first use: OPTIONS to detect LOCK support; cache result per host
• lock → LOCK (if supported); unlock → UNLOCK
• CURLOPT_NETRC = CURL_NETRC_OPTIONAL (credentials from ~/.netrc)
• Strips webdav: prefix before passing URL to libcurl
• Identity string: PWS_TRANSPORT_INFO:1:webdav:WebDAV transport via libcurl
Modify: CMakeLists.txt — MODULE target → pwsafe-webdav.so, link libcurl
• find_package(CURL REQUIRED) inside the plugin target only — main binary stays libcurl-free
Test: Local WebDAV server (e.g. nginx + mod_dav) → open, modify, save, verify on server. Then test with LOCK-capable server (e.g. Apache mod_dav).
All four questions from the original plan are resolved above in Phase 0 and Phase 3. No open questions remain.