* lisp/net/net-utils.el (net-utils--revert-function): New fun.
[emacs.git] / lisp / net / net-utils.el
blobcc28bab733f2b58420576f8254aca8886e76b6fb
1 ;;; net-utils.el --- network functions
3 ;; Copyright (C) 1998-2013 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 <http://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 ;; PATHS
41 ;; On some systems, some of these programs are not in normal user path,
42 ;; but rather in /sbin, /usr/sbin, and so on.
45 ;;; Code:
47 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
48 ;; Customization Variables
49 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
51 (defgroup net-utils nil
52 "Network utility functions."
53 :prefix "net-utils-"
54 :group 'comm
55 :version "20.3")
57 (defcustom net-utils-remove-ctl-m (memq system-type '(windows-nt msdos))
58 "If non-nil, remove control-Ms from output."
59 :group 'net-utils
60 :type 'boolean)
62 (defcustom traceroute-program
63 (if (eq system-type 'windows-nt)
64 "tracert"
65 "traceroute")
66 "Program to trace network hops to a destination."
67 :group 'net-utils
68 :type 'string)
70 (defcustom traceroute-program-options nil
71 "Options for the traceroute program."
72 :group 'net-utils
73 :type '(repeat string))
75 (defcustom ping-program "ping"
76 "Program to send network test packets to a host."
77 :group 'net-utils
78 :type 'string)
80 ;; On GNU/Linux and Irix, the system's ping program seems to send packets
81 ;; indefinitely unless told otherwise
82 (defcustom ping-program-options
83 (and (memq system-type '(gnu/linux irix))
84 (list "-c" "4"))
85 "Options for the ping program.
86 These options can be used to limit how many ICMP packets are emitted."
87 :group 'net-utils
88 :type '(repeat string))
90 (define-obsolete-variable-alias 'ipconfig-program 'ifconfig-program "22.2")
92 (defcustom ifconfig-program
93 (if (eq system-type 'windows-nt)
94 "ipconfig"
95 "ifconfig")
96 "Program to print network configuration information."
97 :group 'net-utils
98 :type 'string)
100 (define-obsolete-variable-alias 'ipconfig-program-options
101 'ifconfig-program-options "22.2")
103 (defcustom ifconfig-program-options
104 (list
105 (if (eq system-type 'windows-nt)
106 "/all" "-a"))
107 "Options for the ifconfig program."
108 :group 'net-utils
109 :type '(repeat string))
111 (defcustom iwconfig-program "iwconfig"
112 "Program to print wireless network configuration information."
113 :group 'net-utils
114 :type 'string
115 :version "23.1")
117 (defcustom iwconfig-program-options nil
118 "Options for the iwconfig program."
119 :group 'net-utils
120 :type '(repeat string)
121 :version "23.1")
123 (defcustom netstat-program "netstat"
124 "Program to print network statistics."
125 :group 'net-utils
126 :type 'string)
128 (defcustom netstat-program-options
129 (list "-a")
130 "Options for the netstat program."
131 :group 'net-utils
132 :type '(repeat string))
134 (defcustom arp-program "arp"
135 "Program to print IP to address translation tables."
136 :group 'net-utils
137 :type 'string)
139 (defcustom arp-program-options
140 (list "-a")
141 "Options for the arp program."
142 :group 'net-utils
143 :type '(repeat string))
145 (defcustom route-program
146 (if (eq system-type 'windows-nt)
147 "route"
148 "netstat")
149 "Program to print routing tables."
150 :group 'net-utils
151 :type 'string)
153 (defcustom route-program-options
154 (if (eq system-type 'windows-nt)
155 (list "print")
156 (list "-r"))
157 "Options for the route program."
158 :group 'net-utils
159 :type '(repeat string))
161 (defcustom nslookup-program "nslookup"
162 "Program to interactively query DNS information."
163 :group 'net-utils
164 :type 'string)
166 (defcustom nslookup-program-options nil
167 "Options for the nslookup program."
168 :group 'net-utils
169 :type '(repeat string))
171 (defcustom nslookup-prompt-regexp "^> "
172 "Regexp to match the nslookup prompt.
174 This variable is only used if the variable
175 `comint-use-prompt-regexp' is non-nil."
176 :group 'net-utils
177 :type 'regexp)
179 (defcustom dig-program "dig"
180 "Program to query DNS information."
181 :group 'net-utils
182 :type 'string)
184 (defcustom ftp-program "ftp"
185 "Program to run to do FTP transfers."
186 :group 'net-utils
187 :type 'string)
189 (defcustom ftp-program-options nil
190 "Options for the ftp program."
191 :group 'net-utils
192 :type '(repeat string))
194 (defcustom ftp-prompt-regexp "^ftp>"
195 "Regexp which matches the FTP program's prompt.
197 This variable is only used if the variable
198 `comint-use-prompt-regexp' is non-nil."
199 :group 'net-utils
200 :type 'regexp)
202 (defcustom smbclient-program "smbclient"
203 "Smbclient program."
204 :group 'net-utils
205 :type 'string)
207 (defcustom smbclient-program-options nil
208 "Options for the smbclient program."
209 :group 'net-utils
210 :type '(repeat string))
212 (defcustom smbclient-prompt-regexp "^smb: \>"
213 "Regexp which matches the smbclient program's prompt.
215 This variable is only used if the variable
216 `comint-use-prompt-regexp' is non-nil."
217 :group 'net-utils
218 :type 'regexp)
220 (defcustom dns-lookup-program "host"
221 "Program to interactively query DNS information."
222 :group 'net-utils
223 :type 'string)
225 (defcustom dns-lookup-program-options nil
226 "Options for the dns-lookup program."
227 :group 'net-utils
228 :type '(repeat string))
230 ;; Internal variables
231 (defvar network-connection-service nil)
232 (defvar network-connection-host nil)
234 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
235 ;; Nslookup goodies
236 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
238 (defvar nslookup-font-lock-keywords
239 (list
240 (list "^[A-Za-z0-9 _]+:" 0 'font-lock-type-face)
241 (list "\\<\\(SOA\\|NS\\|MX\\|A\\|CNAME\\)\\>"
242 1 'font-lock-keyword-face)
243 ;; Dotted quads
244 (list
245 (mapconcat 'identity
246 (make-list 4 "[0-9]+")
247 "\\.")
248 0 'font-lock-variable-name-face)
249 ;; Host names
250 (list
251 (let ((host-expression "[-A-Za-z0-9]+"))
252 (concat
253 (mapconcat 'identity
254 (make-list 2 host-expression)
255 "\\.")
256 "\\(\\." host-expression "\\)*"))
257 0 'font-lock-variable-name-face))
258 "Expressions to font-lock for nslookup.")
260 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
261 ;; General network utilities mode
262 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
264 (defvar net-utils-font-lock-keywords
265 (list
266 ;; Dotted quads
267 (list
268 (mapconcat 'identity (make-list 4 "[0-9]+") "\\.")
269 0 'font-lock-variable-name-face)
270 ;; Simple rfc4291 addresses
271 (list (concat
272 "\\( \\([[:xdigit:]]+\\(:\\|::\\)\\)+[[:xdigit:]]+\\)"
273 "\\|"
274 "\\(::[[:xdigit:]]+\\)")
275 0 'font-lock-variable-name-face)
276 ;; Host names
277 (list
278 (let ((host-expression "[-A-Za-z0-9]+"))
279 (concat
280 (mapconcat 'identity (make-list 2 host-expression) "\\.")
281 "\\(\\." host-expression "\\)*"))
282 0 'font-lock-variable-name-face))
283 "Expressions to font-lock for general network utilities.")
285 (define-derived-mode net-utils-mode special-mode "NetworkUtil"
286 "Major mode for interacting with an external network utility."
287 (set (make-local-variable 'font-lock-defaults)
288 '((net-utils-font-lock-keywords)))
289 (setq-local revert-buffer-function #'net-utils--revert-function))
291 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
292 ;; Utility functions
293 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
295 ;; Simplified versions of some at-point functions from ffap.el.
296 ;; It's not worth loading all of ffap just for these.
297 (defun net-utils-machine-at-point ()
298 (let ((pt (point)))
299 (buffer-substring-no-properties
300 (save-excursion
301 (skip-chars-backward "-a-zA-Z0-9.")
302 (point))
303 (save-excursion
304 (skip-chars-forward "-a-zA-Z0-9.")
305 (skip-chars-backward "." pt)
306 (point)))))
308 (defun net-utils-url-at-point ()
309 (let ((pt (point)))
310 (buffer-substring-no-properties
311 (save-excursion
312 (skip-chars-backward "--:=&?$+@-Z_a-z~#,%")
313 (skip-chars-forward "^A-Za-z0-9" pt)
314 (point))
315 (save-excursion
316 (skip-chars-forward "--:=&?$+@-Z_a-z~#,%")
317 (skip-chars-backward ":;.,!?" pt)
318 (point)))))
320 (defun net-utils-remove-ctrl-m-filter (process output-string)
321 "Remove trailing control Ms."
322 (let ((old-buffer (current-buffer))
323 (filtered-string output-string))
324 (unwind-protect
325 (let ((moving))
326 (set-buffer (process-buffer process))
327 (let ((inhibit-read-only t))
328 (setq moving (= (point) (process-mark process)))
330 (while (string-match "\r" filtered-string)
331 (setq filtered-string
332 (replace-match "" nil nil filtered-string)))
334 (save-excursion
335 ;; Insert the text, moving the process-marker.
336 (goto-char (process-mark process))
337 (insert filtered-string)
338 (set-marker (process-mark process) (point))))
339 (if moving (goto-char (process-mark process))))
340 (set-buffer old-buffer))))
342 (defun net-utils-run-program (name header program args)
343 "Run a network information program."
344 (let ((buf (get-buffer-create (concat "*" name "*"))))
345 (set-buffer buf)
346 (erase-buffer)
347 (insert header "\n")
348 (set-process-filter
349 (apply 'start-process name buf program args)
350 'net-utils-remove-ctrl-m-filter)
351 (display-buffer buf)
352 buf))
354 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
355 ;; General network utilities (diagnostic)
356 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
358 ;; Todo: This data could be saved in a bookmark.
359 (defvar net-utils--revert-cmd nil)
361 (defun net-utils-run-simple (buffer program-name args)
362 "Run a network utility for diagnostic output only."
363 (with-current-buffer (if (stringp buffer) (get-buffer-create buffer) buffer)
364 (let ((proc (get-buffer-process (current-buffer))))
365 (when proc
366 (set-process-filter proc nil)
367 (delete-process proc)))
368 (let ((inhibit-read-only t))
369 (erase-buffer))
370 (net-utils-mode)
371 (setq-local net-utils--revert-cmd
372 `(net-utils-run-simple ,(current-buffer) ,program-name ,args))
373 (set-process-filter
374 (apply 'start-process program-name
375 (current-buffer) program-name args)
376 'net-utils-remove-ctrl-m-filter)
377 (goto-char (point-min))
378 (display-buffer (current-buffer))))
380 (defun net-utils--revert-function (&optional ignore-auto noconfirm)
381 (message "Reverting `%s'..." (buffer-name))
382 (apply (car net-utils--revert-cmd) (cdr net-utils--revert-cmd))
383 (let ((proc (get-buffer-process (current-buffer))))
384 (when proc
385 (set-process-sentinel
386 proc
387 (lambda (process event)
388 (when (string= event "finished\n")
389 (message "Reverting `%s' done" (process-buffer process))))))))
391 ;;;###autoload
392 (defun ifconfig ()
393 "Run ifconfig and display diagnostic output."
394 (interactive)
395 (net-utils-run-simple
396 (format "*%s*" ifconfig-program)
397 ifconfig-program
398 ifconfig-program-options))
400 (defalias 'ipconfig 'ifconfig)
402 ;;;###autoload
403 (defun iwconfig ()
404 "Run iwconfig and display diagnostic output."
405 (interactive)
406 (net-utils-run-simple
407 (format "*%s*" iwconfig-program)
408 iwconfig-program
409 iwconfig-program-options))
411 ;;;###autoload
412 (defun netstat ()
413 "Run netstat and display diagnostic output."
414 (interactive)
415 (net-utils-run-simple
416 (format "*%s*" netstat-program)
417 netstat-program
418 netstat-program-options))
420 ;;;###autoload
421 (defun arp ()
422 "Run arp and display diagnostic output."
423 (interactive)
424 (net-utils-run-simple
425 (format "*%s*" arp-program)
426 arp-program
427 arp-program-options))
429 ;;;###autoload
430 (defun route ()
431 "Run route and display diagnostic output."
432 (interactive)
433 (net-utils-run-simple
434 (format "*%s*" route-program)
435 route-program
436 route-program-options))
438 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
439 ;; Wrappers for external network programs
440 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
442 ;;;###autoload
443 (defun traceroute (target)
444 "Run traceroute program for TARGET."
445 (interactive "sTarget: ")
446 (let ((options
447 (if traceroute-program-options
448 (append traceroute-program-options (list target))
449 (list target))))
450 (net-utils-run-simple
451 (concat "Traceroute" " " target)
452 traceroute-program
453 options)))
455 ;;;###autoload
456 (defun ping (host)
457 "Ping HOST.
458 If your system's ping continues until interrupted, you can try setting
459 `ping-program-options'."
460 (interactive
461 (list (read-from-minibuffer "Ping host: " (net-utils-machine-at-point))))
462 (let ((options
463 (if ping-program-options
464 (append ping-program-options (list host))
465 (list host))))
466 (net-utils-run-program
467 (concat "Ping" " " host)
468 (concat "** Ping ** " ping-program " ** " host)
469 ping-program
470 options)))
472 ;; FIXME -- Needs to be a process filter
473 ;; (defun netstat-with-filter (filter)
474 ;; "Run netstat program."
475 ;; (interactive "sFilter: ")
476 ;; (netstat)
477 ;; (set-buffer (get-buffer "*Netstat*"))
478 ;; (goto-char (point-min))
479 ;; (delete-matching-lines filter))
481 ;;;###autoload
482 (defun nslookup-host (host)
483 "Lookup the DNS information for HOST."
484 (interactive
485 (list (read-from-minibuffer "Lookup host: " (net-utils-machine-at-point))))
486 (let ((options
487 (if nslookup-program-options
488 (append nslookup-program-options (list host))
489 (list host))))
490 (net-utils-run-program
491 "Nslookup"
492 (concat "** "
493 (mapconcat 'identity
494 (list "Nslookup" host nslookup-program)
495 " ** "))
496 nslookup-program
497 options)))
499 ;;;###autoload
500 (defun nslookup ()
501 "Run nslookup program."
502 (interactive)
503 (switch-to-buffer (make-comint "nslookup" nslookup-program))
504 (nslookup-mode))
506 (defvar comint-prompt-regexp)
507 (defvar comint-input-autoexpand)
509 (autoload 'comint-mode "comint" nil t)
511 (defvar nslookup-mode-map
512 (let ((map (make-sparse-keymap)))
513 (define-key map "\t" 'comint-dynamic-complete)
514 map))
516 ;; Using a derived mode gives us keymaps, hooks, etc.
517 (define-derived-mode nslookup-mode comint-mode "Nslookup"
518 "Major mode for interacting with the nslookup program."
519 (set
520 (make-local-variable 'font-lock-defaults)
521 '((nslookup-font-lock-keywords)))
522 (setq comint-prompt-regexp nslookup-prompt-regexp)
523 (setq comint-input-autoexpand t))
525 ;;;###autoload
526 (defun dns-lookup-host (host)
527 "Lookup the DNS information for HOST (name or IP address)."
528 (interactive
529 (list (read-from-minibuffer "Lookup host: " (net-utils-machine-at-point))))
530 (let ((options
531 (if dns-lookup-program-options
532 (append dns-lookup-program-options (list host))
533 (list host))))
534 (net-utils-run-program
535 (concat "DNS Lookup [" host "]")
536 (concat "** "
537 (mapconcat 'identity
538 (list "DNS Lookup" host dns-lookup-program)
539 " ** "))
540 dns-lookup-program
541 options)))
543 (autoload 'ffap-string-at-point "ffap")
545 ;;;###autoload
546 (defun run-dig (host)
547 "Run dig program."
548 (interactive
549 (list
550 (read-from-minibuffer "Lookup host: "
551 (or (ffap-string-at-point 'machine) ""))))
552 (net-utils-run-program
553 "Dig"
554 (concat "** "
555 (mapconcat 'identity
556 (list "Dig" host dig-program)
557 " ** "))
558 dig-program
559 (list host)))
561 (autoload 'comint-exec "comint")
563 ;; This is a lot less than ange-ftp, but much simpler.
564 ;;;###autoload
565 (defun ftp (host)
566 "Run ftp program."
567 (interactive
568 (list
569 (read-from-minibuffer
570 "Ftp to Host: " (net-utils-machine-at-point))))
571 (let ((buf (get-buffer-create (concat "*ftp [" host "]*"))))
572 (set-buffer buf)
573 (ftp-mode)
574 (comint-exec buf (concat "ftp-" host) ftp-program nil
575 (if ftp-program-options
576 (append (list host) ftp-program-options)
577 (list host)))
578 (pop-to-buffer buf)))
580 (defvar ftp-mode-map
581 (let ((map (make-sparse-keymap)))
582 ;; Occasionally useful
583 (define-key map "\t" 'comint-dynamic-complete)
584 map))
586 (define-derived-mode ftp-mode comint-mode "FTP"
587 "Major mode for interacting with the ftp program."
588 (setq comint-prompt-regexp ftp-prompt-regexp)
589 (setq comint-input-autoexpand t)
590 ;; Only add the password-prompting hook if it's not already in the
591 ;; global hook list. This stands a small chance of losing, if it's
592 ;; later removed from the global list (very small, since any
593 ;; password prompts will probably immediately follow the initial
594 ;; connection), but it's better than getting prompted twice for the
595 ;; same password.
596 (unless (memq 'comint-watch-for-password-prompt
597 (default-value 'comint-output-filter-functions))
598 (add-hook 'comint-output-filter-functions 'comint-watch-for-password-prompt
599 nil t)))
601 (defun smbclient (host service)
602 "Connect to SERVICE on HOST via SMB."
603 (interactive
604 (list
605 (read-from-minibuffer
606 "Connect to Host: " (net-utils-machine-at-point))
607 (read-from-minibuffer "SMB Service: ")))
608 (let* ((name (format "smbclient [%s\\%s]" host service))
609 (buf (get-buffer-create (concat "*" name "*")))
610 (service-name (concat "\\\\" host "\\" service)))
611 (set-buffer buf)
612 (smbclient-mode)
613 (comint-exec buf name smbclient-program nil
614 (if smbclient-program-options
615 (append (list service-name) smbclient-program-options)
616 (list service-name)))
617 (pop-to-buffer buf)))
619 (defun smbclient-list-shares (host)
620 "List services on HOST."
621 (interactive
622 (list
623 (read-from-minibuffer
624 "Connect to Host: " (net-utils-machine-at-point))))
625 (let ((buf (get-buffer-create (format "*SMB Shares on %s*" host))))
626 (set-buffer buf)
627 (smbclient-mode)
628 (comint-exec buf "smbclient-list-shares"
629 smbclient-program nil (list "-L" host))
630 (pop-to-buffer buf)))
632 (define-derived-mode smbclient-mode comint-mode "smbclient"
633 "Major mode for interacting with the smbclient program."
634 (setq comint-prompt-regexp smbclient-prompt-regexp)
635 (setq comint-input-autoexpand t)
636 ;; Only add the password-prompting hook if it's not already in the
637 ;; global hook list. This stands a small chance of losing, if it's
638 ;; later removed from the global list (very small, since any
639 ;; password prompts will probably immediately follow the initial
640 ;; connection), but it's better than getting prompted twice for the
641 ;; same password.
642 (unless (memq 'comint-watch-for-password-prompt
643 (default-value 'comint-output-filter-functions))
644 (add-hook 'comint-output-filter-functions 'comint-watch-for-password-prompt
645 nil t)))
648 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
649 ;; Network Connections
650 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
652 ;; Full list is available at:
653 ;; http://www.iana.org/assignments/port-numbers
654 (defvar network-connection-service-alist
655 (list
656 (cons 'echo 7)
657 (cons 'active-users 11)
658 (cons 'daytime 13)
659 (cons 'chargen 19)
660 (cons 'ftp 21)
661 (cons 'telnet 23)
662 (cons 'smtp 25)
663 (cons 'time 37)
664 (cons 'whois 43)
665 (cons 'gopher 70)
666 (cons 'finger 79)
667 (cons 'www 80)
668 (cons 'pop2 109)
669 (cons 'pop3 110)
670 (cons 'sun-rpc 111)
671 (cons 'nntp 119)
672 (cons 'ntp 123)
673 (cons 'netbios-name 137)
674 (cons 'netbios-data 139)
675 (cons 'irc 194)
676 (cons 'https 443)
677 (cons 'rlogin 513))
678 "Alist of services and associated TCP port numbers.
679 This list is not complete.")
681 ;; Workhorse routine
682 (defun run-network-program (process-name host port &optional initial-string)
683 (let ((tcp-connection)
684 (buf))
685 (setq buf (get-buffer-create (concat "*" process-name "*")))
686 (set-buffer buf)
688 (setq tcp-connection
689 (open-network-stream process-name buf host port))
690 (error "Could not open connection to %s" host))
691 (erase-buffer)
692 (set-marker (process-mark tcp-connection) (point-min))
693 (set-process-filter tcp-connection 'net-utils-remove-ctrl-m-filter)
694 (and initial-string
695 (process-send-string tcp-connection
696 (concat initial-string "\r\n")))
697 (display-buffer buf)))
699 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
700 ;; Simple protocols
701 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
703 (defcustom finger-X.500-host-regexps nil
704 "A list of regular expressions matching host names.
705 If a host name passed to `finger' matches one of these regular
706 expressions, it is assumed to be a host that doesn't accept
707 queries of the form USER@HOST, and wants a query containing USER only."
708 :group 'net-utils
709 :type '(repeat regexp)
710 :version "21.1")
712 ;; Finger protocol
713 ;;;###autoload
714 (defun finger (user host)
715 "Finger USER on HOST."
716 ;; One of those great interactive statements that's actually
717 ;; longer than the function call! The idea is that if the user
718 ;; uses a string like "pbreton@cs.umb.edu", we won't ask for the
719 ;; host name. If we don't see an "@", we'll prompt for the host.
720 (interactive
721 (let* ((answer (read-from-minibuffer "Finger User: "
722 (net-utils-url-at-point)))
723 (index (string-match (regexp-quote "@") answer)))
724 (if index
725 (list (substring answer 0 index)
726 (substring answer (1+ index)))
727 (list answer
728 (read-from-minibuffer "At Host: "
729 (net-utils-machine-at-point))))))
730 (let* ((user-and-host (concat user "@" host))
731 (process-name (concat "Finger [" user-and-host "]"))
732 (regexps finger-X.500-host-regexps)
733 found)
734 (and regexps
735 (while (not (string-match (car regexps) host))
736 (setq regexps (cdr regexps)))
737 (when regexps
738 (setq user-and-host user)))
739 (run-network-program
740 process-name
741 host
742 (cdr (assoc 'finger network-connection-service-alist))
743 user-and-host)))
745 (defcustom whois-server-name "rs.internic.net"
746 "Default host name for the whois service."
747 :group 'net-utils
748 :type 'string)
750 (defcustom whois-server-list
751 '(("whois.arin.net") ; Networks, ASN's, and related POC's (numbers)
752 ("rs.internic.net") ; domain related info
753 ("whois.publicinterestregistry.net")
754 ("whois.abuse.net")
755 ("whois.apnic.net")
756 ("nic.ddn.mil")
757 ("whois.nic.mil")
758 ("whois.nic.gov")
759 ("whois.ripe.net"))
760 "A list of whois servers that can be queried."
761 :group 'net-utils
762 :type '(repeat (list string)))
764 ;; FIXME: modern whois clients include a much better tld <-> whois server
765 ;; list, Emacs should probably avoid specifying the server as the client
766 ;; will DTRT anyway... -rfr
767 (defcustom whois-server-tld
768 '(("rs.internic.net" . "com")
769 ("whois.publicinterestregistry.net" . "org")
770 ("whois.ripe.net" . "be")
771 ("whois.ripe.net" . "de")
772 ("whois.ripe.net" . "dk")
773 ("whois.ripe.net" . "it")
774 ("whois.ripe.net" . "fi")
775 ("whois.ripe.net" . "fr")
776 ("whois.ripe.net" . "uk")
777 ("whois.apnic.net" . "au")
778 ("whois.apnic.net" . "ch")
779 ("whois.apnic.net" . "hk")
780 ("whois.apnic.net" . "jp")
781 ("whois.nic.gov" . "gov")
782 ("whois.nic.mil" . "mil"))
783 "Alist to map top level domains to whois servers."
784 :group 'net-utils
785 :type '(repeat (cons string string)))
787 (defcustom whois-guess-server t
788 "If non-nil then whois will try to deduce the appropriate whois
789 server from the query. If the query doesn't look like a domain or hostname
790 then the server named by `whois-server-name' is used."
791 :group 'net-utils
792 :type 'boolean)
794 (defun whois-get-tld (host)
795 "Return the top level domain of `host', or nil if it isn't a domain name."
796 (let ((i (1- (length host)))
797 (max-len (- (length host) 5)))
798 (while (not (or (= i max-len) (char-equal (aref host i) ?.)))
799 (setq i (1- i)))
800 (if (= i max-len)
802 (substring host (1+ i)))))
804 ;; Whois protocol
805 ;;;###autoload
806 (defun whois (arg search-string)
807 "Send SEARCH-STRING to server defined by the `whois-server-name' variable.
808 If `whois-guess-server' is non-nil, then try to deduce the correct server
809 from SEARCH-STRING. With argument, prompt for whois server."
810 (interactive "P\nsWhois: ")
811 (let* ((whois-apropos-host (if whois-guess-server
812 (rassoc (whois-get-tld search-string)
813 whois-server-tld)
814 nil))
815 (server-name (if whois-apropos-host
816 (car whois-apropos-host)
817 whois-server-name))
818 (host
819 (if arg
820 (completing-read "Whois server name: "
821 whois-server-list nil nil "whois.")
822 server-name)))
823 (run-network-program
824 "Whois"
825 host
826 (cdr (assoc 'whois network-connection-service-alist))
827 search-string)))
829 (defcustom whois-reverse-lookup-server "whois.arin.net"
830 "Server which provides inverse DNS mapping."
831 :group 'net-utils
832 :type 'string)
834 ;;;###autoload
835 (defun whois-reverse-lookup ()
836 (interactive)
837 (let ((whois-server-name whois-reverse-lookup-server))
838 (call-interactively 'whois)))
840 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
841 ;;; General Network connection
842 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
844 ;; Using a derived mode gives us keymaps, hooks, etc.
845 (define-derived-mode
846 network-connection-mode comint-mode "Network-Connection"
847 "Major mode for interacting with the network-connection program.")
849 (defun network-connection-mode-setup (host service)
850 (make-local-variable 'network-connection-host)
851 (setq network-connection-host host)
852 (make-local-variable 'network-connection-service)
853 (setq network-connection-service service))
855 ;;;###autoload
856 (defun network-connection-to-service (host service)
857 "Open a network connection to SERVICE on HOST."
858 (interactive
859 (list
860 (read-from-minibuffer "Host: " (net-utils-machine-at-point))
861 (completing-read "Service: "
862 (mapcar
863 (function
864 (lambda (elt)
865 (list (symbol-name (car elt)))))
866 network-connection-service-alist))))
867 (network-connection
868 host
869 (cdr (assoc (intern service) network-connection-service-alist))))
871 ;;;###autoload
872 (defun network-connection (host port)
873 "Open a network connection to HOST on PORT."
874 (interactive "sHost: \nnPort: ")
875 (network-service-connection host (number-to-string port)))
877 (defun network-service-connection (host service)
878 "Open a network connection to SERVICE on HOST."
879 (let* ((process-name (concat "Network Connection [" host " " service "]"))
880 (portnum (string-to-number service))
881 (buf (get-buffer-create (concat "*" process-name "*"))))
882 (or (zerop portnum) (setq service portnum))
883 (make-comint
884 process-name
885 (cons host service))
886 (set-buffer buf)
887 (network-connection-mode)
888 (network-connection-mode-setup host service)
889 (pop-to-buffer buf)))
891 (defvar comint-input-ring)
893 (defun network-connection-reconnect ()
894 "Reconnect a network connection, preserving the old input ring."
895 (interactive)
896 (let ((proc (get-buffer-process (current-buffer)))
897 (old-comint-input-ring comint-input-ring)
898 (host network-connection-host)
899 (service network-connection-service))
900 (if (not (or (not proc)
901 (eq (process-status proc) 'closed)))
902 (message "Still connected")
903 (goto-char (point-max))
904 (insert (format "Reopening connection to %s\n" host))
905 (network-connection host
906 (if (numberp service)
907 service
908 (cdr (assoc service network-connection-service-alist))))
909 (and old-comint-input-ring
910 (setq comint-input-ring old-comint-input-ring)))))
912 (provide 'net-utils)
914 ;;; net-utils.el ends here