webbrowser.py revision 90f5ba538bf40bcf4fd41049c7bf4296d3ffc9c7
190f5ba538bf40bcf4fd41049c7bf4296d3ffc9c7Benjamin Peterson#! /usr/bin/env python3 20a8c29be4b5314d4bf72cb391ab078f7483cf3f7Ka-Ping Yee"""Interfaces for launching and remotely controlling Web browsers.""" 3992d4a3e6e67a05b85350820157028a61d1f22cfGuido van Rossum# Maintained by Georg Brandl. 4c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 5ee763951dc56d4cdf0d39a12214bc1342fc3d93aFred Drakeimport io 6c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeimport os 7d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossumimport shlex 8c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeimport sys 9e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlimport stat 1023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandlimport subprocess 1123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandlimport time 12c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 13e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl__all__ = ["Error", "open", "open_new", "open_new_tab", "get", "register"] 1440fc16059f04ee8fda0b5956cc4883eb21ca8f8cSkip Montanaro 15c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeclass Error(Exception): 16c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake pass 17c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 18658cba6706eb4a2ad8b3e235cf0db9fe1c8e9e6bTim Peters_browsers = {} # Dictionary of available browser controllers 19658cba6706eb4a2ad8b3e235cf0db9fe1c8e9e6bTim Peters_tryorder = [] # Preference order of available browsers 20c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 21e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandldef register(name, klass, instance=None, update_tryorder=1): 22c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake """Register a browser connector and, optionally, connection.""" 23c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake _browsers[name.lower()] = [klass, instance] 24e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if update_tryorder > 0: 25e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _tryorder.append(name) 26e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl elif update_tryorder < 0: 27e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _tryorder.insert(0, name) 28c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 29f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymonddef get(using=None): 30f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond """Return a browser launcher instance appropriate for the environment.""" 3110ff706e2788a7c7ef9f8ea0108a5ede625fedadRaymond Hettinger if using is not None: 32f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond alternatives = [using] 33f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond else: 34f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond alternatives = _tryorder 35f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond for browser in alternatives: 36bac788a3cd348203a5fdabba52e5faf65bf35c5eRaymond Hettinger if '%s' in browser: 3723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # User gave us a command line, split it into name and args 38d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum browser = shlex.split(browser) 39d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum if browser[-1] == '&': 40d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum return BackgroundBrowser(browser[:-1]) 41d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum else: 42d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum return GenericBrowser(browser) 43f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond else: 44e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # User gave us a browser name or path. 45f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake try: 46f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake command = _browsers[browser.lower()] 47f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake except KeyError: 48f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake command = _synthesize(browser) 49e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if command[1] is not None: 50f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond return command[1] 51e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl elif command[0] is not None: 52e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return command[0]() 53f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond raise Error("could not locate runnable browser") 54c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 55c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake# Please note: the following definition hides a builtin function. 56e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# It is recommended one does "import webbrowser" and uses webbrowser.open(url) 57e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# instead of "from webbrowser import *". 58c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 59e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalottidef open(url, new=0, autoraise=True): 60e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl for name in _tryorder: 61e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl browser = get(name) 62e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if browser.open(url, new, autoraise): 63e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return True 64e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return False 65c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 663f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drakedef open_new(url): 67e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return open(url, 1) 68c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 69e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandldef open_new_tab(url): 70e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return open(url, 2) 71f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake 72e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 73e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandldef _synthesize(browser, update_tryorder=1): 74f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake """Attempt to synthesize a controller base on existing controllers. 75f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake 76f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake This is useful to create a controller when a user specifies a path to 77f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake an entry in the BROWSER environment variable -- we can copy a general 78f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake controller to operate using a specific installation of the desired 79f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake browser in this way. 80f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake 81f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake If we can't create a controller in this way, or if there is no 82f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake executable for the requested browser, return [None, None]. 83f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake 84f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake """ 85e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl cmd = browser.split()[0] 86e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if not _iscommand(cmd): 87f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake return [None, None] 88e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl name = os.path.basename(cmd) 89f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake try: 90f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake command = _browsers[name.lower()] 91f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake except KeyError: 92f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake return [None, None] 93f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake # now attempt to clone to fit the new name: 94f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake controller = command[1] 95f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake if controller and name.lower() == controller.basename: 96f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake import copy 97f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake controller = copy.copy(controller) 98f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake controller.name = browser 99f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake controller.basename = os.path.basename(browser) 100e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl register(browser, None, controller, update_tryorder) 101f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake return [None, controller] 102118aa5337c745dece455f4782799c83b9e3a7d4fAndrew M. Kuchling return [None, None] 103f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake 1043f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 105e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif sys.platform[:3] == "win": 106e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl def _isexecutable(cmd): 107e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl cmd = cmd.lower() 1080e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters if os.path.isfile(cmd) and cmd.endswith((".exe", ".bat")): 109e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return True 110e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl for ext in ".exe", ".bat": 111e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if os.path.isfile(cmd + ext): 112e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return True 113e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return False 114e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlelse: 115e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl def _isexecutable(cmd): 116e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if os.path.isfile(cmd): 117e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl mode = os.stat(cmd)[stat.ST_MODE] 118e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if mode & stat.S_IXUSR or mode & stat.S_IXGRP or mode & stat.S_IXOTH: 119e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return True 120e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return False 121e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 1223f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drakedef _iscommand(cmd): 123e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl """Return True if cmd is executable or can be found on the executable 124e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl search path.""" 125e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if _isexecutable(cmd): 126e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return True 1273f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake path = os.environ.get("PATH") 1283f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake if not path: 129bc0e9108261693b6278687f4fb4709ff76c2e543Tim Peters return False 1303f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake for d in path.split(os.pathsep): 1313f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake exe = os.path.join(d, cmd) 132e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if _isexecutable(exe): 133bc0e9108261693b6278687f4fb4709ff76c2e543Tim Peters return True 134bc0e9108261693b6278687f4fb4709ff76c2e543Tim Peters return False 1353f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 1363f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 137e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# General parent classes 138e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 139e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass BaseBrowser(object): 14023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl """Parent class for all browsers. Do not use directly.""" 141887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 14223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl args = ['%s'] 143887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 144e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl def __init__(self, name=""): 145e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl self.name = name 146b980113a8df699797b837f103ac6d2049a214551Georg Brandl self.basename = name 147536cf99536bce562cfcb44a856fac1c84b9de4c3Tim Peters 148e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 149196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz raise NotImplementedError 150196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz 151e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl def open_new(self, url): 152e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return self.open(url, 1) 153e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 154e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl def open_new_tab(self, url): 155e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return self.open(url, 2) 156e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 1573f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 158e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass GenericBrowser(BaseBrowser): 159e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl """Class for all browsers started with a command 160e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl and without remote functionality.""" 1613f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 16223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl def __init__(self, name): 1633172c5d263eeffff1e89d03d79be3ccc1d60fbdeGuido van Rossum if isinstance(name, str): 16423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl self.name = name 165992d4a3e6e67a05b85350820157028a61d1f22cfGuido van Rossum self.args = ["%s"] 16623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 16723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # name should be a list with arguments 16823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl self.name = name[0] 16923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl self.args = name[1:] 170b980113a8df699797b837f103ac6d2049a214551Georg Brandl self.basename = os.path.basename(self.name) 1713f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 172e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 173887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters cmdline = [self.name] + [arg.replace("%s", url) 17423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl for arg in self.args] 17523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl try: 17689f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters if sys.platform[:3] == 'win': 17789f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters p = subprocess.Popen(cmdline) 17889f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters else: 17989f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters p = subprocess.Popen(cmdline, close_fds=True) 18023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return not p.wait() 18123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl except OSError: 18223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return False 18323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl 18423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl 18523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandlclass BackgroundBrowser(GenericBrowser): 18623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl """Class for all browsers which are to be started in the 18723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl background.""" 18823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl 189e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 19023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl cmdline = [self.name] + [arg.replace("%s", url) 19123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl for arg in self.args] 19223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl try: 19389f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters if sys.platform[:3] == 'win': 19489f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters p = subprocess.Popen(cmdline) 19589f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters else: 19689f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters setsid = getattr(os, 'setsid', None) 19789f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters if not setsid: 19889f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters setsid = getattr(os, 'setpgrp', None) 19989f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters p = subprocess.Popen(cmdline, close_fds=True, preexec_fn=setsid) 20023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return (p.poll() is None) 20123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl except OSError: 20223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return False 2033f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 2043f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 205e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass UnixBrowser(BaseBrowser): 206e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl """Parent class for all Unix browsers with remote functionality.""" 2073f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 208e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl raise_opts = None 20923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_args = ['%action', '%s'] 210e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl remote_action = None 211e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl remote_action_newwin = None 212e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl remote_action_newtab = None 21323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl background = False 21423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl redirect_stdout = True 21523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl 21623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl def _invoke(self, args, remote, autoraise): 21723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl raise_opt = [] 21823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if remote and self.raise_opts: 21923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # use autoraise argument only for remote invocation 220e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti autoraise = int(autoraise) 22123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl opt = self.raise_opts[autoraise] 22223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if opt: raise_opt = [opt] 22323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl 22423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl cmdline = [self.name] + raise_opt + args 225887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 22623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if remote or self.background: 227bc2ce57203e1f355004ec95953eae9dec780ef9aAmaury Forgeot d'Arc inout = io.open(os.devnull, "r+") 22823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 22923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # for TTY browsers, we need stdin/out 23023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl inout = None 23123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # if possible, put browser in separate process group, so 23223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # keyboard interrupts don't affect browser as well as Python 23323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl setsid = getattr(os, 'setsid', None) 23423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if not setsid: 23523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl setsid = getattr(os, 'setpgrp', None) 236887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 23723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl p = subprocess.Popen(cmdline, close_fds=True, stdin=inout, 23823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl stdout=(self.redirect_stdout and inout or None), 23923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl stderr=inout, preexec_fn=setsid) 24023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if remote: 24123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # wait five secons. If the subprocess is not finished, the 24223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # remote invocation has (hopefully) started a new instance. 24323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl time.sleep(1) 24423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl rc = p.poll() 24523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if rc is None: 24623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl time.sleep(4) 24723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl rc = p.poll() 24823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if rc is None: 24923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return True 25023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # if remote call failed, open() will try direct invocation 25123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return not rc 25223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl elif self.background: 25323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if p.poll() is None: 25423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return True 25523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 25623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return False 25723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 25823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return not p.wait() 2593f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 260e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 261e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if new == 0: 262e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl action = self.remote_action 263e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl elif new == 1: 264e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl action = self.remote_action_newwin 265e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl elif new == 2: 266e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if self.remote_action_newtab is None: 267e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl action = self.remote_action_newwin 268e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl else: 269e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl action = self.remote_action_newtab 2703f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake else: 27123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl raise Error("Bad 'new' parameter to open(); " + 27223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl "expected 0, 1, or 2, got %s" % new) 273887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 27423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl args = [arg.replace("%s", url).replace("%action", action) 27523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl for arg in self.remote_args] 27623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl success = self._invoke(args, True, autoraise) 27723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if not success: 27823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # remote invocation failed, try straight way 27923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl args = [arg.replace("%s", url) for arg in self.args] 28023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return self._invoke(args, False, False) 28123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 28223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return True 2833f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 2843f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 285e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass Mozilla(UnixBrowser): 286e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl """Launcher class for Mozilla/Netscape browsers.""" 2873f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 28823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl raise_opts = ["-noraise", "-raise"] 2898dd28eb973a1c072448d961a6fb6a8a12cc3c950Neal Norwitz 29023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_args = ['-remote', 'openURL(%s%action)'] 29123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action = "" 29223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newwin = ",new-window" 29323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newtab = ",new-tab" 294887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 29523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl background = True 2968dd28eb973a1c072448d961a6fb6a8a12cc3c950Neal Norwitz 297e8f244305ef4f257f6999b69601f4316b31faa5eGeorg BrandlNetscape = Mozilla 2988dd28eb973a1c072448d961a6fb6a8a12cc3c950Neal Norwitz 2998dd28eb973a1c072448d961a6fb6a8a12cc3c950Neal Norwitz 300e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass Galeon(UnixBrowser): 301e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl """Launcher class for Galeon/Epiphany browsers.""" 302e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 30323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl raise_opts = ["-noraise", ""] 30423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_args = ['%action', '%s'] 30523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action = "-n" 30623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newwin = "-w" 3078dd28eb973a1c072448d961a6fb6a8a12cc3c950Neal Norwitz 30823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl background = True 309e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 310e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 31123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandlclass Opera(UnixBrowser): 31223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl "Launcher class for Opera browser." 3133f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 31423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl raise_opts = ["", "-raise"] 3153f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 31623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_args = ['-remote', 'openURL(%s%action)'] 31723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action = "" 31823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newwin = ",new-window" 31923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newtab = ",new-page" 32023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl background = True 3213f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 322e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 32323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandlclass Elinks(UnixBrowser): 32423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl "Launcher class for Elinks browsers." 325e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 32623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_args = ['-remote', 'openURL(%s%action)'] 32723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action = "" 32823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newwin = ",new-window" 32923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newtab = ",new-tab" 33023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl background = False 3313f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 33223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # elinks doesn't like its stdout to be redirected - 33323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # it uses redirected stdout as a signal to do -dump 33423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl redirect_stdout = False 3353f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 3363f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 33723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandlclass Konqueror(BaseBrowser): 33823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl """Controller for the KDE File Manager (kfm, or Konqueror). 339e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 34023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl See the output of ``kfmclient --commands`` 34123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl for more information on the Konqueror remote-control interface. 34223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl """ 343e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 344e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 34523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # XXX Currently I know no way to prevent KFM from opening a new win. 34623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if new == 2: 34723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl action = "newTab" 34823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 34923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl action = "openURL" 350887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 3512b2b44dc2c2b95569e0e59c6dd4b12148ffba598Amaury Forgeot d'Arc devnull = io.open(os.devnull, "r+") 35223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # if possible, put browser in separate process group, so 35323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # keyboard interrupts don't affect browser as well as Python 35423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl setsid = getattr(os, 'setsid', None) 35523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if not setsid: 35623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl setsid = getattr(os, 'setpgrp', None) 357887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 35823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl try: 35923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl p = subprocess.Popen(["kfmclient", action, url], 36023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl close_fds=True, stdin=devnull, 36123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl stdout=devnull, stderr=devnull) 36223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl except OSError: 36323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # fall through to next variant 36423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl pass 36523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 36623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl p.wait() 36723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # kfmclient's return code unfortunately has no meaning as it seems 36823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return True 369e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 37023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl try: 37123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl p = subprocess.Popen(["konqueror", "--silent", url], 37223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl close_fds=True, stdin=devnull, 37323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl stdout=devnull, stderr=devnull, 37423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl preexec_fn=setsid) 37523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl except OSError: 37623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # fall through to next variant 37723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl pass 37823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 37923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if p.poll() is None: 38023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # Should be running now. 38123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return True 382887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 38323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl try: 38423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl p = subprocess.Popen(["kfm", "-d", url], 38523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl close_fds=True, stdin=devnull, 38623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl stdout=devnull, stderr=devnull, 38723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl preexec_fn=setsid) 38823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl except OSError: 38923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return False 39023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 39123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return (p.poll() is None) 392e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 393e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 394e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass Grail(BaseBrowser): 3953f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake # There should be a way to maintain a connection to Grail, but the 3963f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake # Grail remote control protocol doesn't really allow that at this 39723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # point. It probably never will! 3983f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake def _find_grail_rc(self): 3993f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake import glob 4003f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake import pwd 4013f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake import socket 4023f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake import tempfile 4033f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake tempdir = os.path.join(tempfile.gettempdir(), 4043f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake ".grail-unix") 40516623fe3e606efdedead8ccccaf7ef583e1be97fFred Drake user = pwd.getpwuid(os.getuid())[0] 4063f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake filename = os.path.join(tempdir, user + "-*") 4073f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake maybes = glob.glob(filename) 4083f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake if not maybes: 4093f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake return None 4103f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 4113f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake for fn in maybes: 4123f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake # need to PING each one until we find one that's live 4133f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake try: 4143f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake s.connect(fn) 4153f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake except socket.error: 4163f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake # no good; attempt to clean it out, but don't fail: 4173f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake try: 4183f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake os.unlink(fn) 4193f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake except IOError: 4203f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake pass 4213f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake else: 4223f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake return s 4233f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 4243f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake def _remote(self, action): 4253f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake s = self._find_grail_rc() 4263f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake if not s: 4273f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake return 0 4283f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake s.send(action) 4293f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake s.close() 4303f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake return 1 4313f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 432e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 4333f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake if new: 434e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl ok = self._remote("LOADNEW " + url) 4353f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake else: 436e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl ok = self._remote("LOAD " + url) 437e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return ok 4383f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 439c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 440658cba6706eb4a2ad8b3e235cf0db9fe1c8e9e6bTim Peters# 441f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# Platform support for Unix 442f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# 443c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 444e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# These are the right tests because all these Unix browsers require either 445e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# a console terminal or an X display to run. 446e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 447196f733d935bd51f8674c9761420ce990694f33aNeal Norwitzdef register_X_browsers(): 448d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum 449d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum # The default GNOME browser 450d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum if "GNOME_DESKTOP_SESSION_ID" in os.environ and _iscommand("gnome-open"): 451d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum register("gnome-open", None, BackgroundBrowser("gnome-open")) 452d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum 453d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum # The default KDE browser 454d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum if "KDE_FULL_SESSION" in os.environ and _iscommand("kfmclient"): 455d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum register("kfmclient", Konqueror, Konqueror("kfmclient")) 456d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum 457d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum # The Mozilla/Netscape browsers 4584a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl for browser in ("mozilla-firefox", "firefox", 4594a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl "mozilla-firebird", "firebird", 460477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters "seamonkey", "mozilla", "netscape"): 4614a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl if _iscommand(browser): 4624a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl register(browser, None, Mozilla(browser)) 4634a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl 464e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Konqueror/kfm, the KDE browser. 465b980113a8df699797b837f103ac6d2049a214551Georg Brandl if _iscommand("kfm"): 466b980113a8df699797b837f103ac6d2049a214551Georg Brandl register("kfm", Konqueror, Konqueror("kfm")) 467b980113a8df699797b837f103ac6d2049a214551Georg Brandl elif _iscommand("konqueror"): 468b980113a8df699797b837f103ac6d2049a214551Georg Brandl register("konqueror", Konqueror, Konqueror("konqueror")) 469e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 470e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Gnome's Galeon and Epiphany 471e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl for browser in ("galeon", "epiphany"): 472e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if _iscommand(browser): 473e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl register(browser, None, Galeon(browser)) 474e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 475e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Skipstone, another Gtk/Mozilla based browser 476e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if _iscommand("skipstone"): 47723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl register("skipstone", None, BackgroundBrowser("skipstone")) 478e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 479e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Opera, quite popular 480e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if _iscommand("opera"): 481e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl register("opera", None, Opera("opera")) 482e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 483e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Next, Mosaic -- old but still in use. 484e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if _iscommand("mosaic"): 48523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl register("mosaic", None, BackgroundBrowser("mosaic")) 486e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 487e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Grail, the Python browser. Does anybody still use it? 488e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if _iscommand("grail"): 489e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl register("grail", Grail, None) 490e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 491196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz# Prefer X browsers if present 492196f733d935bd51f8674c9761420ce990694f33aNeal Norwitzif os.environ.get("DISPLAY"): 493196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz register_X_browsers() 494196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz 495e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# Also try console browsers 496e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif os.environ.get("TERM"): 497e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # The Links/elinks browsers <http://artax.karlin.mff.cuni.cz/~mikulas/links/> 498e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if _iscommand("links"): 49923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl register("links", None, GenericBrowser("links")) 500e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if _iscommand("elinks"): 501e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl register("elinks", None, Elinks("elinks")) 502e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # The Lynx browser <http://lynx.isc.org/>, <http://lynx.browser.org/> 503e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if _iscommand("lynx"): 50423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl register("lynx", None, GenericBrowser("lynx")) 505e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # The w3m browser <http://w3m.sourceforge.net/> 506e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if _iscommand("w3m"): 50723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl register("w3m", None, GenericBrowser("w3m")) 5083f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 509f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# 510f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# Platform support for Windows 511f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# 512c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 513f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymondif sys.platform[:3] == "win": 514e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl class WindowsDefault(BaseBrowser): 515e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 516d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum try: 517d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum os.startfile(url) 518d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum except WindowsError: 519d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum # [Error 22] No application is associated with the specified 520d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum # file for this operation: '<URL>' 521d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum return False 522d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum else: 523d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum return True 524e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 525e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _tryorder = [] 526e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _browsers = {} 527d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum 528d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum # First try to use the default Windows browser 529d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum register("windows-default", WindowsDefault) 530d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum 531d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum # Detect some common Windows browsers, fallback to IE 532d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum iexplore = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), 533d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum "Internet Explorer\\IEXPLORE.EXE") 534477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters for browser in ("firefox", "firebird", "seamonkey", "mozilla", 535d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum "netscape", "opera", iexplore): 536e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if _iscommand(browser): 53723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl register(browser, None, BackgroundBrowser(browser)) 538c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 539c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake# 540f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# Platform support for MacOS 541f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# 542c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 543c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Draketry: 544c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake import ic 545c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeexcept ImportError: 546c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake pass 547c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeelse: 548e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl class InternetConfig(BaseBrowser): 549e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 550e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl ic.launchurl(url) 551e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return True # Any way to get status? 552e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 553e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl register("internet-config", InternetConfig, update_tryorder=-1) 554e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 555e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif sys.platform == 'darwin': 556e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Adapted from patch submitted to SourceForge by Steven J. Burr 557e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl class MacOSX(BaseBrowser): 558e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl """Launcher class for Aqua browsers on Mac OS X 559e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 560e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl Optionally specify a browser name on instantiation. Note that this 561e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl will not work for Aqua browsers if the user has moved the application 562e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl package after installation. 563e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 564e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl If no browser is specified, the default browser, as specified in the 565e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl Internet System Preferences panel, will be used. 566e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl """ 567e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl def __init__(self, name): 568e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl self.name = name 569e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 570e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 571e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl assert "'" not in url 57223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # hack for local urls 57323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if not ':' in url: 57423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl url = 'file:'+url 575887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 576e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # new must be 0 or 1 577e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl new = int(bool(new)) 578e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if self.name == "default": 579e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # User called open, open_new or get without a browser parameter 5801cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl script = 'open location "%s"' % url.replace('"', '%22') # opens in default browser 581e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl else: 582e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # User called get and chose a browser 583e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if self.name == "OmniWeb": 584e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl toWindow = "" 585e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl else: 586e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Include toWindow parameter of OpenURL command for browsers 587e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # that support it. 0 == new window; -1 == existing 588e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl toWindow = "toWindow %d" % (new - 1) 5891cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl cmd = 'OpenURL "%s"' % url.replace('"', '%22') 590e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl script = '''tell application "%s" 591e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl activate 592e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl %s %s 593e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl end tell''' % (self.name, cmd, toWindow) 594e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Open pipe to AppleScript through osascript command 595e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl osapipe = os.popen("osascript", "w") 596e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if osapipe is None: 597e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return False 598e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Write script to osascript's stdin 599e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl osapipe.write(script) 600e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl rc = osapipe.close() 601e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return not rc 602e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 603e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Don't clear _tryorder or _browsers since OS X can use above Unix support 604e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # (but we prefer using the OS X specific stuff) 605e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl register("MacOSX", None, MacOSX('default'), -1) 606e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 607f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond 6083a89b2b13134767475c8e0c14381c1a722d7b836Martin v. Löwis# 6093a89b2b13134767475c8e0c14381c1a722d7b836Martin v. Löwis# Platform support for OS/2 6103a89b2b13134767475c8e0c14381c1a722d7b836Martin v. Löwis# 6113a89b2b13134767475c8e0c14381c1a722d7b836Martin v. Löwis 612e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif sys.platform[:3] == "os2" and _iscommand("netscape"): 613e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _tryorder = [] 614e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _browsers = {} 6153a89b2b13134767475c8e0c14381c1a722d7b836Martin v. Löwis register("os2netscape", None, 61623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl GenericBrowser(["start", "netscape", "%s"]), -1) 617e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 6183a89b2b13134767475c8e0c14381c1a722d7b836Martin v. Löwis 619f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# OK, now that we know what the default preference orders for each 620f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# platform are, allow user to override them with the BROWSER variable. 62154f0222547b1e92cd018ef132307a6f793dc9505Raymond Hettingerif "BROWSER" in os.environ: 622e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _userchoices = os.environ["BROWSER"].split(os.pathsep) 623e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _userchoices.reverse() 624e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 625e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Treat choices in same way as if passed into get() but do register 626e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # and prepend to _tryorder 627e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl for cmdline in _userchoices: 628e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if cmdline != '': 6298719ad5ddefadbc08b56a0af91515f050c89c678Benjamin Peterson cmd = _synthesize(cmdline, -1) 6308719ad5ddefadbc08b56a0af91515f050c89c678Benjamin Peterson if cmd[1] is None: 6318719ad5ddefadbc08b56a0af91515f050c89c678Benjamin Peterson register(cmdline, None, GenericBrowser(cmdline), -1) 632e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl cmdline = None # to make del work if _userchoices was empty 633e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl del cmdline 634e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl del _userchoices 635e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 636cdab3bf7eb0810fcda21be065868f3da330779a1Skip Montanaro# what to do if _tryorder is now empty? 637e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 638e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 639e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandldef main(): 640e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl import getopt 641e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl usage = """Usage: %s [-n | -t] url 642e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl -n: open new window 643e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl -t: open new tab""" % sys.argv[0] 644e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl try: 645e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl opts, args = getopt.getopt(sys.argv[1:], 'ntd') 646b940e113bf90ff71b0ef57414ea2beea9d2a4bc0Guido van Rossum except getopt.error as msg: 647be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum print(msg, file=sys.stderr) 648be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum print(usage, file=sys.stderr) 649e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl sys.exit(1) 650e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl new_win = 0 651e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl for o, a in opts: 652e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if o == '-n': new_win = 1 653e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl elif o == '-t': new_win = 2 654b053cd8f40dd19985b16f50661640dcefb69888fGuido van Rossum if len(args) != 1: 655be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum print(usage, file=sys.stderr) 656e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl sys.exit(1) 657e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 658e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl url = args[0] 659e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl open(url, new_win) 660e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 661be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum print("\a") 66223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl 663e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif __name__ == "__main__": 664e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl main() 665