]> code.delx.au - gnu-emacs/blob - lisp/net/browse-url.el
Convert consecutive FSF copyright years to ranges.
[gnu-emacs] / lisp / net / browse-url.el
1 ;;; browse-url.el --- pass a URL to a WWW browser
2
3 ;; Copyright (C) 1995-2011
4 ;; Free Software Foundation, Inc.
5
6 ;; Author: Denis Howe <dbh@doc.ic.ac.uk>
7 ;; Maintainer: FSF
8 ;; Created: 03 Apr 1995
9 ;; Keywords: hypertext, hypermedia, mouse
10
11 ;; This file is part of GNU Emacs.
12
13 ;; GNU Emacs is free software: you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation, either version 3 of the License, or
16 ;; (at your option) any later version.
17
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
22
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
25
26 ;;; Commentary:
27
28 ;; This package provides functions which read a URL (Uniform Resource
29 ;; Locator) from the minibuffer, defaulting to the URL around point,
30 ;; and ask a World-Wide Web browser to load it. It can also load the
31 ;; URL associated with the current buffer. Different browsers use
32 ;; different methods of remote control so there is one function for
33 ;; each supported browser. If the chosen browser is not running, it
34 ;; is started. Currently there is support for the following browsers,
35 ;; some of them probably now obsolete:
36
37 ;; Function Browser Earliest version
38 ;; browse-url-mozilla Mozilla Don't know
39 ;; browse-url-firefox Firefox Don't know (tried with 1.0.1)
40 ;; browse-url-galeon Galeon Don't know
41 ;; browse-url-epiphany Epiphany Don't know
42 ;; browse-url-netscape Netscape 1.1b1
43 ;; browse-url-mosaic XMosaic/mMosaic <= 2.4
44 ;; browse-url-cci XMosaic 2.5
45 ;; browse-url-w3 w3 0
46 ;; browse-url-w3-gnudoit w3 remotely
47 ;; browse-url-text-* Any text browser 0
48 ;; browse-url-generic arbitrary
49 ;; browse-url-default-windows-browser MS-Windows browser
50 ;; browse-url-default-macosx-browser Mac OS X browser
51 ;; browse-url-gnome-moz GNOME interface to Mozilla
52 ;; browse-url-kde KDE konqueror (kfm)
53 ;; browse-url-elinks Elinks Don't know (tried with 0.12.GIT)
54
55 ;; [A version of the Netscape browser is now free software
56 ;; <URL:http://www.mozilla.org/>, albeit not GPLed, so it is
57 ;; reasonable to have that as the default.]
58
59 ;; Note that versions of Netscape before 1.1b1 did not have remote
60 ;; control. <URL:http://www.netscape.com/newsref/std/x-remote.html>.
61
62 ;; Browsers can cache Web pages so it may be necessary to tell them to
63 ;; reload the current page if it has changed (e.g. if you have edited
64 ;; it). There is currently no perfect automatic solution to this.
65
66 ;; Netscape allows you to specify the id of the window you want to
67 ;; control but which window DO you want to control and how do you
68 ;; discover its id?
69
70 ;; William M. Perry's excellent "w3" WWW browser for
71 ;; Emacs <URL:ftp://cs.indiana.edu/pub/elisp/w3/>
72 ;; has a function w3-follow-url-at-point, but that
73 ;; doesn't let you edit the URL like browse-url.
74 ;; The `gnuserv' package that can be used to control it in another
75 ;; Emacs process is available from
76 ;; <URL:ftp://ftp.splode.com/pub/users/friedman/packages/>.
77
78 ;; Lynx is now distributed by the FSF. See also
79 ;; <URL:http://lynx.browser.org/>.
80
81 ;; Free graphical browsers that could be used by `browse-url-generic'
82 ;; include Chimera <URL:ftp://ftp.cs.unlv.edu/pub/chimera> and
83 ;; <URL:http://www.unlv.edu/chimera/>, Arena
84 ;; <URL:ftp://ftp.yggdrasil.com/pub/dist/web/arena> and Amaya
85 ;; <URL:ftp://ftp.w3.org/pub/amaya>. mMosaic
86 ;; <URL:ftp://ftp.enst.fr/pub/mbone/mMosaic/>,
87 ;; <URL:http://www.enst.fr/~dauphin/mMosaic/> (with development
88 ;; support for Java applets and multicast) can be used like Mosaic by
89 ;; setting `browse-url-mosaic-program' appropriately.
90
91 ;; I [Denis Howe, not Dave Love] recommend Nelson Minar
92 ;; <nelson@santafe.edu>'s excellent html-helper-mode.el for editing
93 ;; HTML and thank Nelson for his many useful comments on this code.
94 ;; <URL:http://www.santafe.edu/%7Enelson/hhm-beta/>
95
96 ;; See also hm--html-menus <URL:http://www.tnt.uni-hannover.de/%7Emuenkel/
97 ;; software/own/hm--html-menus/>. For composing correct HTML see also
98 ;; PSGML the general SGML structure editor package
99 ;; <URL:ftp://ftp.lysator.liu.se/pub/sgml>; hm--html-menus can be used
100 ;; with this.
101
102 ;; This package generalises function html-previewer-process in Marc
103 ;; Andreessen's html-mode (LCD modes/html-mode.el.Z). See also the
104 ;; ffap.el package. The huge hyperbole package also contains similar
105 ;; functions.
106
107 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
108 ;; Help!
109
110 ;; Can you write and test some code for the Macintrash and Windoze
111 ;; Netscape remote control APIs? (See the URL above).
112
113 ;; Do any other browsers have remote control?
114
115 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
116 ;; Usage
117
118 ;; To display the URL at or before point:
119 ;; M-x browse-url-at-point RET
120 ;; or, similarly but with the opportunity to edit the URL extracted from
121 ;; the buffer, use:
122 ;; M-x browse-url
123
124 ;; To display a URL by shift-clicking on it, put this in your ~/.emacs
125 ;; file:
126 ;; (global-set-key [S-mouse-2] 'browse-url-at-mouse)
127 ;; (Note that using Shift-mouse-1 is not desirable because
128 ;; that event has a standard meaning in Emacs.)
129
130 ;; To display the current buffer in a web browser:
131 ;; M-x browse-url-of-buffer RET
132
133 ;; To display the current region in a web browser:
134 ;; M-x browse-url-of-region RET
135
136 ;; In Dired, to display the file named on the current line:
137 ;; M-x browse-url-of-dired-file RET
138
139 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
140 ;; Customisation (~/.emacs)
141
142 ;; To see what variables are available for customization, type
143 ;; `M-x set-variable browse-url TAB'. Better, use
144 ;; `M-x customize-group browse-url'.
145
146 ;; Bind the browse-url commands to keys with the `C-c C-z' prefix
147 ;; (as used by html-helper-mode):
148 ;; (global-set-key "\C-c\C-z." 'browse-url-at-point)
149 ;; (global-set-key "\C-c\C-zb" 'browse-url-of-buffer)
150 ;; (global-set-key "\C-c\C-zr" 'browse-url-of-region)
151 ;; (global-set-key "\C-c\C-zu" 'browse-url)
152 ;; (global-set-key "\C-c\C-zv" 'browse-url-of-file)
153 ;; (add-hook 'dired-mode-hook
154 ;; (lambda ()
155 ;; (local-set-key "\C-c\C-zf" 'browse-url-of-dired-file)))
156
157 ;; Browse URLs in mail messages under RMAIL by clicking mouse-2:
158 ;; (add-hook 'rmail-mode-hook (lambda () ; rmail-mode startup
159 ;; (define-key rmail-mode-map [mouse-2] 'browse-url-at-mouse)))
160 ;; Alternatively, add `goto-address' to `rmail-show-message-hook'.
161
162 ;; Gnus provides a standard feature to activate URLs in article
163 ;; buffers for invocation of browse-url.
164
165 ;; Use the Emacs w3 browser when not running under X11:
166 ;; (or (eq window-system 'x)
167 ;; (setq browse-url-browser-function 'browse-url-w3))
168
169 ;; To always save modified buffers before displaying the file in a browser:
170 ;; (setq browse-url-save-file t)
171
172 ;; To get round the Netscape caching problem, you could EITHER have
173 ;; write-file in html-helper-mode make Netscape reload the document:
174 ;;
175 ;; (autoload 'browse-url-netscape-reload "browse-url"
176 ;; "Ask a WWW browser to redisplay the current file." t)
177 ;; (add-hook 'html-helper-mode-hook
178 ;; (lambda ()
179 ;; (add-hook 'local-write-file-hooks
180 ;; (lambda ()
181 ;; (let ((local-write-file-hooks))
182 ;; (save-buffer))
183 ;; (browse-url-netscape-reload)
184 ;; t) ; => file written by hook
185 ;; t))) ; append to l-w-f-hooks
186 ;;
187 ;; OR have browse-url-of-file ask Netscape to load and then reload the
188 ;; file:
189 ;;
190 ;; (add-hook 'browse-url-of-file-hook 'browse-url-netscape-reload)
191
192 ;; You may also want to customise browse-url-netscape-arguments, e.g.
193 ;; (setq browse-url-netscape-arguments '("-install"))
194 ;;
195 ;; or similarly for the other browsers.
196
197 ;; To invoke different browsers for different URLs:
198 ;; (setq browse-url-browser-function '(("^mailto:" . browse-url-mail)
199 ;; ("." . browse-url-netscape)))
200
201 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
202 ;;; Code:
203
204 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
205 ;; Variables
206
207 (eval-when-compile (require 'cl))
208
209 (defgroup browse-url nil
210 "Use a web browser to look at a URL."
211 :prefix "browse-url-"
212 :link '(emacs-commentary-link "browse-url")
213 :group 'external
214 :group 'comm)
215
216 ;;;###autoload
217 (defcustom browse-url-browser-function
218 (cond
219 ((memq system-type '(windows-nt ms-dos cygwin))
220 'browse-url-default-windows-browser)
221 ((memq system-type '(darwin))
222 'browse-url-default-macosx-browser)
223 (t
224 'browse-url-default-browser))
225 "Function to display the current buffer in a WWW browser.
226 This is used by the `browse-url-at-point', `browse-url-at-mouse', and
227 `browse-url-of-file' commands.
228
229 If the value is not a function it should be a list of pairs
230 \(REGEXP . FUNCTION). In this case the function called will be the one
231 associated with the first REGEXP which matches the current URL. The
232 function is passed the URL and any other args of `browse-url'. The last
233 regexp should probably be \".\" to specify a default browser."
234 :type '(choice
235 (function-item :tag "Emacs W3" :value browse-url-w3)
236 (function-item :tag "W3 in another Emacs via `gnudoit'"
237 :value browse-url-w3-gnudoit)
238 (function-item :tag "Mozilla" :value browse-url-mozilla)
239 (function-item :tag "Firefox" :value browse-url-firefox)
240 (function-item :tag "Galeon" :value browse-url-galeon)
241 (function-item :tag "Epiphany" :value browse-url-epiphany)
242 (function-item :tag "Netscape" :value browse-url-netscape)
243 (function-item :tag "Mosaic" :value browse-url-mosaic)
244 (function-item :tag "Mosaic using CCI" :value browse-url-cci)
245 (function-item :tag "Text browser in an xterm window"
246 :value browse-url-text-xterm)
247 (function-item :tag "Text browser in an Emacs window"
248 :value browse-url-text-emacs)
249 (function-item :tag "KDE" :value browse-url-kde)
250 (function-item :tag "Elinks" :value browse-url-elinks)
251 (function-item :tag "Specified by `Browse Url Generic Program'"
252 :value browse-url-generic)
253 (function-item :tag "Default Windows browser"
254 :value browse-url-default-windows-browser)
255 (function-item :tag "Default Mac OS X browser"
256 :value browse-url-default-macosx-browser)
257 (function-item :tag "GNOME invoking Mozilla"
258 :value browse-url-gnome-moz)
259 (function-item :tag "Default browser"
260 :value browse-url-default-browser)
261 (function :tag "Your own function")
262 (alist :tag "Regexp/function association list"
263 :key-type regexp :value-type function))
264 :version "24.1"
265 :group 'browse-url)
266
267 (defcustom browse-url-mailto-function 'browse-url-mail
268 "Function to display mailto: links.
269 This variable uses the same syntax as the
270 `browse-url-browser-function' variable. If the
271 `browse-url-mailto-function' variable is nil, that variable will
272 be used instead."
273 :type '(choice
274 (function-item :tag "Emacs Mail" :value browse-url-mail)
275 (function-item :tag "None" nil))
276 :version "24.1"
277 :group 'browse-url)
278
279 (defcustom browse-url-netscape-program "netscape"
280 ;; Info about netscape-remote from Karl Berry.
281 "The name by which to invoke Netscape.
282
283 The free program `netscape-remote' from
284 <URL:http://home.netscape.com/newsref/std/remote.c> is said to start
285 up very much quicker than `netscape'. Reported to compile on a GNU
286 system, given vroot.h from the same directory, with cc flags
287 -DSTANDALONE -L/usr/X11R6/lib -lXmu -lX11."
288 :type 'string
289 :group 'browse-url)
290
291 (defcustom browse-url-netscape-arguments nil
292 "A list of strings to pass to Netscape as arguments."
293 :type '(repeat (string :tag "Argument"))
294 :group 'browse-url)
295
296 (defcustom browse-url-netscape-startup-arguments browse-url-netscape-arguments
297 "A list of strings to pass to Netscape when it starts up.
298 Defaults to the value of `browse-url-netscape-arguments' at the time
299 `browse-url' is loaded."
300 :type '(repeat (string :tag "Argument"))
301 :group 'browse-url)
302
303 (defcustom browse-url-browser-display nil
304 "The X display for running the browser, if not same as Emacs'."
305 :type '(choice string (const :tag "Default" nil))
306 :group 'browse-url)
307
308 (defcustom browse-url-mozilla-program "mozilla"
309 "The name by which to invoke Mozilla."
310 :type 'string
311 :group 'browse-url)
312
313 (defcustom browse-url-mozilla-arguments nil
314 "A list of strings to pass to Mozilla as arguments."
315 :type '(repeat (string :tag "Argument"))
316 :group 'browse-url)
317
318 (defcustom browse-url-mozilla-startup-arguments browse-url-mozilla-arguments
319 "A list of strings to pass to Mozilla when it starts up.
320 Defaults to the value of `browse-url-mozilla-arguments' at the time
321 `browse-url' is loaded."
322 :type '(repeat (string :tag "Argument"))
323 :group 'browse-url)
324
325 (defcustom browse-url-firefox-program
326 (let ((candidates '("firefox" "iceweasel")))
327 (while (and candidates (not (executable-find (car candidates))))
328 (setq candidates (cdr candidates)))
329 (or (car candidates) "firefox"))
330 "The name by which to invoke Firefox."
331 :type 'string
332 :group 'browse-url)
333
334 (defcustom browse-url-firefox-arguments nil
335 "A list of strings to pass to Firefox as arguments."
336 :type '(repeat (string :tag "Argument"))
337 :group 'browse-url)
338
339 (defcustom browse-url-firefox-startup-arguments browse-url-firefox-arguments
340 "A list of strings to pass to Firefox when it starts up.
341 Defaults to the value of `browse-url-firefox-arguments' at the time
342 `browse-url' is loaded."
343 :type '(repeat (string :tag "Argument"))
344 :group 'browse-url)
345
346 (defcustom browse-url-galeon-program "galeon"
347 "The name by which to invoke Galeon."
348 :type 'string
349 :group 'browse-url)
350
351 (defcustom browse-url-galeon-arguments nil
352 "A list of strings to pass to Galeon as arguments."
353 :type '(repeat (string :tag "Argument"))
354 :group 'browse-url)
355
356 (defcustom browse-url-galeon-startup-arguments browse-url-galeon-arguments
357 "A list of strings to pass to Galeon when it starts up.
358 Defaults to the value of `browse-url-galeon-arguments' at the time
359 `browse-url' is loaded."
360 :type '(repeat (string :tag "Argument"))
361 :group 'browse-url)
362
363 (defcustom browse-url-epiphany-program "epiphany"
364 "The name by which to invoke Epiphany."
365 :type 'string
366 :group 'browse-url)
367
368 (defcustom browse-url-epiphany-arguments nil
369 "A list of strings to pass to Epiphany as arguments."
370 :type '(repeat (string :tag "Argument"))
371 :group 'browse-url)
372
373 (defcustom browse-url-epiphany-startup-arguments browse-url-epiphany-arguments
374 "A list of strings to pass to Epiphany when it starts up.
375 Defaults to the value of `browse-url-epiphany-arguments' at the time
376 `browse-url' is loaded."
377 :type '(repeat (string :tag "Argument"))
378 :group 'browse-url)
379
380 ;; GNOME means of invoking either Mozilla or Netrape.
381 (defvar browse-url-gnome-moz-program "gnome-moz-remote")
382
383 (defcustom browse-url-gnome-moz-arguments '()
384 "A list of strings passed to the GNOME mozilla viewer as arguments."
385 :version "21.1"
386 :type '(repeat (string :tag "Argument"))
387 :group 'browse-url)
388
389 (defcustom browse-url-mozilla-new-window-is-tab nil
390 "Whether to open up new windows in a tab or a new window.
391 If non-nil, then open the URL in a new tab rather than a new window if
392 `browse-url-mozilla' is asked to open it in a new window."
393 :type 'boolean
394 :group 'browse-url)
395
396 (defcustom browse-url-firefox-new-window-is-tab nil
397 "Whether to open up new windows in a tab or a new window.
398 If non-nil, then open the URL in a new tab rather than a new window if
399 `browse-url-firefox' is asked to open it in a new window.
400
401 This option is currently ignored on MS-Windows, since the necessary
402 functionality is not available there."
403 :type 'boolean
404 :group 'browse-url)
405
406 (defcustom browse-url-galeon-new-window-is-tab nil
407 "Whether to open up new windows in a tab or a new window.
408 If non-nil, then open the URL in a new tab rather than a new window if
409 `browse-url-galeon' is asked to open it in a new window."
410 :type 'boolean
411 :group 'browse-url)
412
413 (defcustom browse-url-epiphany-new-window-is-tab nil
414 "Whether to open up new windows in a tab or a new window.
415 If non-nil, then open the URL in a new tab rather than a new window if
416 `browse-url-epiphany' is asked to open it in a new window."
417 :type 'boolean
418 :group 'browse-url)
419
420 (defcustom browse-url-netscape-new-window-is-tab nil
421 "Whether to open up new windows in a tab or a new window.
422 If non-nil, then open the URL in a new tab rather than a new
423 window if `browse-url-netscape' is asked to open it in a new
424 window."
425 :type 'boolean
426 :group 'browse-url)
427
428 (defcustom browse-url-new-window-flag nil
429 "Non-nil means always open a new browser window with appropriate browsers.
430 Passing an interactive argument to \\[browse-url], or specific browser
431 commands reverses the effect of this variable. Requires Netscape version
432 1.1N or later or XMosaic version 2.5 or later if using those browsers."
433 :type 'boolean
434 :group 'browse-url)
435
436 (defcustom browse-url-mosaic-program "xmosaic"
437 "The name by which to invoke Mosaic (or mMosaic)."
438 :type 'string
439 :version "20.3"
440 :group 'browse-url)
441
442 (defcustom browse-url-mosaic-arguments nil
443 "A list of strings to pass to Mosaic as arguments."
444 :type '(repeat (string :tag "Argument"))
445 :group 'browse-url)
446
447 (defcustom browse-url-mosaic-pidfile "~/.mosaicpid"
448 "The name of the pidfile created by Mosaic."
449 :type 'string
450 :group 'browse-url)
451
452 (defcustom browse-url-filename-alist
453 `(("^/\\(ftp@\\|anonymous@\\)?\\([^:]+\\):/*" . "ftp://\\2/")
454 ;; The above loses the username to avoid the browser prompting for
455 ;; it in anonymous cases. If it's not anonymous the next regexp
456 ;; applies.
457 ("^/\\([^:@]+@\\)?\\([^:]+\\):/*" . "ftp://\\1\\2/")
458 ,@(if (memq system-type '(windows-nt ms-dos cygwin))
459 '(("^\\([a-zA-Z]:\\)[\\/]" . "file:///\\1/")
460 ("^[\\/][\\/]+" . "file://")))
461 ("^/+" . "file:///"))
462 "An alist of (REGEXP . STRING) pairs used by `browse-url-of-file'.
463 Any substring of a filename matching one of the REGEXPs is replaced by
464 the corresponding STRING using `replace-match', not treating STRING
465 literally. All pairs are applied in the order given. The default
466 value converts ange-ftp/EFS-style file names into ftp URLs and prepends
467 `file:' to any file name beginning with `/'.
468
469 For example, adding to the default a specific translation of an ange-ftp
470 address to an HTTP URL:
471
472 (setq browse-url-filename-alist
473 '((\"/webmaster@webserver:/home/www/html/\" .
474 \"http://www.acme.co.uk/\")
475 (\"^/\\(ftp@\\|anonymous@\\)?\\([^:]+\\):/*\" . \"ftp://\\2/\")
476 (\"^/\\([^:@]+@\\)?\\([^:]+\\):/*\" . \"ftp://\\1\\2/\")
477 (\"^/+\" . \"file:/\")))"
478 :type '(repeat (cons :format "%v"
479 (regexp :tag "Regexp")
480 (string :tag "Replacement")))
481 :version "23.1"
482 :group 'browse-url)
483
484 (defcustom browse-url-save-file nil
485 "If non-nil, save the buffer before displaying its file.
486 Used by the `browse-url-of-file' command."
487 :type 'boolean
488 :group 'browse-url)
489
490 (defcustom browse-url-of-file-hook nil
491 "Run after `browse-url-of-file' has asked a browser to load a file.
492
493 Set this to `browse-url-netscape-reload' to force Netscape to load the
494 file rather than displaying a cached copy."
495 :type 'hook
496 :options '(browse-url-netscape-reload)
497 :group 'browse-url)
498
499 (defcustom browse-url-CCI-port 3003
500 "Port to access XMosaic via CCI.
501 This can be any number between 1024 and 65535 but must correspond to
502 the value set in the browser."
503 :type 'integer
504 :group 'browse-url)
505
506 (defcustom browse-url-CCI-host "localhost"
507 "Host to access XMosaic via CCI.
508 This should be the host name of the machine running XMosaic with CCI
509 enabled. The port number should be set in `browse-url-CCI-port'."
510 :type 'string
511 :group 'browse-url)
512
513 (defvar browse-url-temp-file-name nil)
514 (make-variable-buffer-local 'browse-url-temp-file-name)
515
516 (defcustom browse-url-xterm-program "xterm"
517 "The name of the terminal emulator used by `browse-url-text-xterm'.
518 This might, for instance, be a separate color version of xterm."
519 :type 'string
520 :group 'browse-url)
521
522 (defcustom browse-url-xterm-args nil
523 "A list of strings defining options for `browse-url-xterm-program'.
524 These might set its size, for instance."
525 :type '(repeat (string :tag "Argument"))
526 :group 'browse-url)
527
528 (defcustom browse-url-gnudoit-program "gnudoit"
529 "The name of the `gnudoit' program used by `browse-url-w3-gnudoit'."
530 :type 'string
531 :group 'browse-url)
532
533 (defcustom browse-url-gnudoit-args '("-q")
534 "A list of strings defining options for `browse-url-gnudoit-program'.
535 These might set the port, for instance."
536 :type '(repeat (string :tag "Argument"))
537 :group 'browse-url)
538
539 (defcustom browse-url-generic-program nil
540 "The name of the browser program used by `browse-url-generic'."
541 :type '(choice string (const :tag "None" nil))
542 :group 'browse-url)
543
544 (defcustom browse-url-generic-args nil
545 "A list of strings defining options for `browse-url-generic-program'."
546 :type '(repeat (string :tag "Argument"))
547 :group 'browse-url)
548
549 (defcustom browse-url-temp-dir temporary-file-directory
550 "The name of a directory for browse-url's temporary files.
551 Such files are generated by functions like `browse-url-of-region'.
552 You might want to set this to somewhere with restricted read permissions
553 for privacy's sake."
554 :type 'string
555 :group 'browse-url)
556
557 (defcustom browse-url-netscape-version 3
558 "The version of Netscape you are using.
559 This affects how URL reloading is done; the mechanism changed
560 incompatibly at version 4."
561 :type 'number
562 :group 'browse-url)
563
564 (defcustom browse-url-text-browser "lynx"
565 "The name of the text browser to invoke."
566 :type 'string
567 :group 'browse-url
568 :version "23.1")
569
570 (defcustom browse-url-text-emacs-args (and (not window-system)
571 '("-show_cursor"))
572 "A list of strings defining options for a text browser in an Emacs buffer.
573
574 The default is none in a window system, otherwise `-show_cursor' to
575 indicate the position of the current link in the absence of
576 highlighting, assuming the normal default for showing the cursor."
577 :type '(repeat (string :tag "Argument"))
578 :version "23.1"
579 :group 'browse-url)
580
581 (defcustom browse-url-text-input-field 'avoid
582 "Action on selecting an existing text browser buffer at an input field.
583 What to do when sending a new URL to an existing text browser buffer in Emacs
584 if the browser cursor is on an input field (in which case the `g' command
585 would be entered as data). Such fields are recognized by the
586 underlines ____. Allowed values: nil: disregard it, `warn': warn the
587 user and don't emit the URL, `avoid': try to avoid the field by moving
588 down (this *won't* always work)."
589 :type '(choice (const :tag "Move to try to avoid field" :value avoid)
590 (const :tag "Disregard" :value nil)
591 (const :tag "Warn, don't emit URL" :value warn))
592 :version "23.1"
593 :group 'browse-url)
594
595 (defcustom browse-url-text-input-attempts 10
596 "How many times to try to move down from a series of text browser input fields."
597 :type 'integer
598 :version "23.1"
599 :group 'browse-url)
600
601 (defcustom browse-url-text-input-delay 0.2
602 "Seconds to wait for a text browser between moves down from an input field."
603 :type 'number
604 :version "23.1"
605 :group 'browse-url)
606
607 (defcustom browse-url-kde-program "kfmclient"
608 "The name by which to invoke the KDE web browser."
609 :type 'string
610 :version "21.1"
611 :group 'browse-url)
612
613 (defcustom browse-url-kde-args '("openURL")
614 "A list of strings defining options for `browse-url-kde-program'."
615 :type '(repeat (string :tag "Argument"))
616 :group 'browse-url)
617
618 (defcustom browse-url-elinks-wrapper '("xterm" "-e")
619 "Wrapper command prepended to the Elinks command-line."
620 :type '(repeat (string :tag "Wrapper"))
621 :group 'browse-url)
622
623 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
624 ;; URL encoding
625
626 (defun browse-url-url-encode-chars (text chars)
627 "URL-encode the chars in TEXT that match CHARS.
628 CHARS is a regexp-like character alternative (e.g., \"[)$]\")."
629 (let ((encoded-text (copy-sequence text))
630 (s 0))
631 (while (setq s (string-match chars encoded-text s))
632 (setq encoded-text
633 (replace-match (format "%%%x"
634 (string-to-char (match-string 0 encoded-text)))
635 t t encoded-text)
636 s (1+ s)))
637 encoded-text))
638
639 (defun browse-url-encode-url (url)
640 "Escape annoying characters in URL.
641 The annoying characters are those that can mislead a web browser
642 regarding its parameter treatment."
643 ;; FIXME: Is there an actual example of a web browser getting
644 ;; confused? (This used to encode commas, but at least Firefox
645 ;; handles commas correctly and doesn't accept encoded commas.)
646 (browse-url-url-encode-chars url "[)$]"))
647
648 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
649 ;; URL input
650
651 (defun browse-url-url-at-point ()
652 (let ((url (thing-at-point 'url)))
653 (set-text-properties 0 (length url) nil url)
654 url))
655
656 ;; Having this as a separate function called by the browser-specific
657 ;; functions allows them to be stand-alone commands, making it easier
658 ;; to switch between browsers.
659
660 (defun browse-url-interactive-arg (prompt)
661 "Read a URL from the minibuffer, prompting with PROMPT.
662 If `transient-mark-mode' is non-nil and the mark is active,
663 it defaults to the current region, else to the URL at or before
664 point. If invoked with a mouse button, it moves point to the
665 position clicked before acting.
666
667 This function returns a list (URL NEW-WINDOW-FLAG)
668 for use in `interactive'."
669 (let ((event (elt (this-command-keys) 0)))
670 (and (listp event) (mouse-set-point event)))
671 (list (read-string prompt (or (and transient-mark-mode mark-active
672 ;; rfc2396 Appendix E.
673 (replace-regexp-in-string
674 "[\t\r\f\n ]+" ""
675 (buffer-substring-no-properties
676 (region-beginning) (region-end))))
677 (browse-url-url-at-point)))
678 (not (eq (null browse-url-new-window-flag)
679 (null current-prefix-arg)))))
680
681 ;; called-interactive-p needs to be called at a function's top-level, hence
682 ;; this macro. We use that rather than interactive-p because
683 ;; use in a keyboard macro should not change this behavior.
684 (defmacro browse-url-maybe-new-window (arg)
685 `(if (or noninteractive (not (called-interactively-p 'any)))
686 ,arg
687 browse-url-new-window-flag))
688
689 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
690 ;; Browse current buffer
691
692 ;;;###autoload
693 (defun browse-url-of-file (&optional file)
694 "Ask a WWW browser to display FILE.
695 Display the current buffer's file if FILE is nil or if called
696 interactively. Turn the filename into a URL with function
697 `browse-url-file-url'. Pass the URL to a browser using the
698 `browse-url' function then run `browse-url-of-file-hook'."
699 (interactive)
700 (or file
701 (setq file (buffer-file-name))
702 (error "Current buffer has no file"))
703 (let ((buf (get-file-buffer file)))
704 (if buf
705 (with-current-buffer buf
706 (cond ((not (buffer-modified-p)))
707 (browse-url-save-file (save-buffer))
708 (t (message "%s modified since last save" file))))))
709 (browse-url (browse-url-file-url file))
710 (run-hooks 'browse-url-of-file-hook))
711
712 (defun browse-url-file-url (file)
713 "Return the URL corresponding to FILE.
714 Use variable `browse-url-filename-alist' to map filenames to URLs."
715 ;; De-munge Cygwin filenames before passing them to Windows browser.
716 (if (eq system-type 'cygwin)
717 (let ((winfile (with-output-to-string
718 (call-process "cygpath" nil standard-output
719 nil "-m" file))))
720 (setq file (substring winfile 0 -1))))
721 (let ((coding (and (default-value 'enable-multibyte-characters)
722 (or file-name-coding-system
723 default-file-name-coding-system))))
724 (if coding (setq file (encode-coding-string file coding))))
725 (setq file (browse-url-url-encode-chars file "[*\"()',=;?% ]"))
726 (dolist (map browse-url-filename-alist)
727 (when (and map (string-match (car map) file))
728 (setq file (replace-match (cdr map) t nil file))))
729 file)
730
731 ;;;###autoload
732 (defun browse-url-of-buffer (&optional buffer)
733 "Ask a WWW browser to display BUFFER.
734 Display the current buffer if BUFFER is nil. Display only the
735 currently visible part of BUFFER (from a temporary file) if buffer is
736 narrowed."
737 (interactive)
738 (save-excursion
739 (and buffer (set-buffer buffer))
740 (let ((file-name
741 ;; Ignore real name if restricted
742 (and (= (- (point-max) (point-min)) (buffer-size))
743 (or buffer-file-name
744 (and (boundp 'dired-directory) dired-directory)))))
745 (or file-name
746 (progn
747 (or browse-url-temp-file-name
748 (setq browse-url-temp-file-name
749 (convert-standard-filename
750 (make-temp-file
751 (expand-file-name "burl" browse-url-temp-dir)
752 nil ".html"))))
753 (setq file-name browse-url-temp-file-name)
754 (write-region (point-min) (point-max) file-name nil 'no-message)))
755 (browse-url-of-file file-name))))
756
757 (defun browse-url-delete-temp-file (&optional temp-file-name)
758 ;; Delete browse-url-temp-file-name from the file system
759 ;; If optional arg TEMP-FILE-NAME is non-nil, delete it instead
760 (let ((file-name (or temp-file-name browse-url-temp-file-name)))
761 (if (and file-name (file-exists-p file-name))
762 (delete-file file-name))))
763
764 (add-hook 'kill-buffer-hook 'browse-url-delete-temp-file)
765
766 (declare-function dired-get-filename "dired"
767 (&optional localp no-error-if-not-filep))
768
769 ;;;###autoload
770 (defun browse-url-of-dired-file ()
771 "In Dired, ask a WWW browser to display the file named on this line."
772 (interactive)
773 (browse-url-of-file (dired-get-filename)))
774
775 ;;;###autoload
776 (defun browse-url-of-region (min max)
777 "Ask a WWW browser to display the current region."
778 (interactive "r")
779 (save-excursion
780 (save-restriction
781 (narrow-to-region min max)
782 (browse-url-of-buffer))))
783
784 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
785 ;; Browser-independent commands
786
787 ;; A generic command to call the current browse-url-browser-function
788
789 ;;;###autoload
790 (defun browse-url (url &rest args)
791 "Ask a WWW browser to load URL.
792 Prompts for a URL, defaulting to the URL at or before point. Variable
793 `browse-url-browser-function' says which browser to use.
794 If the URL is a mailto: URL, consult `browse-url-mailto-function'
795 first, if that exists."
796 (interactive (browse-url-interactive-arg "URL: "))
797 (unless (called-interactively-p 'interactive)
798 (setq args (or args (list browse-url-new-window-flag))))
799 (let ((process-environment (copy-sequence process-environment))
800 (function (or (and (string-match "\\`mailto:" url)
801 browse-url-mailto-function)
802 browse-url-browser-function)))
803 ;; When connected to various displays, be careful to use the display of
804 ;; the currently selected frame, rather than the original start display,
805 ;; which may not even exist any more.
806 (if (stringp (frame-parameter (selected-frame) 'display))
807 (setenv "DISPLAY" (frame-parameter (selected-frame) 'display)))
808 (if (and (consp function)
809 (not (functionp function)))
810 ;; The `function' can be an alist; look down it for first match
811 ;; and apply the function (which might be a lambda).
812 (catch 'done
813 (dolist (bf function)
814 (when (string-match (car bf) url)
815 (apply (cdr bf) url args)
816 (throw 'done t)))
817 (error "No browse-url-browser-function matching URL %s"
818 url))
819 ;; Unbound symbols go down this leg, since void-function from
820 ;; apply is clearer than wrong-type-argument from dolist.
821 (apply function url args))))
822
823 ;;;###autoload
824 (defun browse-url-at-point (&optional arg)
825 "Ask a WWW browser to load the URL at or before point.
826 Doesn't let you edit the URL like `browse-url'. Variable
827 `browse-url-browser-function' says which browser to use."
828 (interactive "P")
829 (let ((url (browse-url-url-at-point)))
830 (if url
831 (browse-url url (if arg
832 (not browse-url-new-window-flag)
833 browse-url-new-window-flag))
834 (error "No URL found"))))
835
836 ;;;###autoload
837 (defun browse-url-at-mouse (event)
838 "Ask a WWW browser to load a URL clicked with the mouse.
839 The URL is the one around or before the position of the mouse click
840 but point is not changed. Doesn't let you edit the URL like
841 `browse-url'. Variable `browse-url-browser-function' says which browser
842 to use."
843 (interactive "e")
844 (save-excursion
845 (mouse-set-point event)
846 ;; This handles browse-url-new-window-flag properly
847 ;; when it gets no arg.
848 (browse-url-at-point)))
849
850 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
851 ;; Browser-specific commands
852
853 ;; --- Default MS-Windows browser ---
854
855 (defvar dos-windows-version)
856 (declare-function w32-shell-execute "w32fns.c") ;; Defined in C.
857
858 (defun browse-url-default-windows-browser (url &optional new-window)
859 (interactive (browse-url-interactive-arg "URL: "))
860 (cond ((eq system-type 'ms-dos)
861 (if dos-windows-version
862 (shell-command (concat "start " (shell-quote-argument url)))
863 (error "Browsing URLs is not supported on this system")))
864 ((eq system-type 'cygwin)
865 (call-process "cygstart" nil nil nil url))
866 (t (w32-shell-execute "open" url))))
867
868 (defun browse-url-default-macosx-browser (url &optional new-window)
869 (interactive (browse-url-interactive-arg "URL: "))
870 (start-process (concat "open " url) nil "open" url))
871
872 ;; --- Netscape ---
873
874 (defun browse-url-process-environment ()
875 "Set DISPLAY in the environment to the X display the browser will use.
876 This is either the value of variable `browse-url-browser-display' if
877 non-nil, or the same display as Emacs if different from the current
878 environment, otherwise just use the current environment."
879 (let ((display (or browse-url-browser-display (browse-url-emacs-display))))
880 (if display
881 (cons (concat "DISPLAY=" display) process-environment)
882 process-environment)))
883
884 (defun browse-url-emacs-display ()
885 "Return the X display Emacs is running on.
886 This is nil if the display is the same as the DISPLAY environment variable.
887
888 Actually Emacs could be using several displays; this just returns the
889 one showing the selected frame."
890 (let ((display (cdr-safe (assq 'display (frame-parameters)))))
891 (and (not (equal display (getenv "DISPLAY")))
892 display)))
893
894 (defun browse-url-default-browser (url &rest args)
895 "Find a suitable browser and ask it to load URL.
896 Default to the URL around or before point.
897
898 When called interactively, if variable `browse-url-new-window-flag' is
899 non-nil, load the document in a new window, if possible, otherwise use
900 a random existing one. A non-nil interactive prefix argument reverses
901 the effect of `browse-url-new-window-flag'.
902
903 When called non-interactively, optional second argument NEW-WINDOW is
904 used instead of `browse-url-new-window-flag'.
905
906 The order attempted is gnome-moz-remote, Mozilla, Firefox,
907 Galeon, Konqueror, Netscape, Mosaic, Lynx in an xterm, and then W3."
908 (apply
909 (cond
910 ((browse-url-can-use-xdg-open) 'browse-url-xdg-open)
911 ((executable-find browse-url-gnome-moz-program) 'browse-url-gnome-moz)
912 ((executable-find browse-url-mozilla-program) 'browse-url-mozilla)
913 ((executable-find browse-url-firefox-program) 'browse-url-firefox)
914 ((executable-find browse-url-galeon-program) 'browse-url-galeon)
915 ((executable-find browse-url-kde-program) 'browse-url-kde)
916 ((executable-find browse-url-netscape-program) 'browse-url-netscape)
917 ((executable-find browse-url-mosaic-program) 'browse-url-mosaic)
918 ((executable-find browse-url-xterm-program) 'browse-url-text-xterm)
919 ((locate-library "w3") 'browse-url-w3)
920 (t
921 (lambda (&rest ignore) (error "No usable browser found"))))
922 url args))
923
924 (defun browse-url-can-use-xdg-open ()
925 "Check if xdg-open can be used, i.e. we are on Gnome, KDE or xfce4."
926 (and (getenv "DISPLAY")
927 (executable-find "xdg-open")
928 ;; xdg-open may call gnome-open and that does not wait for its child
929 ;; to finish. This child may then be killed when the parent dies.
930 ;; Use nohup to work around.
931 (executable-find "nohup")
932 (or (getenv "GNOME_DESKTOP_SESSION_ID")
933 ;; GNOME_DESKTOP_SESSION_ID is deprecated, check on Dbus also.
934 (condition-case nil
935 (eq 0 (call-process
936 "dbus-send" nil nil nil
937 "--dest=org.gnome.SessionManager"
938 "--print-reply"
939 "/org/gnome/SessionManager"
940 "org.gnome.SessionManager.CanShutdown"))
941 (error nil))
942 (equal (getenv "KDE_FULL_SESSION") "true")
943 (condition-case nil
944 (eq 0 (call-process
945 "/bin/sh" nil nil nil
946 "-c"
947 "xprop -root _DT_SAVE_MODE|grep xfce4"))
948 (error nil)))))
949
950
951 ;;;###autoload
952 (defun browse-url-xdg-open (url &optional new-window)
953 (interactive (browse-url-interactive-arg "URL: "))
954 (call-process "nohup" nil nil nil "xdg-open" url))
955
956 ;;;###autoload
957 (defun browse-url-netscape (url &optional new-window)
958 "Ask the Netscape WWW browser to load URL.
959 Default to the URL around or before point. The strings in variable
960 `browse-url-netscape-arguments' are also passed to Netscape.
961
962 When called interactively, if variable `browse-url-new-window-flag' is
963 non-nil, load the document in a new Netscape window, otherwise use a
964 random existing one. A non-nil interactive prefix argument reverses
965 the effect of `browse-url-new-window-flag'.
966
967 If `browse-url-netscape-new-window-is-tab' is non-nil, then
968 whenever a document would otherwise be loaded in a new window, it
969 is loaded in a new tab in an existing window instead.
970
971 When called non-interactively, optional second argument NEW-WINDOW is
972 used instead of `browse-url-new-window-flag'."
973 (interactive (browse-url-interactive-arg "URL: "))
974 (setq url (browse-url-encode-url url))
975 (let* ((process-environment (browse-url-process-environment))
976 (process
977 (apply 'start-process
978 (concat "netscape " url) nil
979 browse-url-netscape-program
980 (append
981 browse-url-netscape-arguments
982 (if (eq window-system 'w32)
983 (list url)
984 (append
985 (if new-window '("-noraise"))
986 (list "-remote"
987 (concat "openURL(" url
988 (if (browse-url-maybe-new-window
989 new-window)
990 (if browse-url-netscape-new-window-is-tab
991 ",new-tab"
992 ",new-window"))
993 ")"))))))))
994 (set-process-sentinel process
995 `(lambda (process change)
996 (browse-url-netscape-sentinel process ,url)))))
997
998 (defun browse-url-netscape-sentinel (process url)
999 "Handle a change to the process communicating with Netscape."
1000 (or (eq (process-exit-status process) 0)
1001 (let* ((process-environment (browse-url-process-environment)))
1002 ;; Netscape not running - start it
1003 (message "Starting %s..." browse-url-netscape-program)
1004 (apply 'start-process (concat "netscape" url) nil
1005 browse-url-netscape-program
1006 (append browse-url-netscape-startup-arguments (list url))))))
1007
1008 (defun browse-url-netscape-reload ()
1009 "Ask Netscape to reload its current document.
1010 How depends on `browse-url-netscape-version'."
1011 (interactive)
1012 ;; Backwards incompatibility reported by
1013 ;; <peter.kruse@psychologie.uni-regensburg.de>.
1014 (browse-url-netscape-send (if (>= browse-url-netscape-version 4)
1015 "xfeDoCommand(reload)"
1016 "reload")))
1017
1018 (defun browse-url-netscape-send (command)
1019 "Send a remote control command to Netscape."
1020 (let* ((process-environment (browse-url-process-environment)))
1021 (apply 'start-process "netscape" nil
1022 browse-url-netscape-program
1023 (append browse-url-netscape-arguments
1024 (list "-remote" command)))))
1025
1026 ;;;###autoload
1027 (defun browse-url-mozilla (url &optional new-window)
1028 "Ask the Mozilla WWW browser to load URL.
1029 Default to the URL around or before point. The strings in variable
1030 `browse-url-mozilla-arguments' are also passed to Mozilla.
1031
1032 When called interactively, if variable `browse-url-new-window-flag' is
1033 non-nil, load the document in a new Mozilla window, otherwise use a
1034 random existing one. A non-nil interactive prefix argument reverses
1035 the effect of `browse-url-new-window-flag'.
1036
1037 If `browse-url-mozilla-new-window-is-tab' is non-nil, then whenever a
1038 document would otherwise be loaded in a new window, it is loaded in a
1039 new tab in an existing window instead.
1040
1041 When called non-interactively, optional second argument NEW-WINDOW is
1042 used instead of `browse-url-new-window-flag'."
1043 (interactive (browse-url-interactive-arg "URL: "))
1044 (setq url (browse-url-encode-url url))
1045 (let* ((process-environment (browse-url-process-environment))
1046 (process
1047 (apply 'start-process
1048 (concat "mozilla " url) nil
1049 browse-url-mozilla-program
1050 (append
1051 browse-url-mozilla-arguments
1052 (list "-remote"
1053 (concat "openURL("
1054 url
1055 (if (browse-url-maybe-new-window
1056 new-window)
1057 (if browse-url-mozilla-new-window-is-tab
1058 ",new-tab"
1059 ",new-window"))
1060 ")"))))))
1061 (set-process-sentinel process
1062 `(lambda (process change)
1063 (browse-url-mozilla-sentinel process ,url)))))
1064
1065 (defun browse-url-mozilla-sentinel (process url)
1066 "Handle a change to the process communicating with Mozilla."
1067 (or (eq (process-exit-status process) 0)
1068 (let* ((process-environment (browse-url-process-environment)))
1069 ;; Mozilla is not running - start it
1070 (message "Starting %s..." browse-url-mozilla-program)
1071 (apply 'start-process (concat "mozilla " url) nil
1072 browse-url-mozilla-program
1073 (append browse-url-mozilla-startup-arguments (list url))))))
1074
1075 ;;;###autoload
1076 (defun browse-url-firefox (url &optional new-window)
1077 "Ask the Firefox WWW browser to load URL.
1078 Default to the URL around or before point. The strings in
1079 variable `browse-url-firefox-arguments' are also passed to
1080 Firefox.
1081
1082 When called interactively, if variable
1083 `browse-url-new-window-flag' is non-nil, load the document in a
1084 new Firefox window, otherwise use a random existing one. A
1085 non-nil interactive prefix argument reverses the effect of
1086 `browse-url-new-window-flag'.
1087
1088 If `browse-url-firefox-new-window-is-tab' is non-nil, then
1089 whenever a document would otherwise be loaded in a new window, it
1090 is loaded in a new tab in an existing window instead.
1091
1092 When called non-interactively, optional second argument
1093 NEW-WINDOW is used instead of `browse-url-new-window-flag'.
1094
1095 On MS-Windows systems the optional `new-window' parameter is
1096 ignored. Firefox for Windows does not support the \"-remote\"
1097 command line parameter. Therefore, the
1098 `browse-url-new-window-flag' and `browse-url-firefox-new-window-is-tab'
1099 are ignored as well. Firefox on Windows will always open the requested
1100 URL in a new window."
1101 (interactive (browse-url-interactive-arg "URL: "))
1102 (setq url (browse-url-encode-url url))
1103 (let* ((process-environment (browse-url-process-environment))
1104 (process
1105 (apply 'start-process
1106 (concat "firefox " url) nil
1107 browse-url-firefox-program
1108 (append
1109 browse-url-firefox-arguments
1110 (if (or (featurep 'dos-w32)
1111 (string-match "win32" system-configuration))
1112 (list url)
1113 (list "-remote"
1114 (concat "openURL("
1115 url
1116 (if (browse-url-maybe-new-window
1117 new-window)
1118 (if browse-url-firefox-new-window-is-tab
1119 ",new-tab"
1120 ",new-window"))
1121 ")")))))))
1122 (set-process-sentinel process
1123 `(lambda (process change)
1124 (browse-url-firefox-sentinel process ,url)))))
1125
1126 (defun browse-url-firefox-sentinel (process url)
1127 "Handle a change to the process communicating with Firefox."
1128 (or (eq (process-exit-status process) 0)
1129 (let* ((process-environment (browse-url-process-environment)))
1130 ;; Firefox is not running - start it
1131 (message "Starting Firefox...")
1132 (apply 'start-process (concat "firefox " url) nil
1133 browse-url-firefox-program
1134 (append browse-url-firefox-startup-arguments (list url))))))
1135
1136 ;;;###autoload
1137 (defun browse-url-galeon (url &optional new-window)
1138 "Ask the Galeon WWW browser to load URL.
1139 Default to the URL around or before point. The strings in variable
1140 `browse-url-galeon-arguments' are also passed to Galeon.
1141
1142 When called interactively, if variable `browse-url-new-window-flag' is
1143 non-nil, load the document in a new Galeon window, otherwise use a
1144 random existing one. A non-nil interactive prefix argument reverses
1145 the effect of `browse-url-new-window-flag'.
1146
1147 If `browse-url-galeon-new-window-is-tab' is non-nil, then whenever a
1148 document would otherwise be loaded in a new window, it is loaded in a
1149 new tab in an existing window instead.
1150
1151 When called non-interactively, optional second argument NEW-WINDOW is
1152 used instead of `browse-url-new-window-flag'."
1153 (interactive (browse-url-interactive-arg "URL: "))
1154 (setq url (browse-url-encode-url url))
1155 (let* ((process-environment (browse-url-process-environment))
1156 (process (apply 'start-process
1157 (concat "galeon " url)
1158 nil
1159 browse-url-galeon-program
1160 (append
1161 browse-url-galeon-arguments
1162 (if (browse-url-maybe-new-window new-window)
1163 (if browse-url-galeon-new-window-is-tab
1164 '("--new-tab")
1165 '("--new-window" "--noraise"))
1166 '("--existing"))
1167 (list url)))))
1168 (set-process-sentinel process
1169 `(lambda (process change)
1170 (browse-url-galeon-sentinel process ,url)))))
1171
1172 (defun browse-url-galeon-sentinel (process url)
1173 "Handle a change to the process communicating with Galeon."
1174 (or (eq (process-exit-status process) 0)
1175 (let* ((process-environment (browse-url-process-environment)))
1176 ;; Galeon is not running - start it
1177 (message "Starting %s..." browse-url-galeon-program)
1178 (apply 'start-process (concat "galeon " url) nil
1179 browse-url-galeon-program
1180 (append browse-url-galeon-startup-arguments (list url))))))
1181
1182 (defun browse-url-epiphany (url &optional new-window)
1183 "Ask the Epiphany WWW browser to load URL.
1184 Default to the URL around or before point. The strings in variable
1185 `browse-url-galeon-arguments' are also passed to Epiphany.
1186
1187 When called interactively, if variable `browse-url-new-window-flag' is
1188 non-nil, load the document in a new Epiphany window, otherwise use a
1189 random existing one. A non-nil interactive prefix argument reverses
1190 the effect of `browse-url-new-window-flag'.
1191
1192 If `browse-url-epiphany-new-window-is-tab' is non-nil, then whenever a
1193 document would otherwise be loaded in a new window, it is loaded in a
1194 new tab in an existing window instead.
1195
1196 When called non-interactively, optional second argument NEW-WINDOW is
1197 used instead of `browse-url-new-window-flag'."
1198 (interactive (browse-url-interactive-arg "URL: "))
1199 (setq url (browse-url-encode-url url))
1200 (let* ((process-environment (browse-url-process-environment))
1201 (process (apply 'start-process
1202 (concat "epiphany " url)
1203 nil
1204 browse-url-epiphany-program
1205 (append
1206 browse-url-epiphany-arguments
1207 (if (browse-url-maybe-new-window new-window)
1208 (if browse-url-epiphany-new-window-is-tab
1209 '("--new-tab")
1210 '("--new-window" "--noraise"))
1211 '("--existing"))
1212 (list url)))))
1213 (set-process-sentinel process
1214 `(lambda (process change)
1215 (browse-url-epiphany-sentinel process ,url)))))
1216
1217 (defun browse-url-epiphany-sentinel (process url)
1218 "Handle a change to the process communicating with Epiphany."
1219 (or (eq (process-exit-status process) 0)
1220 (let* ((process-environment (browse-url-process-environment)))
1221 ;; Epiphany is not running - start it
1222 (message "Starting %s..." browse-url-epiphany-program)
1223 (apply 'start-process (concat "epiphany " url) nil
1224 browse-url-epiphany-program
1225 (append browse-url-epiphany-startup-arguments (list url))))))
1226
1227 (defvar url-handler-regexp)
1228
1229 ;;;###autoload
1230 (defun browse-url-emacs (url &optional new-window)
1231 "Ask Emacs to load URL into a buffer and show it in another window."
1232 (interactive (browse-url-interactive-arg "URL: "))
1233 (require 'url-handlers)
1234 (let ((file-name-handler-alist
1235 (cons (cons url-handler-regexp 'url-file-handler)
1236 file-name-handler-alist)))
1237 ;; Ignore `new-window': with all other browsers the URL is always shown
1238 ;; in another window than the current Emacs one since it's shown in
1239 ;; another application's window.
1240 ;; (if new-window (find-file-other-window url) (find-file url))
1241 (find-file-other-window url)))
1242
1243 ;;;###autoload
1244 (defun browse-url-gnome-moz (url &optional new-window)
1245 "Ask Mozilla/Netscape to load URL via the GNOME program `gnome-moz-remote'.
1246 Default to the URL around or before point. The strings in variable
1247 `browse-url-gnome-moz-arguments' are also passed.
1248
1249 When called interactively, if variable `browse-url-new-window-flag' is
1250 non-nil, load the document in a new browser window, otherwise use an
1251 existing one. A non-nil interactive prefix argument reverses the
1252 effect of `browse-url-new-window-flag'.
1253
1254 When called non-interactively, optional second argument NEW-WINDOW is
1255 used instead of `browse-url-new-window-flag'."
1256 (interactive (browse-url-interactive-arg "URL: "))
1257 (apply 'start-process (concat "gnome-moz-remote " url)
1258 nil
1259 browse-url-gnome-moz-program
1260 (append
1261 browse-url-gnome-moz-arguments
1262 (if (browse-url-maybe-new-window new-window)
1263 '("--newwin"))
1264 (list "--raise" url))))
1265
1266 ;; --- Mosaic ---
1267
1268 ;;;###autoload
1269 (defun browse-url-mosaic (url &optional new-window)
1270 "Ask the XMosaic WWW browser to load URL.
1271
1272 Default to the URL around or before point. The strings in variable
1273 `browse-url-mosaic-arguments' are also passed to Mosaic and the
1274 program is invoked according to the variable
1275 `browse-url-mosaic-program'.
1276
1277 When called interactively, if variable `browse-url-new-window-flag' is
1278 non-nil, load the document in a new Mosaic window, otherwise use a
1279 random existing one. A non-nil interactive prefix argument reverses
1280 the effect of `browse-url-new-window-flag'.
1281
1282 When called non-interactively, optional second argument NEW-WINDOW is
1283 used instead of `browse-url-new-window-flag'."
1284 (interactive (browse-url-interactive-arg "Mosaic URL: "))
1285 (let ((pidfile (expand-file-name browse-url-mosaic-pidfile))
1286 pid)
1287 (if (file-readable-p pidfile)
1288 (save-excursion
1289 (find-file pidfile)
1290 (goto-char (point-min))
1291 (setq pid (read (current-buffer)))
1292 (kill-buffer nil)))
1293 (if (and pid (zerop (signal-process pid 0))) ; Mosaic running
1294 (save-excursion
1295 (find-file (format "/tmp/Mosaic.%d" pid))
1296 (erase-buffer)
1297 (insert (if (browse-url-maybe-new-window new-window)
1298 "newwin\n"
1299 "goto\n")
1300 url "\n")
1301 (save-buffer)
1302 (kill-buffer nil)
1303 ;; Send signal SIGUSR to Mosaic
1304 (message "Signaling Mosaic...")
1305 (signal-process pid 'SIGUSR1)
1306 ;; Or you could try:
1307 ;; (call-process "kill" nil 0 nil "-USR1" (int-to-string pid))
1308 (message "Signaling Mosaic...done")
1309 )
1310 ;; Mosaic not running - start it
1311 (message "Starting %s..." browse-url-mosaic-program)
1312 (apply 'start-process "xmosaic" nil browse-url-mosaic-program
1313 (append browse-url-mosaic-arguments (list url)))
1314 (message "Starting %s...done" browse-url-mosaic-program))))
1315
1316 ;; --- Mosaic using CCI ---
1317
1318 ;;;###autoload
1319 (defun browse-url-cci (url &optional new-window)
1320 "Ask the XMosaic WWW browser to load URL.
1321 Default to the URL around or before point.
1322
1323 This function only works for XMosaic version 2.5 or later. You must
1324 select `CCI' from XMosaic's File menu, set the CCI Port Address to the
1325 value of variable `browse-url-CCI-port', and enable `Accept requests'.
1326
1327 When called interactively, if variable `browse-url-new-window-flag' is
1328 non-nil, load the document in a new browser window, otherwise use a
1329 random existing one. A non-nil interactive prefix argument reverses
1330 the effect of `browse-url-new-window-flag'.
1331
1332 When called non-interactively, optional second argument NEW-WINDOW is
1333 used instead of `browse-url-new-window-flag'."
1334 (interactive (browse-url-interactive-arg "Mosaic URL: "))
1335 (open-network-stream "browse-url" " *browse-url*"
1336 browse-url-CCI-host browse-url-CCI-port)
1337 ;; Todo: start browser if fails
1338 (process-send-string "browse-url"
1339 (concat "get url (" url ") output "
1340 (if (browse-url-maybe-new-window new-window)
1341 "new"
1342 "current")
1343 "\r\n"))
1344 (process-send-string "browse-url" "disconnect\r\n")
1345 (delete-process "browse-url"))
1346
1347 ;; --- W3 ---
1348
1349 ;; External.
1350 (declare-function w3-fetch-other-window "ext:w3m" (&optional url))
1351 (declare-function w3-fetch "ext:w3m" (&optional url target))
1352
1353 ;;;###autoload
1354 (defun browse-url-w3 (url &optional new-window)
1355 "Ask the w3 WWW browser to load URL.
1356 Default to the URL around or before point.
1357
1358 When called interactively, if variable `browse-url-new-window-flag' is
1359 non-nil, load the document in a new window. A non-nil interactive
1360 prefix argument reverses the effect of `browse-url-new-window-flag'.
1361
1362 When called non-interactively, optional second argument NEW-WINDOW is
1363 used instead of `browse-url-new-window-flag'."
1364 (interactive (browse-url-interactive-arg "W3 URL: "))
1365 (require 'w3) ; w3-fetch-other-window not autoloaded
1366 (if (browse-url-maybe-new-window new-window)
1367 (w3-fetch-other-window url)
1368 (w3-fetch url)))
1369
1370 ;;;###autoload
1371 (defun browse-url-w3-gnudoit (url &optional new-window)
1372 ;; new-window ignored
1373 "Ask another Emacs running gnuserv to load the URL using the W3 browser.
1374 The `browse-url-gnudoit-program' program is used with options given by
1375 `browse-url-gnudoit-args'. Default to the URL around or before point."
1376 (interactive (browse-url-interactive-arg "W3 URL: "))
1377 (apply 'start-process (concat "gnudoit:" url) nil
1378 browse-url-gnudoit-program
1379 (append browse-url-gnudoit-args
1380 (list (concat "(w3-fetch \"" url "\")")
1381 "(raise-frame)"))))
1382
1383 ;; --- Lynx in an xterm ---
1384
1385 ;;;###autoload
1386 (defun browse-url-text-xterm (url &optional new-window)
1387 ;; new-window ignored
1388 "Ask a text browser to load URL.
1389 URL defaults to the URL around or before point.
1390 This runs the text browser specified by `browse-url-text-browser'.
1391 in an Xterm window using the Xterm program named by `browse-url-xterm-program'
1392 with possible additional arguments `browse-url-xterm-args'."
1393 (interactive (browse-url-interactive-arg "Text browser URL: "))
1394 (apply #'start-process `(,(concat browse-url-text-browser url)
1395 nil ,browse-url-xterm-program
1396 ,@browse-url-xterm-args "-e" ,browse-url-text-browser
1397 ,url)))
1398
1399 ;; --- Lynx in an Emacs "term" window ---
1400
1401 (declare-function term-char-mode "term" ())
1402 (declare-function term-send-down "term" ())
1403 (declare-function term-send-string "term" (proc str))
1404
1405 ;;;###autoload
1406 (defun browse-url-text-emacs (url &optional new-buffer)
1407 "Ask a text browser to load URL.
1408 URL defaults to the URL around or before point.
1409 This runs the text browser specified by `browse-url-text-browser'.
1410 With a prefix argument, it runs a new browser process in a new buffer.
1411
1412 When called interactively, if variable `browse-url-new-window-flag' is
1413 non-nil, load the document in a new browser process in a new term window,
1414 otherwise use any existing one. A non-nil interactive prefix argument
1415 reverses the effect of `browse-url-new-window-flag'.
1416
1417 When called non-interactively, optional second argument NEW-WINDOW is
1418 used instead of `browse-url-new-window-flag'."
1419 (interactive (browse-url-interactive-arg "Text browser URL: "))
1420 (let* ((system-uses-terminfo t) ; Lynx uses terminfo
1421 ;; (term-term-name "vt100") ; ??
1422 (buf (get-buffer "*text browser*"))
1423 (proc (and buf (get-buffer-process buf)))
1424 (n browse-url-text-input-attempts))
1425 (require 'term)
1426 (if (and (browse-url-maybe-new-window new-buffer) buf)
1427 ;; Rename away the OLD buffer. This isn't very polite, but
1428 ;; term insists on working in a buffer named *lynx* and would
1429 ;; choke on *lynx*<1>
1430 (progn (set-buffer buf)
1431 (rename-uniquely)))
1432 (if (or (browse-url-maybe-new-window new-buffer)
1433 (not buf)
1434 (not proc)
1435 (not (memq (process-status proc) '(run stop))))
1436 ;; start a new text browser
1437 (progn
1438 (setq buf
1439 (apply #'make-term
1440 `(,browse-url-text-browser
1441 ,browse-url-text-browser
1442 nil ,@browse-url-text-emacs-args
1443 ,url)))
1444 (switch-to-buffer buf)
1445 (term-char-mode)
1446 (set-process-sentinel
1447 (get-buffer-process buf)
1448 ;; Don't leave around a dead one (especially because of its
1449 ;; munged keymap.)
1450 (lambda (process event)
1451 (if (not (memq (process-status process) '(run stop)))
1452 (let ((buf (process-buffer process)))
1453 (if buf (kill-buffer buf)))))))
1454 ;; Send the url to the text browser in the old buffer
1455 (let ((win (get-buffer-window buf t)))
1456 (if win
1457 (select-window win)
1458 (switch-to-buffer buf)))
1459 (if (eq (following-char) ?_)
1460 (cond ((eq browse-url-text-input-field 'warn)
1461 (error "Please move out of the input field first"))
1462 ((eq browse-url-text-input-field 'avoid)
1463 (while (and (eq (following-char) ?_) (> n 0))
1464 (term-send-down) ; down arrow
1465 (sit-for browse-url-text-input-delay))
1466 (if (eq (following-char) ?_)
1467 (error "Cannot move out of the input field, sorry")))))
1468 (term-send-string proc (concat "g" ; goto
1469 "\C-u" ; kill default url
1470 url
1471 "\r")))))
1472
1473 ;; --- mailto ---
1474
1475 (autoload 'rfc2368-parse-mailto-url "rfc2368")
1476
1477 ;;;###autoload
1478 (defun browse-url-mail (url &optional new-window)
1479 "Open a new mail message buffer within Emacs for the RFC 2368 URL.
1480 Default to using the mailto: URL around or before point as the
1481 recipient's address. Supplying a non-nil interactive prefix argument
1482 will cause the mail to be composed in another window rather than the
1483 current one.
1484
1485 When called interactively, if variable `browse-url-new-window-flag' is
1486 non-nil use `compose-mail-other-window', otherwise `compose-mail'. A
1487 non-nil interactive prefix argument reverses the effect of
1488 `browse-url-new-window-flag'.
1489
1490 When called non-interactively, optional second argument NEW-WINDOW is
1491 used instead of `browse-url-new-window-flag'."
1492 (interactive (browse-url-interactive-arg "Mailto URL: "))
1493 (save-excursion
1494 (let* ((alist (rfc2368-parse-mailto-url url))
1495 (to (assoc "To" alist))
1496 (subject (assoc "Subject" alist))
1497 (body (assoc "Body" alist))
1498 (rest (delq to (delq subject (delq body alist))))
1499 (to (cdr to))
1500 (subject (cdr subject))
1501 (body (cdr body))
1502 (mail-citation-hook (unless body mail-citation-hook)))
1503 (if (browse-url-maybe-new-window new-window)
1504 (compose-mail-other-window to subject rest nil
1505 (list 'insert-buffer (current-buffer)))
1506 (compose-mail to subject rest nil nil
1507 (list 'insert-buffer (current-buffer))))
1508 (when body
1509 (goto-char (point-min))
1510 (unless (or (search-forward (concat "\n" mail-header-separator "\n")
1511 nil 'move)
1512 (bolp))
1513 (insert "\n"))
1514 (goto-char (prog1
1515 (point)
1516 (insert (replace-regexp-in-string "\r\n" "\n" body))
1517 (unless (bolp)
1518 (insert "\n"))))))))
1519
1520 ;; --- Random browser ---
1521
1522 ;;;###autoload
1523 (defun browse-url-generic (url &optional new-window)
1524 ;; new-window ignored
1525 "Ask the WWW browser defined by `browse-url-generic-program' to load URL.
1526 Default to the URL around or before point. A fresh copy of the
1527 browser is started up in a new process with possible additional arguments
1528 `browse-url-generic-args'. This is appropriate for browsers which
1529 don't offer a form of remote control."
1530 (interactive (browse-url-interactive-arg "URL: "))
1531 (if (not browse-url-generic-program)
1532 (error "No browser defined (`browse-url-generic-program')"))
1533 (apply 'call-process browse-url-generic-program nil
1534 0 nil
1535 (append browse-url-generic-args (list url))))
1536
1537 ;;;###autoload
1538 (defun browse-url-kde (url &optional new-window)
1539 "Ask the KDE WWW browser to load URL.
1540 Default to the URL around or before point."
1541 (interactive (browse-url-interactive-arg "KDE URL: "))
1542 (message "Sending URL to KDE...")
1543 (apply #'start-process (concat "KDE " url) nil browse-url-kde-program
1544 (append browse-url-kde-args (list url))))
1545
1546 (defun browse-url-elinks-new-window (url)
1547 "Ask the Elinks WWW browser to load URL in a new window."
1548 (let ((process-environment (browse-url-process-environment)))
1549 (apply #'start-process
1550 (append (list (concat "elinks:" url)
1551 nil)
1552 browse-url-elinks-wrapper
1553 (list "elinks" url)))))
1554
1555 ;;;###autoload
1556 (defun browse-url-elinks (url &optional new-window)
1557 "Ask the Elinks WWW browser to load URL.
1558 Default to the URL around the point.
1559
1560 The document is loaded in a new tab of a running Elinks or, if
1561 none yet running, a newly started instance.
1562
1563 The Elinks command will be prepended by the program+arguments
1564 from `browse-url-elinks-wrapper'."
1565 (interactive (browse-url-interactive-arg "URL: "))
1566 (setq url (browse-url-encode-url url))
1567 (if new-window
1568 (browse-url-elinks-new-window url)
1569 (let ((process-environment (browse-url-process-environment))
1570 (elinks-ping-process (start-process "elinks-ping" nil
1571 "elinks" "-remote" "ping()")))
1572 (set-process-sentinel elinks-ping-process
1573 `(lambda (process change)
1574 (browse-url-elinks-sentinel process ,url))))))
1575
1576 (defun browse-url-elinks-sentinel (process url)
1577 "Determines if Elinks is running or a new one has to be started."
1578 (let ((exit-status (process-exit-status process)))
1579 ;; Try to determine if an instance is running or if we have to
1580 ;; create a new one.
1581 (case exit-status
1582 (5
1583 ;; No instance, start a new one.
1584 (browse-url-elinks-new-window url))
1585 (0
1586 ;; Found an instance, open URL in new tab.
1587 (let ((process-environment (browse-url-process-environment)))
1588 (start-process (concat "elinks:" url) nil
1589 "elinks" "-remote"
1590 (concat "openURL(\"" url "\",new-tab)"))))
1591 (otherwise
1592 (error "Unrecognized exit-code %d of process `elinks'"
1593 exit-status)))))
1594
1595 (provide 'browse-url)
1596
1597 ;;; browse-url.el ends here