xref: /freebsd/contrib/sendmail/contrib/etrn.pl (revision aa0a1e58)
1#!/usr/local/bin/perl -w
2#
3# Copyright (c) 1996-2000 by John T. Beck <john@beck.org>
4# All rights reserved.
5#
6# Copyright (c) 2000 by Sun Microsystems, Inc.
7# All rights reserved.
8#
9#ident	"@(#)etrn.pl	1.1	00/09/06 SMI"
10
11require 5.005;				# minimal Perl version required
12use strict;
13use English;
14
15# hardcoded constants, should work fine for BSD-based systems
16use Socket;
17use Getopt::Std;
18use vars qw($opt_v);
19my $sockaddr = 'S n a4 x8';
20
21# system requirements:
22# 	must have 'hostname' program.
23
24my $port = 'smtp';
25select(STDERR);
26
27chop(my $name = `hostname || uname -n`);
28
29(my $hostname, my $aliases, my $type, my $len, undef) = gethostbyname($name);
30
31my $usage = "Usage: $PROGRAM_NAME [-v] host [args]";
32getopts('v');
33my $verbose = $opt_v;
34my $server = shift(@ARGV);
35my @hosts = @ARGV;
36die $usage unless $server;
37my @cwfiles = ();
38my $alarm_action = "";
39
40if (!@hosts) {
41	push(@hosts, $hostname);
42
43	open(CF, "</etc/mail/sendmail.cf") ||
44	    die "open /etc/mail/sendmail.cf: $ERRNO";
45	while (<CF>){
46		# look for a line starting with "Fw"
47		if (/^Fw.*$/) {
48			my $cwfile = $ARG;
49			chop($cwfile);
50			my $optional = /^Fw-o/;
51			# extract the file name
52			$cwfile =~ s,^Fw[^/]*,,;
53
54			# strip the options after the filename
55			$cwfile =~ s/ [^ ]+$//;
56
57			if (-r $cwfile) {
58				push (@cwfiles, $cwfile);
59			} else {
60				die "$cwfile is not readable" unless $optional;
61			}
62		}
63		# look for a line starting with "Cw"
64		if (/^Cw(.*)$/) {
65			my @cws = split (' ', $1);
66			while (@cws) {
67				my $thishost = shift(@cws);
68				push(@hosts, $thishost)
69				    unless $thishost =~ "$hostname|localhost";
70			}
71		}
72	}
73	close(CF);
74
75	for my $cwfile (@cwfiles) {
76		if (open(CW, "<$cwfile")) {
77			while (<CW>) {
78			        next if /^\#/;
79				my $thishost = $ARG;
80				chop($thishost);
81				push(@hosts, $thishost)
82				    unless $thishost =~ $hostname;
83			}
84			close(CW);
85		} else {
86			die "open $cwfile: $ERRNO";
87		}
88	}
89}
90
91($name, $aliases, my $proto) = getprotobyname('tcp');
92($name, $aliases, $port) = getservbyname($port, 'tcp')
93	unless $port =~ /^\d+/;
94
95# look it up
96
97($name, $aliases, $type, $len, my $thataddr) = gethostbyname($server);
98(!defined($name)) && die "gethostbyname failed, unknown host $server";
99
100# get a connection
101my $that = pack($sockaddr, &AF_INET, $port, $thataddr);
102socket(S, &AF_INET, &SOCK_STREAM, $proto)
103	|| die "socket: $ERRNO";
104print "server = $server\n" if (defined($verbose));
105&alarm("connect to $server");
106if (! connect(S, $that)) {
107	die "cannot connect to $server: $ERRNO\n";
108}
109alarm(0);
110select((select(S), $OUTPUT_AUTOFLUSH = 1)[0]);	# don't buffer output to S
111
112# read the greeting
113&alarm("greeting with $server");
114while (<S>) {
115	alarm(0);
116	print if $verbose;
117	if (/^(\d+)([- ])/) {
118		# SMTP's initial greeting response code is 220.
119		if ($1 != 220) {
120			&alarm("giving up after bad response from $server");
121			&read_response($2, $verbose);
122			alarm(0);
123			print STDERR "$server: NOT 220 greeting: $ARG"
124				if ($verbose);
125		}
126		last if ($2 eq " ");
127	} else {
128		print STDERR "$server: NOT 220 greeting: $ARG"
129			if ($verbose);
130		close(S);
131	}
132	&alarm("greeting with $server");
133}
134alarm(0);
135
136&alarm("sending ehlo to $server");
137&ps("ehlo $hostname");
138my $etrn_support = 0;
139while (<S>) {
140	if (/^250([- ])ETRN(.+)$/) {
141		$etrn_support = 1;
142	}
143	print if $verbose;
144	last if /^\d+ /;
145}
146alarm(0);
147
148if ($etrn_support) {
149	print "ETRN supported\n" if ($verbose);
150	&alarm("sending etrn to $server");
151	while (@hosts) {
152		$server = shift(@hosts);
153		&ps("etrn $server");
154		while (<S>) {
155			print if $verbose;
156			last if /^\d+ /;
157		}
158		sleep(1);
159	}
160} else {
161	print "\nETRN not supported\n\n"
162}
163
164&alarm("sending 'quit' to $server");
165&ps("quit");
166while (<S>) {
167	print if $verbose;
168	last if /^\d+ /;
169}
170close(S);
171alarm(0);
172
173select(STDOUT);
174exit(0);
175
176# print to the server (also to stdout, if -v)
177sub ps
178{
179	my ($p) = @_;
180	print ">>> $p\n" if $verbose;
181	print S "$p\n";
182}
183
184sub alarm
185{
186	($alarm_action) = @_;
187	alarm(10);
188	$SIG{ALRM} = 'handle_alarm';
189}
190
191sub handle_alarm
192{
193	&giveup($alarm_action);
194}
195
196sub giveup
197{
198	my $reason = @_;
199	(my $pk, my $file, my $line);
200	($pk, $file, $line) = caller;
201
202	print "Timed out during $reason\n" if $verbose;
203	exit(1);
204}
205
206# read the rest of the current smtp daemon's response (and toss it away)
207sub read_response
208{
209	(my $done, $verbose) = @_;
210	(my @resp);
211	print my $s if $verbose;
212	while (($done eq "-") && ($s = <S>) && ($s =~ /^\d+([- ])/)) {
213		print $s if $verbose;
214		$done = $1;
215		push(@resp, $s);
216	}
217	return @resp;
218}
219