webbrowser.py revision 4a5a91838b7318cc89a2ff2018b26940a5960a29
1e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl#! /usr/bin/env python
20a8c29be4b5314d4bf72cb391ab078f7483cf3f7Ka-Ping Yee"""Interfaces for launching and remotely controlling Web browsers."""
3c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
4c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeimport os
5c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeimport sys
6e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlimport stat
7c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
8e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl__all__ = ["Error", "open", "open_new", "open_new_tab", "get", "register"]
940fc16059f04ee8fda0b5956cc4883eb21ca8f8cSkip Montanaro
10c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeclass Error(Exception):
11c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake    pass
12c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
13658cba6706eb4a2ad8b3e235cf0db9fe1c8e9e6bTim Peters_browsers = {}          # Dictionary of available browser controllers
14658cba6706eb4a2ad8b3e235cf0db9fe1c8e9e6bTim Peters_tryorder = []          # Preference order of available browsers
15c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
16e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandldef register(name, klass, instance=None, update_tryorder=1):
17c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake    """Register a browser connector and, optionally, connection."""
18c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake    _browsers[name.lower()] = [klass, instance]
19e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if update_tryorder > 0:
20e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        _tryorder.append(name)
21e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    elif update_tryorder < 0:
22e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        _tryorder.insert(0, name)
23c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
24f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymonddef get(using=None):
25f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond    """Return a browser launcher instance appropriate for the environment."""
2610ff706e2788a7c7ef9f8ea0108a5ede625fedadRaymond Hettinger    if using is not None:
27f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond        alternatives = [using]
28f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond    else:
29f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond        alternatives = _tryorder
30f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond    for browser in alternatives:
31bac788a3cd348203a5fdabba52e5faf65bf35c5eRaymond Hettinger        if '%s' in browser:
32f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond            # User gave us a command line, don't mess with it.
33f7eb4faf38fc9e4a215acae3323140b99cdce08fEric S. Raymond            return GenericBrowser(browser)
34f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond        else:
35e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            # User gave us a browser name or path.
36f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake            try:
37f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake                command = _browsers[browser.lower()]
38f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake            except KeyError:
39f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake                command = _synthesize(browser)
40e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            if command[1] is not None:
41f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond                return command[1]
42e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            elif command[0] is not None:
43e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                return command[0]()
44f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond    raise Error("could not locate runnable browser")
45c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
46c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake# Please note: the following definition hides a builtin function.
47e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# It is recommended one does "import webbrowser" and uses webbrowser.open(url)
48e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# instead of "from webbrowser import *".
49c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
50f79cb2db3eae59f80e8031d45376dc5f48d2af04Eric S. Raymonddef open(url, new=0, autoraise=1):
51e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    for name in _tryorder:
52e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        browser = get(name)
53e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        if browser.open(url, new, autoraise):
54e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            return True
55e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    return False
56c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
573f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drakedef open_new(url):
58e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    return open(url, 1)
59c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
60e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandldef open_new_tab(url):
61e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    return open(url, 2)
62f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake
63e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
64e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandldef _synthesize(browser, update_tryorder=1):
65f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    """Attempt to synthesize a controller base on existing controllers.
66f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake
67f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    This is useful to create a controller when a user specifies a path to
68f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    an entry in the BROWSER environment variable -- we can copy a general
69f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    controller to operate using a specific installation of the desired
70f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    browser in this way.
71f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake
72f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    If we can't create a controller in this way, or if there is no
73f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    executable for the requested browser, return [None, None].
74f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake
75f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    """
76e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    cmd = browser.split()[0]
77e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if not _iscommand(cmd):
78f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake        return [None, None]
79e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    name = os.path.basename(cmd)
80f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    try:
81f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake        command = _browsers[name.lower()]
82f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    except KeyError:
83f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake        return [None, None]
84f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    # now attempt to clone to fit the new name:
85f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    controller = command[1]
86f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake    if controller and name.lower() == controller.basename:
87f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake        import copy
88f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake        controller = copy.copy(controller)
89f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake        controller.name = browser
90f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake        controller.basename = os.path.basename(browser)
91e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        register(browser, None, controller, update_tryorder)
92f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake        return [None, controller]
93118aa5337c745dece455f4782799c83b9e3a7d4fAndrew M. Kuchling    return [None, None]
94f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake
953f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
96e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif sys.platform[:3] == "win":
97e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    def _isexecutable(cmd):
98e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        cmd = cmd.lower()
99e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        if os.path.isfile(cmd) and (cmd.endswith(".exe") or
100e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                                    cmd.endswith(".bat")):
101e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            return True
102e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        for ext in ".exe", ".bat":
103e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            if os.path.isfile(cmd + ext):
104e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                return True
105e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        return False
106e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlelse:
107e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    def _isexecutable(cmd):
108e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        if os.path.isfile(cmd):
109e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            mode = os.stat(cmd)[stat.ST_MODE]
110e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            if mode & stat.S_IXUSR or mode & stat.S_IXGRP or mode & stat.S_IXOTH:
111e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                return True
112e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        return False
113e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
1143f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drakedef _iscommand(cmd):
115e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    """Return True if cmd is executable or can be found on the executable
116e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    search path."""
117e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if _isexecutable(cmd):
118e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        return True
1193f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    path = os.environ.get("PATH")
1203f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    if not path:
121bc0e9108261693b6278687f4fb4709ff76c2e543Tim Peters        return False
1223f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    for d in path.split(os.pathsep):
1233f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        exe = os.path.join(d, cmd)
124e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        if _isexecutable(exe):
125bc0e9108261693b6278687f4fb4709ff76c2e543Tim Peters            return True
126bc0e9108261693b6278687f4fb4709ff76c2e543Tim Peters    return False
1273f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
1283f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
129e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# General parent classes
130e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
131e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass BaseBrowser(object):
132e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    """Parent class for all browsers."""
133e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
134e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    def __init__(self, name=""):
135e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        self.name = name
136b980113a8df699797b837f103ac6d2049a214551Georg Brandl        self.basename = name
137e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
138196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz    def open(self, url, new=0, autoraise=1):
139196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz        raise NotImplementedError
140196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz
141e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    def open_new(self, url):
142e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        return self.open(url, 1)
143e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
144e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    def open_new_tab(self, url):
145e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        return self.open(url, 2)
146e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
1473f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
148e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass GenericBrowser(BaseBrowser):
149e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    """Class for all browsers started with a command
150e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl       and without remote functionality."""
1513f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
1523f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    def __init__(self, cmd):
1533f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        self.name, self.args = cmd.split(None, 1)
154b980113a8df699797b837f103ac6d2049a214551Georg Brandl        self.basename = os.path.basename(self.name)
1553f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
1563f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    def open(self, url, new=0, autoraise=1):
157925f14427416c1c5a8c6e71d17daac20e248c7b0Fred Drake        assert "'" not in url
1583f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        command = "%s %s" % (self.name, self.args)
159e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        rc = os.system(command % url)
160e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        return not rc
1613f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
1623f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
163e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass UnixBrowser(BaseBrowser):
164e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    """Parent class for all Unix browsers with remote functionality."""
1653f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
166e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    raise_opts = None
1673f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
168e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_cmd = ''
169e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action = None
170e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action_newwin = None
171e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action_newtab = None
172e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_background = False
173e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
174e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    def _remote(self, url, action, autoraise):
175e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        autoraise = int(bool(autoraise)) # always 0/1
176e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        raise_opt = self.raise_opts and self.raise_opts[autoraise] or ''
177e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        cmd = "%s %s %s '%s' >/dev/null 2>&1" % (self.name, raise_opt,
178e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                                                 self.remote_cmd, action)
179196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz        if self.remote_background:
180e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            cmd += ' &'
1813f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        rc = os.system(cmd)
1823f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        if rc:
1831cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl            cmd = "%s %s" % (self.name, url)
1841cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl            if self.remote_background:
1851cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl                cmd += " &"
186e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            # bad return status, try again with simpler command
1871cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl            rc = os.system(cmd)
1883f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        return not rc
1893f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
1903f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    def open(self, url, new=0, autoraise=1):
191e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        assert "'" not in url
192e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        if new == 0:
193e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            action = self.remote_action
194e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        elif new == 1:
195e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            action = self.remote_action_newwin
196e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        elif new == 2:
197e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            if self.remote_action_newtab is None:
198e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                action = self.remote_action_newwin
199e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            else:
200e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                action = self.remote_action_newtab
2013f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        else:
202e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            raise Error("Bad 'new' parameter to open(); expected 0, 1, or 2, got %s" % new)
203e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        return self._remote(url, action % url, autoraise)
2043f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
2053f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
206e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass Mozilla(UnixBrowser):
207e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    """Launcher class for Mozilla/Netscape browsers."""
2083f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
209e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    raise_opts = ("-noraise", "-raise")
2108dd28eb973a1c072448d961a6fb6a8a12cc3c950Neal Norwitz
211e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_cmd = '-remote'
212e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action = "openURL(%s)"
213e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action_newwin = "openURL(%s,new-window)"
214e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action_newtab = "openURL(%s,new-tab)"
2151cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl    remote_background = True
2168dd28eb973a1c072448d961a6fb6a8a12cc3c950Neal Norwitz
217e8f244305ef4f257f6999b69601f4316b31faa5eGeorg BrandlNetscape = Mozilla
2188dd28eb973a1c072448d961a6fb6a8a12cc3c950Neal Norwitz
2198dd28eb973a1c072448d961a6fb6a8a12cc3c950Neal Norwitz
220e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass Galeon(UnixBrowser):
221e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    """Launcher class for Galeon/Epiphany browsers."""
222e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
223e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    raise_opts = ("-noraise", "")
224e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action = "-n '%s'"
225e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action_newwin = "-w '%s'"
2268dd28eb973a1c072448d961a6fb6a8a12cc3c950Neal Norwitz
227e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_background = True
228e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
229e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
230e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass Konqueror(BaseBrowser):
2313f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    """Controller for the KDE File Manager (kfm, or Konqueror).
2323f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
2333f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    See http://developer.kde.org/documentation/other/kfmclient.html
2343f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    for more information on the Konqueror remote-control interface.
2353f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
2363f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    """
2373f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
238e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    def _remote(self, url, action):
239e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        # kfmclient is the new KDE way of opening URLs.
240520cdf733aa8bfff48369822802a2df913851fcbNeal Norwitz        cmd = "kfmclient %s >/dev/null 2>&1" % action
2413f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        rc = os.system(cmd)
242e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        # Fall back to other variants.
2433f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        if rc:
244e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            if _iscommand("konqueror"):
245e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                rc = os.system(self.name + " --silent '%s' &" % url)
246e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            elif _iscommand("kfm"):
2471cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl                rc = os.system(self.name + " -d '%s' &" % url)
2483f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        return not rc
2493f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
250e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    def open(self, url, new=0, autoraise=1):
2513f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        # XXX Currently I know no way to prevent KFM from
2523f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        # opening a new win.
253520cdf733aa8bfff48369822802a2df913851fcbNeal Norwitz        assert "'" not in url
254e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        if new == 2:
255e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            action = "newTab '%s'" % url
256e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        else:
257e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            action = "openURL '%s'" % url
258e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        ok = self._remote(url, action)
259e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        return ok
260e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
261e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
262e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass Opera(UnixBrowser):
263e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    "Launcher class for Opera browser."
2643f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
265e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    raise_opts = ("", "-raise")
2663f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
267e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_cmd = '-remote'
268e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action = "openURL(%s)"
269e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action_newwin = "openURL(%s,new-window)"
270e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action_newtab = "openURL(%s,new-page)"
2711cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl    remote_background = True
2723f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
273e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
274e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass Elinks(UnixBrowser):
275e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    "Launcher class for Elinks browsers."
276e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
277e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_cmd = '-remote'
278e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action = "openURL(%s)"
279e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action_newwin = "openURL(%s,new-window)"
280e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    remote_action_newtab = "openURL(%s,new-tab)"
281e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
282e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    def _remote(self, url, action, autoraise):
283e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        # elinks doesn't like its stdout to be redirected -
284e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        # it uses redirected stdout as a signal to do -dump
285e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        cmd = "%s %s '%s' 2>/dev/null" % (self.name,
286e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                                          self.remote_cmd, action)
287e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        rc = os.system(cmd)
288e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        if rc:
289e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            rc = os.system("%s %s" % (self.name, url))
290e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        return not rc
291e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
292e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
293e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass Grail(BaseBrowser):
2943f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    # There should be a way to maintain a connection to Grail, but the
2953f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    # Grail remote control protocol doesn't really allow that at this
2963f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    # point.  It probably neverwill!
2973f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    def _find_grail_rc(self):
2983f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        import glob
2993f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        import pwd
3003f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        import socket
3013f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        import tempfile
3023f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        tempdir = os.path.join(tempfile.gettempdir(),
3033f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake                               ".grail-unix")
30416623fe3e606efdedead8ccccaf7ef583e1be97fFred Drake        user = pwd.getpwuid(os.getuid())[0]
3053f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        filename = os.path.join(tempdir, user + "-*")
3063f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        maybes = glob.glob(filename)
3073f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        if not maybes:
3083f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake            return None
3093f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
3103f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        for fn in maybes:
3113f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake            # need to PING each one until we find one that's live
3123f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake            try:
3133f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake                s.connect(fn)
3143f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake            except socket.error:
3153f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake                # no good; attempt to clean it out, but don't fail:
3163f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake                try:
3173f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake                    os.unlink(fn)
3183f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake                except IOError:
3193f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake                    pass
3203f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake            else:
3213f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake                return s
3223f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
3233f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    def _remote(self, action):
3243f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        s = self._find_grail_rc()
3253f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        if not s:
3263f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake            return 0
3273f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        s.send(action)
3283f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        s.close()
3293f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        return 1
3303f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
3313f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake    def open(self, url, new=0, autoraise=1):
3323f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        if new:
333e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            ok = self._remote("LOADNEW " + url)
3343f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake        else:
335e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            ok = self._remote("LOAD " + url)
336e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        return ok
3373f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
338c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
339658cba6706eb4a2ad8b3e235cf0db9fe1c8e9e6bTim Peters#
340f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# Platform support for Unix
341f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond#
342c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
343e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# These are the right tests because all these Unix browsers require either
344e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# a console terminal or an X display to run.
345e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
346196f733d935bd51f8674c9761420ce990694f33aNeal Norwitzdef register_X_browsers():
347e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # The default Gnome browser
348e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if _iscommand("gconftool-2"):
349e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        # get the web browser string from gconftool
350e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        gc = 'gconftool-2 -g /desktop/gnome/url-handlers/http/command'
351e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        out = os.popen(gc)
352e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        commd = out.read().strip()
353e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        retncode = out.close()
354e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
355e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        # if successful, register it
356e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        if retncode == None and len(commd) != 0:
357e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            register("gnome", None, GenericBrowser(
358e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                commd + " '%s' >/dev/null &"))
359e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
3604a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl   # First, the Mozilla/Netscape browsers
3614a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl    for browser in ("mozilla-firefox", "firefox",
3624a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl                    "mozilla-firebird", "firebird",
3634a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl                    "mozilla", "netscape"):
3644a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl        if _iscommand(browser):
3654a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl            register(browser, None, Mozilla(browser))
3664a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl
367e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # Konqueror/kfm, the KDE browser.
368b980113a8df699797b837f103ac6d2049a214551Georg Brandl    if _iscommand("kfm"):
369b980113a8df699797b837f103ac6d2049a214551Georg Brandl        register("kfm", Konqueror, Konqueror("kfm"))
370b980113a8df699797b837f103ac6d2049a214551Georg Brandl    elif _iscommand("konqueror"):
371b980113a8df699797b837f103ac6d2049a214551Georg Brandl        register("konqueror", Konqueror, Konqueror("konqueror"))
372e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
373e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # Gnome's Galeon and Epiphany
374e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    for browser in ("galeon", "epiphany"):
375e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        if _iscommand(browser):
376e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            register(browser, None, Galeon(browser))
377e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
378e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # Skipstone, another Gtk/Mozilla based browser
379e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if _iscommand("skipstone"):
380e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        register("skipstone", None, GenericBrowser("skipstone '%s' &"))
381e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
382e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # Opera, quite popular
383e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if _iscommand("opera"):
384e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        register("opera", None, Opera("opera"))
385e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
386e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # Next, Mosaic -- old but still in use.
387e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if _iscommand("mosaic"):
388e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        register("mosaic", None, GenericBrowser("mosaic '%s' &"))
389e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
390e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # Grail, the Python browser. Does anybody still use it?
391e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if _iscommand("grail"):
392e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        register("grail", Grail, None)
393e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
394196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz# Prefer X browsers if present
395196f733d935bd51f8674c9761420ce990694f33aNeal Norwitzif os.environ.get("DISPLAY"):
396196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz    register_X_browsers()
397196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz
398e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# Also try console browsers
399e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif os.environ.get("TERM"):
400e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # The Links/elinks browsers <http://artax.karlin.mff.cuni.cz/~mikulas/links/>
401e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if _iscommand("links"):
402e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        register("links", None, GenericBrowser("links '%s'"))
403e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if _iscommand("elinks"):
404e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        register("elinks", None, Elinks("elinks"))
405e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # The Lynx browser <http://lynx.isc.org/>, <http://lynx.browser.org/>
406e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if _iscommand("lynx"):
407e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        register("lynx", None, GenericBrowser("lynx '%s'"))
408e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # The w3m browser <http://w3m.sourceforge.net/>
409e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if _iscommand("w3m"):
410e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        register("w3m", None, GenericBrowser("w3m '%s'"))
4113f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake
412f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond#
413f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# Platform support for Windows
414f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond#
415c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
416f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymondif sys.platform[:3] == "win":
417e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    class WindowsDefault(BaseBrowser):
418e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        def open(self, url, new=0, autoraise=1):
419e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            os.startfile(url)
420e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            return True # Oh, my...
421e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
422e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    _tryorder = []
423e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    _browsers = {}
424e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # Prefer mozilla/netscape/opera if present
425e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    for browser in ("firefox", "firebird", "mozilla", "netscape", "opera"):
426e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        if _iscommand(browser):
427e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            register(browser, None, GenericBrowser(browser + ' %s'))
428c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake    register("windows-default", WindowsDefault)
429c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
430c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake#
431f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# Platform support for MacOS
432f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond#
433c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake
434c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Draketry:
435c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake    import ic
436c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeexcept ImportError:
437c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake    pass
438c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeelse:
439e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    class InternetConfig(BaseBrowser):
440e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        def open(self, url, new=0, autoraise=1):
441e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            ic.launchurl(url)
442e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            return True # Any way to get status?
443e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
444e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    register("internet-config", InternetConfig, update_tryorder=-1)
445e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
446e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif sys.platform == 'darwin':
447e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # Adapted from patch submitted to SourceForge by Steven J. Burr
448e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    class MacOSX(BaseBrowser):
449e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        """Launcher class for Aqua browsers on Mac OS X
450e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
451e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        Optionally specify a browser name on instantiation.  Note that this
452e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        will not work for Aqua browsers if the user has moved the application
453e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        package after installation.
454e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
455e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        If no browser is specified, the default browser, as specified in the
456e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        Internet System Preferences panel, will be used.
457e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        """
458e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        def __init__(self, name):
459e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            self.name = name
460e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
461e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        def open(self, url, new=0, autoraise=1):
462e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            assert "'" not in url
463e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            # new must be 0 or 1
464e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            new = int(bool(new))
465e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            if self.name == "default":
466e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                # User called open, open_new or get without a browser parameter
4671cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl                script = 'open location "%s"' % url.replace('"', '%22') # opens in default browser
468e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            else:
469e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                # User called get and chose a browser
470e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                if self.name == "OmniWeb":
471e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                    toWindow = ""
472e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                else:
473e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                    # Include toWindow parameter of OpenURL command for browsers
474e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                    # that support it.  0 == new window; -1 == existing
475e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                    toWindow = "toWindow %d" % (new - 1)
4761cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl                cmd = 'OpenURL "%s"' % url.replace('"', '%22')
477e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                script = '''tell application "%s"
478e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                                activate
479e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                                %s %s
480e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                            end tell''' % (self.name, cmd, toWindow)
481e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            # Open pipe to AppleScript through osascript command
482e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            osapipe = os.popen("osascript", "w")
483e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            if osapipe is None:
484e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl                return False
485e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            # Write script to osascript's stdin
486e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            osapipe.write(script)
487e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            rc = osapipe.close()
488e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            return not rc
489e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
490e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # Don't clear _tryorder or _browsers since OS X can use above Unix support
491e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # (but we prefer using the OS X specific stuff)
492e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    register("MacOSX", None, MacOSX('default'), -1)
493e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
494f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond
4953a89b2b13134767475c8e0c14381c1a722d7b836Martin v. Löwis#
4963a89b2b13134767475c8e0c14381c1a722d7b836Martin v. Löwis# Platform support for OS/2
4973a89b2b13134767475c8e0c14381c1a722d7b836Martin v. Löwis#
4983a89b2b13134767475c8e0c14381c1a722d7b836Martin v. Löwis
499e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif sys.platform[:3] == "os2" and _iscommand("netscape"):
500e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    _tryorder = []
501e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    _browsers = {}
5023a89b2b13134767475c8e0c14381c1a722d7b836Martin v. Löwis    register("os2netscape", None,
503e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl             GenericBrowser("start netscape %s"), -1)
504e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
5053a89b2b13134767475c8e0c14381c1a722d7b836Martin v. Löwis
506f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# OK, now that we know what the default preference orders for each
507f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# platform are, allow user to override them with the BROWSER variable.
50854f0222547b1e92cd018ef132307a6f793dc9505Raymond Hettingerif "BROWSER" in os.environ:
509e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    _userchoices = os.environ["BROWSER"].split(os.pathsep)
510e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    _userchoices.reverse()
511e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
512e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # Treat choices in same way as if passed into get() but do register
513e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    # and prepend to _tryorder
514e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    for cmdline in _userchoices:
515e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        if cmdline != '':
516e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl            _synthesize(cmdline, -1)
517e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    cmdline = None # to make del work if _userchoices was empty
518e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    del cmdline
519e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    del _userchoices
520e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
521cdab3bf7eb0810fcda21be065868f3da330779a1Skip Montanaro# what to do if _tryorder is now empty?
522e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
523e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
524e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandldef main():
525e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    import getopt
526e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    usage = """Usage: %s [-n | -t] url
527e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    -n: open new window
528e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    -t: open new tab""" % sys.argv[0]
529e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    try:
530e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        opts, args = getopt.getopt(sys.argv[1:], 'ntd')
531e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    except getopt.error, msg:
532e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        print >>sys.stderr, msg
533e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        print >>sys.stderr, usage
534e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        sys.exit(1)
535e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    new_win = 0
536e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    for o, a in opts:
537e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        if o == '-n': new_win = 1
538e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        elif o == '-t': new_win = 2
539e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    if len(args) <> 1:
540e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        print >>sys.stderr, usage
541e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl        sys.exit(1)
542e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
543e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    url = args[0]
544e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    open(url, new_win)
545e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl
546e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif __name__ == "__main__":
547e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl    main()
548