home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / webbrowser.py < prev    next >
Text File  |  2003-12-30  |  11KB  |  370 lines

  1. """Interfaces for launching and remotely controlling Web browsers."""
  2.  
  3. import os
  4. import sys
  5.  
  6. __all__ = ["Error", "open", "get", "register"]
  7.  
  8. class Error(Exception):
  9.     pass
  10.  
  11. _browsers = {}          # Dictionary of available browser controllers
  12. _tryorder = []          # Preference order of available browsers
  13.  
  14. def register(name, klass, instance=None):
  15.     """Register a browser connector and, optionally, connection."""
  16.     _browsers[name.lower()] = [klass, instance]
  17.  
  18. def get(using=None):
  19.     """Return a browser launcher instance appropriate for the environment."""
  20.     if using is not None:
  21.         alternatives = [using]
  22.     else:
  23.         alternatives = _tryorder
  24.     for browser in alternatives:
  25.         if browser.find('%s') > -1:
  26.             # User gave us a command line, don't mess with it.
  27.             return GenericBrowser(browser)
  28.         else:
  29.             # User gave us a browser name.
  30.             try:
  31.                 command = _browsers[browser.lower()]
  32.             except KeyError:
  33.                 command = _synthesize(browser)
  34.             if command[1] is None:
  35.                 return command[0]()
  36.             else:
  37.                 return command[1]
  38.     raise Error("could not locate runnable browser")
  39.  
  40. # Please note: the following definition hides a builtin function.
  41.  
  42. def open(url, new=0, autoraise=1):
  43.     get().open(url, new, autoraise)
  44.  
  45. def open_new(url):
  46.     get().open(url, 1)
  47.  
  48.  
  49. def _synthesize(browser):
  50.     """Attempt to synthesize a controller base on existing controllers.
  51.  
  52.     This is useful to create a controller when a user specifies a path to
  53.     an entry in the BROWSER environment variable -- we can copy a general
  54.     controller to operate using a specific installation of the desired
  55.     browser in this way.
  56.  
  57.     If we can't create a controller in this way, or if there is no
  58.     executable for the requested browser, return [None, None].
  59.  
  60.     """
  61.     if not os.path.exists(browser):
  62.         return [None, None]
  63.     name = os.path.basename(browser)
  64.     try:
  65.         command = _browsers[name.lower()]
  66.     except KeyError:
  67.         return [None, None]
  68.     # now attempt to clone to fit the new name:
  69.     controller = command[1]
  70.     if controller and name.lower() == controller.basename:
  71.         import copy
  72.         controller = copy.copy(controller)
  73.         controller.name = browser
  74.         controller.basename = os.path.basename(browser)
  75.         register(browser, None, controller)
  76.         return [None, controller]
  77.     return [None, None]
  78.  
  79.  
  80. def _iscommand(cmd):
  81.     """Return True if cmd can be found on the executable search path."""
  82.     path = os.environ.get("PATH")
  83.     if not path:
  84.         return False
  85.     for d in path.split(os.pathsep):
  86.         exe = os.path.join(d, cmd)
  87.         if os.path.isfile(exe):
  88.             return True
  89.     return False
  90.  
  91.  
  92. PROCESS_CREATION_DELAY = 4
  93.  
  94.  
  95. class GenericBrowser:
  96.     def __init__(self, cmd):
  97.         self.name, self.args = cmd.split(None, 1)
  98.         self.basename = os.path.basename(self.name)
  99.  
  100.     def open(self, url, new=0, autoraise=1):
  101.         assert "'" not in url
  102.         command = "%s %s" % (self.name, self.args)
  103.         os.system(command % url)
  104.  
  105.     def open_new(self, url):
  106.         self.open(url)
  107.  
  108.  
  109. class Netscape:
  110.     "Launcher class for Netscape browsers."
  111.     def __init__(self, name):
  112.         self.name = name
  113.         self.basename = os.path.basename(name)
  114.  
  115.     def _remote(self, action, autoraise):
  116.         raise_opt = ("-noraise", "-raise")[autoraise]
  117.         cmd = "%s %s -remote '%s' >/dev/null 2>&1" % (self.name,
  118.                                                       raise_opt,
  119.                                                       action)
  120.         rc = os.system(cmd)
  121.         if rc:
  122.             import time
  123.             os.system("%s &" % self.name)
  124.             time.sleep(PROCESS_CREATION_DELAY)
  125.             rc = os.system(cmd)
  126.         return not rc
  127.  
  128.     def open(self, url, new=0, autoraise=1):
  129.         if new:
  130.             self._remote("openURL(%s, new-window)"%url, autoraise)
  131.         else:
  132.             self._remote("openURL(%s)" % url, autoraise)
  133.  
  134.     def open_new(self, url):
  135.         self.open(url, 1)
  136.  
  137.  
  138. class Galeon:
  139.     """Launcher class for Galeon browsers."""
  140.     def __init__(self, name):
  141.         self.name = name
  142.         self.basename = os.path.basename(name)
  143.  
  144.     def _remote(self, action, autoraise):
  145.         raise_opt = ("--noraise", "")[autoraise]
  146.         cmd = "%s %s %s >/dev/null 2>&1" % (self.name, raise_opt, action)
  147.         rc = os.system(cmd)
  148.         if rc:
  149.             import time
  150.             os.system("%s >/dev/null 2>&1 &" % self.name)
  151.             time.sleep(PROCESS_CREATION_DELAY)
  152.             rc = os.system(cmd)
  153.         return not rc
  154.  
  155.     def open(self, url, new=0, autoraise=1):
  156.         if new:
  157.             self._remote("-w '%s'" % url, autoraise)
  158.         else:
  159.             self._remote("-n '%s'" % url, autoraise)
  160.  
  161.     def open_new(self, url):
  162.         self.open(url, 1)
  163.  
  164.  
  165. class Konqueror:
  166.     """Controller for the KDE File Manager (kfm, or Konqueror).
  167.  
  168.     See http://developer.kde.org/documentation/other/kfmclient.html
  169.     for more information on the Konqueror remote-control interface.
  170.  
  171.     """
  172.     def __init__(self):
  173.         if _iscommand("konqueror"):
  174.             self.name = self.basename = "konqueror"
  175.         else:
  176.             self.name = self.basename = "kfm"
  177.  
  178.     def _remote(self, action):
  179.         cmd = "kfmclient %s >/dev/null 2>&1" % action
  180.         rc = os.system(cmd)
  181.         if rc:
  182.             import time
  183.             if self.basename == "konqueror":
  184.                 os.system(self.name + " --silent &")
  185.             else:
  186.                 os.system(self.name + " -d &")
  187.             time.sleep(PROCESS_CREATION_DELAY)
  188.             rc = os.system(cmd)
  189.         return not rc
  190.  
  191.     def open(self, url, new=1, autoraise=1):
  192.         # XXX Currently I know no way to prevent KFM from
  193.         # opening a new win.
  194.         assert "'" not in url
  195.         self._remote("openURL '%s'" % url)
  196.  
  197.     open_new = open
  198.  
  199.  
  200. class Grail:
  201.     # There should be a way to maintain a connection to Grail, but the
  202.     # Grail remote control protocol doesn't really allow that at this
  203.     # point.  It probably neverwill!
  204.     def _find_grail_rc(self):
  205.         import glob
  206.         import pwd
  207.         import socket
  208.         import tempfile
  209.         tempdir = os.path.join(tempfile.gettempdir(),
  210.                                ".grail-unix")
  211.         user = pwd.getpwuid(os.getuid())[0]
  212.         filename = os.path.join(tempdir, user + "-*")
  213.         maybes = glob.glob(filename)
  214.         if not maybes:
  215.             return None
  216.         s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
  217.         for fn in maybes:
  218.             # need to PING each one until we find one that's live
  219.             try:
  220.                 s.connect(fn)
  221.             except socket.error:
  222.                 # no good; attempt to clean it out, but don't fail:
  223.                 try:
  224.                     os.unlink(fn)
  225.                 except IOError:
  226.                     pass
  227.             else:
  228.                 return s
  229.  
  230.     def _remote(self, action):
  231.         s = self._find_grail_rc()
  232.         if not s:
  233.             return 0
  234.         s.send(action)
  235.         s.close()
  236.         return 1
  237.  
  238.     def open(self, url, new=0, autoraise=1):
  239.         if new:
  240.             self._remote("LOADNEW " + url)
  241.         else:
  242.             self._remote("LOAD " + url)
  243.  
  244.     def open_new(self, url):
  245.         self.open(url, 1)
  246.  
  247.  
  248. class WindowsDefault:
  249.     def open(self, url, new=0, autoraise=1):
  250.         os.startfile(url)
  251.  
  252.     def open_new(self, url):
  253.         self.open(url)
  254.  
  255. #
  256. # Platform support for Unix
  257. #
  258.  
  259. # This is the right test because all these Unix browsers require either
  260. # a console terminal of an X display to run.  Note that we cannot split
  261. # the TERM and DISPLAY cases, because we might be running Python from inside
  262. # an xterm.
  263. if os.environ.get("TERM") or os.environ.get("DISPLAY"):
  264.     _tryorder = ["links", "lynx", "w3m"]
  265.  
  266.     # Easy cases first -- register console browsers if we have them.
  267.     if os.environ.get("TERM"):
  268.         # The Links browser <http://artax.karlin.mff.cuni.cz/~mikulas/links/>
  269.         if _iscommand("links"):
  270.             register("links", None, GenericBrowser("links '%s'"))
  271.         # The Lynx browser <http://lynx.browser.org/>
  272.         if _iscommand("lynx"):
  273.             register("lynx", None, GenericBrowser("lynx '%s'"))
  274.         # The w3m browser <http://ei5nazha.yz.yamagata-u.ac.jp/~aito/w3m/eng/>
  275.         if _iscommand("w3m"):
  276.             register("w3m", None, GenericBrowser("w3m '%s'"))
  277.  
  278.     # X browsers have more in the way of options
  279.     if os.environ.get("DISPLAY"):
  280.         _tryorder = ["galeon", "skipstone", "mozilla", "netscape",
  281.                      "kfm", "grail"] + _tryorder
  282.  
  283.         # First, the Netscape series
  284.         if _iscommand("mozilla"):
  285.             register("mozilla", None, Netscape("mozilla"))
  286.         if _iscommand("netscape"):
  287.             register("netscape", None, Netscape("netscape"))
  288.  
  289.         # Next, Mosaic -- old but still in use.
  290.         if _iscommand("mosaic"):
  291.             register("mosaic", None, GenericBrowser(
  292.                 "mosaic '%s' >/dev/null &"))
  293.  
  294.         # Gnome's Galeon
  295.         if _iscommand("galeon"):
  296.             register("galeon", None, Galeon("galeon"))
  297.  
  298.         # Skipstone, another Gtk/Mozilla based browser
  299.         if _iscommand("skipstone"):
  300.             register("skipstone", None, GenericBrowser(
  301.                 "skipstone '%s' >/dev/null &"))
  302.  
  303.         # Konqueror/kfm, the KDE browser.
  304.         if _iscommand("kfm") or _iscommand("konqueror"):
  305.             register("kfm", Konqueror, Konqueror())
  306.  
  307.         # Grail, the Python browser.
  308.         if _iscommand("grail"):
  309.             register("grail", Grail, None)
  310.  
  311.  
  312. class InternetConfig:
  313.     def open(self, url, new=0, autoraise=1):
  314.         ic.launchurl(url)
  315.  
  316.     def open_new(self, url):
  317.         self.open(url)
  318.  
  319.  
  320. #
  321. # Platform support for Windows
  322. #
  323.  
  324. if sys.platform[:3] == "win":
  325.     _tryorder = ["netscape", "windows-default"]
  326.     register("windows-default", WindowsDefault)
  327.  
  328. #
  329. # Platform support for MacOS
  330. #
  331.  
  332. try:
  333.     import ic
  334. except ImportError:
  335.     pass
  336. else:
  337.     # internet-config is the only supported controller on MacOS,
  338.     # so don't mess with the default!
  339.     _tryorder = ["internet-config"]
  340.     register("internet-config", InternetConfig)
  341.  
  342. #
  343. # Platform support for OS/2
  344. #
  345.  
  346. if sys.platform[:3] == "os2" and _iscommand("netscape.exe"):
  347.     _tryorder = ["os2netscape"]
  348.     register("os2netscape", None,
  349.              GenericBrowser("start netscape.exe %s"))
  350.  
  351. # OK, now that we know what the default preference orders for each
  352. # platform are, allow user to override them with the BROWSER variable.
  353. #
  354. if "BROWSER" in os.environ:
  355.     # It's the user's responsibility to register handlers for any unknown
  356.     # browser referenced by this value, before calling open().
  357.     _tryorder = os.environ["BROWSER"].split(os.pathsep)
  358.  
  359. for cmd in _tryorder:
  360.     if not cmd.lower() in _browsers:
  361.         if _iscommand(cmd.lower()):
  362.             register(cmd.lower(), None, GenericBrowser(
  363.                 "%s '%%s'" % cmd.lower()))
  364. cmd = None # to make del work if _tryorder was empty
  365. del cmd
  366.  
  367. _tryorder = filter(lambda x: x.lower() in _browsers
  368.                    or x.find("%s") > -1, _tryorder)
  369. # what to do if _tryorder is now empty?
  370.