webbrowser.py 5.48 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
"""Remote-control interfaces to some browsers."""

import os
import sys


PROCESS_CREATION_DELAY = 4


class Error(Exception):
    pass


_browsers = {}

def register(name, klass, instance=None):
    """Register a browser connector and, optionally, connection."""
    _browsers[name.lower()] = [klass, instance]


def get(name=None):
    """Retrieve a connection to a browser by type name, or the default
    browser."""
    name = name or DEFAULT_BROWSER
    try:
        L = _browsers[name.lower()]
    except KeyError:
        raise ValueError, "unknown browser type: " + `name`
    if L[1] is None:
        L[1] = L[0]()
    return L[1]


# Please note: the following definition hides a builtin function.

def open(url, new=0):
    get().open(url, new)


def open_new(url):
    get().open_new(url)


def _iscommand(cmd):
    """Return true if cmd can be found on the executable search path."""
    path = os.environ.get("PATH")
    if not path:
        return 0
    for d in path.split(os.pathsep):
        exe = os.path.join(d, cmd)
        if os.path.isfile(exe):
            return 1
    return 0


class CommandLineBrowser:
    _browsers = []
    if os.environ.get("DISPLAY"):
        _browsers.extend([
            ("netscape", "netscape %s >/dev/null &"),
            ("mosaic", "mosaic %s >/dev/null &"),
            ])
    _browsers.extend([
        ("lynx", "lynx %s"),
        ("w3m", "w3m %s"),
        ])

    def open(self, url, new=0):
        for exe, cmd in self._browsers:
            if _iscommand(exe):
                os.system(cmd % url)
                return
        raise Error("could not locate runnable browser")

    def open_new(self, url):
        self.open(url)

register("command-line", CommandLineBrowser)


class Netscape:
    autoRaise = 1

    def _remote(self, action):
        raise_opt = ("-noraise", "-raise")[self.autoRaise]
        cmd = "netscape %s -remote '%s' >/dev/null 2>&1" % (raise_opt, action)
        rc = os.system(cmd)
        if rc:
            import time
            os.system("netscape -no-about-splash &")
            time.sleep(PROCESS_CREATION_DELAY)
            rc = os.system(cmd)
        return not rc

    def open(self, url, new=0):
        if new:
            self.open_new(url)
        else:
            self._remote("openURL(%s)" % url)

    def open_new(self, url):
        self._remote("openURL(%s, new-window)" % url)

register("netscape", Netscape)


class Konquerer:
    """Controller for the KDE File Manager (kfm, or Konquerer).

    See http://developer.kde.org/documentation/other/kfmclient.html
    for more information on the Konquerer remote-control interface.

    """
    def _remote(self, action):
        cmd = "kfmclient %s >/dev/null 2>&1" % action
        rc = os.system(cmd)
        if rc:
            import time
            os.system("kfm -d &")
            time.sleep(PROCESS_CREATION_DELAY)
            rc = os.system(cmd)
        return not rc

    def open(self, url, new=1):
	# XXX currently I know no way to prevent KFM from opening a new win.
        self.open_new(url)

    def open_new(self, url):
        self._remote("openURL %s" % url)

register("kfm", Konquerer)


class Grail:
    # There should be a way to maintain a connection to Grail, but the
    # Grail remote control protocol doesn't really allow that at this
    # point.  It probably never will!

    def _find_grail_rc(self):
        import glob
        import pwd
        import socket
        import tempfile
        tempdir = os.path.join(tempfile.gettempdir(), ".grail-unix")
        user = pwd.getpwuid(_os.getuid())[0]
        filename = os.path.join(tempdir, user + "-*")
        maybes = glob.glob(filename)
        if not maybes:
            return None
        s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        for fn in maybes:
            # need to PING each one until we find one that's live
            try:
                s.connect(fn)
            except socket.error:
                # no good; attempt to clean it out, but don't fail:
                try:
                    os.unlink(fn)
                except IOError:
                    pass
            else:
                return s

    def _remote(self, action):
        s = self._find_grail_rc()
        if not s:
            return 0
        s.send(action)
        s.close()
        return 1

    def open(self, url, new=0):
        if new:
            self.open_new(url)
        else:
            self._remote("LOAD " + url)

    def open_new(self, url):
        self._remote("LOADNEW " + url)

register("grail", Grail)


class WindowsDefault:
    def open(self, url, new=0):
186
        os.startfile(url)
187 188 189 190 191 192 193 194 195 196 197 198

    def open_new(self, url):
        self.open(url)


DEFAULT_BROWSER = "command-line"

if sys.platform[:3] == "win":
    del _browsers["kfm"]
    register("windows-default", WindowsDefault)
    DEFAULT_BROWSER = "windows-default"
elif os.environ.get("DISPLAY"):
199
    if _iscommand("netscape"):
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
        DEFAULT_BROWSER = "netscape"

# If the $BROWSER environment variable is set and true, let that be
# the name of the browser to use:
#
DEFAULT_BROWSER = os.environ.get("BROWSER") or DEFAULT_BROWSER


# Now try to support the MacOS world.  This is the only supported
# controller on that platform, so don't mess with the default!

try:
    import ic
except ImportError:
    pass
else:
    class InternetConfig:
        def open(self, url, new=0):
            ic.launcurl(url)

        def open_new(self, url):
            self.open(url)

    _browsers.clear()
    register("internet-config", InternetConfig)
    DEFAULT_BROWSER = "internet-config"