Document reserved keys
[emacs.git] / lisp / net / net-utils.el
blob9edd42b857a81d20e9071a52d76f341d9478cc81
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 (define-obsolete-variable-alias 'ipconfig-program 'ifconfig-program "22.2")
91 (defcustom ifconfig-program
92 (cond ((eq system-type 'windows-nt) "ipconfig")
93 ((executable-find "ifconfig") "ifconfig")
94 ((net-utils--executable-find-sbin "ifconfig"))
95 ((net-utils--executable-find-sbin "ip"))
96 (t "ip"))
97 "Program to print network configuration information."
98 :version "25.1" ; add ip
99 :group 'net-utils
100 :type 'string)
102 (define-obsolete-variable-alias 'ipconfig-program-options
103 'ifconfig-program-options "22.2")
105 (defcustom ifconfig-program-options
106 (cond ((string-match "ipconfig\\'" ifconfig-program) '("/all"))
107 ((string-match "ifconfig\\'" ifconfig-program) '("-a"))
108 ((string-match "ip\\'" ifconfig-program) '("addr")))
109 "Options for the ifconfig program."
110 :version "25.1"
111 :set-after '(ifconfig-program)
112 :group 'net-utils
113 :type '(repeat string))
115 (defcustom iwconfig-program
116 (cond ((executable-find "iwconfig") "iwconfig")
117 ((net-utils--executable-find-sbin "iw") "iw")
118 (t "iw"))
119 "Program to print wireless network configuration information."
120 :group 'net-utils
121 :type 'string
122 :version "26.1")
124 (defcustom iwconfig-program-options
125 (cond ((string-match-p "iw\\'" iwconfig-program) (list "dev"))
126 (t nil))
127 "Options for the iwconfig program."
128 :group 'net-utils
129 :type '(repeat string)
130 :version "26.1")
132 (defcustom netstat-program
133 (cond ((executable-find "netstat") "netstat")
134 ((net-utils--executable-find-sbin "ss"))
135 (t "ss"))
136 "Program to print network statistics."
137 :group 'net-utils
138 :type 'string
139 :version "26.1")
141 (defcustom netstat-program-options
142 (list "-a")
143 "Options for the netstat program."
144 :group 'net-utils
145 :type '(repeat string))
147 (defcustom arp-program (or (net-utils--executable-find-sbin "arp") "arp")
148 "Program to print IP to address translation tables."
149 :group 'net-utils
150 :type 'string)
152 (defcustom arp-program-options
153 (list "-a")
154 "Options for the arp program."
155 :group 'net-utils
156 :type '(repeat string))
158 (defcustom route-program
159 (cond ((eq system-type 'windows-nt) "route")
160 ((executable-find "netstat") "netstat")
161 ((net-utils--executable-find-sbin "netstat"))
162 ((executable-find "ip") "ip")
163 ((net-utils--executable-find-sbin "ip"))
164 (t "ip"))
165 "Program to print routing tables."
166 :group 'net-utils
167 :type 'string
168 :version "26.1")
170 (defcustom route-program-options
171 (cond ((eq system-type 'windows-nt) (list "print"))
172 ((string-match-p "netstat\\'" route-program) (list "-r"))
173 (t (list "route")))
174 "Options for the route program."
175 :group 'net-utils
176 :type '(repeat string)
177 :version "26.1")
179 (defcustom nslookup-program "nslookup"
180 "Program to interactively query DNS information."
181 :group 'net-utils
182 :type 'string)
184 (defcustom nslookup-program-options nil
185 "Options for the nslookup program."
186 :group 'net-utils
187 :type '(repeat string))
189 (defcustom nslookup-prompt-regexp "^> "
190 "Regexp to match the nslookup prompt.
192 This variable is only used if the variable
193 `comint-use-prompt-regexp' is non-nil."
194 :group 'net-utils
195 :type 'regexp)
197 (defcustom dig-program "dig"
198 "Program to query DNS information."
199 :group 'net-utils
200 :type 'string)
202 (defcustom dig-program-options nil
203 "Options for the dig program."
204 :group 'net-utils
205 :type '(repeat string)
206 :version "26.1")
208 (defcustom ftp-program "ftp"
209 "Program to run to do FTP transfers."
210 :group 'net-utils
211 :type 'string)
213 (defcustom ftp-program-options nil
214 "Options for the ftp program."
215 :group 'net-utils
216 :type '(repeat string))
218 (defcustom ftp-prompt-regexp "^ftp>"
219 "Regexp which matches the FTP program's prompt.
221 This variable is only used if the variable
222 `comint-use-prompt-regexp' is non-nil."
223 :group 'net-utils
224 :type 'regexp)
226 (defcustom smbclient-program "smbclient"
227 "Smbclient program."
228 :group 'net-utils
229 :type 'string)
231 (defcustom smbclient-program-options nil
232 "Options for the smbclient program."
233 :group 'net-utils
234 :type '(repeat string))
236 (defcustom smbclient-prompt-regexp "^smb: >"
237 "Regexp which matches the smbclient program's prompt.
239 This variable is only used if the variable
240 `comint-use-prompt-regexp' is non-nil."
241 :group 'net-utils
242 :type 'regexp)
244 (defcustom dns-lookup-program "host"
245 "Program to interactively query DNS information."
246 :group 'net-utils
247 :type 'string)
249 (defcustom dns-lookup-program-options nil
250 "Options for the dns-lookup program."
251 :group 'net-utils
252 :type '(repeat string))
254 ;; Internal variables
255 (defvar network-connection-service nil)
256 (defvar network-connection-host nil)
258 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
259 ;; Nslookup goodies
260 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
262 (defvar nslookup-font-lock-keywords
263 (list
264 (list "^[A-Za-z0-9 _]+:" 0 'font-lock-type-face)
265 (list "\\<\\(SOA\\|NS\\|MX\\|A\\|CNAME\\)\\>"
266 1 'font-lock-keyword-face)
267 ;; Dotted quads
268 (list
269 (mapconcat 'identity
270 (make-list 4 "[0-9]+")
271 "\\.")
272 0 'font-lock-variable-name-face)
273 ;; Host names
274 (list
275 (let ((host-expression "[-A-Za-z0-9]+"))
276 (concat
277 (mapconcat 'identity
278 (make-list 2 host-expression)
279 "\\.")
280 "\\(\\." host-expression "\\)*"))
281 0 'font-lock-variable-name-face))
282 "Expressions to font-lock for nslookup.")
284 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
285 ;; General network utilities mode
286 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
288 (defvar net-utils-font-lock-keywords
289 (list
290 ;; Dotted quads
291 (list
292 (mapconcat 'identity (make-list 4 "[0-9]+") "\\.")
293 0 'font-lock-variable-name-face)
294 ;; Simple rfc4291 addresses
295 (list (concat
296 "\\( \\([[:xdigit:]]+\\(:\\|::\\)\\)+[[:xdigit:]]+\\)"
297 "\\|"
298 "\\(::[[:xdigit:]]+\\)")
299 0 'font-lock-variable-name-face)
300 ;; Host names
301 (list
302 (let ((host-expression "[-A-Za-z0-9]+"))
303 (concat
304 (mapconcat 'identity (make-list 2 host-expression) "\\.")
305 "\\(\\." host-expression "\\)*"))
306 0 'font-lock-variable-name-face))
307 "Expressions to font-lock for general network utilities.")
309 (define-derived-mode net-utils-mode special-mode "NetworkUtil"
310 "Major mode for interacting with an external network utility."
311 (set (make-local-variable 'font-lock-defaults)
312 '((net-utils-font-lock-keywords)))
313 (setq-local revert-buffer-function #'net-utils--revert-function))
315 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
316 ;; Utility functions
317 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
319 ;; Simplified versions of some at-point functions from ffap.el.
320 ;; It's not worth loading all of ffap just for these.
321 (defun net-utils-machine-at-point ()
322 (let ((pt (point)))
323 (buffer-substring-no-properties
324 (save-excursion
325 (skip-chars-backward "-a-zA-Z0-9.")
326 (point))
327 (save-excursion
328 (skip-chars-forward "-a-zA-Z0-9.")
329 (skip-chars-backward "." pt)
330 (point)))))
332 (defun net-utils-url-at-point ()
333 (let ((pt (point)))
334 (buffer-substring-no-properties
335 (save-excursion
336 (skip-chars-backward "--:=&?$+@-Z_a-z~#,%")
337 (skip-chars-forward "^A-Za-z0-9" pt)
338 (point))
339 (save-excursion
340 (skip-chars-forward "--:=&?$+@-Z_a-z~#,%")
341 (skip-chars-backward ":;.,!?" pt)
342 (point)))))
344 (defun net-utils-remove-ctrl-m-filter (process output-string)
345 "Remove trailing control Ms."
346 (with-current-buffer (process-buffer process)
347 (save-excursion
348 (let ((inhibit-read-only t)
349 (filtered-string output-string))
350 (while (string-match "\r" filtered-string)
351 (setq filtered-string
352 (replace-match "" nil nil filtered-string)))
353 ;; Insert the text, moving the process-marker.
354 (goto-char (process-mark process))
355 (insert filtered-string)
356 (set-marker (process-mark process) (point))))))
358 (declare-function w32-get-console-output-codepage "w32proc.c" ())
360 (defun net-utils-run-program (name header program args)
361 "Run a network information program."
362 (let ((buf (get-buffer-create (concat "*" name "*")))
363 (coding-system-for-read
364 ;; MS-Windows versions of network utilities output text
365 ;; encoded in the console (a.k.a. "OEM") codepage, which is
366 ;; different from the default system (a.k.a. "ANSI")
367 ;; codepage.
368 (if (eq system-type 'windows-nt)
369 (intern (format "cp%d" (w32-get-console-output-codepage)))
370 coding-system-for-read)))
371 (set-buffer buf)
372 (erase-buffer)
373 (insert header "\n")
374 (set-process-filter
375 (apply 'start-process name buf program args)
376 'net-utils-remove-ctrl-m-filter)
377 (display-buffer buf)
378 buf))
380 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
381 ;; General network utilities (diagnostic)
382 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
384 ;; Todo: This data could be saved in a bookmark.
385 (defvar net-utils--revert-cmd nil)
387 (defun net-utils-run-simple (buffer program-name args &optional nodisplay)
388 "Run a network utility for diagnostic output only."
389 (with-current-buffer (if (stringp buffer) (get-buffer-create buffer) buffer)
390 (let ((proc (get-buffer-process (current-buffer))))
391 (when proc
392 (set-process-filter proc nil)
393 (delete-process proc)))
394 (let ((inhibit-read-only t)
395 (coding-system-for-read
396 ;; MS-Windows versions of network utilities output text
397 ;; encoded in the console (a.k.a. "OEM") codepage, which is
398 ;; different from the default system (a.k.a. "ANSI")
399 ;; codepage.
400 (if (eq system-type 'windows-nt)
401 (intern (format "cp%d" (w32-get-console-output-codepage)))
402 coding-system-for-read)))
403 (erase-buffer))
404 (net-utils-mode)
405 (setq-local net-utils--revert-cmd
406 `(net-utils-run-simple ,(current-buffer)
407 ,program-name ,args nodisplay))
408 (set-process-filter
409 (apply 'start-process program-name
410 (current-buffer) program-name args)
411 'net-utils-remove-ctrl-m-filter)
412 (unless nodisplay (display-buffer (current-buffer)))))
414 (defun net-utils--revert-function (&optional ignore-auto noconfirm)
415 (message "Reverting `%s'..." (buffer-name))
416 (apply (car net-utils--revert-cmd) (cdr net-utils--revert-cmd))
417 (let ((proc (get-buffer-process (current-buffer))))
418 (when proc
419 (set-process-sentinel
420 proc
421 (lambda (process event)
422 (when (string= event "finished\n")
423 (message "Reverting `%s' done" (process-buffer process))))))))
425 ;;;###autoload
426 (defun ifconfig ()
427 "Run `ifconfig-program' and display diagnostic output."
428 (interactive)
429 (net-utils-run-simple
430 (format "*%s*" ifconfig-program)
431 ifconfig-program
432 ifconfig-program-options))
434 (defalias 'ipconfig 'ifconfig)
436 ;;;###autoload
437 (defun iwconfig ()
438 "Run `iwconfig-program' and display diagnostic output."
439 (interactive)
440 (net-utils-run-simple
441 (format "*%s*" iwconfig-program)
442 iwconfig-program
443 iwconfig-program-options))
445 ;;;###autoload
446 (defun netstat ()
447 "Run `netstat-program' and display diagnostic output."
448 (interactive)
449 (net-utils-run-simple
450 (format "*%s*" netstat-program)
451 netstat-program
452 netstat-program-options))
454 ;;;###autoload
455 (defun arp ()
456 "Run `arp-program' and display diagnostic output."
457 (interactive)
458 (net-utils-run-simple
459 (format "*%s*" arp-program)
460 arp-program
461 arp-program-options))
463 ;;;###autoload
464 (defun route ()
465 "Run `route-program' and display diagnostic output."
466 (interactive)
467 (net-utils-run-simple
468 (format "*%s*" route-program)
469 route-program
470 route-program-options))
472 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
473 ;; Wrappers for external network programs
474 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
476 ;;;###autoload
477 (defun traceroute (target)
478 "Run `traceroute-program' for TARGET."
479 (interactive "sTarget: ")
480 (let ((options
481 (if traceroute-program-options
482 (append traceroute-program-options (list target))
483 (list target))))
484 (net-utils-run-simple
485 (concat "Traceroute" " " target)
486 traceroute-program
487 options)))
489 ;;;###autoload
490 (defun ping (host)
491 "Ping HOST.
492 If your system's ping continues until interrupted, you can try setting
493 `ping-program-options'."
494 (interactive
495 (list (read-from-minibuffer "Ping host: " (net-utils-machine-at-point))))
496 (let ((options
497 (if ping-program-options
498 (append ping-program-options (list host))
499 (list host))))
500 (net-utils-run-program
501 (concat "Ping" " " host)
502 (concat "** Ping ** " ping-program " ** " host)
503 ping-program
504 options)))
506 ;; FIXME -- Needs to be a process filter
507 ;; (defun netstat-with-filter (filter)
508 ;; "Run netstat program."
509 ;; (interactive "sFilter: ")
510 ;; (netstat)
511 ;; (set-buffer (get-buffer "*Netstat*"))
512 ;; (goto-char (point-min))
513 ;; (delete-matching-lines filter))
515 ;;;###autoload
516 (defun nslookup-host (host &optional name-server)
517 "Look up the DNS information for HOST (name or IP address).
518 Optional argument NAME-SERVER says which server to use for
519 DNS resolution.
520 Interactively, prompt for NAME-SERVER if invoked with prefix argument.
522 This command uses `nslookup-program' for looking up the DNS information."
523 (interactive
524 (list (read-from-minibuffer "Lookup host: " (net-utils-machine-at-point))
525 (if current-prefix-arg (read-from-minibuffer "Name server: "))))
526 (let ((options
527 (append nslookup-program-options (list host)
528 (if name-server (list name-server)))))
529 (net-utils-run-program
530 "Nslookup"
531 (concat "** "
532 (mapconcat 'identity
533 (list "Nslookup" host nslookup-program)
534 " ** "))
535 nslookup-program
536 options)))
538 ;;;###autoload
539 (defun nslookup ()
540 "Run `nslookup-program'."
541 (interactive)
542 (switch-to-buffer (make-comint "nslookup" nslookup-program))
543 (nslookup-mode))
545 (defvar comint-prompt-regexp)
546 (defvar comint-input-autoexpand)
548 (autoload 'comint-mode "comint" nil t)
550 (defvar nslookup-mode-map
551 (let ((map (make-sparse-keymap)))
552 (define-key map "\t" 'completion-at-point)
553 map))
555 ;; Using a derived mode gives us keymaps, hooks, etc.
556 (define-derived-mode nslookup-mode comint-mode "Nslookup"
557 "Major mode for interacting with the nslookup program."
558 (set
559 (make-local-variable 'font-lock-defaults)
560 '((nslookup-font-lock-keywords)))
561 (setq comint-prompt-regexp nslookup-prompt-regexp)
562 (setq comint-input-autoexpand t))
564 ;;;###autoload
565 (defun dns-lookup-host (host &optional name-server)
566 "Look up the DNS information for HOST (name or IP address).
567 Optional argument NAME-SERVER says which server to use for
568 DNS resolution.
569 Interactively, prompt for NAME-SERVER if invoked with prefix argument.
571 This command uses `dns-lookup-program' for looking up the DNS information."
572 (interactive
573 (list (read-from-minibuffer "Lookup host: " (net-utils-machine-at-point))
574 (if current-prefix-arg (read-from-minibuffer "Name server: "))))
575 (let ((options
576 (append dns-lookup-program-options (list host)
577 (if name-server (list name-server)))))
578 (net-utils-run-program
579 (concat "DNS Lookup [" host "]")
580 (concat "** "
581 (mapconcat 'identity
582 (list "DNS Lookup" host dns-lookup-program)
583 " ** "))
584 dns-lookup-program
585 options)))
587 ;;;###autoload
588 (defun run-dig (host &optional name-server)
589 "Look up DNS information for HOST (name or IP address).
590 Optional argument NAME-SERVER says which server to use for
591 DNS resolution.
592 Interactively, prompt for NAME-SERVER if invoked with prefix argument.
594 This command uses `dig-program' for looking up the DNS information."
595 (interactive
596 (list (read-from-minibuffer "Lookup host: " (net-utils-machine-at-point))
597 (if current-prefix-arg (read-from-minibuffer "Name server: "))))
598 (let ((options
599 (append dig-program-options (list host)
600 (if name-server (list (concat "@" name-server))))))
601 (net-utils-run-program
602 "Dig"
603 (concat "** "
604 (mapconcat 'identity
605 (list "Dig" host dig-program)
606 " ** "))
607 dig-program
608 options)))
610 (autoload 'comint-exec "comint")
612 ;; This is a lot less than ange-ftp, but much simpler.
613 ;;;###autoload
614 (defun ftp (host)
615 "Run `ftp-program' to connect to HOST."
616 (interactive
617 (list
618 (read-from-minibuffer
619 "Ftp to Host: " (net-utils-machine-at-point))))
620 (let ((buf (get-buffer-create (concat "*ftp [" host "]*"))))
621 (set-buffer buf)
622 (ftp-mode)
623 (comint-exec buf (concat "ftp-" host) ftp-program nil
624 (if ftp-program-options
625 (append (list host) ftp-program-options)
626 (list host)))
627 (pop-to-buffer buf)))
629 (defvar ftp-mode-map
630 (let ((map (make-sparse-keymap)))
631 ;; Occasionally useful
632 (define-key map "\t" 'completion-at-point)
633 map))
635 (define-derived-mode ftp-mode comint-mode "FTP"
636 "Major mode for interacting with the ftp program."
637 (setq comint-prompt-regexp ftp-prompt-regexp)
638 (setq comint-input-autoexpand t)
639 ;; Only add the password-prompting hook if it's not already in the
640 ;; global hook list. This stands a small chance of losing, if it's
641 ;; later removed from the global list (very small, since any
642 ;; password prompts will probably immediately follow the initial
643 ;; connection), but it's better than getting prompted twice for the
644 ;; same password.
645 (unless (memq 'comint-watch-for-password-prompt
646 (default-value 'comint-output-filter-functions))
647 (add-hook 'comint-output-filter-functions 'comint-watch-for-password-prompt
648 nil t)))
650 (defun smbclient (host service)
651 "Connect to SERVICE on HOST via SMB.
653 This command uses `smbclient-program' to connect to HOST."
654 (interactive
655 (list
656 (read-from-minibuffer
657 "Connect to Host: " (net-utils-machine-at-point))
658 (read-from-minibuffer "SMB Service: ")))
659 (let* ((name (format "smbclient [%s\\%s]" host service))
660 (buf (get-buffer-create (concat "*" name "*")))
661 (service-name (concat "\\\\" host "\\" service)))
662 (set-buffer buf)
663 (smbclient-mode)
664 (comint-exec buf name smbclient-program nil
665 (if smbclient-program-options
666 (append (list service-name) smbclient-program-options)
667 (list service-name)))
668 (pop-to-buffer buf)))
670 (defun smbclient-list-shares (host)
671 "List services on HOST.
672 This command uses `smbclient-program' to connect to HOST."
673 (interactive
674 (list
675 (read-from-minibuffer
676 "Connect to Host: " (net-utils-machine-at-point))))
677 (let ((buf (get-buffer-create (format "*SMB Shares on %s*" host))))
678 (set-buffer buf)
679 (smbclient-mode)
680 (comint-exec buf "smbclient-list-shares"
681 smbclient-program nil (list "-L" host))
682 (pop-to-buffer buf)))
684 (define-derived-mode smbclient-mode comint-mode "smbclient"
685 "Major mode for interacting with the smbclient program."
686 (setq comint-prompt-regexp smbclient-prompt-regexp)
687 (setq comint-input-autoexpand t)
688 ;; Only add the password-prompting hook if it's not already in the
689 ;; global hook list. This stands a small chance of losing, if it's
690 ;; later removed from the global list (very small, since any
691 ;; password prompts will probably immediately follow the initial
692 ;; connection), but it's better than getting prompted twice for the
693 ;; same password.
694 (unless (memq 'comint-watch-for-password-prompt
695 (default-value 'comint-output-filter-functions))
696 (add-hook 'comint-output-filter-functions 'comint-watch-for-password-prompt
697 nil t)))
700 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
701 ;; Network Connections
702 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
704 ;; Full list is available at:
705 ;; http://www.iana.org/assignments/port-numbers
706 (defvar network-connection-service-alist
707 (list
708 (cons 'echo 7)
709 (cons 'active-users 11)
710 (cons 'daytime 13)
711 (cons 'chargen 19)
712 (cons 'ftp 21)
713 (cons 'telnet 23)
714 (cons 'smtp 25)
715 (cons 'time 37)
716 (cons 'whois 43)
717 (cons 'gopher 70)
718 (cons 'finger 79)
719 (cons 'www 80)
720 (cons 'pop2 109)
721 (cons 'pop3 110)
722 (cons 'sun-rpc 111)
723 (cons 'nntp 119)
724 (cons 'ntp 123)
725 (cons 'netbios-name 137)
726 (cons 'netbios-data 139)
727 (cons 'irc 194)
728 (cons 'https 443)
729 (cons 'rlogin 513))
730 "Alist of services and associated TCP port numbers.
731 This list is not complete.")
733 ;; Workhorse routine
734 (defun run-network-program (process-name host port &optional initial-string)
735 (let ((tcp-connection)
736 (buf))
737 (setq buf (get-buffer-create (concat "*" process-name "*")))
738 (set-buffer buf)
740 (setq tcp-connection
741 (open-network-stream process-name buf host port))
742 (error "Could not open connection to %s" host))
743 (erase-buffer)
744 (set-marker (process-mark tcp-connection) (point-min))
745 (set-process-filter tcp-connection 'net-utils-remove-ctrl-m-filter)
746 (and initial-string
747 (process-send-string tcp-connection
748 (concat initial-string "\r\n")))
749 (display-buffer buf)))
751 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
752 ;; Simple protocols
753 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
755 (defcustom finger-X.500-host-regexps nil
756 "A list of regular expressions matching host names.
757 If a host name passed to `finger' matches one of these regular
758 expressions, it is assumed to be a host that doesn't accept
759 queries of the form USER@HOST, and wants a query containing USER only."
760 :group 'net-utils
761 :type '(repeat regexp)
762 :version "21.1")
764 ;; Finger protocol
765 ;;;###autoload
766 (defun finger (user host)
767 "Finger USER on HOST.
768 This command uses `finger-X.500-host-regexps'
769 and `network-connection-service-alist', which see."
770 ;; One of those great interactive statements that's actually
771 ;; longer than the function call! The idea is that if the user
772 ;; uses a string like "pbreton@cs.umb.edu", we won't ask for the
773 ;; host name. If we don't see an "@", we'll prompt for the host.
774 (interactive
775 (let* ((answer (read-from-minibuffer "Finger User: "
776 (net-utils-url-at-point)))
777 (index (string-match (regexp-quote "@") answer)))
778 (if index
779 (list (substring answer 0 index)
780 (substring answer (1+ index)))
781 (list answer
782 (read-from-minibuffer "At Host: "
783 (net-utils-machine-at-point))))))
784 (let* ((user-and-host (concat user "@" host))
785 (process-name (concat "Finger [" user-and-host "]"))
786 (regexps finger-X.500-host-regexps)
787 found)
788 (and regexps
789 (while (not (string-match (car regexps) host))
790 (setq regexps (cdr regexps)))
791 (when regexps
792 (setq user-and-host user)))
793 (run-network-program
794 process-name
795 host
796 (cdr (assoc 'finger network-connection-service-alist))
797 user-and-host)))
799 (defcustom whois-server-name "rs.internic.net"
800 "Default host name for the whois service."
801 :group 'net-utils
802 :type 'string)
804 (defcustom whois-server-list
805 '(("whois.arin.net") ; Networks, ASN's, and related POC's (numbers)
806 ("rs.internic.net") ; domain related info
807 ("whois.publicinterestregistry.net")
808 ("whois.abuse.net")
809 ("whois.apnic.net")
810 ("nic.ddn.mil")
811 ("whois.nic.mil")
812 ("whois.nic.gov")
813 ("whois.ripe.net"))
814 "A list of whois servers that can be queried."
815 :group 'net-utils
816 :type '(repeat (list string)))
818 ;; FIXME: modern whois clients include a much better tld <-> whois server
819 ;; list, Emacs should probably avoid specifying the server as the client
820 ;; will DTRT anyway... -rfr
821 (defcustom whois-server-tld
822 '(("rs.internic.net" . "com")
823 ("whois.publicinterestregistry.net" . "org")
824 ("whois.ripe.net" . "be")
825 ("whois.ripe.net" . "de")
826 ("whois.ripe.net" . "dk")
827 ("whois.ripe.net" . "it")
828 ("whois.ripe.net" . "fi")
829 ("whois.ripe.net" . "fr")
830 ("whois.ripe.net" . "uk")
831 ("whois.apnic.net" . "au")
832 ("whois.apnic.net" . "ch")
833 ("whois.apnic.net" . "hk")
834 ("whois.apnic.net" . "jp")
835 ("whois.nic.gov" . "gov")
836 ("whois.nic.mil" . "mil"))
837 "Alist to map top level domains to whois servers."
838 :group 'net-utils
839 :type '(repeat (cons string string)))
841 (defcustom whois-guess-server t
842 "If non-nil then whois will try to deduce the appropriate whois
843 server from the query. If the query doesn't look like a domain or hostname
844 then the server named by `whois-server-name' is used."
845 :group 'net-utils
846 :type 'boolean)
848 (defun whois-get-tld (host)
849 "Return the top level domain of `host', or nil if it isn't a domain name."
850 (let ((i (1- (length host)))
851 (max-len (- (length host) 5)))
852 (while (not (or (= i max-len) (char-equal (aref host i) ?.)))
853 (setq i (1- i)))
854 (if (= i max-len)
856 (substring host (1+ i)))))
858 ;; Whois protocol
859 ;;;###autoload
860 (defun whois (arg search-string)
861 "Send SEARCH-STRING to server defined by the `whois-server-name' variable.
862 If `whois-guess-server' is non-nil, then try to deduce the correct server
863 from SEARCH-STRING. With argument, prompt for whois server.
864 The port is deduced from `network-connection-service-alist'."
865 (interactive "P\nsWhois: ")
866 (let* ((whois-apropos-host (if whois-guess-server
867 (rassoc (whois-get-tld search-string)
868 whois-server-tld)
869 nil))
870 (server-name (if whois-apropos-host
871 (car whois-apropos-host)
872 whois-server-name))
873 (host
874 (if arg
875 (completing-read "Whois server name: "
876 whois-server-list nil nil "whois.")
877 server-name)))
878 (run-network-program
879 "Whois"
880 host
881 (cdr (assoc 'whois network-connection-service-alist))
882 search-string)))
884 (defcustom whois-reverse-lookup-server "whois.arin.net"
885 "Server which provides inverse DNS mapping."
886 :group 'net-utils
887 :type 'string)
889 ;;;###autoload
890 (defun whois-reverse-lookup ()
891 (interactive)
892 (let ((whois-server-name whois-reverse-lookup-server))
893 (call-interactively 'whois)))
895 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
896 ;;; General Network connection
897 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
899 ;; Using a derived mode gives us keymaps, hooks, etc.
900 (define-derived-mode
901 network-connection-mode comint-mode "Network-Connection"
902 "Major mode for interacting with the network-connection program.")
904 (defun network-connection-mode-setup (host service)
905 (make-local-variable 'network-connection-host)
906 (setq network-connection-host host)
907 (make-local-variable 'network-connection-service)
908 (setq network-connection-service service))
910 ;;;###autoload
911 (defun network-connection-to-service (host service)
912 "Open a network connection to SERVICE on HOST.
913 This command uses `network-connection-service-alist', which see."
914 (interactive
915 (list
916 (read-from-minibuffer "Host: " (net-utils-machine-at-point))
917 (completing-read "Service: "
918 (mapcar
919 (function
920 (lambda (elt)
921 (list (symbol-name (car elt)))))
922 network-connection-service-alist))))
923 (network-connection
924 host
925 (cdr (assoc (intern service) network-connection-service-alist))))
927 ;;;###autoload
928 (defun network-connection (host port)
929 "Open a network connection to HOST on PORT."
930 (interactive "sHost: \nnPort: ")
931 (network-service-connection host (number-to-string port)))
933 (defun network-service-connection (host service)
934 "Open a network connection to SERVICE on HOST.
935 The port to use is determined from `network-connection-service-alist'."
936 (let* ((process-name (concat "Network Connection [" host " " service "]"))
937 (portnum (string-to-number service))
938 (buf (get-buffer-create (concat "*" process-name "*"))))
939 (or (zerop portnum) (setq service portnum))
940 (make-comint
941 process-name
942 (cons host service))
943 (set-buffer buf)
944 (network-connection-mode)
945 (network-connection-mode-setup host service)
946 (pop-to-buffer buf)))
948 (defvar comint-input-ring)
950 (defun network-connection-reconnect ()
951 "Reconnect a network connection, preserving the old input ring.
952 This command uses `network-connection-service-alist', which see."
953 (interactive)
954 (let ((proc (get-buffer-process (current-buffer)))
955 (old-comint-input-ring comint-input-ring)
956 (host network-connection-host)
957 (service network-connection-service))
958 (if (not (or (not proc)
959 (eq (process-status proc) 'closed)))
960 (message "Still connected")
961 (goto-char (point-max))
962 (insert (format "Reopening connection to %s\n" host))
963 (network-connection host
964 (if (numberp service)
965 service
966 (cdr (assoc service network-connection-service-alist))))
967 (and old-comint-input-ring
968 (setq comint-input-ring old-comint-input-ring)))))
970 (provide 'net-utils)
972 ;;; net-utils.el ends here