webbrowser.py revision c70b4483d2c5042c68198dc7c4945ef3cfc95b27
1c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake"""Remote-control interfaces to some browsers.""" 2c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 3c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeimport os 4c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeimport sys 5c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 6c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 7c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred DrakePROCESS_CREATION_DELAY = 4 8c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 9c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 10c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeclass Error(Exception): 11c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake pass 12c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 13c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 14c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake_browsers = {} 15c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 16c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakedef register(name, klass, instance=None): 17c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake """Register a browser connector and, optionally, connection.""" 18c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake _browsers[name.lower()] = [klass, instance] 19c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 20c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 21c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakedef get(name=None): 22c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake """Retrieve a connection to a browser by type name, or the default 23c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake browser.""" 24c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake name = name or DEFAULT_BROWSER 25c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake try: 26c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake L = _browsers[name.lower()] 27c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake except KeyError: 28c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake raise ValueError, "unknown browser type: " + `name` 29c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake if L[1] is None: 30c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake L[1] = L[0]() 31c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake return L[1] 32c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 33c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 34c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake# Please note: the following definition hides a builtin function. 35c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 36c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakedef open(url, new=0): 37c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake get().open(url, new) 38c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 39c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 40c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakedef open_new(url): 41c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake get().open_new(url) 42c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 43c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 44c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakedef _iscommand(cmd): 45c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake """Return true if cmd can be found on the executable search path.""" 46c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake path = os.environ.get("PATH") 47c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake if not path: 48c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake return 0 49c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake for d in path.split(os.pathsep): 50c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake exe = os.path.join(d, cmd) 51c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake if os.path.isfile(exe): 52c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake return 1 53c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake return 0 54c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 55c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 56c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeclass CommandLineBrowser: 57c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake _browsers = [] 58c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake if os.environ.get("DISPLAY"): 59c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake _browsers.extend([ 60c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake ("netscape", "netscape %s >/dev/null &"), 61c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake ("mosaic", "mosaic %s >/dev/null &"), 62c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake ]) 63c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake _browsers.extend([ 64c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake ("lynx", "lynx %s"), 65c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake ("w3m", "w3m %s"), 66c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake ]) 67c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 68c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def open(self, url, new=0): 69c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake for exe, cmd in self._browsers: 70c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake if _iscommand(exe): 71c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake os.system(cmd % url) 72c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake return 73c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake raise Error("could not locate runnable browser") 74c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 75c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def open_new(self, url): 76c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake self.open(url) 77c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 78c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeregister("command-line", CommandLineBrowser) 79c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 80c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 81c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeclass Netscape: 82c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake autoRaise = 1 83c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 84c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def _remote(self, action): 85c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake raise_opt = ("-noraise", "-raise")[self.autoRaise] 86c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake cmd = "netscape %s -remote '%s' >/dev/null 2>&1" % (raise_opt, action) 87c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake rc = os.system(cmd) 88c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake if rc: 89c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake import time 90c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake os.system("netscape -no-about-splash &") 91c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake time.sleep(PROCESS_CREATION_DELAY) 92c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake rc = os.system(cmd) 93c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake return not rc 94c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 95c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def open(self, url, new=0): 96c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake if new: 97c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake self.open_new(url) 98c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake else: 99c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake self._remote("openURL(%s)" % url) 100c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 101c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def open_new(self, url): 102c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake self._remote("openURL(%s, new-window)" % url) 103c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 104c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeregister("netscape", Netscape) 105c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 106c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 107c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeclass Konquerer: 108c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake """Controller for the KDE File Manager (kfm, or Konquerer). 109c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 110c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake See http://developer.kde.org/documentation/other/kfmclient.html 111c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake for more information on the Konquerer remote-control interface. 112c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 113c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake """ 114c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def _remote(self, action): 115c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake cmd = "kfmclient %s >/dev/null 2>&1" % action 116c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake rc = os.system(cmd) 117c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake if rc: 118c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake import time 119c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake os.system("kfm -d &") 120c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake time.sleep(PROCESS_CREATION_DELAY) 121c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake rc = os.system(cmd) 122c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake return not rc 123c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 124c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def open(self, url, new=1): 125c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake # XXX currently I know no way to prevent KFM from opening a new win. 126c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake self.open_new(url) 127c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 128c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def open_new(self, url): 129c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake self._remote("openURL %s" % url) 130c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 131c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeregister("kfm", Konquerer) 132c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 133c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 134c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeclass Grail: 135c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake # There should be a way to maintain a connection to Grail, but the 136c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake # Grail remote control protocol doesn't really allow that at this 137c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake # point. It probably never will! 138c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 139c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def _find_grail_rc(self): 140c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake import glob 141c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake import pwd 142c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake import socket 143c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake import tempfile 144c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake tempdir = os.path.join(tempfile.gettempdir(), ".grail-unix") 145c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake user = pwd.getpwuid(_os.getuid())[0] 146c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake filename = os.path.join(tempdir, user + "-*") 147c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake maybes = glob.glob(filename) 148c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake if not maybes: 149c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake return None 150c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 151c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake for fn in maybes: 152c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake # need to PING each one until we find one that's live 153c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake try: 154c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake s.connect(fn) 155c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake except socket.error: 156c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake # no good; attempt to clean it out, but don't fail: 157c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake try: 158c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake os.unlink(fn) 159c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake except IOError: 160c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake pass 161c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake else: 162c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake return s 163c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 164c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def _remote(self, action): 165c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake s = self._find_grail_rc() 166c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake if not s: 167c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake return 0 168c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake s.send(action) 169c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake s.close() 170c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake return 1 171c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 172c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def open(self, url, new=0): 173c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake if new: 174c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake self.open_new(url) 175c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake else: 176c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake self._remote("LOAD " + url) 177c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 178c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def open_new(self, url): 179c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake self._remote("LOADNEW " + url) 180c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 181c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeregister("grail", Grail) 182c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 183c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 184c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeclass WindowsDefault: 185c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def open(self, url, new=0): 186c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake import win32api, win32con 187c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake win32api.ShellExecute(0, "open", url, None, ".", 188c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake win32con.SW_SHOWNORMAL) 189c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 190c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def open_new(self, url): 191c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake self.open(url) 192c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 193c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 194c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred DrakeDEFAULT_BROWSER = "command-line" 195c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 196c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeif sys.platform[:3] == "win": 197c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake del _browsers["kfm"] 198c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake register("windows-default", WindowsDefault) 199c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake DEFAULT_BROWSER = "windows-default" 200c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeelif os.environ.get("DISPLAY"): 201c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake if os.environ.get("KDEDIR"): 202c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake DEFAULT_BROWSER = "kfm" 203c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake elif _iscommand("netscape"): 204c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake DEFAULT_BROWSER = "netscape" 205c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 206c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake# If the $BROWSER environment variable is set and true, let that be 207c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake# the name of the browser to use: 208c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake# 209c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred DrakeDEFAULT_BROWSER = os.environ.get("BROWSER") or DEFAULT_BROWSER 210c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 211c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 212c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake# Now try to support the MacOS world. This is the only supported 213c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake# controller on that platform, so don't mess with the default! 214c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 215c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Draketry: 216c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake import ic 217c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeexcept ImportError: 218c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake pass 219c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeelse: 220c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake class InternetConfig: 221c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def open(self, url, new=0): 222c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake ic.launcurl(url) 223c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 224c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake def open_new(self, url): 225c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake self.open(url) 226c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 227c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake _browsers.clear() 228c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake register("internet-config", InternetConfig) 229c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake DEFAULT_BROWSER = "internet-config" 230