* international/titdic-cnv.el (dos-8+3-filename):
[bpt/emacs.git] / lisp / net / browse-url.el
index b3276ef..3685c8a 100644 (file)
@@ -12,7 +12,7 @@
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; browse-url-cci                     XMosaic     2.5
 ;; browse-url-w3                      w3          0
 ;; browse-url-w3-gnudoit              w3 remotely
-;; browse-url-iximosaic               IXI Mosaic  ?
-;; browse-url-lynx-*                 Lynx           0
-;; browse-url-grail                   Grail       0.3b1
-;; browse-url-mmm                     MMM         ?
+;; browse-url-text-*                 Any text browser     0
 ;; browse-url-generic                 arbitrary
 ;; browse-url-default-windows-browser MS-Windows browser
 ;; browse-url-default-macosx-browser  Mac OS X browser
 ;; browse-url-gnome-moz               GNOME interface to Mozilla
 ;; browse-url-kde                     KDE konqueror (kfm)
+;; browse-url-elinks                  Elinks      Don't know (tried with 0.12.GIT)
 
 ;; [A version of the Netscape browser is now free software
 ;; <URL:http://www.mozilla.org/>, albeit not GPLed, so it is
@@ -71,7 +69,7 @@
 ;; control but which window DO you want to control and how do you
 ;; discover its id?
 
-;; William M. Perry's excellent "w3" WWW browser for
+;; William M.  Perry's excellent "w3" WWW browser for
 ;; Emacs <URL:ftp://cs.indiana.edu/pub/elisp/w3/>
 ;; has a function w3-follow-url-at-point, but that
 ;; doesn't let you edit the URL like browse-url.
 ;; Emacs process is available from
 ;; <URL:ftp://ftp.splode.com/pub/users/friedman/packages/>.
 
-;; Grail is the freely available WWW browser implemented in Python, a
-;; cool object-oriented freely available interpreted language.  Grail
-;; 0.3b1 was the first version to have remote control as distributed.
-;; For more information on Grail see
-;; <URL:http://grail.cnri.reston.va.us/> and for more information on
-;; Python see <url:http://www.python.org/>.  Grail support in
-;; browse-url.el written by Barry Warsaw <bwarsaw@python.org>.
-
 ;; Lynx is now distributed by the FSF.  See also
 ;; <URL:http://lynx.browser.org/>.
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Variables
 
-(eval-when-compile (require 'thingatpt)
+(eval-when-compile (require 'cl)
+                  (require 'thingatpt)
                    (require 'term)
                   (require 'dired)
                    (require 'executable)
     'browse-url-default-windows-browser)
    ((memq system-type '(darwin)) 'browse-url-default-macosx-browser)
    (t 'browse-url-default-browser))
-  "*Function to display the current buffer in a WWW browser.
+  "Function to display the current buffer in a WWW browser.
 This is used by the `browse-url-at-point', `browse-url-at-mouse', and
 `browse-url-of-file' commands.
 
@@ -255,14 +246,12 @@ regexp should probably be \".\" to specify a default browser."
          (function-item :tag "Netscape" :value  browse-url-netscape)
          (function-item :tag "Mosaic" :value  browse-url-mosaic)
          (function-item :tag "Mosaic using CCI" :value  browse-url-cci)
-         (function-item :tag "IXI Mosaic" :value  browse-url-iximosaic)
-         (function-item :tag "Lynx in an xterm window"
-                        :value browse-url-lynx-xterm)
-         (function-item :tag "Lynx in an Emacs window"
-                        :value browse-url-lynx-emacs)
-         (function-item :tag "Grail" :value  browse-url-grail)
-         (function-item :tag "MMM" :value  browse-url-mmm)
+         (function-item :tag "Text browser in an xterm window"
+                        :value browse-url-text-xterm)
+         (function-item :tag "Text browser in an Emacs window"
+                        :value browse-url-text-emacs)
          (function-item :tag "KDE" :value browse-url-kde)
+         (function-item :tag "Elinks" :value browse-url-elinks)
          (function-item :tag "Specified by `Browse Url Generic Program'"
                         :value browse-url-generic)
          (function-item :tag "Default Windows browser"
@@ -281,7 +270,7 @@ regexp should probably be \".\" to specify a default browser."
 
 (defcustom browse-url-netscape-program "netscape"
   ;; Info about netscape-remote from Karl Berry.
-  "*The name by which to invoke Netscape.
+  "The name by which to invoke Netscape.
 
 The free program `netscape-remote' from
 <URL:http://home.netscape.com/newsref/std/remote.c> is said to start
@@ -292,34 +281,34 @@ system, given vroot.h from the same directory, with cc flags
   :group 'browse-url)
 
 (defcustom browse-url-netscape-arguments nil
-  "*A list of strings to pass to Netscape as arguments."
+  "A list of strings to pass to Netscape as arguments."
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
 (defcustom browse-url-netscape-startup-arguments browse-url-netscape-arguments
-  "*A list of strings to pass to Netscape when it starts up.
+  "A list of strings to pass to Netscape when it starts up.
 Defaults to the value of `browse-url-netscape-arguments' at the time
 `browse-url' is loaded."
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
 (defcustom browse-url-browser-display nil
-  "*The X display for running the browser, if not same as Emacs'."
+  "The X display for running the browser, if not same as Emacs'."
   :type '(choice string (const :tag "Default" nil))
   :group 'browse-url)
 
 (defcustom browse-url-mozilla-program "mozilla"
-  "*The name by which to invoke Mozilla."
+  "The name by which to invoke Mozilla."
   :type 'string
   :group 'browse-url)
 
 (defcustom browse-url-mozilla-arguments nil
-  "*A list of strings to pass to Mozilla as arguments."
+  "A list of strings to pass to Mozilla as arguments."
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
 (defcustom browse-url-mozilla-startup-arguments browse-url-mozilla-arguments
-  "*A list of strings to pass to Mozilla when it starts up.
+  "A list of strings to pass to Mozilla when it starts up.
 Defaults to the value of `browse-url-mozilla-arguments' at the time
 `browse-url' is loaded."
   :type '(repeat (string :tag "Argument"))
@@ -327,17 +316,17 @@ Defaults to the value of `browse-url-mozilla-arguments' at the time
 
 ;;;###autoload
 (defcustom browse-url-firefox-program "firefox"
-  "*The name by which to invoke Firefox."
+  "The name by which to invoke Firefox."
   :type 'string
   :group 'browse-url)
 
 (defcustom browse-url-firefox-arguments nil
-  "*A list of strings to pass to Firefox as arguments."
+  "A list of strings to pass to Firefox as arguments."
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
 (defcustom browse-url-firefox-startup-arguments browse-url-firefox-arguments
-  "*A list of strings to pass to Firefox when it starts up.
+  "A list of strings to pass to Firefox when it starts up.
 Defaults to the value of `browse-url-firefox-arguments' at the time
 `browse-url' is loaded."
   :type '(repeat (string :tag "Argument"))
@@ -345,34 +334,34 @@ Defaults to the value of `browse-url-firefox-arguments' at the time
 
 ;;;###autoload
 (defcustom browse-url-galeon-program "galeon"
-  "*The name by which to invoke Galeon."
+  "The name by which to invoke Galeon."
   :type 'string
   :group 'browse-url)
 
 (defcustom browse-url-galeon-arguments nil
-  "*A list of strings to pass to Galeon as arguments."
+  "A list of strings to pass to Galeon as arguments."
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
 (defcustom browse-url-galeon-startup-arguments browse-url-galeon-arguments
-  "*A list of strings to pass to Galeon when it starts up.
+  "A list of strings to pass to Galeon when it starts up.
 Defaults to the value of `browse-url-galeon-arguments' at the time
 `browse-url' is loaded."
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
 (defcustom browse-url-epiphany-program "epiphany"
-  "*The name by which to invoke Epiphany."
+  "The name by which to invoke Epiphany."
   :type 'string
   :group 'browse-url)
 
 (defcustom browse-url-epiphany-arguments nil
-  "*A list of strings to pass to Epiphany as arguments."
+  "A list of strings to pass to Epiphany as arguments."
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
 (defcustom browse-url-epiphany-startup-arguments browse-url-epiphany-arguments
-  "*A list of strings to pass to Epiphany when it starts up.
+  "A list of strings to pass to Epiphany when it starts up.
 Defaults to the value of `browse-url-epiphany-arguments' at the time
 `browse-url' is loaded."
   :type '(repeat (string :tag "Argument"))
@@ -382,20 +371,20 @@ Defaults to the value of `browse-url-epiphany-arguments' at the time
 (defvar browse-url-gnome-moz-program "gnome-moz-remote")
 
 (defcustom browse-url-gnome-moz-arguments '()
-  "*A list of strings passed to the GNOME mozilla viewer as arguments."
+  "A list of strings passed to the GNOME mozilla viewer as arguments."
   :version "21.1"
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
 (defcustom browse-url-mozilla-new-window-is-tab nil
-  "*Whether to open up new windows in a tab or a new window.
+  "Whether to open up new windows in a tab or a new window.
 If non-nil, then open the URL in a new tab rather than a new window if
 `browse-url-mozilla' is asked to open it in a new window."
   :type 'boolean
   :group 'browse-url)
 
 (defcustom browse-url-firefox-new-window-is-tab nil
-  "*Whether to open up new windows in a tab or a new window.
+  "Whether to open up new windows in a tab or a new window.
 If non-nil, then open the URL in a new tab rather than a new window if
 `browse-url-firefox' is asked to open it in a new window.
 
@@ -405,21 +394,21 @@ functionality is not available there."
   :group 'browse-url)
 
 (defcustom browse-url-galeon-new-window-is-tab nil
-  "*Whether to open up new windows in a tab or a new window.
+  "Whether to open up new windows in a tab or a new window.
 If non-nil, then open the URL in a new tab rather than a new window if
 `browse-url-galeon' is asked to open it in a new window."
   :type 'boolean
   :group 'browse-url)
 
 (defcustom browse-url-epiphany-new-window-is-tab nil
-  "*Whether to open up new windows in a tab or a new window.
+  "Whether to open up new windows in a tab or a new window.
 If non-nil, then open the URL in a new tab rather than a new window if
 `browse-url-epiphany' is asked to open it in a new window."
   :type 'boolean
   :group 'browse-url)
 
 (defcustom browse-url-netscape-new-window-is-tab nil
-  "*Whether to open up new windows in a tab or a new window.
+  "Whether to open up new windows in a tab or a new window.
 If non-nil, then open the URL in a new tab rather than a new
 window if `browse-url-netscape' is asked to open it in a new
 window."
@@ -427,7 +416,7 @@ window."
   :group 'browse-url)
 
 (defcustom browse-url-new-window-flag nil
-  "*If non-nil, always open a new browser window with appropriate browsers.
+  "Non-nil means always open a new browser window with appropriate browsers.
 Passing an interactive argument to \\[browse-url], or specific browser
 commands reverses the effect of this variable.  Requires Netscape version
 1.1N or later or XMosaic version 2.5 or later if using those browsers."
@@ -435,33 +424,32 @@ commands reverses the effect of this variable.  Requires Netscape version
   :group 'browse-url)
 
 (defcustom browse-url-mosaic-program "xmosaic"
-  "*The name by which to invoke Mosaic (or mMosaic)."
+  "The name by which to invoke Mosaic (or mMosaic)."
   :type 'string
   :version "20.3"
   :group 'browse-url)
 
 (defcustom browse-url-mosaic-arguments nil
-  "*A list of strings to pass to Mosaic as arguments."
+  "A list of strings to pass to Mosaic as arguments."
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
 (defcustom browse-url-mosaic-pidfile "~/.mosaicpid"
-  "*The name of the pidfile created by Mosaic."
+  "The name of the pidfile created by Mosaic."
   :type 'string
   :group 'browse-url)
 
 (defcustom browse-url-filename-alist
-  (\`                                  ; Backquote syntax won't work.
-   (("^/\\(ftp@\\|anonymous@\\)?\\([^:]+\\):/*" . "ftp://\\2/")
+  `(("^/\\(ftp@\\|anonymous@\\)?\\([^:]+\\):/*" . "ftp://\\2/")
     ;; The above loses the username to avoid the browser prompting for
     ;; it in anonymous cases.  If it's not anonymous the next regexp
     ;; applies.
     ("^/\\([^:@]+@\\)?\\([^:]+\\):/*" . "ftp://\\1\\2/")
-    (,@ (if (memq system-type '(windows-nt ms-dos cygwin))
-           '(("^\\([a-zA-Z]:\\)[\\/]" . "file:\\1/")
-              ("^[\\/][\\/]+" . "file://"))))
-    ("^/+" . "file:/")))
-  "*An alist of (REGEXP . STRING) pairs used by `browse-url-of-file'.
+    ,@(if (memq system-type '(windows-nt ms-dos cygwin))
+          '(("^\\([a-zA-Z]:\\)[\\/]" . "file:\\1/")
+            ("^[\\/][\\/]+" . "file://")))
+    ("^/+" . "file:/"))
+  "An alist of (REGEXP . STRING) pairs used by `browse-url-of-file'.
 Any substring of a filename matching one of the REGEXPs is replaced by
 the corresponding STRING using `replace-match', not treating STRING
 literally.  All pairs are applied in the order given.  The default
@@ -476,8 +464,7 @@ address to an HTTP URL:
             \"http://www.acme.co.uk/\")
             (\"^/\\(ftp@\\|anonymous@\\)?\\([^:]+\\):/*\" . \"ftp://\\2/\")
             (\"^/\\([^:@]+@\\)?\\([^:]+\\):/*\" . \"ftp://\\1\\2/\")
-           (\"^/+\" . \"file:/\")))
-"
+           (\"^/+\" . \"file:/\")))"
   :type '(repeat (cons :format "%v"
                        (regexp :tag "Regexp")
                        (string :tag "Replacement")))
@@ -485,13 +472,13 @@ address to an HTTP URL:
   :group 'browse-url)
 
 (defcustom browse-url-save-file nil
-  "*If non-nil, save the buffer before displaying its file.
+  "If non-nil, save the buffer before displaying its file.
 Used by the `browse-url-of-file' command."
   :type 'boolean
   :group 'browse-url)
 
 (defcustom browse-url-of-file-hook nil
-  "*Run after `browse-url-of-file' has asked a browser to load a file.
+  "Run after `browse-url-of-file' has asked a browser to load a file.
 
 Set this to `browse-url-netscape-reload' to force Netscape to load the
 file rather than displaying a cached copy."
@@ -500,14 +487,14 @@ file rather than displaying a cached copy."
   :group 'browse-url)
 
 (defcustom browse-url-CCI-port 3003
-  "*Port to access XMosaic via CCI.
+  "Port to access XMosaic via CCI.
 This can be any number between 1024 and 65535 but must correspond to
 the value set in the browser."
   :type 'integer
   :group 'browse-url)
 
 (defcustom browse-url-CCI-host "localhost"
-  "*Host to access XMosaic via CCI.
+  "Host to access XMosaic via CCI.
 This should be the host name of the machine running XMosaic with CCI
 enabled.  The port number should be set in `browse-url-CCI-port'."
   :type 'string
@@ -515,102 +502,137 @@ enabled.  The port number should be set in `browse-url-CCI-port'."
 
 (defvar browse-url-temp-file-name nil)
 (make-variable-buffer-local 'browse-url-temp-file-name)
-
+  
 (defcustom browse-url-xterm-program "xterm"
-  "*The name of the terminal emulator used by `browse-url-lynx-xterm'.
+  "The name of the terminal emulator used by `browse-url-text-xterm'.
 This might, for instance, be a separate color version of xterm."
   :type 'string
   :group 'browse-url)
 
 (defcustom browse-url-xterm-args nil
-  "*A list of strings defining options for `browse-url-xterm-program'.
+  "A list of strings defining options for `browse-url-xterm-program'.
 These might set its size, for instance."
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
-(defcustom browse-url-lynx-emacs-args (and (not window-system)
-                                           '("-show_cursor"))
-  "*A list of strings defining options for Lynx in an Emacs buffer.
-
-The default is none in a window system, otherwise `-show_cursor' to
-indicate the position of the current link in the absence of
-highlighting, assuming the normal default for showing the cursor."
-  :type '(repeat (string :tag "Argument"))
-  :version "20.3"
-  :group 'browse-url)
-
 (defcustom browse-url-gnudoit-program "gnudoit"
-  "*The name of the `gnudoit' program used by `browse-url-w3-gnudoit'."
+  "The name of the `gnudoit' program used by `browse-url-w3-gnudoit'."
   :type 'string
   :group 'browse-url)
 
 (defcustom browse-url-gnudoit-args '("-q")
-  "*A list of strings defining options for `browse-url-gnudoit-program'.
+  "A list of strings defining options for `browse-url-gnudoit-program'.
 These might set the port, for instance."
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
 (defcustom browse-url-generic-program nil
-  "*The name of the browser program used by `browse-url-generic'."
+  "The name of the browser program used by `browse-url-generic'."
   :type '(choice string (const :tag "None" nil))
   :group 'browse-url)
 
 (defcustom browse-url-generic-args nil
-  "*A list of strings defining options for `browse-url-generic-program'."
+  "A list of strings defining options for `browse-url-generic-program'."
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
 (defcustom browse-url-temp-dir temporary-file-directory
-  "*The name of a directory for browse-url's temporary files.
+  "The name of a directory for browse-url's temporary files.
 Such files are generated by functions like `browse-url-of-region'.
 You might want to set this to somewhere with restricted read permissions
 for privacy's sake."
   :type 'string
   :group 'browse-url)
 
-(defcustom browse-url-netscape-version
-  3
-  "*The version of Netscape you are using.
+(defcustom browse-url-netscape-version 3
+  "The version of Netscape you are using.
 This affects how URL reloading is done; the mechanism changed
 incompatibly at version 4."
   :type 'number
   :group 'browse-url)
 
-(defcustom browse-url-lynx-input-field 'avoid
-  "*Action on selecting an existing Lynx buffer at an input field.
-What to do when sending a new URL to an existing Lynx buffer in Emacs
-if the Lynx cursor is on an input field (in which case the `g' command
+(defcustom browse-url-text-browser "lynx"
+  "The name of the text browser to invoke."
+  :type 'string
+  :group 'browse-url
+  :version "23.1")
+
+(defcustom browse-url-text-emacs-args (and (not window-system)
+                                          '("-show_cursor"))
+  "A list of strings defining options for a text browser in an Emacs buffer.
+
+The default is none in a window system, otherwise `-show_cursor' to
+indicate the position of the current link in the absence of
+highlighting, assuming the normal default for showing the cursor."
+  :type '(repeat (string :tag "Argument"))
+  :version "23.1"
+  :group 'browse-url)
+
+(defcustom browse-url-text-input-field 'avoid
+  "Action on selecting an existing text browser buffer at an input field.
+What to do when sending a new URL to an existing text browser buffer in Emacs
+if the browser cursor is on an input field (in which case the `g' command
 would be entered as data).  Such fields are recognized by the
-underlines ____.  Allowed values: nil: disregard it, 'warn: warn the
-user and don't emit the URL, 'avoid: try to avoid the field by moving
+underlines ____.  Allowed values: nil: disregard it, `warn': warn the
+user and don't emit the URL, `avoid': try to avoid the field by moving
 down (this *won't* always work)."
   :type '(choice (const :tag "Move to try to avoid field" :value avoid)
                  (const :tag "Disregard" :value nil)
                  (const :tag "Warn, don't emit URL" :value warn))
-  :version "20.3"
+  :version "23.1"
   :group 'browse-url)
 
-(defcustom browse-url-lynx-input-attempts 10
-  "*How many times to try to move down from a series of lynx input fields."
+(defcustom browse-url-text-input-attempts 10
+  "How many times to try to move down from a series of text browser input fields."
   :type 'integer
+  :version "23.1"
   :group 'browse-url)
 
-(defcustom browse-url-lynx-input-delay 0.2
-  "*How many seconds to wait for lynx between moves down from an input field."
+(defcustom browse-url-text-input-delay 0.2
+  "Seconds to wait for a text browser between moves down from an input field."
   :type 'number
+  :version "23.1"
   :group 'browse-url)
 
 (defcustom browse-url-kde-program "kfmclient"
-  "*The name by which to invoke the KDE web browser."
+  "The name by which to invoke the KDE web browser."
   :type 'string
   :version "21.1"
   :group 'browse-url)
 
 (defcustom browse-url-kde-args '("openURL")
-  "*A list of strings defining options for `browse-url-kde-program'."
+  "A list of strings defining options for `browse-url-kde-program'."
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
+(defcustom browse-url-elinks-wrapper '("xterm" "-e")
+  "*Wrapper command prepended to the Elinks command-line."
+  :type '(repeat (string :tag "Wrapper"))
+  :group 'browse-url)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; URL encoding
+
+(defun browse-url-url-encode-chars (text chars)
+  "URL-encode the chars in TEXT that match CHARS.
+CHARS is a regexp-like character alternative (e.g., \"[,)$]\")."
+  (let ((encoded-text (copy-sequence text))
+       (s 0))
+    (while (setq s (string-match chars encoded-text s))
+      (setq encoded-text
+           (replace-match (format "%%%x"
+                                  (string-to-char (match-string 0 encoded-text)))
+                          t t encoded-text)
+           s (1+ s)))
+    encoded-text))
+
+(defun browse-url-encode-url (url)
+  "Escape annoying characters in URL.
+The annoying characters are those that can mislead a webbrowser
+regarding its parameter treatment.  For instance, `,' can
+be misleading because it could be used to separate URLs."
+  (browse-url-url-encode-chars url "[,)$]"))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; URL input
 
@@ -669,8 +691,7 @@ interactively.  Turn the filename into a URL with function
       (error "Current buffer has no file"))
   (let ((buf (get-file-buffer file)))
     (if buf
-       (save-excursion
-         (set-buffer buf)
+       (with-current-buffer buf
          (cond ((not (buffer-modified-p)))
                (browse-url-save-file (save-buffer))
                (t (message "%s modified since last save" file))))))
@@ -684,14 +705,7 @@ Use variable `browse-url-filename-alist' to map filenames to URLs."
                     (or file-name-coding-system
                         default-file-name-coding-system))))
     (if coding (setq file (encode-coding-string file coding))))
-  ;; URL-encode special chars, do % first
-  (let ((s 0))
-    (while (setq s (string-match "%" file s))
-      (setq file (replace-match "%25" t t file)
-           s (1+ s))))
-  (while (string-match "[*\"()',=;? ]" file)
-    (let ((enc (format "%%%x" (aref file (match-beginning 0)))))
-      (setq file (replace-match enc t t file))))
+  (setq file (browse-url-url-encode-chars file "[*\"()',=;?% ]"))
   (dolist (map browse-url-filename-alist)
     (when (and map (string-match (car map) file))
       (setq file (replace-match (cdr map) t nil file))))
@@ -811,6 +825,7 @@ to use."
 ;; --- Default MS-Windows browser ---
 
 (defvar dos-windows-version)
+(declare-function w32-shell-execute "w32fns.c")    ;; Defined in C.
 
 (defun browse-url-default-windows-browser (url &optional new-window)
   (interactive (browse-url-interactive-arg "URL: "))
@@ -860,24 +875,21 @@ When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'.
 
 The order attempted is gnome-moz-remote, Mozilla, Firefox,
-Galeon, Konqueror, Netscape, Mosaic, IXI Mosaic, Lynx in an
-xterm, MMM, and then W3."
+Galeon, Konqueror, Netscape, Mosaic, Lynx in an xterm, and then W3."
   (apply
-    (cond
-     ((executable-find browse-url-gnome-moz-program) 'browse-url-gnome-moz)
-     ((executable-find browse-url-mozilla-program) 'browse-url-mozilla)
-     ((executable-find browse-url-firefox-program) 'browse-url-firefox)
-     ((executable-find browse-url-galeon-program) 'browse-url-galeon)
-     ((executable-find browse-url-kde-program) 'browse-url-kde)
-     ((executable-find browse-url-netscape-program) 'browse-url-netscape)
-     ((executable-find browse-url-mosaic-program) 'browse-url-mosaic)
-     ((executable-find "tellw3b") 'browse-url-iximosaic)
-     ((executable-find browse-url-xterm-program) 'browse-url-lynx-xterm)
-     ((executable-find "mmm") 'browse-url-mmm)
-     ((locate-library "w3") 'browse-url-w3)
-     (t
-      (lambda (&ignore args) (error "No usable browser found"))))
-     url args))
+   (cond
+    ((executable-find browse-url-gnome-moz-program) 'browse-url-gnome-moz)
+    ((executable-find browse-url-mozilla-program) 'browse-url-mozilla)
+    ((executable-find browse-url-firefox-program) 'browse-url-firefox)
+    ((executable-find browse-url-galeon-program) 'browse-url-galeon)
+    ((executable-find browse-url-kde-program) 'browse-url-kde)
+    ((executable-find browse-url-netscape-program) 'browse-url-netscape)
+    ((executable-find browse-url-mosaic-program) 'browse-url-mosaic)
+    ((executable-find browse-url-xterm-program) 'browse-url-text-xterm)
+    ((locate-library "w3") 'browse-url-w3)
+    (t
+     (lambda (&ignore args) (error "No usable browser found"))))
+   url args))
 
 ;;;###autoload
 (defun browse-url-netscape (url &optional new-window)
@@ -897,11 +909,7 @@ is loaded in a new tab in an existing window instead.
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'."
   (interactive (browse-url-interactive-arg "URL: "))
-  ;; URL encode any `confusing' characters in the URL.  This needs to
-  ;; include at least commas; presumably also close parens and dollars.
-  (while (string-match "[,)$]" url)
-    (setq url (replace-match
-              (format "%%%x" (string-to-char (match-string 0 url))) t t url)))
+  (setq url (browse-url-encode-url url))
   (let* ((process-environment (browse-url-process-environment))
         (process
          (apply 'start-process
@@ -943,7 +951,7 @@ How depends on `browse-url-netscape-version'."
   ;; <peter.kruse@psychologie.uni-regensburg.de>.
   (browse-url-netscape-send (if (>= browse-url-netscape-version 4)
                                "xfeDoCommand(reload)"
-                               "reload")))
+                             "reload")))
 
 (defun browse-url-netscape-send (command)
   "Send a remote control command to Netscape."
@@ -971,11 +979,7 @@ new tab in an existing window instead.
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'."
   (interactive (browse-url-interactive-arg "URL: "))
-  ;; URL encode any `confusing' characters in the URL.  This needs to
-  ;; include at least commas; presumably also close parens and dollars.
-  (while (string-match "[,)$]" url)
-    (setq url (replace-match
-              (format "%%%x" (string-to-char (match-string 0 url))) t t url)))
+  (setq url (browse-url-encode-url url))
   (let* ((process-environment (browse-url-process-environment))
          (process
          (apply 'start-process
@@ -1033,11 +1037,7 @@ command line parameter.  Therefore, the
 are ignored as well.  Firefox on Windows will always open the requested
 URL in a new window."
   (interactive (browse-url-interactive-arg "URL: "))
-  ;; URL encode any `confusing' characters in the URL.  This needs to
-  ;; include at least commas; presumably also close parens.
-  (while (string-match "[,)]" url)
-    (setq url (replace-match
-              (format "%%%x" (string-to-char (match-string 0 url))) t t url)))
+  (setq url (browse-url-encode-url url))
   (let* ((process-environment (browse-url-process-environment))
         (process
          (apply 'start-process
@@ -1089,11 +1089,7 @@ new tab in an existing window instead.
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'."
   (interactive (browse-url-interactive-arg "URL: "))
-  ;; URL encode any `confusing' characters in the URL.  This needs to
-  ;; include at least commas; presumably also close parens and dollars.
-  (while (string-match "[,)$]" url)
-    (setq url (replace-match
-              (format "%%%x" (string-to-char (match-string 0 url))) t t url)))
+  (setq url (browse-url-encode-url url))
   (let* ((process-environment (browse-url-process-environment))
          (process (apply 'start-process
                         (concat "galeon " url)
@@ -1138,11 +1134,7 @@ new tab in an existing window instead.
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'."
   (interactive (browse-url-interactive-arg "URL: "))
-  ;; URL encode any `confusing' characters in the URL.  This needs to
-  ;; include at least commas; presumably also close parens and dollars.
-  (while (string-match "[,)$]" url)
-    (setq url (replace-match
-              (format "%%%x" (string-to-char (match-string 0 url))) t t url)))
+  (setq url (browse-url-encode-url url))
   (let* ((process-environment (browse-url-process-environment))
          (process (apply 'start-process
                         (concat "epiphany " url)
@@ -1170,6 +1162,22 @@ used instead of `browse-url-new-window-flag'."
               browse-url-epiphany-program
               (append browse-url-epiphany-startup-arguments (list url))))))
 
+(defvar url-handler-regexp)
+
+;;;###autoload
+(defun browse-url-emacs (url &optional new-window)
+  "Ask Emacs to load URL into a buffer and show it in another window."
+  (interactive (browse-url-interactive-arg "URL: "))
+  (require 'url-handlers)
+  (let ((file-name-handler-alist
+         (cons (cons url-handler-regexp 'url-file-handler)
+               file-name-handler-alist)))
+    ;; Ignore `new-window': with all other browsers the URL is always shown
+    ;; in another window than the current Emacs one since it's shown in
+    ;; another application's window.
+    ;; (if new-window (find-file-other-window url) (find-file url))
+    (find-file-other-window url)))
+
 ;;;###autoload
 (defun browse-url-gnome-moz (url &optional new-window)
   "Ask Mozilla/Netscape to load URL via the GNOME program `gnome-moz-remote'.
@@ -1190,7 +1198,7 @@ used instead of `browse-url-new-window-flag'."
         (append
          browse-url-gnome-moz-arguments
          (if (browse-url-maybe-new-window new-window)
-           '("--newwin"))
+             '("--newwin"))
          (list "--raise" url))))
 
 ;; --- Mosaic ---
@@ -1243,29 +1251,6 @@ used instead of `browse-url-new-window-flag'."
             (append browse-url-mosaic-arguments (list url)))
       (message "Starting %s...done" browse-url-mosaic-program))))
 
-;; --- Grail ---
-
-(defvar browse-url-grail
-  (concat (or (getenv "GRAILDIR") "~/.grail") "/user/rcgrail.py")
-  "Location of Grail remote control client script `rcgrail.py'.
-Typically found in $GRAILDIR/rcgrail.py, or ~/.grail/user/rcgrail.py.")
-
-;;;###autoload
-(defun browse-url-grail (url &optional new-window)
-  "Ask the Grail WWW browser to load URL.
-Default to the URL around or before point.  Runs the program in the
-variable `browse-url-grail'."
-  (interactive (browse-url-interactive-arg "Grail URL: "))
-  (message "Sending URL to Grail...")
-  (save-excursion
-    (set-buffer (get-buffer-create " *Shell Command Output*"))
-    (erase-buffer)
-    ;; don't worry about this failing.
-    (if (browse-url-maybe-new-window new-window)
-       (call-process browse-url-grail nil 0 nil "-b" url)
-      (call-process browse-url-grail nil 0 nil url))
-    (message "Sending URL to Grail... done")))
-
 ;; --- Mosaic using CCI ---
 
 ;;;###autoload
@@ -1297,17 +1282,6 @@ used instead of `browse-url-new-window-flag'."
   (process-send-string "browse-url" "disconnect\r\n")
   (delete-process "browse-url"))
 
-;; --- IXI Mosaic ---
-
-;;;###autoload
-(defun browse-url-iximosaic (url &optional new-window)
-  ;; new-window ignored
-  "Ask the IXIMosaic WWW browser to load URL.
-Default to the URL around or before point."
-  (interactive (browse-url-interactive-arg "IXI Mosaic URL: "))
-  (start-process "tellw3b" nil "tellw3b"
-                "-service WWW_BROWSER ixi_showurl " url))
-
 ;; --- W3 ---
 
 ;;;###autoload
@@ -1322,7 +1296,7 @@ prefix argument reverses the effect of `browse-url-new-window-flag'.
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'."
   (interactive (browse-url-interactive-arg "W3 URL: "))
-  (require 'w3)                                ; w3-fetch-other-window not autoloaded
+  (require 'w3)                        ; w3-fetch-other-window not autoloaded
   (if (browse-url-maybe-new-window new-window)
       (w3-fetch-other-window url)
     (w3-fetch url)))
@@ -1334,47 +1308,50 @@ used instead of `browse-url-new-window-flag'."
 The `browse-url-gnudoit-program' program is used with options given by
 `browse-url-gnudoit-args'.  Default to the URL around or before point."
   (interactive (browse-url-interactive-arg "W3 URL: "))
-    (apply 'start-process (concat "gnudoit:" url) nil
-          browse-url-gnudoit-program
-          (append browse-url-gnudoit-args
-                  (list (concat "(w3-fetch \"" url "\")")
-                        "(raise-frame)"))))
+  (apply 'start-process (concat "gnudoit:" url) nil
+        browse-url-gnudoit-program
+        (append browse-url-gnudoit-args
+                (list (concat "(w3-fetch \"" url "\")")
+                      "(raise-frame)"))))
 
 ;; --- Lynx in an xterm ---
 
 ;;;###autoload
-(defun browse-url-lynx-xterm (url &optional new-window)
+(defun browse-url-text-xterm (url &optional new-window)
   ;; new-window ignored
-  "Ask the Lynx WWW browser to load URL.
-Default to the URL around or before point.  A new Lynx process is run
+  "Ask a text browser to load URL.
+URL defaults to the URL around or before point. 
+This runs the text browser specified by `browse-url-text-browser'.
 in an Xterm window using the Xterm program named by `browse-url-xterm-program'
 with possible additional arguments `browse-url-xterm-args'."
-  (interactive (browse-url-interactive-arg "Lynx URL: "))
-  (apply #'start-process `(,(concat "lynx" url) nil ,browse-url-xterm-program
-             ,@browse-url-xterm-args "-e" "lynx"
-            ,url)))
+  (interactive (browse-url-interactive-arg "Text browser URL: "))
+  (apply #'start-process `(,(concat browse-url-text-browser url)
+                          nil ,browse-url-xterm-program
+                          ,@browse-url-xterm-args "-e" browse-url-text-browser
+                          ,url)))
 
 ;; --- Lynx in an Emacs "term" window ---
 
 ;;;###autoload
-(defun browse-url-lynx-emacs (url &optional new-buffer)
-  "Ask the Lynx WWW browser to load URL.
-Default to the URL around or before point.  With a prefix argument, run
-a new Lynx process in a new buffer.
+(defun browse-url-text-emacs (url &optional new-buffer)
+  "Ask a text browser to load URL.
+URL defaults to the URL around or before point. 
+This runs the text browser specified by `browse-url-text-browser'.
+With a prefix argument, it runs a new browser process in a new buffer.
 
 When called interactively, if variable `browse-url-new-window-flag' is
-non-nil, load the document in a new lynx in a new term window,
+non-nil, load the document in a new browser process in a new term window,
 otherwise use any existing one.  A non-nil interactive prefix argument
 reverses the effect of `browse-url-new-window-flag'.
 
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'."
-  (interactive (browse-url-interactive-arg "Lynx URL: "))
-  (let* ((system-uses-terminfo t)       ; Lynx uses terminfo
+  (interactive (browse-url-interactive-arg "Text browser URL: "))
+  (let* ((system-uses-terminfo t)     ; Lynx uses terminfo
         ;; (term-term-name "vt100") ; ??
-        (buf (get-buffer "*lynx*"))
+        (buf (get-buffer "*text browser*"))
         (proc (and buf (get-buffer-process buf)))
-        (n browse-url-lynx-input-attempts))
+        (n browse-url-text-input-attempts))
     (if (and (browse-url-maybe-new-window new-buffer) buf)
        ;; Rename away the OLD buffer. This isn't very polite, but
        ;; term insists on working in a buffer named *lynx* and would
@@ -1385,11 +1362,13 @@ used instead of `browse-url-new-window-flag'."
            (not buf)
            (not proc)
            (not (memq (process-status proc) '(run stop))))
-       ;; start a new lynx
+       ;; start a new text browser
        (progn
           (setq buf
                 (apply #'make-term
-                       `("lynx" "lynx" nil ,@browse-url-lynx-emacs-args
+                       `(,browse-url-text-browser
+                        ,browse-url-text-browser
+                        nil ,@browse-url-text-emacs-args
                         ,url)))
           (switch-to-buffer buf)
           (term-char-mode)
@@ -1401,44 +1380,25 @@ used instead of `browse-url-new-window-flag'."
              (if (not (memq (process-status process) '(run stop)))
                  (let ((buf (process-buffer process)))
                    (if buf (kill-buffer buf)))))))
-      ;; send the url to lynx in the old buffer
+      ;; Send the url to the text browser in the old buffer
       (let ((win (get-buffer-window buf t)))
        (if win
            (select-window win)
          (switch-to-buffer buf)))
       (if (eq (following-char) ?_)
-         (cond ((eq browse-url-lynx-input-field 'warn)
+         (cond ((eq browse-url-text-input-field 'warn)
                 (error "Please move out of the input field first"))
-               ((eq browse-url-lynx-input-field 'avoid)
+               ((eq browse-url-text-input-field 'avoid)
                 (while (and (eq (following-char) ?_) (> n 0))
-                  (term-send-down) ; down arrow
-                  (sit-for browse-url-lynx-input-delay))
+                  (term-send-down)     ; down arrow
+                  (sit-for browse-url-text-input-delay))
                 (if (eq (following-char) ?_)
                     (error "Cannot move out of the input field, sorry")))))
-      (term-send-string proc (concat "g" ; goto
+      (term-send-string proc (concat "g"    ; goto
                                     "\C-u" ; kill default url
                                     url
                                     "\r")))))
 
-;; --- MMM ---
-
-;;;###autoload
-(defun browse-url-mmm (url &optional new-window)
-  "Ask the MMM WWW browser to load URL.
-Default to the URL around or before point."
-  (interactive (browse-url-interactive-arg "MMM URL: "))
-  (message "Sending URL to MMM...")
-  (save-excursion
-    (set-buffer (get-buffer-create " *Shell Command Output*"))
-    (erase-buffer)
-    ;; mmm_remote just SEGVs if the file isn't there...
-    (if (or (file-exists-p (expand-file-name "~/.mmm_remote"))
-           ;; location in v 0.4:
-           (file-exists-p (expand-file-name "~/.mmm/remote")))
-       (call-process "mmm_remote" nil 0 nil url)
-      (call-process "mmm" nil 0 nil "-external" url))
-    (message "Sending URL to MMM... done")))
-
 ;; --- mailto ---
 
 (autoload 'rfc2368-parse-mailto-url "rfc2368")
@@ -1491,7 +1451,7 @@ browser is started up in a new process with possible additional arguments
 don't offer a form of remote control."
   (interactive (browse-url-interactive-arg "URL: "))
   (if (not browse-url-generic-program)
-    (error "No browser defined (`browse-url-generic-program')"))
+      (error "No browser defined (`browse-url-generic-program')"))
   (apply 'call-process browse-url-generic-program nil
         0 nil
         (append browse-url-generic-args (list url))))
@@ -1503,9 +1463,58 @@ Default to the URL around or before point."
   (interactive (browse-url-interactive-arg "KDE URL: "))
   (message "Sending URL to KDE...")
   (apply #'start-process (concat "KDE " url) nil browse-url-kde-program
-                        (append browse-url-kde-args (list url))))
+        (append browse-url-kde-args (list url))))
+
+(defun browse-url-elinks-new-window (url)
+  "Ask the Elinks WWW browser to load URL in a new window."
+  (let ((process-environment (browse-url-process-environment)))     
+    (apply #'start-process
+          (append (list (concat "elinks:" url)
+                        nil)
+                  browse-url-elinks-wrapper
+                  (list "elinks" url)))))
+
+;;;###autoload
+(defun browse-url-elinks (url &optional new-window)
+  "Ask the Elinks WWW browser to load URL.
+Default to the URL around the point.
+
+The document is loaded in a new tab of a running Elinks or, if
+none yet running, a newly started instance.
+
+The Elinks command will be prepended by the program+arguments
+from `browse-url-elinks-wrapper'."
+  (interactive (browse-url-interactive-arg "URL: "))
+  (setq url (browse-url-encode-url url))
+  (if new-window
+      (browse-url-elinks-new-window url)
+    (let ((process-environment (browse-url-process-environment))
+         (elinks-ping-process (start-process "elinks-ping" nil
+                                             "elinks" "-remote" "ping()")))
+      (set-process-sentinel elinks-ping-process
+                           `(lambda (process change)
+                              (browse-url-elinks-sentinel process ,url))))))
+
+(defun browse-url-elinks-sentinel (process url)
+  "Determines if Elinks is running or a new one has to be started."
+  (let ((exit-status (process-exit-status process)))
+    ;; Try to determine if an instance is running or if we have to
+    ;; create a new one.
+    (case exit-status
+         (5
+          ;; No instance, start a new one.
+          (browse-url-elinks-new-window url))
+         (0
+          ;; Found an instance, open URL in new tab.
+          (let ((process-environment (browse-url-process-environment)))
+            (start-process (concat "elinks:" url) nil
+                           "elinks" "-remote"
+                           (concat "openURL(\"" url "\",new-tab)"))))
+         (otherwise
+          (error "Unrecognized exit-code %d of process `elinks'"
+                 exit-status)))))
 
 (provide 'browse-url)
 
-;;; arch-tag: d2079573-5c06-4097-9598-f550fba19430
+;; arch-tag: d2079573-5c06-4097-9598-f550fba19430
 ;;; browse-url.el ends here