]> code.delx.au - gnu-emacs/blobdiff - lisp/net/browse-url.el
Merge from emacs--rel--22
[gnu-emacs] / lisp / net / browse-url.el
index b97eda6472b73c2d59095b5075ba758fdb3224ea..b3276ef9c409c257e5bfa90c925008fcab27702d 100644 (file)
@@ -1,7 +1,7 @@
 ;;; browse-url.el --- pass a URL to a WWW browser
 
-;; Copyright (C) 1995, 96, 97, 98, 99, 2000, 2001
-;;   Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+;;   2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 ;; Author: Denis Howe <dbh@doc.ic.ac.uk>
 ;; Maintainer: FSF
@@ -22,8 +22,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
@@ -38,6 +38,7 @@
 
 ;; Function                           Browser     Earliest version
 ;; browse-url-mozilla                 Mozilla     Don't know
+;; browse-url-firefox                 Firefox     Don't know (tried with 1.0.1)
 ;; browse-url-galeon                  Galeon      Don't know
 ;; browse-url-epiphany                Epiphany    Don't know
 ;; browse-url-netscape                Netscape    1.1b1
@@ -248,6 +249,7 @@ regexp should probably be \".\" to specify a default browser."
          (function-item :tag "W3 in another Emacs via `gnudoit'"
                         :value  browse-url-w3-gnudoit)
          (function-item :tag "Mozilla" :value  browse-url-mozilla)
+         (function-item :tag "Firefox" :value browse-url-firefox)
          (function-item :tag "Galeon" :value  browse-url-galeon)
          (function-item :tag "Epiphany" :value  browse-url-epiphany)
          (function-item :tag "Netscape" :value  browse-url-netscape)
@@ -323,6 +325,25 @@ Defaults to the value of `browse-url-mozilla-arguments' at the time
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
+;;;###autoload
+(defcustom browse-url-firefox-program "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."
+  :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.
+Defaults to the value of `browse-url-firefox-arguments' at the time
+`browse-url' is loaded."
+  :type '(repeat (string :tag "Argument"))
+  :group 'browse-url)
+
+;;;###autoload
 (defcustom browse-url-galeon-program "galeon"
   "*The name by which to invoke Galeon."
   :type 'string
@@ -357,6 +378,15 @@ Defaults to the value of `browse-url-epiphany-arguments' at the time
   :type '(repeat (string :tag "Argument"))
   :group 'browse-url)
 
