diff --git a/res/doc b/res/doc index 54133c7..cb52836 100644 --- a/res/doc +++ b/res/doc @@ -52,7 +52,12 @@ # screenshots - toggles FeatureSettings.Screenshots # force_wifi - toggles DeveloperSettings.ForceWifiOn (note: the setting doesn't apply until you toggle WiFi) # nickel_extras - the mimetype of the plugin, or one of: -# web_browser +# web_browser - opens the web browser to the default homepage +# web_browser: - opens the web browser to the specified URL +# web_browser: - opens the web browser to the specified URL and injects the specified CSS (which can contain spaces and colons) into all pages +# web_browser:modal - opens the web browser to the default homepage as a pop-up window +# web_browser:modal: - see above +# web_browser:modal: - see above # unblock_it # sketch_pad # solitaire diff --git a/src/action_cc.cc b/src/action_cc.cc index 3084f09..116dc56 100644 --- a/src/action_cc.cc +++ b/src/action_cc.cc @@ -295,43 +295,79 @@ NM_ACTION_(nickel_setting) { NM_ACTION_(nickel_extras) { #define NM_ERR_RET nullptr - if (!strcmp(arg, "web_browser")) { - //libnickel 4.6 * _ZN26N3SettingsExtrasControllerC2Ev - void (*N3SettingsExtrasController_N3SettingsExtrasController)(N3SettingsExtrasController*); - reinterpret_cast(N3SettingsExtrasController_N3SettingsExtrasController) = dlsym(RTLD_DEFAULT, "_ZN26N3SettingsExtrasControllerC2Ev"); - NM_ASSERT(N3SettingsExtrasController_N3SettingsExtrasController, "could not dlsym N3SettingsExtrasController constructor"); + if (!strncmp(arg, "web_browser", 11)) { + bool modal; + QUrl *url; + QString *css; - //libnickel 4.6 * _ZN26N3SettingsExtrasControllerD1Ev - void (*N3SettingsExtrasController_N3SettingsExtrasControllerD)(N3SettingsExtrasController*); - reinterpret_cast(N3SettingsExtrasController_N3SettingsExtrasControllerD) = dlsym(RTLD_DEFAULT, "_ZN26N3SettingsExtrasControllerD1Ev"); - NM_ASSERT(N3SettingsExtrasController_N3SettingsExtrasControllerD, "could not dlsym N3SettingsExtrasController destructor"); + if (!strcmp(arg, "web_browser")) { + modal = false; + url = new QUrl(); + css = new QString(""); + } else { + char *tmp1 = strdupa(arg); // strsep and strtrim will modify it + char *arg1 = strtrim(strsep(&tmp1, ":")); + char *arg2 = strtrim(tmp1); - //libnickel 4.6 * _ZN26N3SettingsExtrasController11openBrowserEv - void (*N3SettingsExtrasController_openBrowser)(N3SettingsExtrasController*); - reinterpret_cast(N3SettingsExtrasController_openBrowser) = dlsym(RTLD_DEFAULT, "_ZN26N3SettingsExtrasController11openBrowserEv"); - NM_ASSERT(N3SettingsExtrasController_openBrowser, "could not dlsym BrowserWorkflowManager::openBrowser"); + if (!arg2 || strcmp(arg1, "web_browser")) + NM_RETURN_ERR("unknown beta feature name or plugin mimetype '%s' (split: '%s')", arg, arg1); - N3SettingsExtrasController *nse = alloca(128); // as of 4.20.14622, it's actually 48 bytes, but we're going to stay on the safe side - N3SettingsExtrasController_N3SettingsExtrasController(nse); - N3SettingsExtrasController_openBrowser(nse); - N3SettingsExtrasController_N3SettingsExtrasControllerD(nse); + QString tmp = QString::fromUtf8(arg2).trimmed(); - // the QObject is only used to pass events to it, but there's something I'm missing here which leads to it segfaulting after connecting to WiFi if it isn't already connected - /* - //libnickel 4.11.11911 * _ZN22BrowserWorkflowManagerC1EP7QObject - void (*BrowserWorkflowManager_BrowserWorkflowManager)(BrowserWorkflowManager*, QObject*); + if (tmp.section(':', 0, 0).trimmed() == "modal") { + modal = true; + tmp = tmp.section(':', 1).trimmed(); + } else { + modal = false; + } + + if (tmp.contains(' ')) { + css = new QString(tmp.section(' ', 1).trimmed()); + url = new QUrl(tmp.section(' ', 0, 0).trimmed(), QUrl::ParsingMode::StrictMode); + if (!url->isValid() || url->isRelative()) + NM_RETURN_ERR("invalid url '%s' (argument: '%s') (note: if your url has spaces, they need to be escaped)", qPrintable(tmp.section(' ', 0, 0)), arg); + } else if (tmp.length()) { + url = new QUrl(tmp, QUrl::ParsingMode::StrictMode); + css = new QString(""); + if (!url->isValid() || url->isRelative()) + NM_RETURN_ERR("invalid url '%s' (argument: '%s') (note: if your url has spaces, they need to be escaped)", qPrintable(tmp.section(' ', 0, 0)), arg); + } else { + url = new QUrl(); + css = new QString(""); + } + } + + NM_LOG("web browser '%s' (modal=%d, url='%s', css='%s')", arg, modal, url->isValid() ? qPrintable(url->toString()) : "(home)", qPrintable(*css)); + + //libnickel 4.6 * _ZN22BrowserWorkflowManager14sharedInstanceEv _ZN22BrowserWorkflowManagerC1EP7QObject + BrowserWorkflowManager *(*BrowserWorkflowManager_sharedInstance)(); + void (*BrowserWorkflowManager_BrowserWorkflowManager)(BrowserWorkflowManager*, QObject*); // 4.11.11911+ + reinterpret_cast(BrowserWorkflowManager_sharedInstance) = dlsym(RTLD_DEFAULT, "_ZN22BrowserWorkflowManager14sharedInstanceEv"); reinterpret_cast(BrowserWorkflowManager_BrowserWorkflowManager) = dlsym(RTLD_DEFAULT, "_ZN22BrowserWorkflowManagerC1EP7QObject"); - NM_ASSERT(BrowserWorkflowManager_BrowserWorkflowManager, "could not dlsym BrowserWorkflowManager constructor"); + NM_ASSERT(BrowserWorkflowManager_sharedInstance || BrowserWorkflowManager_BrowserWorkflowManager, "could not dlsym BrowserWorkflowManager constructor (4.11.11911+) or sharedInstance"); //libnickel 4.6 * _ZN22BrowserWorkflowManager11openBrowserEbRK4QUrlRK7QString - void (*BrowserWorkflowManager_openBrowser)(BrowserWorkflowManager*, bool, QUrl const&, QString const&); // the bool is whether to open it as a modal, the string is CSS to inject + void (*BrowserWorkflowManager_openBrowser)(BrowserWorkflowManager*, bool, QUrl*, QString*); // the bool is whether to open it as a modal, the QUrl is the URL to load(if !QUrl::isValid(), it loads the homepage), the string is CSS to inject reinterpret_cast(BrowserWorkflowManager_openBrowser) = dlsym(RTLD_DEFAULT, "_ZN22BrowserWorkflowManager11openBrowserEbRK4QUrlRK7QString"); NM_ASSERT(BrowserWorkflowManager_openBrowser, "could not dlsym BrowserWorkflowManager::openBrowser"); - BrowserWorkflowManager *bwm = alloca(128); // as of 4.20.14622, it's actually 20 bytes, but we're going to stay on the safe side - BrowserWorkflowManager_BrowserWorkflowManager(bwm, new QObject()); - BrowserWorkflowManager_openBrowser(bwm, false, QUrl(), QStringLiteral("")); // if !QUrl::isValid(), it loads the homepage - */ + // note: everything must be on the heap since if it isn't connected, it + // passes it as-is to the connected signal, which will be used + // after this action returns. + + BrowserWorkflowManager *bwm; + + if (BrowserWorkflowManager_BrowserWorkflowManager) { + bwm = calloc(1, 128); // as of 4.20.14622, it's actually 20 bytes, but we're going to stay on the safe side + NM_ASSERT(bwm, "could not allocate memory for BrowserWorkflowManager"); + BrowserWorkflowManager_BrowserWorkflowManager(bwm, nullptr); + } else { + bwm = BrowserWorkflowManager_sharedInstance(); + NM_ASSERT(bwm, "could not get shared browser workflow manager pointer"); + } + + BrowserWorkflowManager_openBrowser(bwm, modal, url, css); + NM_RETURN_OK(nm_action_result_silent()); }