|
|
1.1 root 1: /*
2: * smtp -- client, send mail to remote smtp server
3: * TODO:
4: * allow partial delivery to multiple recipients when only some
5: * fail (maybe)
6: * send stuff from cmds.h instead of hard-coded here
7: */
8:
9: #define USAGE "usage: %s [-u] [-H helohost] [-d domain] [-a addr] [-f] [-D] [-L loglevel] sender targethost recip1 recip2 ...\n"
10:
11: #include <stdio.h>
12: #include <ctype.h>
13: #include <sysexits.h>
14: #include "addrformat.h"
15: #include "smtp.h"
16: #include "string.h"
17: #include "aux.h"
18: #include "sys.h"
19:
20: #ifndef DIALER
21: #define DIALER "tcp"
22: #endif
23:
24: #ifndef SERVNAME
25: #define SERVNAME "smtp" /* service we wanna talk to */
26: #endif
27:
28: char *progname;
29: int debug;
30: char *helohost;
31: int kludgepause = 0;
32:
33: char *strcat(), *strcpy();
34: extern char *convertaddr();
35: extern int ipcdebug;
36: extern char *ipcpath();
37:
38: static int errno;
39: static char errstr[128];
40:
41: char *convertto();
42:
43: /*
44: * main - parse arguments and handle options
45: */
46: main(argc, argv)
47: int argc;
48: char *argv[];
49: {
50: register int c;
51: int errflg = 0;
52: int unixformat = 0;
53: int filter = 0;
54: char *domain = 0;
55: char *sender = 0;
56: char *host = 0;
57: char *addr = 0;
58: namelist *recips, *newname(), *appendname();
59: FILE *sfi, *sfo;
60: string *replyaddr=s_new();
61: string *hh;
62:
63: extern int optind;
64: extern char *optarg;
65:
66: umask(2);
67:
68: progname = argv[0];
69: Openlog("smtp", LOG_PID, LOG_SMTP);
70: setlogmask(LOG_UPTO(DEFAULT_LOG_LEVEL));
71: while ((c = getopt(argc, argv, "ga:uDd:H:fL:K")) != EOF)
72: switch (c) {
73: case 'a': addr = optarg; break;
74: case 'u': unixformat++; break;
75: case 'D': debug++; ipcdebug++; break;
76: case 'd': domain = optarg; break;
77: case 'H': helohost = optarg; break;
78: case 'f': filter++; break;
79: case 'K': kludgepause++; break;
80: case 'L': setloglevel(optarg); break;
81: case '?':
82: default:
83: errflg++;
84: break;
85: }
86: if (errflg || (argc - optind) < 3) {
87: (void) fprintf(stderr, USAGE, progname);
88: Syslog(LOG_WARNING, "SMTP illegal usage.");
89: bomb(EX_USAGE);
90: }
91:
92: /*
93: * figure out what to call ourselves
94: */
95: if (helohost==NULL)
96: helohost=s_to_c(s_copy(sysname_read()));
97:
98: /*
99: * if there is no domain in the helo host name
100: * and we the -d option is specified, domainify
101: * the helo host
102: */
103: if(strchr(helohost, '.')==0 && domain){
104: hh = s_copy(helohost);
105: s_append(hh, domain);
106: helohost = s_to_c(hh);
107: }
108:
109: /*
110: * put our address onto the reply address
111: */
112: if(strchr(argv[optind], '!')==0 || !domain){
113: s_append(replyaddr, helohost);
114: s_append(replyaddr, "!");
115: s_append(replyaddr, argv[optind]);
116: } else {
117: s_append(replyaddr, argv[optind]);
118: }
119: optind++;
120:
121: /*
122: * convert the arguments to 822 form
123: */
124: sender = convertaddr(s_to_c(replyaddr), domain, SOURCEROUTE);
125: host = argv[optind++];
126: recips = newname(convertto(argv[optind++], unixformat, host));
127: for (; optind < argc; optind++)
128: recips = appendname(recips, convertto(argv[optind], unixformat, host));
129:
130: /*
131: * run as a filter
132: */
133: if ( filter ) {
134: do_data(unixformat, stdin, stdout, sender, recips, domain);
135: exit(0);
136: }
137:
138: /*
139: * open connection
140: */
141: setup(addr ? addr : host, &sfi, &sfo);
142:
143: /*
144: * hold the conversation
145: */
146: converse(unixformat, sender, recips, domain, sfi, sfo, stdin);
147: /* converse terminates with the appropriate exit code */
148: }
149:
150: namelist *
151: newname(s)
152: char *s;
153: {
154: namelist *np;
155:
156: np = (namelist *)malloc(sizeof(namelist));
157: if (np == NULL) {
158: Syslog(LOG_WARNING, "could not alloc (newname)");
159: bomb(1);
160: }
161: np->name = s;
162: np->next = NULL;
163: return np;
164: }
165:
166: /* could add at beginning, but let's maintain original order */
167: namelist *
168: appendname(nl, s)
169: char *s;
170: namelist *nl;
171: {
172: register namelist *tl;
173:
174: if (nl == NULL)
175: bomb(1); /* shouldn't happen */
176: for (tl=nl; tl->next!=NULL; tl=tl->next)
177: ;
178: tl->next = newname(s);
179: return nl;
180: }
181:
182: /*
183: * convert a destination address to outgoing format
184: *
185: * if unixformat, just leave it alone
186: *
187: * if not add the destination host name.
188: */
189: char *
190: convertto(recip, unixformat, desthost)
191: char *recip;
192: char *desthost;
193: {
194: static string *buf;
195:
196: if(unixformat)
197: return recip;
198:
199: buf = s_reset(buf);
200: s_append(buf, desthost);
201: s_append(buf, "!");
202: s_append(buf, recip);
203: return convertaddr(s_to_c(buf), 0, SOURCEROUTE);
204: }
205:
206:
207: /*
208: * setup -- setup tcp/ip connection to/from server
209: */
210: setup(host, sfip, sfop)
211: char *host;
212: FILE **sfip, **sfop;
213: {
214: int s;
215: char *path;
216: int localerr;
217:
218: path = ipcpath(host, DIALER, SERVNAME);
219: Syslog(LOG_DEBUG, "Opening connection to %s\n", path);
220: if ((s = ipcopen(path, "")) < 0) {
221: extern int ipcerrno;
222: extern char syserrstr[];
223:
224: char errbuf[256];
225: sprintf(errbuf, "SMTP connect error to %s", host);
226: ipcperror(errbuf);
227: Syslog(LOG_INFO, "%s: %s\n", errbuf, syserrstr);
228: bomb(ipcerrno);
229: }
230:
231: if (((*sfip = fdopen(s, "r")) == (FILE *) NULL) ||
232: ((*sfop = fdopen(s, "w")) == (FILE *) NULL)) {
233: perror("setup - fdopen");
234: Syslog(LOG_INFO, "setup - fdopen");
235: bomb(EX_IOERR);
236: }
237: }
238:
239:
240: /*
241: * bomb(code) - exit program, map smtp error code into mailsystem code
242: * Codes with EX_ are from <sysexits.h>
243: * Lines with FOO are placeholders until we decrypt more appropriate codes.
244: */
245: bomb(code)
246: int code;
247: {
248: switch(code) {
249: case 451: /* some temporary error */
250: exit(EX_TEMPFAIL); /* try later */
251: /*NOTREACHED*/
252: case 554: /* syntax error in address */
253: case 501: /* data format error */
254: exit(EX_DATAERR);
255: /*NOTREACHED*/
256: case 550: /* no such user */
257: exit(EX_NOUSER);
258: /*NOTREACHED*/
259: case EX_USAGE:
260: case EX_DATAERR:
261: case EX_NOINPUT:
262: case EX_NOUSER:
263: case EX_NOHOST:
264: case EX_UNAVAILABLE:
265: case EX_SOFTWARE:
266: case EX_OSERR:
267: case EX_OSFILE:
268: case EX_CANTCREAT:
269: case EX_IOERR:
270: case EX_TEMPFAIL:
271: case EX_PROTOCOL:
272: case EX_NOPERM:
273: exit(code);
274: /*NOTREACHED*/
275: default: /* can't happen? */
276: if ((code >= 400) && (code <= 499))
277: exit(EX_TEMPFAIL);
278: else {
279: Syslog(LOG_WARNING, "SMTP protocol error %d\n", code);
280: exit(EX_PROTOCOL); /* unknown error */
281: }
282: }
283: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.