1 # include <ctype.h>
2 # include <wellknown.h>
3 # include <sysexits.h>
4 # include <stdio.h>
5 # include <useful.h>
6 
7 static char	SccsId[] =	"@(#)usersmtp.c	3.3	11/08/81";
8 
9 /*
10 **  TCP -- TCP/Ethernet/ARPAnet mailer
11 **
12 **	This arranges to send a message over the TCP connection.
13 */
14 
15 # define MAXLINE	200
16 
17 char	*MailCommand =	"/usr/lib/sendmail";
18 char	*MailUser =	"network";
19 char	*MailPassword =	"mailhack";
20 FILE	*InConnection;
21 FILE	*OutConnection;
22 bool	Verbose;
23 bool	Debug;
24 int	Status;			/* exit status */
25 
26 main(argc, argv)
27 	int argc;
28 	char **argv;
29 {
30 	while (argc > 1 && argv[1][0] == '-')
31 	{
32 		register char *p = *++argv;
33 
34 		argc--;
35 		switch (p[1])
36 		{
37 		  case 'v':
38 			Verbose = TRUE;
39 			break;
40 
41 		  case 'd':
42 			Debug = TRUE;
43 			break;
44 		}
45 	}
46 
47 	if (argc < 4)
48 	{
49 		if (Debug)
50 			printf("Usage\n");
51 		exit(EX_USAGE);
52 	}
53 
54 	if (openconnection(argv[2]) < 0)
55 		exit(Status);
56 
57 	Status = runsmtp(argv[1], &argv[3]);
58 
59 	closeconnection();
60 
61 	if (Debug)
62 		printf("Finishing with stat %d\n", Status);
63 
64 	exit(Status);
65 }
66 /*
67 **  OPENCONNECTION -- open connection to SMTP socket
68 **
69 **	Parameters:
70 **		host -- the name of the host to connect to.  This
71 **			will be replaced by the canonical name of
72 **			the host.
73 **
74 **	Returns:
75 **		File descriptor of connection.
76 **		-1 on error.
77 **
78 **	Side Effects:
79 **		sets 'Status' to represent the problem on error.
80 */
81 
82 openconnection(host)
83 	char *host;
84 {
85 	char cmdbuf[100];
86 	register int fd;
87 
88 	/* create the command name */
89 	sprintf(cmdbuf, "%s -as%s%s", MailCommand,
90 					Verbose ? " -v" : "",
91 					Debug ? " -d" : "");
92 
93 	if (Debug)
94 		printf("Creating connection to \"%s\" on %s\n", cmdbuf, host);
95 
96 	/* verify host name */
97 	if (rhost(&host) < 0)
98 	{
99 		if (Debug)
100 			printf("Unknown host %s\n", host);
101 		Status = EX_NOHOST;
102 		return (-1);
103 	}
104 
105 	/* create connection (we hope) */
106 	fd = rexec(&host, SHELLSERVER, cmdbuf, MailUser, MailPassword);
107 	if (fd < 0)
108 	{
109 		Status = EX_TEMPFAIL;
110 		return (-1);
111 	}
112 	InConnection = fdopen(fd, "r");
113 	OutConnection = fdopen(fd, "w");
114 	if (InConnection == NULL || OutConnection == NULL)
115 	{
116 		Status = EX_SOFTWARE;
117 		return (-1);
118 	}
119 
120 	if (Debug)
121 		printf("Connection open to %s\n", host);
122 
123 	return (0);
124 }
125 /*
126 **	CLOSECONNECTION -- close the connection to the SMTP server.
127 **
128 **	This routine also sends a handshake.
129 **
130 **	Parameters:
131 **		none.
132 **
133 **	Returns:
134 **		none.
135 **
136 **	Side Effects:
137 **		Closes the connection.
138 */
139 
140 closeconnection()
141 {
142 	register int r;
143 
144 	message("QUIT");
145 	r = reply();
146 
147 	if (Debug)
148 		printf("Closing connection, reply = %d\n", r);
149 }
150 /*
151 **  RUNSMTP -- run the SMTP protocol over connection.
152 **
153 **	Parameters:
154 **		fr -- from person.
155 **		tolist -- list of recipients.
156 **
157 **	Returns:
158 **		none.
159 **
160 **	Side Effects:
161 **		Sends the mail via SMTP.
162 */
163 
164 # define REPLYTYPE(r)	((r) / 100)
165 
166 runsmtp(fr, tolist)
167 	char *fr;
168 	char **tolist;
169 {
170 	register int r;
171 	register char **t;
172 	char buf[MAXLINE];
173 
174 	/*
175 	**  Get the greeting message.
176 	**	This should appear spontaneously.
177 	*/
178 
179 	r = reply();
180 	if (REPLYTYPE(r) != 2)
181 		return (EX_TEMPFAIL);
182 
183 	/*
184 	**  Send the MAIL command.
185 	**	Designates the sender.
186 	*/
187 
188 	message("MAIL From:<%s>", fr);
189 	r = reply();
190 	if (REPLYTYPE(r) == 4)
191 		return (EX_TEMPFAIL);
192 	if (r != 250)
193 		return (EX_SOFTWARE);
194 
195 	/*
196 	**  Send the recipients.
197 	*/
198 
199 	for (t = tolist; *t != NULL; t++)
200 	{
201 		message("MRCP To:<%s>", *t);
202 		r = reply();
203 		if (REPLYTYPE(r) == 4)
204 			return (EX_TEMPFAIL);
205 		if (r != 250)
206 			return (EX_NOUSER);
207 	}
208 
209 	/*
210 	**  Send the data.
211 	**	Dot hiding is done here.
212 	*/
213 
214 	message("DATA");
215 	r = reply();
216 	if (REPLYTYPE(r) == 4)
217 		return (EX_TEMPFAIL);
218 	if (r != 354)
219 		return (EX_SOFTWARE);
220 	while (fgets(buf, sizeof buf, stdin) != NULL)
221 	{
222 		/* change trailing newline to crlf */
223 		register char *p = index(buf, '\n');
224 
225 		if (p != NULL)
226 			*p = '\0';
227 		message("%s%s", buf[0] == '.' ? "." : "", buf);
228 	}
229 	message(".");
230 	r = reply();
231 	if (REPLYTYPE(r) == 4)
232 		return (EX_TEMPFAIL);
233 	if (r != 250)
234 		return (EX_SOFTWARE);
235 
236 	/*
237 	**  Make the actual delivery happen.
238 	*/
239 
240 	message("DOIT");
241 	r = reply();
242 	if (r != 250)
243 		return (EX_TEMPFAIL);
244 
245 	return (EX_OK);
246 }
247 /*
248 **  REPLY -- read arpanet reply
249 **
250 **	Parameters:
251 **		none.
252 **
253 **	Returns:
254 **		reply code it reads.
255 **
256 **	Side Effects:
257 **		flushes the mail file.
258 */
259 
260 reply()
261 {
262 	fflush(OutConnection);
263 
264 	if (Debug)
265 		printf("reply\n");
266 
267 	/* read the input line */
268 	for (;;)
269 	{
270 		char buf[MAXLINE];
271 		register int r;
272 
273 		if (fgets(buf, sizeof buf, InConnection) == NULL)
274 			return (-1);
275 		if (Verbose)
276 			fputs(buf, stdout);
277 		if (buf[3] == '-' || !isdigit(buf[0]))
278 			continue;
279 		r = atoi(buf);
280 		if (r < 100)
281 			continue;
282 		return (r);
283 	}
284 }
285 /*
286 **  MESSAGE -- send message to server
287 **
288 **	Parameters:
289 **		f -- format
290 **		a, b, c -- parameters
291 **
292 **	Returns:
293 **		none.
294 **
295 **	Side Effects:
296 **		writes message to OutChannel.
297 */
298 
299 message(f, a, b, c)
300 	char *f;
301 {
302 	char buf[100];
303 
304 	sprintf(buf, f, a, b, c);
305 	strcat(buf, "\r\n");
306 	if (Debug)
307 		fputs(buf, stdout);
308 	fputs(buf, OutConnection);
309 }
310