Closed Bug 1716200 Opened 3 years ago Closed 2 years ago

Windows API: add function to open arbitrary URIs

Categories

(Thunderbird :: Add-Ons: Extensions API, enhancement)

enhancement

Tracking

(thunderbird_esr102 wontfix)

RESOLVED FIXED
114 Branch
Tracking Status
thunderbird_esr102 --- wontfix

People

(Reporter: tdulcet, Assigned: TbSync)

References

Details

Attachments

(3 files)

This is a follow up to bug 1664708. The windows.openDefaultBrowser() function only supports HTTP and HTTPS URLs and not all the other URIs that most browsers support. I need a function like windows.openDefaultApp() or windows.openExternally() (suggested here) to open arbitrary URIs with the user's default application for the particular URI scheme, the same as if they clicked on a link to the URI in an e-mail. I am trying to create a simple extension where users can select text to open unlinked URIs, URLs, email addresses, telephone numbers, etc.

In Firefox, this can be achieved using the tabs.update() function, although in Thunderbird that only seems to work on mailto: URIs and it also has unwanted side effect of blanking out the message.

Just a thought, why not present the text as links in an html page? Then I think Thunderbird should open those as if they were in the email themselves.

Attached image image.png

(In reply to Mark Banner (:standard8) from comment #1)

Just a thought, why not present the text as links in an html page? Then I think Thunderbird should open those as if they were in the email themselves.

Sure, I may provide an option to automatically convert URIs/URLs to links. However, the user does not necessary want to link everything that could be interpreted as a URI/URL, as there can be a lot of ambiguity. That would also not work if it were already linked to something else. In addition, I want to allow users to select partial or multiple URIs/URLs and well as e-mail addresses and telephone numbers. I have an extension that works fine in Firefox and Chrome to open arbitrary URIs from the context menu, although in Thunderbird it can only open HTTP/HTTPS URLs.

See the attached screenshot for an example. It recognizes the (800) 555-0199 as a phone number and provides the option of calling it by converting it to a tel: URI (RFC 3966). However, in Thunderbird the extension cannot open a tel: URI…

At least as a workaround, I think you could probably create a tab, using browser.tabs.create with the required url and potentially close it afterwards. It might be worth asking the Firefox WebExtensions developer team if there's a way for WebExtensions to do this without opening tabs.

If you open the JavaScript console of Thunderbird (Shift+CTRL+J) and enter the following:

let uri = Services.io.newURI("tel://<what ever you need>");
Cc["@mozilla.org/uriloader/external-protocol-service;1"]
.getService(Ci.nsIExternalProtocolService)
.loadURI(uri);

What happens? Would that be what you need? I do not remember why we added the restriction to http/https in openDefaultBrowser.

(In reply to John Bieling (:TbSync) from comment #4)

What happens? Would that be what you need? I do not remember why we added the restriction to http/https in openDefaultBrowser.

Yes, it correctly opens the external application. That is exactly what I need.

Attached image image.png

In the meantime while we wait for the potential new API, maybe the existing windows.openDefaultBrowser() function could be updated to make the url parameter optional. In this case, if possible, it would just open a blank browser window, so the user could more easily paste in any unsupported URIs, such as my tel: URI example in comment 2 above. While this would of course not be ideal nor fully support my use case, but it would still be an improvement on the status quo for users.

Currently my Link Creator add-on automatically copies any non HTTP/HTTPS URIs to the clipboard, but the user then has to manually open their browser and paste them into the address bar. See the attached screenshot for an example of the notification my add-on displays in this case. Allowing the windows.openDefaultBrowser() function to open a blank browser window/tab would at least eliminate this first step for users.

I am really having a hard time with this request. Not even Firefox allows this the way you propose (via a menu action).

What I propose to do instead:

  • Let the menu action open a tab (browser.tabs.create({url: "tel.html?<payloaddata>}), which spells out something like "Redirecting to tel:// protocol handler"
  • Have a script in tel.html do document.location.hef = "tel://<payloaddata>"
  • Thunderbirds protocol handler will kick in and either perform a default action or prompt the user
  • Either let the tab open or let it close itself after it changed the location

Could you live with that?

(In reply to John Bieling (:TbSync) from comment #7)

I am really having a hard time with this request. Not even Firefox allows this the way you propose (via a menu action).

I am not sure what you mean by this. My add-on works fine in Firefox (and Chrome) with no limits on the types of URIs it can open, except of course data: (bug 1317166), about: (bug 1269456) and other privileged URIs. This issue is that unlike Firefox, TB is not a browser, so it needs to open all URIs in an external program, but the provided windows.openDefaultBrowser() function does not support arbitrary URIs and the tabs.update() method does not work in TB (see comment 0).

Could you live with that?

Sure, but this seems like a nasty hack which would provide poor UX and could potentially open the extension up to all kinds of XSS vulnerabilities. Your proposal in comment 4 for a new API seemed like a much better idea. Note that the tel: URI was just an example, my extension actually supports all arbitrary URI schemes as long as they follow the various URI/IRI RFCs and the user has a program installed that can handle them.

Can you provide a code snippet, which works in Firefox and allows to open arbitrary uris from a menus.onClicked event?

Edit: Found it. You just call tabs.update() as stated in comment #0.

I have been playing with tabs.create() and tabs.update() and the reason this fails is that we do not have gBrowser and gBrowser.getTabDialogBox() which is expected here:
https://searchfox.org/mozilla-central/rev/0907529ff72c456ddb47839f5f7ba16291f28dce/toolkit/mozapps/handling/ContentDispatchChooser.sys.mjs#341

If I make this condition always fail, tabs.create() and tabs.update() seem to work with arbitrary uris, since the app prompter falls back to using the stand alone dialog instead of the overlay tabbed dialog.

I am really having a hard time with this request. Not even Firefox allows this the way you propose (via a menu action).

I was obviously wrong, as tabs.update() can launch the external app without clearing the current tab. I had assumed two things:

  1. Clearing the current tab during tabs.update() is normal
  2. You need to create a new tab even in firefox, which would be close to what I proposed in comment #7 (but you do not even need the handler.html file, you can really just use the destination uri directly, if ContentDispatchChooser.sys.mjs is patched).

I have yet to understand, why the currently displayed tab/message is cleared for us.

Assignee: nobody → john
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true

@tdulcet:

I think https://phabricator.services.mozilla.com/D174220 should fix your issue. Right?
Try run is here, does that work as expected?
https://treeherder.mozilla.org/jobs?repo=try-comm-central&revision=ddfd547d0910547c726ce1cfae175268cbe933cf

There will be more needed in this patch, probably have to adapt tabs.create() as well and open it up to support mid: urls. The tabs API does work in general for us (tabs.query(), tabs.get() etc.) but tabs.create() and tabs.update() are artificially limited to content tabs. I come to believe we have to generalize that.

This has been a confusing issue and it took a while to get behind it. Sorry for that.

There is only one major difference between TB and FF -> You do not want to open/update http(s):// links in Thunderbird. So the only extra case in your add-on is to use windows.openDefaultBrowser() for http(s):// links, to overwrite the default protocol handler of TB. For everything else, both - FF and TB - should behave the same and tabs.update() must work the same for both. There is no need for an additional openDefaultApp() API method.

Wow, thank you for debugging this and finding a solution! I guess I should have instead requested in this bug that the tabs.update() function be fixed rather than requesting this new API. As you explained in comment 12, the concept of a tab is very different between FF and TB, so I did not think there was any chance that the tabs.update() function could or would be fixed in TB.

Anyway, this will be a huge improvement for users. Thanks for the additional information in comment 13 regarding the differences between FF and TB, I was just about to ask about that. This should allow me to simplify my extension and remove a lot of the TB specific code.

Try run is here, does that work as expected?

I just updated my local copy of the extension and tried it with your try build. Overall, it seems to work great! Just a couple of things I noticed:

  • The mailto: URI does not work, although no errors are logged in the extension or browser consoles.
  • The tabs.update() function does not work at all in the compose window, I just get an Uncaught (in promise) Error: tabs.update is not applicable to this tab. error.

Note that my extension also uses the tabs.create() function when opening multiple URIs at once (i.e. when the use selects a block of text with multiple embedded URIs), but it sounds like you are planning to fix this as well in your patch.

Attachment #9326199 - Attachment description: Bug 1716200 - Make tabs.update() to be compatible with firefox. r=mkmelin → WIP: Bug 1716200 - Make tabs.update() and tabs.reload() to be compatible with firefox. r=darktrojan
Attachment #9326199 - Attachment description: WIP: Bug 1716200 - Make tabs.update() and tabs.reload() to be compatible with firefox. r=darktrojan → Bug 1716200 - Make tabs.update() and tabs.reload() to be compatible with firefox. r=darktrojan

The mailto: URI does not work, although no errors are logged in the extension or browser consoles.

mailto: is broken elsewhere, do not know where. Needs to be fixed in a different bug. Maybe the protocol handler does not like pointing back at itself. What happens if your default mail app is NOT Thunderbird?

The tabs.update() function does not work at all in the compose window, I just get an Uncaught (in promise) Error: tabs.update is not applicable to this tab. error.

Fixed in the updated patch.

Note that my extension also uses the tabs.create() function when opening multiple URIs at once (i.e. when the use selects a block of text with multiple embedded URIs), but it sounds like you are planning to fix this as well in your patch.

Hm, what is the issue here? What I did now is to make all browser.tabs.* methods work with all tabs in general, but reload() throws if you try to reload a non-content tab and update() throws if you try to load a content page into a non-content tab.

I have not changed create(). Maybe at a later time we could unify our message urls and always return mid: urls, instead of mailbox: or imap: what we currently do. These urls are not usable besides looking at them. Once we always return mid: urls, we could update create() and update() to support mid: urls in message tabs. But not now.

You have to manually decide, if you want to open tabs in TB or in FF and either pick tabs.create() or windows.openDefaultBrowser()

(In reply to John Bieling (:TbSync) from comment #15)

mailto: is broken elsewhere, do not know where. Needs to be fixed in a different bug. Maybe the protocol handler does not like pointing back at itself. What happens if your default mail app is NOT Thunderbird?

Hmm, clicking a real mailto: link in TB works as expected, so this bug must be only add-ons related. It also opens the compose window in the current TB instance, even if that is not the user's default mail app, which I think is what they would expect. For example, if I click a real mailto: link in TB Daily, it opens in TB Daily, even though TB ESR is my default mail app. Anyway, would you like me to file a new bug?

Fixed in the updated patch.

Thanks!

Hm, what is the issue here? What I did now is to make all browser.tabs.* methods work with all tabs in general

I was referring to comment 12, where you said:

There will be more needed in this patch, probably have to adapt tabs.create() as well

Currently in the latest TB Daily, tabs.create() with an arbitrary URI just opens a blank tab and does not prompt the user to open their external application. Does your updated patch fix this?

For clarity, based on comment 13, I was going to update my add-on to use windows.openDefaultBrowser() when opening all HTTP/HTTPS URLs, tabs.update() when opening a single arbitrary URI and tabs.create() for multiple arbitrary URIs.

(BTW, the notifications.on* API is also broken in TB Beta/Daily. I could file a new bug about this as well, if someone does not beat me to it... It looks like I might have a lot of bug filing to do in my future.)

mailto

For me, this does not work if executed from the console:

Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService).loadURI(Services.io.newURI("mailto:user@inter.net"));

That is not limited to add-ons. There is something broken elsewhere. It does work in Firefox.

Currently in the latest TB Daily, tabs.create() with an arbitrary URI just opens a blank tab and does not prompt the user to open their external application. Does your updated patch fix this?

Hm. I think that does not work, because it triggers the overlay prompter and not the dialog prompter. That needs a new bug.

For clarity, based on comment 13, I was going to update my add-on to use windows.openDefaultBrowser() when opening all HTTP/HTTPS URLs, tabs.update() when opening a single arbitrary URI and tabs.create() for multiple arbitrary URIs.

Workaround for open.create(): You could you instead open a placeholder content tab and let that update itself to the arbitrary url (piped in via url parameter). Since you have code running in the tab, you could even close it once done.

(BTW, the notifications.on* API is also broken in TB Beta/Daily. I could file a new bug about this as well, if someone does not beat me to it... It looks like I might have a lot of bug filing to do in my future.)

Yes, please, with steps to reproduce (a reproducer add-on would be great)

Blocks: 1828089
Depends on: 1828102
Blocks: 1828110
Attachment #9326199 - Attachment description: Bug 1716200 - Make tabs.update() and tabs.reload() to be compatible with firefox. r=darktrojan → Bug 1716200 - Make tabs.update() and tabs.reload() compatible with Firefox. r=darktrojan

Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/48d0e557b95f
Make tabs.update() and tabs.reload() compatible with Firefox. r=darktrojan

Status: ASSIGNED → RESOLVED
Closed: 2 years ago
Resolution: --- → FIXED
Target Milestone: --- → 114 Branch
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: