Allow 'browse-url-emacs' to fetch URL in the selected window
[emacs.git] / lisp / net / net-utils.el
blobc9e80804bd39d1bca1253f0f742243af5cb1d83e
1 ;;; net-utils.el --- network functions
3 ;; Copyright (C) 1998-2018 Free Software Foundation, Inc.
5 ;; Author: Peter Breton <pbreton@cs.umb.edu>
6 ;; Created: Sun Mar 16 1997
7 ;; Keywords: network comm
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
24 ;;; Commentary:
27 ;; There are three main areas of functionality:
29 ;; * Wrap common network utility programs (ping, traceroute, netstat,
30 ;; nslookup, arp, route). Note that these wrappers are of the diagnostic
31 ;; functions of these programs only.
33 ;; * Implement some very basic protocols in Emacs Lisp (finger and whois)
35 ;; * Support connections to HOST/PORT, generally for debugging and the like.
36 ;; In other words, for doing much the same thing as "telnet HOST PORT", and
37 ;; then typing commands.
39 ;;; Code:
41 ;; On some systems, programs like ifconfig are not in normal user
42 ;; path, but rather in /sbin, /usr/sbin, etc (but non-root users can
43 ;; still use them for queries). Actually the trend these
44 ;; days is for /sbin to be a symlink to /usr/sbin, but we still need to
45 ;; search both for older systems.
46 (defun net-utils--executable-find-sbin (command)
47 "Return absolute name of COMMAND if found in an sbin directory."
48 (let ((exec-path '("/sbin" "/usr/sbin" "/usr/local/sbin")))
49 (executable-find command)))
51 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
52 ;; Customization Variables
53 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
55 (defgroup net-utils nil
56 "Network utility functions."
57 :prefix "net-utils-"
58 :group 'comm
59 :version "20.3")
61 (defcustom traceroute-program
62 (if (eq system-type 'windows-nt)
63 "tracert"
64 "traceroute")
65 "Program to trace network hops to a destination."
66 :group 'net-utils
67 :type 'string)
69 (defcustom traceroute-program-options nil
70 "Options for the traceroute program."
71 :group 'net-utils
72 :type '(repeat string))
74 (defcustom ping-program "ping"
75 "Program to send network test packets to a host."
76 :group 'net-utils
77 :type 'string)
79 ;; On GNU/Linux and Irix, the system's ping program seems to send packets
80 ;; indefinitely unless told otherwise
81 (defcustom ping-program-options
82 (and (eq system-type 'gnu/linux)
83 (list "-c" "4"))
84 "Options for the ping program.
85 These options can be used to limit how many ICMP packets are emitted."
86 :group 'net-utils
87 :type '(repeat string))
89 (defcustom ifconfig-program
90 (cond ((eq system-type 'windows-nt) "ipconfig")
91 ((executable-find "ifconfig") "ifconfig")
92 ((net-utils--executable-find-sbin "ifconfig"))
93 ((net-utils--executable-find-sbin "ip"))
94 (t "ip"))
95 "Program to print network configuration information."
96 :version "25.1" ; add ip
97 :group 'net-utils
98 :type 'string)
100 (defcustom ifconfig-program-options
101 (cond ((string-match "ipconfig\\'" ifconfig-program) '("/all"))
102 ((string-match "ifconfig\\'" ifconfig-program) '("-a"))
103 ((string-match "ip\\'" ifconfig-program) '("addr")))
104 "Options for the ifconfig program."
105 :version "25.1"
106 :set-after '(ifconfig-program)
107 :group 'net-utils
108 :type '(repeat string))
110 (defcustom iwconfig-program
111 (cond ((executable-find "iwconfig") "iwconfig")
112 ((net-utils--executable-find-sbin "iw") "iw")
113 (t "iw"))
114 "Program to print wireless network configuration information."
115 :group 'net-utils
116 :type 'string
117 :version "26.1")
119 (defcustom iwconfig-program-options
120 (cond ((string-match-p "iw\\'" iwconfig-program) (list "dev"))
121 (t nil))
122 "Options for the iwconfig program."
123 :group 'net-utils
124 :type '(repeat string)
125 :version "26.1")
127 (defcustom netstat-program
128 (cond ((executable-find "netstat") "netstat")
129 ((net-utils--executable-find-sbin "ss"))
130 (t "ss"))
131 "Program to print network statistics."
132 :group 'net-utils
133 :type 'string
134 :version "26.1")
136 (defcustom netstat-program-options
137 (list "-a")
138 "Options for the netstat program."
139 :group 'net-utils
140 :type '(repeat string))
142 (defcustom arp-program (or (net-utils--executable-find-sbin "arp") "arp")
143 "Program to print IP to address translation tables."
144 :group 'net-utils
145 :type 'string)
147 (defcustom arp-program-options
148 (list "-a")
149 "Options for the arp program."
150 :group 'net-utils
151 :type '(repeat string))
153 (defcustom route-program
154 (cond ((eq system-type 'windows-nt) "route")
155 ((executable-find "netstat") "netstat")
156 ((net-utils--executable-find-sbin "netstat"))
157 ((executable-find "ip") "ip")
158 ((net-utils--executable-find-sbin "ip"))
159 (t "ip"))
160 "Program to print routing tables."
161 :group 'net-utils
162 :type 'string
163 :version "26.1")
165 (defcustom route-program-options
166 (cond ((eq system-type 'windows-nt) (list "print"))
167 ((string-match-p "netstat\\'" route-program) (list "-r"))
168 (t (list "route")))
169 "Options for the route program."
170 :group 'net-utils
171 :type '(repeat string)
172 :version "26.1")
174 (defcustom nslookup-program "nslookup"
175 "Program to interactively query DNS information."
176 :group 'net-utils
177 :type 'string)
179 (defcustom nslookup-program-options nil
180 "Options for the nslookup program."
181 :group 'net-utils
182 :type '(repeat string))
184 (defcustom nslookup-prompt-regexp "^> "
185 "Regexp to match the nslookup prompt.
187 This variable is only used if the variable
188 `comint-use-prompt-regexp' is non-nil."
189 :group 'net-utils
190 :type 'regexp)
192 (defcustom dig-program "dig"
193 "Program to query DNS information."
194 :group 'net-utils
195 :type 'string)
197 (defcustom dig-program-options nil
198 "Options for the dig program."
199 :group 'net-utils
200 :type '(repeat string)
201 :version "26.1")
203 (defcustom ftp-program "ftp"
204 "Program to run to do FTP transfers."
205 :group 'net-utils
206 :type 'string)
208 (defcustom ftp-program-options nil
209 "Options for the ftp program."
210 :group 'net-utils
211 :type '(repeat string))
213 (defcustom ftp-prompt-regexp "^ftp>"
214 "Regexp which matches the FTP program's prompt.
216 This variable is only used if the variable
217 `comint-use-prompt-regexp' is non-nil."
218 :group 'net-utils
219 :type 'regexp)
221 (defcustom smbclient-program "smbclient"
222 "Smbclient program."
223 :group 'net-utils
224 :type 'string)
226 (defcustom smbclient-program-options nil
227 "Options for the smbclient program."
228 :group 'net-utils
229 :type '(repeat string))
231 (defcustom smbclient-prompt-regexp "^smb: >"
232 "Regexp which matches the smbclient program's prompt.
234 This variable is only used if the variable
235 `comint-use-prompt-regexp' is non-nil."
236 :group 'net-utils
237 :type 'regexp)
239 (defcustom dns-lookup-program "host"
240 "Program to interactively query DNS information."
241 :group 'net-utils
242 :type 'string)
244 (defcustom dns-lookup-program-options nil
245 "Options for the dns-lookup program."
246 :group 'net-utils
247 :type '(repeat string))
249 ;; Internal variables
250 (defvar network-connection-service nil)
251 (defvar network-connection-host nil)
253 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
254 ;; Nslookup goodies
255 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
257 (defvar nslookup-font-lock-keywords
258 (list
259 (list "^[A-Za-z0-9 _]+:" 0 'font-lock-type-face)
260 (list "\\<\\(SOA\\|NS\\|MX\\|A\\|CNAME\\)\\>"
261 1 'font-lock-keyword-face)
262 ;; Dotted quads
263 (list
264 (mapconcat 'identity
265 (make-list 4 "[0-9]+")
266 "\\.")
267 0 'font-lock-variable-name-face)
268 ;; Host names
269 (list
270 (let ((host-expression "[-A-Za-z0-9]+"))
271 (concat
272 (mapconcat 'identity
273 (make-list 2 host-expression)
274 "\\.")
275 "\\(\\." host-expression "\\)*"))
276 0 'font-lock-variable-name-face))
277 "Expressions to font-lock for nslookup.")
279 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
280 ;; General network utilities mode
281 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
283 (defvar net-utils-font-lock-keywords
284 (list
285 ;; Dotted quads
286 (list
287 (mapconcat 'identity (make-list 4 "[0-9]+") "\\.")
288 0 'font-lock-variable-name-face)
289 ;; Simple rfc4291 addresses
290 (list (concat
291 "\\( \\([[:xdigit:]]+\\(:\\|::\\)\\)+[[:xdigit:]]+\\)"
292 "\\|"
293 "\\(::[[:xdigit:]]+\\)")
294 0 'font-lock-variable-name-face)
295 ;; Host names
296 (list
297 (let ((host-expression "[-A-Za-z0-9]+"))
298 (concat
299 (mapconcat 'identity (make-list 2 host-expression) "\\.")
300 "\\(\\." host-expression "\\)*"))
301 0 'font-lock-variable-name-face))
302 "Expressions to font-lock for general network utilities.")
304 (define-derived-mode net-utils-mode special-mode "NetworkUtil"
305 "Major mode for interacting with an external network utility."
306 (set (make-local-variable 'font-lock-defaults)
307 '((net-utils-font-lock-keywords)))
308 (setq-local revert-buffer-function #'net-utils--revert-function))
310 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
311 ;; Utility functions
312 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
314 ;; Simplified versions of some at-point functions from ffap.el.
315 ;; It's not worth loading all of ffap just for these.
316 (defun net-utils-machine-at-point ()
317 (let ((pt (point)))
318 (buffer-substring-no-properties
319 (save-excursion
320 (skip-chars-backward "-a-zA-Z0-9.")
321 (point))
322 (save-excursion
323 (skip-chars-forward "-a-zA-Z0-9.")
324 (skip-chars-backward "." pt)
325 (point)))))
327 (defun net-utils-url-at-point ()
328 (let ((pt (point)))
329 (buffer-substring-no-properties
330 (save-excursion
331 (skip-chars-backward "--:=&?$+@-Z_a-z~#,%")
332 (skip-chars-forward "^A-Za-z0-9" pt)
333 (point))
334 (save-excursion
335 (skip-chars-forward "--:=&?$+@-Z_a-z~#,%")
336 (skip-chars-backward ":;.,!?" pt)
337 (point)))))
339 (defun net-utils-remove-ctrl-m-filter (process output-string)
340 "Remove trailing control Ms."
341 (with-current-buffer (process-buffer process)
342 (save-excursion
343 (let ((inhibit-read-only t)
344 (filtered-string output-string))
345 (while (string-match "\r" filtered-string)
346 (setq filtered-string
347 (replace-match "" nil nil filtered-string)))
348 ;; Insert the text, moving the process-marker.
349 (goto-char (process-mark process))
350 (insert filtered-string)
351 (set-marker (process-mark process) (point))))))
353 (declare-function w32-get-console-output-codepage "w32proc.c" ())
355 (defun net-utils-run-program (name header program args)
356 "Run a network information program."
357 (let ((buf (get-buffer-create (concat "*" name "*")))
358 (coding-system-for-read
359 ;; MS-Windows versions of network utilities output text
360 ;; encoded in the console (a.k.a. "OEM") codepage, which is
361 ;; different from the default system (a.k.a. "ANSI")
362 ;; codepage.
363 (if (eq system-type 'windows-nt)
364 (intern (format "cp%d" (w32-get-console-output-codepage)))
365 coding-system-for-read)))
366 (set-buffer buf)
367 (erase-buffer)
368 (insert header "\n")
369 (set-process-filter
370 (apply 'start-process name buf program args)
371 'net-utils-remove-ctrl-m-filter)
372 (display-buffer buf)
373 buf))
375 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
376 ;; General network utilities (diagnostic)
377 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
379 ;; Todo: This data could be saved in a bookmark.
380 (defvar net-utils--revert-cmd nil)
382 (defun net-utils-run-simple (buffer program-name args &optional nodisplay)
383 "Run a network utility for diagnostic output only."
384 (with-current-buffer (if (stringp buffer) (get-buffer-create buffer) buffer)
385 (let ((proc (get-buffer-process (current-buffer))))
386 (when proc
387 (set-process-filter proc nil)
388 (delete-process proc)))
389 (let ((inhibit-read-only t)
390 (coding-system-for-read
391 ;; MS-Windows versions of network utilities output text
392 ;; encoded in the console (a.k.a. "OEM") codepage, which is
393 ;; different from the default system (a.k.a. "ANSI")
394 ;; codepage.
395 (if (eq system-type 'windows-nt)
396 (intern (format "cp%d" (w32-get-console-output-codepage)))
397 coding-system-for-read)))
398 (erase-buffer))
399 (net-utils-mode)
400 (setq-local net-utils--revert-cmd
401 `(net-utils-run-simple ,(current-buffer)
402 ,program-name ,args nodisplay))
403 (set-process-filter
404 (apply 'start-process program-name
405 (current-buffer) program-name args)
406 'net-utils-remove-ctrl-m-filter)
407 (unless nodisplay (display-buffer (current-buffer)))))
409 (defun net-utils--revert-function (&optional ignore-auto noconfirm)
410 (message "Reverting `%s'..." (buffer-name))
411 (apply (car net-utils--revert-cmd) (cdr net-utils--revert-cmd))
412 (let ((proc (get-buffer-process (current-buffer))))
413 (when proc
414 (set-process-sentinel
415 proc
416 (lambda (process event)
417 (when (string= event "finished\n")
418 (message "Reverting `%s' done" (process-buffer process))))))))
420 ;;;###autoload
421 (defun ifconfig ()
422 "Run `ifconfig-program' and display diagnostic output."
423 (interactive)
424 (net-utils-run-simple
425 (format "*%s*" ifconfig-program)
426 ifconfig-program
427 ifconfig-program-options))
429 (defalias 'ipconfig 'ifconfig)
431 ;;;###autoload
432 (defun iwconfig ()
433 "Run `iwconfig-program' and display diagnostic output."
434 (interactive)
435 (net-utils-run-simple
436 (format "*%s*" iwconfig-program)
437 iwconfig-program
438 iwconfig-program-options))
440 ;;;###autoload
441 (defun netstat ()
442 "Run `netstat-program' and display diagnostic output."
443 (interactive)
444 (net-utils-run-simple
445 (format "*%s*" netstat-program)
446 netstat-program
447 netstat-program-options))
449 ;;;###autoload
450 (defun arp ()
451 "Run `arp-program' and display diagnostic output."
452 (interactive)
453 (net-utils-run-simple
454 (format "*%s*" arp-program)
455 arp-program
456 arp-program-options))
458 ;;;###autoload
459 (defun route ()
460 "Run `route-program' and display diagnostic output."
461 (interactive)
462 (net-utils-run-simple
463 (format "*%s*" route-program)
464 route-program
465 route-program-options))
467 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
468 ;; Wrappers for external network programs
469 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
471 ;;;###autoload
472 (defun traceroute (target)
473 "Run `traceroute-program' for TARGET."
474 (interactive "sTarget: ")
475 (let ((options
476 (if traceroute-program-options
477 (append traceroute-program-options (list target))
478 (list target))))
479 (net-utils-run-simple
480 (concat "Traceroute" " " target)
481 traceroute-program
482 options)))
484 ;;;###autoload
485 (defun ping (host)
486 "Ping HOST.
487 If your system's ping continues until interrupted, you can try setting
488 `ping-program-options'."
489 (interactive
490 (list (read-from-minibuffer "Ping host: " (net-utils-machine-at-point))))
491 (let ((options
492 (if ping-program-options
493 (append ping-program-options (list host))
494 (list host))))
495 (net-utils-run-program
496 (concat "Ping" " " host)
497 (concat "** Ping ** " ping-program " ** " host)
498 ping-program
499 options)))
501 ;; FIXME -- Needs to be a process filter
502 ;; (defun netstat-with-filter (filter)
503 ;; "Run netstat program."
504 ;; (interactive "sFilter: ")
505 ;; (netstat)
506 ;; (set-buffer (get-buffer "*Netstat*"))
507 ;; (goto-char (point-min))
508 ;; (delete-matching-lines filter))
510 ;;;###autoload
511 (defun nslookup-host (host &optional name-server)
512 "Look up the DNS information for HOST (name or IP address).
513 Optional argument NAME-SERVER says which server to use for
514 DNS resolution.
515 Interactively, prompt for NAME-SERVER if invoked with prefix argument.
517 This command uses `nslookup-program' for looking up the DNS information."
518 (interactive
519 (list (read-from-minibuffer "Lookup host: " (net-utils-machine-at-point))
520 (if current-prefix-arg (read-from-minibuffer "Name server: "))))
521 (let ((options
522 (append nslookup-program-options (list host)
523 (if name-server (list name-server)))))
524 (net-utils-run-program
525 "Nslookup"
526 (concat "** "
527 (mapconcat 'identity
528 (list "Nslookup" host nslookup-program)
529 " ** "))
530 nslookup-program
531 options)))
533 ;;;###autoload
534 (defun nslookup ()
535 "Run `nslookup-program'."
536 (interactive)
537 (switch-to-buffer (make-comint "nslookup" nslookup-program))
538 (nslookup-mode))
540 (defvar comint-prompt-regexp)
541 (defvar comint-input-autoexpand)
543 (autoload 'comint-mode "comint" nil t)
545 (defvar nslookup-mode-map
546 (let ((map (make-sparse-keymap)))
547 (define-key map "\t" 'completion-at-point)
548 map))
550 ;; Using a derived mode gives us keymaps, hooks, etc.
551 (define-derived-mode nslookup-mode comint-mode "Nslookup"
552 "Major mode for interacting with the nslookup program."
553 (set
554 (make-local-variable 'font-lock-defaults)
555 '((nslookup-font-lock-keywords)))
556 (setq comint-prompt-regexp nslookup-prompt-regexp)
557 (setq comint-input-autoexpand t))
559 ;;;###autoload
560 (defun dns-lookup-host (host &optional name-server)
561 "Look up the DNS information for HOST (name or IP address).
562 Optional argument NAME-SERVER says which server to use for
563 DNS resolution.
564 Interactively, prompt for NAME-SERVER if invoked with prefix argument.
566 This command uses `dns-lookup-program' for looking up the DNS information."
567 (interactive
568 (list (read-from-minibuffer "Lookup host: " (net-utils-machine-at-point))
569 (if current-prefix-arg (read-from-minibuffer "Name server: "))))
570 (let ((options
571 (append dns-lookup-program-options (list host)
572 (if name-server (list name-server)))))
573 (net-utils-run-program
574 (concat "DNS Lookup [" host "]")
575 (concat "** "
576 (mapconcat 'identity
577 (list "DNS Lookup" host dns-lookup-program)
578 " ** "))
579 dns-lookup-program
580 options)))
582 ;;;###autoload
583 (defun run-dig (host &optional name-server)
584 "Look up DNS information for HOST (name or IP address).
585 Optional argument NAME-SERVER says which server to use for
586 DNS resolution.
587 Interactively, prompt for NAME-SERVER if invoked with prefix argument.
589 This command uses `dig-program' for looking up the DNS information."
590 (interactive
591 (list (read-from-minibuffer "Lookup host: " (net-utils-machine-at-point))
592 (if current-prefix-arg (read-from-minibuffer "Name server: "))))
593 (let ((options
594 (append dig-program-options (list host)
595 (if name-server (list (concat "@" name-server))))))
596 (net-utils-run-program
597 "Dig"
598 (concat "** "
599 (mapconcat 'identity
600 (list "Dig" host dig-program)
601 " ** "))
602 dig-program
603 options)))
605 (autoload 'comint-exec "comint")
607 ;; This is a lot less than ange-ftp, but much simpler.
608 ;;;###autoload
609 (defun ftp (host)
610 "Run `ftp-program' to connect to HOST."
611 (interactive
612 (list
613 (read-from-minibuffer
614 "Ftp to Host: " (net-utils-machine-at-point))))
615 (let ((buf (get-buffer-create (concat "*ftp [" host "]*"))))
616 (set-buffer buf)
617 (ftp-mode)
618 (comint-exec buf (concat "ftp-" host) ftp-program nil
619 (if ftp-program-options
620 (append (list host) ftp-program-options)
621 (list host)))
622 (pop-to-buffer buf)))
624 (defvar ftp-mode-map
625 (let ((map (make-sparse-keymap)))
626 ;; Occasionally useful
627 (define-key map "\t" 'completion-at-point)
628 map))
630 (define-derived-mode ftp-mode comint-mode "FTP"
631 "Major mode for interacting with the ftp program."
632 (setq comint-prompt-regexp ftp-prompt-regexp)
633 (setq comint-input-autoexpand t)
634 ;; Only add the password-prompting hook if it's not already in the
635 ;; global hook list. This stands a small chance of losing, if it's
636 ;; later removed from the global list (very small, since any
637 ;; password prompts will probably immediately follow the initial
638 ;; connection), but it's better than getting prompted twice for the
639 ;; same password.
640 (unless (memq 'comint-watch-for-password-prompt
641 (default-value 'comint-output-filter-functions))
642 (add-hook 'comint-output-filter-functions 'comint-watch-for-password-prompt
643 nil t)))
645 (defun smbclient (host service)
646 "Connect to SERVICE on HOST via SMB.
648 This command uses `smbclient-program' to connect to HOST."
649 (interactive
650 (list
651 (read-from-minibuffer
652 "Connect to Host: " (net-utils-machine-at-point))
653 (read-from-minibuffer "SMB Service: ")))
654 (let* ((name (format "smbclient [%s\\%s]" host service))
655 (buf (get-buffer-create (concat "*" name "*")))
656 (service-name (concat "\\\\" host "\\" service)))
657 (set-buffer buf)
658 (smbclient-mode)
659 (comint-exec buf name smbclient-program nil
660 (if smbclient-program-options
661 (append (list service-name) smbclient-program-options)
662 (list service-name)))
663 (pop-to-buffer buf)))
665 (defun smbclient-list-shares (host)
666 "List services on HOST.
667 This command uses `smbclient-program' to connect to HOST."
668 (interactive
669 (list
670 (read-from-minibuffer
671 "Connect to Host: " (net-utils-machine-at-point))))
672 (let ((buf (get-buffer-create (format "*SMB Shares on %s*" host))))
673 (set-buffer buf)
674 (smbclient-mode)
675 (comint-exec buf "smbclient-list-shares"
676 smbclient-program nil (list "-L" host))
677 (pop-to-buffer buf)))
679 (define-derived-mode smbclient-mode comint-mode "smbclient"
680 "Major mode for interacting with the smbclient program."
681 (setq comint-prompt-regexp smbclient-prompt-regexp)
682 (setq comint-input-autoexpand t)
683 ;; Only add the password-prompting hook if it's not already in the
684 ;; global hook list. This stands a small chance of losing, if it's
685 ;; later removed from the global list (very small, since any
686 ;; password prompts will probably immediately follow the initial
687 ;; connection), but it's better than getting prompted twice for the
688 ;; same password.
689 (unless (memq 'comint-watch-for-password-prompt
690 (default-value 'comint-output-filter-functions))
691 (add-hook 'comint-output-filter-functions 'comint-watch-for-password-prompt
692 nil t)))
695 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
696 ;; Network Connections
697 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
699 ;; Full list is available at:
700 ;; http://www.iana.org/assignments/port-numbers
701 (defvar network-connection-service-alist
702 (list
703 (cons 'echo 7)
704 (cons 'active-users 11)
705 (cons 'daytime 13)
706 (cons 'chargen 19)
707 (cons 'ftp 21)
708 (cons 'telnet 23)
709 (cons 'smtp 25)
710 (cons 'time 37)
711 (cons 'whois 43)
712 (cons 'gopher 70)
713 (cons 'finger 79)
714 (cons 'www 80)
715 (cons 'pop2 109)
716 (cons 'pop3 110)
717 (cons 'sun-rpc 111)
718 (cons 'nntp 119)
719 (cons 'ntp 123)
720 (cons 'netbios-name 137)
721 (cons 'netbios-data 139)
722 (cons 'irc 194)
723 (cons 'https 443)
724 (cons 'rlogin 513))
725 "Alist of services and associated TCP port numbers.
726 This list is not complete.")
728 ;; Workhorse routine
729 (defun run-network-program (process-name host port &optional initial-string)
730 (let ((tcp-connection)
731 (buf))
732 (setq buf (get-buffer-create (concat "*" process-name "*")))
733 (set-buffer buf)
735 (setq tcp-connection
736 (open-network-stream process-name buf host port))
737 (error "Could not open connection to %s" host))
738 (erase-buffer)
739 (set-marker (process-mark tcp-connection) (point-min))
740 (set-process-filter tcp-connection 'net-utils-remove-ctrl-m-filter)
741 (and initial-string
742 (process-send-string tcp-connection
743 (concat initial-string "\r\n")))
744 (display-buffer buf)))
746 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
747 ;; Simple protocols
748 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
750 (defcustom finger-X.500-host-regexps nil
751 "A list of regular expressions matching host names.
752 If a host name passed to `finger' matches one of these regular
753 expressions, it is assumed to be a host that doesn't accept
754 queries of the form USER@HOST, and wants a query containing USER only."
755 :group 'net-utils
756 :type '(repeat regexp)
757 :version "21.1")
759 ;; Finger protocol
760 ;;;###autoload
761 (defun finger (user host)
762 "Finger USER on HOST.
763 This command uses `finger-X.500-host-regexps'
764 and `network-connection-service-alist', which see."
765 ;; One of those great interactive statements that's actually
766 ;; longer than the function call! The idea is that if the user
767 ;; uses a string like "pbreton@cs.umb.edu", we won't ask for the
768 ;; host name. If we don't see an "@", we'll prompt for the host.
769 (interactive
770 (let* ((answer (read-from-minibuffer "Finger User: "
771 (net-utils-url-at-point)))
772 (index (string-match (regexp-quote "@") answer)))
773 (if index
774 (list (substring answer 0 index)
775 (substring answer (1+ index)))
776 (list answer
777 (read-from-minibuffer "At Host: "
778 (net-utils-machine-at-point))))))
779 (let* ((user-and-host (concat user "@" host))
780 (process-name (concat "Finger [" user-and-host "]"))
781 (regexps finger-X.500-host-regexps)
782 found)
783 (and regexps
784 (while (not (string-match (car regexps) host))
785 (setq regexps (cdr regexps)))
786 (when regexps
787 (setq user-and-host user)))
788 (run-network-program
789 process-name
790 host
791 (cdr (assoc 'finger network-connection-service-alist))
792 user-and-host)))
794 (defcustom whois-server-name "rs.internic.net"
795 "Default host name for the whois service."
796 :group 'net-utils
797 :type 'string)
799 (defcustom whois-server-list
800 '(("whois.arin.net") ; Networks, ASN's, and related POC's (numbers)
801 ("rs.internic.net") ; domain related info
802 ("whois.publicinterestregistry.net")
803 ("whois.abuse.net")
804 ("whois.apnic.net")
805 ("nic.ddn.mil")
806 ("whois.nic.mil")
807 ("whois.nic.gov")
808 ("whois.ripe.net"))
809 "A list of whois servers that can be queried."
810 :group 'net-utils
811 :type '(repeat (list string)))
813 ;; FIXME: modern whois clients include a much better tld <-> whois server
814 ;; list, Emacs should probably avoid specifying the server as the client
815 ;; will DTRT anyway... -rfr
816 (defcustom whois-server-tld
817 '(("rs.internic.net" . "com")
818 ("whois.publicinterestregistry.net" . "org")
819 ("whois.ripe.net" . "be")
820 ("whois.ripe.net" . "de")
821 ("whois.ripe.net" . "dk")
822 ("whois.ripe.net" . "it")
823 ("whois.ripe.net" . "fi")
824 ("whois.ripe.net" . "fr")
825 ("whois.ripe.net" . "uk")
826 ("whois.apnic.net" . "au")
827 ("whois.apnic.net" . "ch")
828 ("whois.apnic.net" . "hk")
829 ("whois.apnic.net" . "jp")
830 ("whois.nic.gov" . "gov")
831 ("whois.nic.mil" . "mil"))
832 "Alist to map top level domains to whois servers."
833 :group 'net-utils
834 :type '(repeat (cons string string)))
836 (defcustom whois-guess-server t
837 "If non-nil then whois will try to deduce the appropriate whois
838 server from the query. If the query doesn't look like a domain or hostname
839 then the server named by `whois-server-name' is used."
840 :group 'net-utils
841 :type 'boolean)
843 (defun whois-get-tld (host)
844 "Return the top level domain of `host', or nil if it isn't a domain name."
845 (let ((i (1- (length host)))
846 (max-len (- (length host) 5)))
847 (while (not (or (= i max-len) (char-equal (aref host i) ?.)))
848 (setq i (1- i)))
849 (if (= i max-len)
851 (substring host (1+ i)))))
853 ;; Whois protocol
854 ;;;###autoload
855 (defun whois (arg search-string)
856 "Send SEARCH-STRING to server defined by the `whois-server-name' variable.
857 If `whois-guess-server' is non-nil, then try to deduce the correct server
858 from SEARCH-STRING. With argument, prompt for whois server.
859 The port is deduced from `network-connection-service-alist'."
860 (interactive "P\nsWhois: ")
861 (let* ((whois-apropos-host (if whois-guess-server
862 (rassoc (whois-get-tld search-string)
863 whois-server-tld)
864 nil))
865 (server-name (if whois-apropos-host
866 (car whois-apropos-host)
867 whois-server-name))
868 (host
869 (if arg
870 (completing-read "Whois server name: "
871 whois-server-list nil nil "whois.")
872 server-name)))
873 (run-network-program
874 "Whois"
875 host
876 (cdr (assoc 'whois network-connection-service-alist))
877 search-string)))
879 (defcustom whois-reverse-lookup-server "whois.arin.net"
880 "Server which provides inverse DNS mapping."
881 :group 'net-utils
882 :type 'string)
884 ;;;###autoload
885 (defun whois-reverse-lookup ()
886 (interactive)
887 (let ((whois-server-name whois-reverse-lookup-server))
888 (call-interactively 'whois)))
890 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
891 ;;; General Network connection
892 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
894 ;; Using a derived mode gives us keymaps, hooks, etc.
895 (define-derived-mode
896 network-connection-mode comint-mode "Network-Connection"
897 "Major mode for interacting with the network-connection program.")
899 (defun network-connection-mode-setup (host service)
900 (make-local-variable 'network-connection-host)
901 (setq network-connection-host host)
902 (make-local-variable 'network-connection-service)
903 (setq network-connection-service service))
905 ;;;###autoload
906 (defun network-connection-to-service (host service)
907 "Open a network connection to SERVICE on HOST.
908 This command uses `network-connection-service-alist', which see."
909 (interactive
910 (list
911 (read-from-minibuffer "Host: " (net-utils-machine-at-point))
912 (completing-read "Service: "
913 (mapcar
914 (function
915 (lambda (elt)
916 (list (symbol-name (car elt)))))
917 network-connection-service-alist))))
918 (network-connection
919 host
920 (cdr (assoc (intern service) network-connection-service-alist))))
922 ;;;###autoload
923 (defun network-connection (host port)
924 "Open a network connection to HOST on PORT."
925 (interactive "sHost: \nnPort: ")
926 (network-service-connection host (number-to-string port)))
928 (defun network-service-connection (host service)
929 "Open a network connection to SERVICE on HOST.
930 The port to use is determined from `network-connection-service-alist'."
931 (let* ((process-name (concat "Network Connection [" host " " service "]"))
932 (portnum (string-to-number service))
933 (buf (get-buffer-create (concat "*" process-name "*"))))
934 (or (zerop portnum) (setq service portnum))
935 (make-comint
936 process-name
937 (cons host service))
938 (set-buffer buf)
939 (network-connection-mode)
940 (network-connection-mode-setup host service)
941 (pop-to-buffer buf)))
943 (defvar comint-input-ring)
945 (defun network-connection-reconnect ()
946 "Reconnect a network connection, preserving the old input ring.
947 This command uses `network-connection-service-alist', which see."
948 (interactive)
949 (let ((proc (get-buffer-process (current-buffer)))
950 (old-comint-input-ring comint-input-ring)
951 (host network-connection-host)
952 (service network-connection-service))
953 (if (not (or (not proc)
954 (eq (process-status proc) 'closed)))
955 (message "Still connected")
956 (goto-char (point-max))
957 (insert (format "Reopening connection to %s\n" host))
958 (network-connection host
959 (if (numberp service)
960 service
961 (cdr (assoc service network-connection-service-alist))))
962 (and old-comint-input-ring
963 (setq comint-input-ring old-comint-input-ring)))))
965 (provide 'net-utils)
967 ;;; net-utils.el ends here