+;; GNOME means of invoking either Mozilla or Netrape.
+(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."
+  :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.
 If non-nil, then open the URL in a new tab rather than a new window if
@@ -364,6 +394,16 @@ If non-nil, then open the URL in a new tab rather than a new window if
   :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.
+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.
+
+This option is currently ignored on MS-Windows, since the necessary
+functionality is not available there."
+  :type 'boolean
+  :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.
 If non-nil, then open the URL in a new tab rather than a new window if
@@ -378,6 +418,14 @@ If non-nil, then open the URL in a new tab rather than a new window if
   :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.
+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."
+  :type 'boolean
+  :group 'browse-url)
+
 (defcustom browse-url-new-window-flag nil
   "*If non-nil, always open a new browser window with appropriate browsers.
 Passing an interactive argument to \\[browse-url], or specific browser
@@ -470,7 +518,7 @@ enabled.  The port number should be set in `browse-url-CCI-port'."
 
 (defcustom browse-url-xterm-program "xterm"
   "*The name of the terminal emulator used by `browse-url-lynx-xterm'.
-This might, for instance, be a separate colour version of xterm."
+This might, for instance, be a separate color version of xterm."
   :type 'string
   :group 'browse-url)
 
@@ -566,6 +614,7 @@ down (this *won't* always work)."
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; URL input
 
+;;;###autoload
 (defun browse-url-url-at-point ()
   (let ((url (thing-at-point 'url)))
     (set-text-properties 0 (length url) nil url)
@@ -577,20 +626,30 @@ down (this *won't* always work)."
 
 (defun browse-url-interactive-arg (prompt)
   "Read a URL from the minibuffer, prompting with PROMPT.
-Default to the URL at or before point.  If invoked with a mouse button,
-set point to the position clicked first.  Return a list for use in
-`interactive' containing the URL and `browse-url-new-window-flag' or its
-negation if a prefix argument was given."
+If `transient-mark-mode' is non-nil and the mark is active,
+it defaults to the current region, else to the URL at or before
+point.  If invoked with a mouse button, it moves point to the
+position clicked before acting.
+
+This function returns a list (URL NEW-WINDOW-FLAG)
+for use in `interactive'."
   (let ((event (elt (this-command-keys) 0)))
     (and (listp event) (mouse-set-point event)))
-  (list (read-string prompt (browse-url-url-at-point))
+  (list (read-string prompt (or (and transient-mark-mode mark-active
+                                    ;; rfc2396 Appendix E.
+                                    (replace-regexp-in-string
+                                     "[\t\r\f\n ]+" ""
+                                     (buffer-substring-no-properties
+                                      (region-beginning) (region-end))))
+                               (browse-url-url-at-point)))
        (not (eq (null browse-url-new-window-flag)
                 (null current-prefix-arg)))))
 
-;; interactive-p needs to be called at a function's top-level, hence
-;; the macro.
+;; called-interactive-p needs to be called at a function's top-level, hence
+;; this macro.  We use that rather than interactive-p because
+;; use in a keyboard macro should not change this behavior.
 (defmacro browse-url-maybe-new-window (arg)
-  `(if (not (interactive-p))
+  `(if (or noninteractive (not (called-interactively-p)))
        ,arg
      browse-url-new-window-flag))
 
@@ -621,6 +680,10 @@ interactively.  Turn the filename into a URL with function
 (defun browse-url-file-url (file)
   "Return the URL corresponding to FILE.
 Use variable `browse-url-filename-alist' to map filenames to URLs."
+  (let ((coding (and default-enable-multibyte-characters
+                    (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))
@@ -654,7 +717,8 @@ narrowed."
                (setq browse-url-temp-file-name
                      (convert-standard-filename
                       (make-temp-file
-                       (expand-file-name "burl" browse-url-temp-dir)))))
+                       (expand-file-name "burl" browse-url-temp-dir)
+                       nil ".html"))))
            (setq file-name browse-url-temp-file-name)
            (write-region (point-min) (point-max) file-name nil 'no-message)))
       (browse-url-of-file file-name))))
@@ -696,17 +760,23 @@ Prompts for a URL, defaulting to the URL at or before point.  Variable
   (interactive (browse-url-interactive-arg "URL: "))
   (unless (interactive-p)
     (setq args (or args (list browse-url-new-window-flag))))
-  (if (functionp browse-url-browser-function)
-      (apply browse-url-browser-function url args)
-    ;; The `function' can be an alist; look down it for first match
-    ;; and apply the function (which might be a lambda).
-    (catch 'done
-      (dolist (bf browse-url-browser-function)
-       (when (string-match (car bf) url)
-         (apply (cdr bf) url args)
-         (throw 'done t)))
-      (error "No browse-url-browser-function matching URL %s"
-            url))))
+  (let ((process-environment (copy-sequence process-environment)))
+    ;; When connected to various displays, be careful to use the display of
+    ;; the currently selected frame, rather than the original start display,
+    ;; which may not even exist any more.
+    (if (stringp (frame-parameter (selected-frame) 'display))
+        (setenv "DISPLAY" (frame-parameter (selected-frame) 'display)))
+    (if (functionp browse-url-browser-function)
+        (apply browse-url-browser-function url args)
+      ;; The `function' can be an alist; look down it for first match
+      ;; and apply the function (which might be a lambda).
+      (catch 'done
+        (dolist (bf browse-url-browser-function)
+          (when (string-match (car bf) url)
+            (apply (cdr bf) url args)
+            (throw 'done t)))
+        (error "No browse-url-browser-function matching URL %s"
+               url)))))
 
 ;;;###autoload
 (defun browse-url-at-point (&optional arg)
@@ -740,6 +810,8 @@ to use."
 
 ;; --- Default MS-Windows browser ---
 
+(defvar dos-windows-version)
+
 (defun browse-url-default-windows-browser (url &optional new-window)
   (interactive (browse-url-interactive-arg "URL: "))
   (if (eq system-type 'ms-dos)
@@ -787,12 +859,14 @@ 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'.
 
-The order attempted is gnome-moz-remote, Mozilla, Galeon, Netscape,
-Mosaic, IXI Mosaic, Lynx in an xterm, MMM, Konqueror, and then W3."
+The order attempted is gnome-moz-remote, Mozilla, Firefox,
+Galeon, Konqueror, Netscape, Mosaic, IXI Mosaic, Lynx in an
+xterm, MMM, 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)
@@ -800,7 +874,9 @@ Mosaic, IXI Mosaic, Lynx in an xterm, MMM, Konqueror, and then W3."
      ((executable-find "tellw3b") 'browse-url-iximosaic)
      ((executable-find browse-url-xterm-program) 'browse-url-lynx-xterm)
      ((executable-find "mmm") 'browse-url-mmm)
-     (t 'browse-url-w3))
+     ((locate-library "w3") 'browse-url-w3)
+     (t
+      (lambda (&ignore args) (error "No usable browser found"))))
      url args))
 
 ;;;###autoload
@@ -814,30 +890,37 @@ non-nil, load the document in a new Netscape window, otherwise use a
 random existing one.  A non-nil interactive prefix argument reverses
 the effect of `browse-url-new-window-flag'.
 
+If `browse-url-netscape-new-window-is-tab' is non-nil, then
+whenever a document would otherwise be loaded in a new window, it
+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.
-  (while (string-match "[,)]" url)
+  ;; 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)))
   (let* ((process-environment (browse-url-process-environment))
-         (process (apply 'start-process
-                        (concat "netscape " url) nil
-                        browse-url-netscape-program
-                        (append
-                         browse-url-netscape-arguments
-                         (if (eq window-system 'w32)
-                             (list url)
-                           (append
-                            (if new-window '("-noraise"))
-                            (list "-remote"
-                                  (concat "openURL(" url
-                                          (if (browse-url-maybe-new-window
-                                               new-window)
-                                              ",new-window")
-                                          ")"))))))))
+        (process
+         (apply 'start-process
+                (concat "netscape " url) nil
+                browse-url-netscape-program
+                (append
+                 browse-url-netscape-arguments
+                 (if (eq window-system 'w32)
+                     (list url)
+                   (append
+                    (if new-window '("-noraise"))
+                    (list "-remote"
+                          (concat "openURL(" url
+                                  (if (browse-url-maybe-new-window
+                                       new-window)
+                                      (if browse-url-netscape-new-window-is-tab
+                                          ",new-tab"
+                                        ",new-window"))
+                                  ")"))))))))
     (set-process-sentinel process
                          `(lambda (process change)
                             (browse-url-netscape-sentinel process ,url)))))
@@ -847,7 +930,7 @@ used instead of `browse-url-new-window-flag'."
   (or (eq (process-exit-status process) 0)
       (let* ((process-environment (browse-url-process-environment)))
        ;; Netscape not running - start it
-       (message "Starting Netscape...")
+       (message "Starting %s..." browse-url-netscape-program)
        (apply 'start-process (concat "netscape" url) nil
               browse-url-netscape-program
               (append browse-url-netscape-startup-arguments (list url))))))
@@ -889,8 +972,8 @@ 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.
-  (while (string-match "[,)]" url)
+  ;; 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)))
   (let* ((process-environment (browse-url-process-environment))
@@ -918,11 +1001,76 @@ used instead of `browse-url-new-window-flag'."
   (or (eq (process-exit-status process) 0)
       (let* ((process-environment (browse-url-process-environment)))
        ;; Mozilla is not running - start it
-       (message "Starting Mozilla...")
+       (message "Starting %s..." browse-url-mozilla-program)
        (apply 'start-process (concat "mozilla " url) nil
               browse-url-mozilla-program
               (append browse-url-mozilla-startup-arguments (list url))))))
 
+;;;###autoload
+(defun browse-url-firefox (url &optional new-window)
+  "Ask the Firefox WWW browser to load URL.
+Default to the URL around or before point.  The strings in
+variable `browse-url-firefox-arguments' are also passed to
+Firefox.
+
+When called interactively, if variable
+`browse-url-new-window-flag' is non-nil, load the document in a
+new Firefox window, otherwise use a random existing one.  A
+non-nil interactive prefix argument reverses the effect of
+`browse-url-new-window-flag'.
+
+If `browse-url-firefox-new-window-is-tab' is non-nil, then
+whenever a document would otherwise be loaded in a new window, it
+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'.
+
+On MS-Windows systems the optional `new-window' parameter is
+ignored.  Firefox for Windows does not support the \"-remote\"
+command line parameter.  Therefore, the
+`browse-url-new-window-flag' and `browse-url-firefox-new-window-is-tab'
+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)))
+  (let* ((process-environment (browse-url-process-environment))
+        (process
+         (apply 'start-process
+                (concat "firefox " url) nil
+                browse-url-firefox-program
+                (append
+                 browse-url-firefox-arguments
+                 (if (or (featurep 'dos-w32)
+                         (string-match "win32" system-configuration))
+                     (list url)
+                   (list "-remote"
+                         (concat "openURL("
+                                 url
+                                 (if (browse-url-maybe-new-window
+                                      new-window)
+                                     (if browse-url-firefox-new-window-is-tab
+                                         ",new-tab"
+                                       ",new-window"))
+                                 ")")))))))
+    (set-process-sentinel process
+                         `(lambda (process change)
+                            (browse-url-firefox-sentinel process ,url)))))
+
+(defun browse-url-firefox-sentinel (process url)
+  "Handle a change to the process communicating with Firefox."
+  (or (eq (process-exit-status process) 0)
+      (let* ((process-environment (browse-url-process-environment)))
+       ;; Firefox is not running - start it
+       (message "Starting Firefox...")
+       (apply 'start-process (concat "firefox " url) nil
+              browse-url-firefox-program
+              (append browse-url-firefox-startup-arguments (list url))))))
+
 ;;;###autoload
 (defun browse-url-galeon (url &optional new-window)
   "Ask the Galeon WWW browser to load URL.
@@ -942,8 +1090,8 @@ 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.
-  (while (string-match "[,)]" url)
+  ;; 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)))
   (let* ((process-environment (browse-url-process-environment))
@@ -968,7 +1116,7 @@ used instead of `browse-url-new-window-flag'."
   (or (eq (process-exit-status process) 0)
       (let* ((process-environment (browse-url-process-environment)))
        ;; Galeon is not running - start it
-       (message "Starting Galeon...")
+       (message "Starting %s..." browse-url-galeon-program)
        (apply 'start-process (concat "galeon " url) nil
               browse-url-galeon-program
               (append browse-url-galeon-startup-arguments (list url))))))
@@ -991,8 +1139,8 @@ 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.
-  (while (string-match "[,)]" url)
+  ;; 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)))
   (let* ((process-environment (browse-url-process-environment))
@@ -1017,19 +1165,11 @@ used instead of `browse-url-new-window-flag'."
   (or (eq (process-exit-status process) 0)
       (let* ((process-environment (browse-url-process-environment)))
        ;; Epiphany is not running - start it
-       (message "Starting Epiphany...")
+       (message "Starting %s..." browse-url-epiphany-program)
        (apply 'start-process (concat "epiphany " url) nil
               browse-url-epiphany-program
               (append browse-url-epiphany-startup-arguments (list url))))))
 
-;; GNOME means of invoking either Mozilla or Netrape.
-(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."
-  :version "21.1"
-  :type '(repeat (string :tag "Argument"))
-  :group 'browse-url)
-
 ;;;###autoload
 (defun browse-url-gnome-moz (url &optional new-window)
   "Ask Mozilla/Netscape to load URL via the GNOME program `gnome-moz-remote'.
@@ -1091,17 +1231,17 @@ used instead of `browse-url-new-window-flag'."
          (save-buffer)
          (kill-buffer nil)
          ;; Send signal SIGUSR to Mosaic
-         (message "Signalling Mosaic...")
+         (message "Signaling Mosaic...")
          (signal-process pid 'SIGUSR1)
          ;; Or you could try:
          ;; (call-process "kill" nil 0 nil "-USR1" (int-to-string pid))
-         (message "Signalling Mosaic...done")
+         (message "Signaling Mosaic...done")
          )
       ;; Mosaic not running - start it
-      (message "Starting Mosaic...")
+      (message "Starting %s..." browse-url-mosaic-program)
       (apply 'start-process "xmosaic" nil browse-url-mosaic-program
             (append browse-url-mosaic-arguments (list url)))
-      (message "Starting Mosaic...done"))))
+      (message "Starting %s...done" browse-url-mosaic-program))))
 
 ;; --- Grail ---
 
@@ -1301,9 +1441,11 @@ Default to the URL around or before point."
 
 ;; --- mailto ---
 
+(autoload 'rfc2368-parse-mailto-url "rfc2368")
+
 ;;;###autoload
 (defun browse-url-mail (url &optional new-window)
-  "Open a new mail message buffer within Emacs.
+  "Open a new mail message buffer within Emacs for the RFC 2368 URL.
 Default to using the mailto: URL around or before point as the
 recipient's address.  Supplying a non-nil interactive prefix argument
 will cause the mail to be composed in another window rather than the
@@ -1318,14 +1460,24 @@ When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'."
   (interactive (browse-url-interactive-arg "Mailto URL: "))
   (save-excursion
-    (let ((to (if (string-match "^mailto:" url)
-                 (substring url 7)
-               url)))
+    (let* ((alist (rfc2368-parse-mailto-url url))
+          (to (assoc "To" alist))
+          (subject (assoc "Subject" alist))
+          (body (assoc "Body" alist))
+          (rest (delete to (delete subject (delete body alist))))
+          (to (cdr to))
+          (subject (cdr subject))
+          (body (cdr body))
+          (mail-citation-hook (unless body mail-citation-hook)))
       (if (browse-url-maybe-new-window new-window)
-         (compose-mail-other-window to nil nil nil
-                                    (list 'insert-buffer (current-buffer)))
-       (compose-mail to nil nil nil nil
-                     (list 'insert-buffer (current-buffer)))))))
+         (compose-mail-other-window to subject rest nil
+                                    (if body
+                                        (list 'insert body)
+                                      (list 'insert-buffer (current-buffer))))
+       (compose-mail to subject rest nil nil
+                     (if body
+                         (list 'insert body)
+                       (list 'insert-buffer (current-buffer))))))))
 
 ;; --- Random browser ---
 
@@ -1340,8 +1492,8 @@ 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')"))
-  (apply 'start-process (concat browse-url-generic-program url) nil
-        browse-url-generic-program
+  (apply 'call-process browse-url-generic-program nil
+        0 nil
         (append browse-url-generic-args (list url))))
 
 ;;;###autoload
@@ -1355,4 +1507,5 @@ Default to the URL around or before point."
 
 (provide 'browse-url)
 
+;;; arch-tag: d2079573-5c06-4097-9598-f550fba19430
 ;;; browse-url.el ends here