Blame


1 5cdb1798 2005-10-29 devnull #include "common.h"
2 5cdb1798 2005-10-29 devnull #include "smtp.h"
3 5cdb1798 2005-10-29 devnull #include <ctype.h>
4 5cdb1798 2005-10-29 devnull #include <mp.h>
5 5cdb1798 2005-10-29 devnull #include <libsec.h>
6 5cdb1798 2005-10-29 devnull #include <auth.h>
7 5cdb1798 2005-10-29 devnull #include <ndb.h>
8 5cdb1798 2005-10-29 devnull
9 5cdb1798 2005-10-29 devnull static char* connect(char*);
10 5cdb1798 2005-10-29 devnull static char* dotls(char*);
11 5cdb1798 2005-10-29 devnull static char* doauth(char*);
12 5cdb1798 2005-10-29 devnull char* hello(char*, int);
13 5cdb1798 2005-10-29 devnull char* mailfrom(char*);
14 5cdb1798 2005-10-29 devnull char* rcptto(char*);
15 5cdb1798 2005-10-29 devnull char* data(String*, Biobuf*);
16 5cdb1798 2005-10-29 devnull void quit(char*);
17 5cdb1798 2005-10-29 devnull int getreply(void);
18 5cdb1798 2005-10-29 devnull void addhostdom(String*, char*);
19 5cdb1798 2005-10-29 devnull String* bangtoat(char*);
20 5cdb1798 2005-10-29 devnull String* convertheader(String*);
21 5cdb1798 2005-10-29 devnull int printheader(void);
22 5cdb1798 2005-10-29 devnull char* domainify(char*, char*);
23 5cdb1798 2005-10-29 devnull void putcrnl(char*, int);
24 5cdb1798 2005-10-29 devnull char* getcrnl(String*);
25 5cdb1798 2005-10-29 devnull int printdate(Node*);
26 5cdb1798 2005-10-29 devnull char *rewritezone(char *);
27 5cdb1798 2005-10-29 devnull int dBprint(char*, ...);
28 5cdb1798 2005-10-29 devnull int dBputc(int);
29 5cdb1798 2005-10-29 devnull String* fixrouteaddr(String*, Node*, Node*);
30 5cdb1798 2005-10-29 devnull char* expand_addr(char* a);
31 5cdb1798 2005-10-29 devnull int ping;
32 5cdb1798 2005-10-29 devnull int insecure;
33 5cdb1798 2005-10-29 devnull
34 5cdb1798 2005-10-29 devnull #define Retry "Retry, Temporary Failure"
35 5cdb1798 2005-10-29 devnull #define Giveup "Permanent Failure"
36 5cdb1798 2005-10-29 devnull
37 5cdb1798 2005-10-29 devnull int debug; /* true if we're debugging */
38 5cdb1798 2005-10-29 devnull String *reply; /* last reply */
39 5cdb1798 2005-10-29 devnull String *toline;
40 5cdb1798 2005-10-29 devnull int alarmscale;
41 5cdb1798 2005-10-29 devnull int last = 'n'; /* last character sent by putcrnl() */
42 5cdb1798 2005-10-29 devnull int filter;
43 5cdb1798 2005-10-29 devnull int trysecure; /* Try to use TLS if the other side supports it */
44 5cdb1798 2005-10-29 devnull int tryauth; /* Try to authenticate, if supported */
45 5cdb1798 2005-10-29 devnull int quitting; /* when error occurs in quit */
46 5cdb1798 2005-10-29 devnull char *quitrv; /* deferred return value when in quit */
47 5cdb1798 2005-10-29 devnull char ddomain[1024]; /* domain name of destination machine */
48 5cdb1798 2005-10-29 devnull char *gdomain; /* domain name of gateway */
49 5cdb1798 2005-10-29 devnull char *uneaten; /* first character after rfc822 headers */
50 5cdb1798 2005-10-29 devnull char *farend; /* system we are trying to send to */
51 5cdb1798 2005-10-29 devnull char *user; /* user we are authenticating as, if authenticating */
52 5cdb1798 2005-10-29 devnull char hostdomain[256];
53 5cdb1798 2005-10-29 devnull Biobuf bin;
54 5cdb1798 2005-10-29 devnull Biobuf bout;
55 5cdb1798 2005-10-29 devnull Biobuf berr;
56 5cdb1798 2005-10-29 devnull Biobuf bfile;
57 5cdb1798 2005-10-29 devnull
58 5cdb1798 2005-10-29 devnull void
59 5cdb1798 2005-10-29 devnull usage(void)
60 5cdb1798 2005-10-29 devnull {
61 5cdb1798 2005-10-29 devnull fprint(2, "usage: smtp [-adips] [-uuser] [-hhost] [.domain] net!host[!service] sender rcpt-list\n");
62 5cdb1798 2005-10-29 devnull exits(Giveup);
63 5cdb1798 2005-10-29 devnull }
64 5cdb1798 2005-10-29 devnull
65 5cdb1798 2005-10-29 devnull int
66 5cdb1798 2005-10-29 devnull timeout(void *x, char *msg)
67 5cdb1798 2005-10-29 devnull {
68 5cdb1798 2005-10-29 devnull USED(x);
69 5cdb1798 2005-10-29 devnull syslog(0, "smtp.fail", "interrupt: %s: %s", farend, msg);
70 5cdb1798 2005-10-29 devnull if(strstr(msg, "alarm")){
71 5cdb1798 2005-10-29 devnull fprint(2, "smtp timeout: connection to %s timed out\n", farend);
72 5cdb1798 2005-10-29 devnull if(quitting)
73 5cdb1798 2005-10-29 devnull exits(quitrv);
74 5cdb1798 2005-10-29 devnull exits(Retry);
75 5cdb1798 2005-10-29 devnull }
76 5cdb1798 2005-10-29 devnull if(strstr(msg, "closed pipe")){
77 5cdb1798 2005-10-29 devnull /* call _exits() to prevent Bio from trying to flush closed pipe */
78 5cdb1798 2005-10-29 devnull fprint(2, "smtp timeout: connection closed to %s\n", farend);
79 5cdb1798 2005-10-29 devnull if(quitting){
80 5cdb1798 2005-10-29 devnull syslog(0, "smtp.fail", "closed pipe to %s", farend);
81 5cdb1798 2005-10-29 devnull _exits(quitrv);
82 5cdb1798 2005-10-29 devnull }
83 5cdb1798 2005-10-29 devnull _exits(Retry);
84 5cdb1798 2005-10-29 devnull }
85 5cdb1798 2005-10-29 devnull return 0;
86 5cdb1798 2005-10-29 devnull }
87 5cdb1798 2005-10-29 devnull
88 5cdb1798 2005-10-29 devnull void
89 5cdb1798 2005-10-29 devnull removenewline(char *p)
90 5cdb1798 2005-10-29 devnull {
91 5cdb1798 2005-10-29 devnull int n = strlen(p)-1;
92 5cdb1798 2005-10-29 devnull
93 5cdb1798 2005-10-29 devnull if(n < 0)
94 5cdb1798 2005-10-29 devnull return;
95 5cdb1798 2005-10-29 devnull if(p[n] == '\n')
96 5cdb1798 2005-10-29 devnull p[n] = 0;
97 5cdb1798 2005-10-29 devnull }
98 5cdb1798 2005-10-29 devnull
99 5cdb1798 2005-10-29 devnull void
100 5cdb1798 2005-10-29 devnull threadmain(int argc, char **argv)
101 5cdb1798 2005-10-29 devnull {
102 5cdb1798 2005-10-29 devnull char hellodomain[256];
103 5cdb1798 2005-10-29 devnull char *host, *domain;
104 5cdb1798 2005-10-29 devnull String *from;
105 5cdb1798 2005-10-29 devnull String *fromm;
106 5cdb1798 2005-10-29 devnull String *sender;
107 5cdb1798 2005-10-29 devnull char *addr;
108 5cdb1798 2005-10-29 devnull char *rv, *trv;
109 5cdb1798 2005-10-29 devnull int i, ok, rcvrs;
110 5cdb1798 2005-10-29 devnull char **errs;
111 5cdb1798 2005-10-29 devnull
112 5cdb1798 2005-10-29 devnull alarmscale = 60*1000; /* minutes */
113 5cdb1798 2005-10-29 devnull quotefmtinstall();
114 5cdb1798 2005-10-29 devnull errs = malloc(argc*sizeof(char*));
115 5cdb1798 2005-10-29 devnull reply = s_new();
116 5cdb1798 2005-10-29 devnull host = 0;
117 5cdb1798 2005-10-29 devnull ARGBEGIN{
118 5cdb1798 2005-10-29 devnull case 'a':
119 5cdb1798 2005-10-29 devnull tryauth = 1;
120 5cdb1798 2005-10-29 devnull trysecure = 1;
121 5cdb1798 2005-10-29 devnull break;
122 5cdb1798 2005-10-29 devnull case 'f':
123 5cdb1798 2005-10-29 devnull filter = 1;
124 5cdb1798 2005-10-29 devnull break;
125 5cdb1798 2005-10-29 devnull case 'd':
126 5cdb1798 2005-10-29 devnull debug = 1;
127 5cdb1798 2005-10-29 devnull break;
128 5cdb1798 2005-10-29 devnull case 'g':
129 5cdb1798 2005-10-29 devnull gdomain = ARGF();
130 5cdb1798 2005-10-29 devnull break;
131 5cdb1798 2005-10-29 devnull case 'h':
132 5cdb1798 2005-10-29 devnull host = ARGF();
133 5cdb1798 2005-10-29 devnull break;
134 5cdb1798 2005-10-29 devnull case 'i':
135 5cdb1798 2005-10-29 devnull insecure = 1;
136 5cdb1798 2005-10-29 devnull break;
137 5cdb1798 2005-10-29 devnull case 'p':
138 5cdb1798 2005-10-29 devnull alarmscale = 10*1000; /* tens of seconds */
139 5cdb1798 2005-10-29 devnull ping = 1;
140 5cdb1798 2005-10-29 devnull break;
141 5cdb1798 2005-10-29 devnull case 's':
142 5cdb1798 2005-10-29 devnull trysecure = 1;
143 5cdb1798 2005-10-29 devnull break;
144 5cdb1798 2005-10-29 devnull case 'u':
145 5cdb1798 2005-10-29 devnull user = ARGF();
146 5cdb1798 2005-10-29 devnull break;
147 5cdb1798 2005-10-29 devnull default:
148 5cdb1798 2005-10-29 devnull usage();
149 5cdb1798 2005-10-29 devnull break;
150 5cdb1798 2005-10-29 devnull }ARGEND;
151 5cdb1798 2005-10-29 devnull
152 5cdb1798 2005-10-29 devnull Binit(&berr, 2, OWRITE);
153 5cdb1798 2005-10-29 devnull Binit(&bfile, 0, OREAD);
154 5cdb1798 2005-10-29 devnull
155 5cdb1798 2005-10-29 devnull /*
156 5cdb1798 2005-10-29 devnull * get domain and add to host name
157 5cdb1798 2005-10-29 devnull */
158 5cdb1798 2005-10-29 devnull if(*argv && **argv=='.') {
159 5cdb1798 2005-10-29 devnull domain = *argv;
160 5cdb1798 2005-10-29 devnull argv++; argc--;
161 5cdb1798 2005-10-29 devnull } else
162 5cdb1798 2005-10-29 devnull domain = domainname_read();
163 5cdb1798 2005-10-29 devnull if(host == 0)
164 5cdb1798 2005-10-29 devnull host = sysname_read();
165 5cdb1798 2005-10-29 devnull strcpy(hostdomain, domainify(host, domain));
166 5cdb1798 2005-10-29 devnull strcpy(hellodomain, domainify(sysname_read(), domain));
167 5cdb1798 2005-10-29 devnull
168 5cdb1798 2005-10-29 devnull /*
169 5cdb1798 2005-10-29 devnull * get destination address
170 5cdb1798 2005-10-29 devnull */
171 5cdb1798 2005-10-29 devnull if(*argv == 0)
172 5cdb1798 2005-10-29 devnull usage();
173 5cdb1798 2005-10-29 devnull addr = *argv++; argc--;
174 5cdb1798 2005-10-29 devnull // expand $smtp if necessary
175 5cdb1798 2005-10-29 devnull addr = expand_addr(addr);
176 5cdb1798 2005-10-29 devnull farend = addr;
177 5cdb1798 2005-10-29 devnull
178 5cdb1798 2005-10-29 devnull /*
179 5cdb1798 2005-10-29 devnull * get sender's machine.
180 5cdb1798 2005-10-29 devnull * get sender in internet style. domainify if necessary.
181 5cdb1798 2005-10-29 devnull */
182 5cdb1798 2005-10-29 devnull if(*argv == 0)
183 5cdb1798 2005-10-29 devnull usage();
184 5cdb1798 2005-10-29 devnull sender = unescapespecial(s_copy(*argv++));
185 5cdb1798 2005-10-29 devnull argc--;
186 5cdb1798 2005-10-29 devnull fromm = s_clone(sender);
187 5cdb1798 2005-10-29 devnull rv = strrchr(s_to_c(fromm), '!');
188 5cdb1798 2005-10-29 devnull if(rv)
189 5cdb1798 2005-10-29 devnull *rv = 0;
190 5cdb1798 2005-10-29 devnull else
191 5cdb1798 2005-10-29 devnull *s_to_c(fromm) = 0;
192 5cdb1798 2005-10-29 devnull from = bangtoat(s_to_c(sender));
193 5cdb1798 2005-10-29 devnull
194 5cdb1798 2005-10-29 devnull /*
195 5cdb1798 2005-10-29 devnull * send the mail
196 5cdb1798 2005-10-29 devnull */
197 5cdb1798 2005-10-29 devnull if(filter){
198 5cdb1798 2005-10-29 devnull Binit(&bout, 1, OWRITE);
199 5cdb1798 2005-10-29 devnull rv = data(from, &bfile);
200 5cdb1798 2005-10-29 devnull if(rv != 0)
201 5cdb1798 2005-10-29 devnull goto error;
202 5cdb1798 2005-10-29 devnull exits(0);
203 5cdb1798 2005-10-29 devnull }
204 5cdb1798 2005-10-29 devnull
205 5cdb1798 2005-10-29 devnull /* 10 minutes to get through the initial handshake */
206 5cdb1798 2005-10-29 devnull atnotify(timeout, 1);
207 5cdb1798 2005-10-29 devnull
208 5cdb1798 2005-10-29 devnull alarm(10*alarmscale);
209 5cdb1798 2005-10-29 devnull if((rv = connect(addr)) != 0)
210 5cdb1798 2005-10-29 devnull exits(rv);
211 5cdb1798 2005-10-29 devnull alarm(10*alarmscale);
212 5cdb1798 2005-10-29 devnull if((rv = hello(hellodomain, 0)) != 0)
213 5cdb1798 2005-10-29 devnull goto error;
214 5cdb1798 2005-10-29 devnull alarm(10*alarmscale);
215 5cdb1798 2005-10-29 devnull if((rv = mailfrom(s_to_c(from))) != 0)
216 5cdb1798 2005-10-29 devnull goto error;
217 5cdb1798 2005-10-29 devnull
218 5cdb1798 2005-10-29 devnull ok = 0;
219 5cdb1798 2005-10-29 devnull rcvrs = 0;
220 5cdb1798 2005-10-29 devnull /* if any rcvrs are ok, we try to send the message */
221 5cdb1798 2005-10-29 devnull for(i = 0; i < argc; i++){
222 5cdb1798 2005-10-29 devnull if((trv = rcptto(argv[i])) != 0){
223 5cdb1798 2005-10-29 devnull /* remember worst error */
224 5cdb1798 2005-10-29 devnull if(rv != Giveup)
225 5cdb1798 2005-10-29 devnull rv = trv;
226 5cdb1798 2005-10-29 devnull errs[rcvrs] = strdup(s_to_c(reply));
227 5cdb1798 2005-10-29 devnull removenewline(errs[rcvrs]);
228 5cdb1798 2005-10-29 devnull } else {
229 5cdb1798 2005-10-29 devnull ok++;
230 5cdb1798 2005-10-29 devnull errs[rcvrs] = 0;
231 5cdb1798 2005-10-29 devnull }
232 5cdb1798 2005-10-29 devnull rcvrs++;
233 5cdb1798 2005-10-29 devnull }
234 5cdb1798 2005-10-29 devnull
235 5cdb1798 2005-10-29 devnull /* if no ok rcvrs or worst error is retry, give up */
236 5cdb1798 2005-10-29 devnull if(ok == 0 || rv == Retry)
237 5cdb1798 2005-10-29 devnull goto error;
238 5cdb1798 2005-10-29 devnull
239 5cdb1798 2005-10-29 devnull if(ping){
240 5cdb1798 2005-10-29 devnull quit(0);
241 5cdb1798 2005-10-29 devnull exits(0);
242 5cdb1798 2005-10-29 devnull }
243 5cdb1798 2005-10-29 devnull
244 5cdb1798 2005-10-29 devnull rv = data(from, &bfile);
245 5cdb1798 2005-10-29 devnull if(rv != 0)
246 5cdb1798 2005-10-29 devnull goto error;
247 5cdb1798 2005-10-29 devnull quit(0);
248 5cdb1798 2005-10-29 devnull if(rcvrs == ok)
249 5cdb1798 2005-10-29 devnull exits(0);
250 5cdb1798 2005-10-29 devnull
251 5cdb1798 2005-10-29 devnull /*
252 5cdb1798 2005-10-29 devnull * here when some but not all rcvrs failed
253 5cdb1798 2005-10-29 devnull */
254 5cdb1798 2005-10-29 devnull fprint(2, "%s connect to %s:\n", thedate(), addr);
255 5cdb1798 2005-10-29 devnull for(i = 0; i < rcvrs; i++){
256 5cdb1798 2005-10-29 devnull if(errs[i]){
257 5cdb1798 2005-10-29 devnull syslog(0, "smtp.fail", "delivery to %s at %s failed: %s", argv[i], addr, errs[i]);
258 5cdb1798 2005-10-29 devnull fprint(2, " mail to %s failed: %s", argv[i], errs[i]);
259 5cdb1798 2005-10-29 devnull }
260 5cdb1798 2005-10-29 devnull }
261 5cdb1798 2005-10-29 devnull exits(Giveup);
262 5cdb1798 2005-10-29 devnull
263 5cdb1798 2005-10-29 devnull /*
264 5cdb1798 2005-10-29 devnull * here when all rcvrs failed
265 5cdb1798 2005-10-29 devnull */
266 5cdb1798 2005-10-29 devnull error:
267 5cdb1798 2005-10-29 devnull removenewline(s_to_c(reply));
268 5cdb1798 2005-10-29 devnull syslog(0, "smtp.fail", "%s to %s failed: %s",
269 5cdb1798 2005-10-29 devnull ping ? "ping" : "delivery",
270 5cdb1798 2005-10-29 devnull addr, s_to_c(reply));
271 5cdb1798 2005-10-29 devnull fprint(2, "%s connect to %s:\n%s\n", thedate(), addr, s_to_c(reply));
272 5cdb1798 2005-10-29 devnull if(!filter)
273 5cdb1798 2005-10-29 devnull quit(rv);
274 5cdb1798 2005-10-29 devnull exits(rv);
275 5cdb1798 2005-10-29 devnull }
276 5cdb1798 2005-10-29 devnull
277 5cdb1798 2005-10-29 devnull /*
278 5cdb1798 2005-10-29 devnull * connect to the remote host
279 5cdb1798 2005-10-29 devnull */
280 5cdb1798 2005-10-29 devnull static char *
281 5cdb1798 2005-10-29 devnull connect(char* net)
282 5cdb1798 2005-10-29 devnull {
283 5cdb1798 2005-10-29 devnull char buf[256];
284 5cdb1798 2005-10-29 devnull int fd;
285 5cdb1798 2005-10-29 devnull
286 5cdb1798 2005-10-29 devnull fd = mxdial(net, ddomain, gdomain);
287 5cdb1798 2005-10-29 devnull
288 5cdb1798 2005-10-29 devnull if(fd < 0){
289 5cdb1798 2005-10-29 devnull rerrstr(buf, sizeof(buf));
290 5cdb1798 2005-10-29 devnull Bprint(&berr, "smtp: %s (%s)\n", buf, net);
291 5cdb1798 2005-10-29 devnull syslog(0, "smtp.fail", "%s (%s)", buf, net);
292 5cdb1798 2005-10-29 devnull if(strstr(buf, "illegal")
293 5cdb1798 2005-10-29 devnull || strstr(buf, "unknown")
294 5cdb1798 2005-10-29 devnull || strstr(buf, "can't translate"))
295 5cdb1798 2005-10-29 devnull return Giveup;
296 5cdb1798 2005-10-29 devnull else
297 5cdb1798 2005-10-29 devnull return Retry;
298 5cdb1798 2005-10-29 devnull }
299 5cdb1798 2005-10-29 devnull Binit(&bin, fd, OREAD);
300 5cdb1798 2005-10-29 devnull fd = dup(fd, -1);
301 5cdb1798 2005-10-29 devnull Binit(&bout, fd, OWRITE);
302 5cdb1798 2005-10-29 devnull return 0;
303 5cdb1798 2005-10-29 devnull }
304 5cdb1798 2005-10-29 devnull
305 5cdb1798 2005-10-29 devnull static char smtpthumbs[] = "/sys/lib/tls/smtp";
306 5cdb1798 2005-10-29 devnull static char smtpexclthumbs[] = "/sys/lib/tls/smtp.exclude";
307 5cdb1798 2005-10-29 devnull
308 5cdb1798 2005-10-29 devnull /*
309 5cdb1798 2005-10-29 devnull * exchange names with remote host, attempt to
310 5cdb1798 2005-10-29 devnull * enable encryption and optionally authenticate.
311 5cdb1798 2005-10-29 devnull * not fatal if we can't.
312 5cdb1798 2005-10-29 devnull */
313 5cdb1798 2005-10-29 devnull static char *
314 5cdb1798 2005-10-29 devnull dotls(char *me)
315 5cdb1798 2005-10-29 devnull {
316 5cdb1798 2005-10-29 devnull TLSconn *c;
317 5cdb1798 2005-10-29 devnull Thumbprint *goodcerts;
318 5cdb1798 2005-10-29 devnull char *h;
319 5cdb1798 2005-10-29 devnull int fd;
320 5cdb1798 2005-10-29 devnull uchar hash[SHA1dlen];
321 5cdb1798 2005-10-29 devnull
322 5cdb1798 2005-10-29 devnull c = mallocz(sizeof(*c), 1); /* Note: not freed on success */
323 5cdb1798 2005-10-29 devnull if (c == nil)
324 5cdb1798 2005-10-29 devnull return Giveup;
325 5cdb1798 2005-10-29 devnull
326 5cdb1798 2005-10-29 devnull dBprint("STARTTLS\r\n");
327 5cdb1798 2005-10-29 devnull if (getreply() != 2)
328 5cdb1798 2005-10-29 devnull return Giveup;
329 5cdb1798 2005-10-29 devnull
330 5cdb1798 2005-10-29 devnull fd = tlsClient(Bfildes(&bout), c);
331 5cdb1798 2005-10-29 devnull if (fd < 0) {
332 5cdb1798 2005-10-29 devnull syslog(0, "smtp", "tlsClient to %q: %r", ddomain);
333 5cdb1798 2005-10-29 devnull return Giveup;
334 5cdb1798 2005-10-29 devnull }
335 5cdb1798 2005-10-29 devnull goodcerts = initThumbprints(smtpthumbs, smtpexclthumbs);
336 5cdb1798 2005-10-29 devnull if (goodcerts == nil) {
337 5cdb1798 2005-10-29 devnull free(c);
338 5cdb1798 2005-10-29 devnull close(fd);
339 5cdb1798 2005-10-29 devnull syslog(0, "smtp", "bad thumbprints in %s", smtpthumbs);
340 5cdb1798 2005-10-29 devnull return Giveup; /* how to recover? TLS is started */
341 5cdb1798 2005-10-29 devnull }
342 5cdb1798 2005-10-29 devnull
343 5cdb1798 2005-10-29 devnull /* compute sha1 hash of remote's certificate, see if we know it */
344 5cdb1798 2005-10-29 devnull sha1(c->cert, c->certlen, hash, nil);
345 5cdb1798 2005-10-29 devnull if (!okThumbprint(hash, goodcerts)) {
346 5cdb1798 2005-10-29 devnull /* TODO? if not excluded, add hash to thumb list */
347 5cdb1798 2005-10-29 devnull free(c);
348 5cdb1798 2005-10-29 devnull close(fd);
349 5cdb1798 2005-10-29 devnull h = malloc(2*sizeof hash + 1);
350 5cdb1798 2005-10-29 devnull if (h != nil) {
351 5cdb1798 2005-10-29 devnull enc16(h, 2*sizeof hash + 1, hash, sizeof hash);
352 5cdb1798 2005-10-29 devnull // print("x509 sha1=%s", h);
353 5cdb1798 2005-10-29 devnull syslog(0, "smtp",
354 5cdb1798 2005-10-29 devnull "remote cert. has bad thumbprint: x509 sha1=%s server=%q",
355 5cdb1798 2005-10-29 devnull h, ddomain);
356 5cdb1798 2005-10-29 devnull free(h);
357 5cdb1798 2005-10-29 devnull }
358 5cdb1798 2005-10-29 devnull return Giveup; /* how to recover? TLS is started */
359 5cdb1798 2005-10-29 devnull }
360 5cdb1798 2005-10-29 devnull freeThumbprints(goodcerts);
361 5cdb1798 2005-10-29 devnull Bterm(&bin);
362 5cdb1798 2005-10-29 devnull Bterm(&bout);
363 5cdb1798 2005-10-29 devnull
364 5cdb1798 2005-10-29 devnull /*
365 5cdb1798 2005-10-29 devnull * set up bin & bout to use the TLS fd, i/o upon which generates
366 5cdb1798 2005-10-29 devnull * i/o on the original, underlying fd.
367 5cdb1798 2005-10-29 devnull */
368 5cdb1798 2005-10-29 devnull Binit(&bin, fd, OREAD);
369 5cdb1798 2005-10-29 devnull fd = dup(fd, -1);
370 5cdb1798 2005-10-29 devnull Binit(&bout, fd, OWRITE);
371 5cdb1798 2005-10-29 devnull
372 5cdb1798 2005-10-29 devnull syslog(0, "smtp", "started TLS to %q", ddomain);
373 5cdb1798 2005-10-29 devnull return(hello(me, 1));
374 5cdb1798 2005-10-29 devnull }
375 5cdb1798 2005-10-29 devnull
376 5cdb1798 2005-10-29 devnull static char *
377 5cdb1798 2005-10-29 devnull doauth(char *methods)
378 5cdb1798 2005-10-29 devnull {
379 5cdb1798 2005-10-29 devnull char *buf, *base64;
380 5cdb1798 2005-10-29 devnull int n;
381 5cdb1798 2005-10-29 devnull DS ds;
382 5cdb1798 2005-10-29 devnull UserPasswd *p;
383 5cdb1798 2005-10-29 devnull
384 5cdb1798 2005-10-29 devnull dial_string_parse(ddomain, &ds);
385 5cdb1798 2005-10-29 devnull
386 5cdb1798 2005-10-29 devnull if(user != nil)
387 5cdb1798 2005-10-29 devnull p = auth_getuserpasswd(nil,
388 5cdb1798 2005-10-29 devnull "proto=pass service=smtp server=%q user=%q", ds.host, user);
389 5cdb1798 2005-10-29 devnull else
390 5cdb1798 2005-10-29 devnull p = auth_getuserpasswd(nil,
391 5cdb1798 2005-10-29 devnull "proto=pass service=smtp server=%q", ds.host);
392 5cdb1798 2005-10-29 devnull if (p == nil)
393 5cdb1798 2005-10-29 devnull return Giveup;
394 5cdb1798 2005-10-29 devnull
395 5cdb1798 2005-10-29 devnull if (strstr(methods, "LOGIN")){
396 5cdb1798 2005-10-29 devnull dBprint("AUTH LOGIN\r\n");
397 5cdb1798 2005-10-29 devnull if (getreply() != 3)
398 5cdb1798 2005-10-29 devnull return Retry;
399 5cdb1798 2005-10-29 devnull
400 5cdb1798 2005-10-29 devnull n = strlen(p->user);
401 5cdb1798 2005-10-29 devnull base64 = malloc(2*n);
402 5cdb1798 2005-10-29 devnull if (base64 == nil)
403 5cdb1798 2005-10-29 devnull return Retry; /* Out of memory */
404 5cdb1798 2005-10-29 devnull enc64(base64, 2*n, (uchar *)p->user, n);
405 5cdb1798 2005-10-29 devnull dBprint("%s\r\n", base64);
406 5cdb1798 2005-10-29 devnull if (getreply() != 3)
407 5cdb1798 2005-10-29 devnull return Retry;
408 5cdb1798 2005-10-29 devnull
409 5cdb1798 2005-10-29 devnull n = strlen(p->passwd);
410 5cdb1798 2005-10-29 devnull base64 = malloc(2*n);
411 5cdb1798 2005-10-29 devnull if (base64 == nil)
412 5cdb1798 2005-10-29 devnull return Retry; /* Out of memory */
413 5cdb1798 2005-10-29 devnull enc64(base64, 2*n, (uchar *)p->passwd, n);
414 5cdb1798 2005-10-29 devnull dBprint("%s\r\n", base64);
415 5cdb1798 2005-10-29 devnull if (getreply() != 2)
416 5cdb1798 2005-10-29 devnull return Retry;
417 5cdb1798 2005-10-29 devnull
418 5cdb1798 2005-10-29 devnull free(base64);
419 5cdb1798 2005-10-29 devnull }
420 5cdb1798 2005-10-29 devnull else
421 5cdb1798 2005-10-29 devnull if (strstr(methods, "PLAIN")){
422 5cdb1798 2005-10-29 devnull n = strlen(p->user) + strlen(p->passwd) + 3;
423 5cdb1798 2005-10-29 devnull buf = malloc(n);
424 5cdb1798 2005-10-29 devnull base64 = malloc(2 * n);
425 5cdb1798 2005-10-29 devnull if (buf == nil || base64 == nil) {
426 5cdb1798 2005-10-29 devnull free(buf);
427 5cdb1798 2005-10-29 devnull return Retry; /* Out of memory */
428 5cdb1798 2005-10-29 devnull }
429 5cdb1798 2005-10-29 devnull snprint(buf, n, "%c%s%c%s", 0, p->user, 0, p->passwd);
430 5cdb1798 2005-10-29 devnull enc64(base64, 2 * n, (uchar *)buf, n - 1);
431 5cdb1798 2005-10-29 devnull free(buf);
432 5cdb1798 2005-10-29 devnull dBprint("AUTH PLAIN %s\r\n", base64);
433 5cdb1798 2005-10-29 devnull free(base64);
434 5cdb1798 2005-10-29 devnull if (getreply() != 2)
435 5cdb1798 2005-10-29 devnull return Retry;
436 5cdb1798 2005-10-29 devnull }
437 5cdb1798 2005-10-29 devnull else
438 5cdb1798 2005-10-29 devnull return "No supported AUTH method";
439 5cdb1798 2005-10-29 devnull return(0);
440 5cdb1798 2005-10-29 devnull }
441 5cdb1798 2005-10-29 devnull
442 5cdb1798 2005-10-29 devnull char *
443 5cdb1798 2005-10-29 devnull hello(char *me, int encrypted)
444 5cdb1798 2005-10-29 devnull {
445 5cdb1798 2005-10-29 devnull int ehlo;
446 5cdb1798 2005-10-29 devnull String *r;
447 5cdb1798 2005-10-29 devnull char *ret, *s, *t;
448 5cdb1798 2005-10-29 devnull
449 5cdb1798 2005-10-29 devnull if (!encrypted)
450 5cdb1798 2005-10-29 devnull switch(getreply()){
451 5cdb1798 2005-10-29 devnull case 2:
452 5cdb1798 2005-10-29 devnull break;
453 5cdb1798 2005-10-29 devnull case 5:
454 5cdb1798 2005-10-29 devnull return Giveup;
455 5cdb1798 2005-10-29 devnull default:
456 5cdb1798 2005-10-29 devnull return Retry;
457 5cdb1798 2005-10-29 devnull }
458 5cdb1798 2005-10-29 devnull
459 5cdb1798 2005-10-29 devnull ehlo = 1;
460 5cdb1798 2005-10-29 devnull Again:
461 5cdb1798 2005-10-29 devnull if(ehlo)
462 5cdb1798 2005-10-29 devnull dBprint("EHLO %s\r\n", me);
463 5cdb1798 2005-10-29 devnull else
464 5cdb1798 2005-10-29 devnull dBprint("HELO %s\r\n", me);
465 5cdb1798 2005-10-29 devnull switch (getreply()) {
466 5cdb1798 2005-10-29 devnull case 2:
467 5cdb1798 2005-10-29 devnull break;
468 5cdb1798 2005-10-29 devnull case 5:
469 5cdb1798 2005-10-29 devnull if(ehlo){
470 5cdb1798 2005-10-29 devnull ehlo = 0;
471 5cdb1798 2005-10-29 devnull goto Again;
472 5cdb1798 2005-10-29 devnull }
473 5cdb1798 2005-10-29 devnull return Giveup;
474 5cdb1798 2005-10-29 devnull default:
475 5cdb1798 2005-10-29 devnull return Retry;
476 5cdb1798 2005-10-29 devnull }
477 5cdb1798 2005-10-29 devnull r = s_clone(reply);
478 5cdb1798 2005-10-29 devnull if(r == nil)
479 5cdb1798 2005-10-29 devnull return Retry; /* Out of memory or couldn't get string */
480 5cdb1798 2005-10-29 devnull
481 5cdb1798 2005-10-29 devnull /* Invariant: every line has a newline, a result of getcrlf() */
482 5cdb1798 2005-10-29 devnull for(s = s_to_c(r); (t = strchr(s, '\n')) != nil; s = t + 1){
483 5cdb1798 2005-10-29 devnull *t = '\0';
484 5cdb1798 2005-10-29 devnull for (t = s; *t != '\0'; t++)
485 5cdb1798 2005-10-29 devnull *t = toupper(*t);
486 5cdb1798 2005-10-29 devnull if(!encrypted && trysecure &&
487 5cdb1798 2005-10-29 devnull (strcmp(s, "250-STARTTLS") == 0 ||
488 5cdb1798 2005-10-29 devnull strcmp(s, "250 STARTTLS") == 0)){
489 5cdb1798 2005-10-29 devnull s_free(r);
490 5cdb1798 2005-10-29 devnull return(dotls(me));
491 5cdb1798 2005-10-29 devnull }
492 5cdb1798 2005-10-29 devnull if(tryauth && (encrypted || insecure) &&
493 5cdb1798 2005-10-29 devnull (strncmp(s, "250 AUTH", strlen("250 AUTH")) == 0 ||
494 5cdb1798 2005-10-29 devnull strncmp(s, "250-AUTH", strlen("250 AUTH")) == 0)){
495 5cdb1798 2005-10-29 devnull ret = doauth(s + strlen("250 AUTH "));
496 5cdb1798 2005-10-29 devnull s_free(r);
497 5cdb1798 2005-10-29 devnull return ret;
498 5cdb1798 2005-10-29 devnull }
499 5cdb1798 2005-10-29 devnull }
500 5cdb1798 2005-10-29 devnull s_free(r);
501 5cdb1798 2005-10-29 devnull return 0;
502 5cdb1798 2005-10-29 devnull }
503 5cdb1798 2005-10-29 devnull
504 5cdb1798 2005-10-29 devnull /*
505 5cdb1798 2005-10-29 devnull * report sender to remote
506 5cdb1798 2005-10-29 devnull */
507 5cdb1798 2005-10-29 devnull char *
508 5cdb1798 2005-10-29 devnull mailfrom(char *from)
509 5cdb1798 2005-10-29 devnull {
510 5cdb1798 2005-10-29 devnull if(!returnable(from))
511 5cdb1798 2005-10-29 devnull dBprint("MAIL FROM:<>\r\n");
512 5cdb1798 2005-10-29 devnull else
513 5cdb1798 2005-10-29 devnull if(strchr(from, '@'))
514 5cdb1798 2005-10-29 devnull dBprint("MAIL FROM:<%s>\r\n", from);
515 5cdb1798 2005-10-29 devnull else
516 5cdb1798 2005-10-29 devnull dBprint("MAIL FROM:<%s@%s>\r\n", from, hostdomain);
517 5cdb1798 2005-10-29 devnull switch(getreply()){
518 5cdb1798 2005-10-29 devnull case 2:
519 5cdb1798 2005-10-29 devnull break;
520 5cdb1798 2005-10-29 devnull case 5:
521 5cdb1798 2005-10-29 devnull return Giveup;
522 5cdb1798 2005-10-29 devnull default:
523 5cdb1798 2005-10-29 devnull return Retry;
524 5cdb1798 2005-10-29 devnull }
525 5cdb1798 2005-10-29 devnull return 0;
526 5cdb1798 2005-10-29 devnull }
527 5cdb1798 2005-10-29 devnull
528 5cdb1798 2005-10-29 devnull /*
529 5cdb1798 2005-10-29 devnull * report a recipient to remote
530 5cdb1798 2005-10-29 devnull */
531 5cdb1798 2005-10-29 devnull char *
532 5cdb1798 2005-10-29 devnull rcptto(char *to)
533 5cdb1798 2005-10-29 devnull {
534 5cdb1798 2005-10-29 devnull String *s;
535 5cdb1798 2005-10-29 devnull
536 5cdb1798 2005-10-29 devnull s = unescapespecial(bangtoat(to));
537 5cdb1798 2005-10-29 devnull if(toline == 0)
538 5cdb1798 2005-10-29 devnull toline = s_new();
539 5cdb1798 2005-10-29 devnull else
540 5cdb1798 2005-10-29 devnull s_append(toline, ", ");
541 5cdb1798 2005-10-29 devnull s_append(toline, s_to_c(s));
542 5cdb1798 2005-10-29 devnull if(strchr(s_to_c(s), '@'))
543 5cdb1798 2005-10-29 devnull dBprint("RCPT TO:<%s>\r\n", s_to_c(s));
544 5cdb1798 2005-10-29 devnull else {
545 5cdb1798 2005-10-29 devnull s_append(toline, "@");
546 5cdb1798 2005-10-29 devnull s_append(toline, ddomain);
547 5cdb1798 2005-10-29 devnull dBprint("RCPT TO:<%s@%s>\r\n", s_to_c(s), ddomain);
548 5cdb1798 2005-10-29 devnull }
549 5cdb1798 2005-10-29 devnull alarm(10*alarmscale);
550 5cdb1798 2005-10-29 devnull switch(getreply()){
551 5cdb1798 2005-10-29 devnull case 2:
552 5cdb1798 2005-10-29 devnull break;
553 5cdb1798 2005-10-29 devnull case 5:
554 5cdb1798 2005-10-29 devnull return Giveup;
555 5cdb1798 2005-10-29 devnull default:
556 5cdb1798 2005-10-29 devnull return Retry;
557 5cdb1798 2005-10-29 devnull }
558 5cdb1798 2005-10-29 devnull return 0;
559 5cdb1798 2005-10-29 devnull }
560 5cdb1798 2005-10-29 devnull
561 5cdb1798 2005-10-29 devnull static char hex[] = "0123456789abcdef";
562 5cdb1798 2005-10-29 devnull
563 5cdb1798 2005-10-29 devnull /*
564 5cdb1798 2005-10-29 devnull * send the damn thing
565 5cdb1798 2005-10-29 devnull */
566 5cdb1798 2005-10-29 devnull char *
567 5cdb1798 2005-10-29 devnull data(String *from, Biobuf *b)
568 5cdb1798 2005-10-29 devnull {
569 5cdb1798 2005-10-29 devnull char *buf, *cp;
570 5cdb1798 2005-10-29 devnull int i, n, nbytes, bufsize, eof, r;
571 5cdb1798 2005-10-29 devnull String *fromline;
572 5cdb1798 2005-10-29 devnull char errmsg[Errlen];
573 5cdb1798 2005-10-29 devnull char id[40];
574 5cdb1798 2005-10-29 devnull
575 5cdb1798 2005-10-29 devnull /*
576 5cdb1798 2005-10-29 devnull * input the header.
577 5cdb1798 2005-10-29 devnull */
578 5cdb1798 2005-10-29 devnull
579 5cdb1798 2005-10-29 devnull buf = malloc(1);
580 5cdb1798 2005-10-29 devnull if(buf == 0){
581 5cdb1798 2005-10-29 devnull s_append(s_restart(reply), "out of memory");
582 5cdb1798 2005-10-29 devnull return Retry;
583 5cdb1798 2005-10-29 devnull }
584 5cdb1798 2005-10-29 devnull n = 0;
585 5cdb1798 2005-10-29 devnull eof = 0;
586 5cdb1798 2005-10-29 devnull for(;;){
587 5cdb1798 2005-10-29 devnull cp = Brdline(b, '\n');
588 5cdb1798 2005-10-29 devnull if(cp == nil){
589 5cdb1798 2005-10-29 devnull eof = 1;
590 5cdb1798 2005-10-29 devnull break;
591 5cdb1798 2005-10-29 devnull }
592 5cdb1798 2005-10-29 devnull nbytes = Blinelen(b);
593 5cdb1798 2005-10-29 devnull buf = realloc(buf, n+nbytes+1);
594 5cdb1798 2005-10-29 devnull if(buf == 0){
595 5cdb1798 2005-10-29 devnull s_append(s_restart(reply), "out of memory");
596 5cdb1798 2005-10-29 devnull return Retry;
597 5cdb1798 2005-10-29 devnull }
598 5cdb1798 2005-10-29 devnull strncpy(buf+n, cp, nbytes);
599 5cdb1798 2005-10-29 devnull n += nbytes;
600 5cdb1798 2005-10-29 devnull if(nbytes == 1) /* end of header */
601 5cdb1798 2005-10-29 devnull break;
602 5cdb1798 2005-10-29 devnull }
603 5cdb1798 2005-10-29 devnull buf[n] = 0;
604 5cdb1798 2005-10-29 devnull bufsize = n;
605 5cdb1798 2005-10-29 devnull
606 5cdb1798 2005-10-29 devnull /*
607 5cdb1798 2005-10-29 devnull * parse the header, turn all addresses into @ format
608 5cdb1798 2005-10-29 devnull */
609 5cdb1798 2005-10-29 devnull yyinit(buf, n);
610 5cdb1798 2005-10-29 devnull yyparse();
611 5cdb1798 2005-10-29 devnull
612 5cdb1798 2005-10-29 devnull /*
613 5cdb1798 2005-10-29 devnull * print message observing '.' escapes and using \r\n for \n
614 5cdb1798 2005-10-29 devnull */
615 5cdb1798 2005-10-29 devnull alarm(20*alarmscale);
616 5cdb1798 2005-10-29 devnull if(!filter){
617 5cdb1798 2005-10-29 devnull dBprint("DATA\r\n");
618 5cdb1798 2005-10-29 devnull switch(getreply()){
619 5cdb1798 2005-10-29 devnull case 3:
620 5cdb1798 2005-10-29 devnull break;
621 5cdb1798 2005-10-29 devnull case 5:
622 5cdb1798 2005-10-29 devnull free(buf);
623 5cdb1798 2005-10-29 devnull return Giveup;
624 5cdb1798 2005-10-29 devnull default:
625 5cdb1798 2005-10-29 devnull free(buf);
626 5cdb1798 2005-10-29 devnull return Retry;
627 5cdb1798 2005-10-29 devnull }
628 5cdb1798 2005-10-29 devnull }
629 5cdb1798 2005-10-29 devnull /*
630 5cdb1798 2005-10-29 devnull * send header. add a message-id, a sender, and a date if there
631 5cdb1798 2005-10-29 devnull * isn't one
632 5cdb1798 2005-10-29 devnull */
633 5cdb1798 2005-10-29 devnull nbytes = 0;
634 5cdb1798 2005-10-29 devnull fromline = convertheader(from);
635 5cdb1798 2005-10-29 devnull uneaten = buf;
636 5cdb1798 2005-10-29 devnull
637 5cdb1798 2005-10-29 devnull srand(truerand());
638 5cdb1798 2005-10-29 devnull if(messageid == 0){
639 5cdb1798 2005-10-29 devnull for(i=0; i<16; i++){
640 5cdb1798 2005-10-29 devnull r = rand()&0xFF;
641 5cdb1798 2005-10-29 devnull id[2*i] = hex[r&0xF];
642 5cdb1798 2005-10-29 devnull id[2*i+1] = hex[(r>>4)&0xF];
643 5cdb1798 2005-10-29 devnull }
644 5cdb1798 2005-10-29 devnull id[2*i] = '\0';
645 5cdb1798 2005-10-29 devnull nbytes += Bprint(&bout, "Message-ID: <%s@%s>\r\n", id, hostdomain);
646 5cdb1798 2005-10-29 devnull if(debug)
647 5cdb1798 2005-10-29 devnull Bprint(&berr, "Message-ID: <%s@%s>\r\n", id, hostdomain);
648 5cdb1798 2005-10-29 devnull }
649 5cdb1798 2005-10-29 devnull
650 5cdb1798 2005-10-29 devnull if(originator==0){
651 5cdb1798 2005-10-29 devnull nbytes += Bprint(&bout, "From: %s\r\n", s_to_c(fromline));
652 5cdb1798 2005-10-29 devnull if(debug)
653 5cdb1798 2005-10-29 devnull Bprint(&berr, "From: %s\r\n", s_to_c(fromline));
654 5cdb1798 2005-10-29 devnull }
655 5cdb1798 2005-10-29 devnull s_free(fromline);
656 5cdb1798 2005-10-29 devnull
657 5cdb1798 2005-10-29 devnull if(destination == 0 && toline)
658 5cdb1798 2005-10-29 devnull if(*s_to_c(toline) == '@'){ /* route addr */
659 5cdb1798 2005-10-29 devnull nbytes += Bprint(&bout, "To: <%s>\r\n", s_to_c(toline));
660 5cdb1798 2005-10-29 devnull if(debug)
661 5cdb1798 2005-10-29 devnull Bprint(&berr, "To: <%s>\r\n", s_to_c(toline));
662 5cdb1798 2005-10-29 devnull } else {
663 5cdb1798 2005-10-29 devnull nbytes += Bprint(&bout, "To: %s\r\n", s_to_c(toline));
664 5cdb1798 2005-10-29 devnull if(debug)
665 5cdb1798 2005-10-29 devnull Bprint(&berr, "To: %s\r\n", s_to_c(toline));
666 5cdb1798 2005-10-29 devnull }
667 5cdb1798 2005-10-29 devnull
668 5cdb1798 2005-10-29 devnull if(date==0 && udate)
669 5cdb1798 2005-10-29 devnull nbytes += printdate(udate);
670 5cdb1798 2005-10-29 devnull if (usys)
671 5cdb1798 2005-10-29 devnull uneaten = usys->end + 1;
672 5cdb1798 2005-10-29 devnull nbytes += printheader();
673 5cdb1798 2005-10-29 devnull if (*uneaten != '\n')
674 5cdb1798 2005-10-29 devnull putcrnl("\n", 1);
675 5cdb1798 2005-10-29 devnull
676 5cdb1798 2005-10-29 devnull /*
677 5cdb1798 2005-10-29 devnull * send body
678 5cdb1798 2005-10-29 devnull */
679 5cdb1798 2005-10-29 devnull
680 5cdb1798 2005-10-29 devnull putcrnl(uneaten, buf+n - uneaten);
681 5cdb1798 2005-10-29 devnull nbytes += buf+n - uneaten;
682 5cdb1798 2005-10-29 devnull if(eof == 0){
683 5cdb1798 2005-10-29 devnull for(;;){
684 5cdb1798 2005-10-29 devnull n = Bread(b, buf, bufsize);
685 5cdb1798 2005-10-29 devnull if(n < 0){
686 5cdb1798 2005-10-29 devnull rerrstr(errmsg, sizeof(errmsg));
687 5cdb1798 2005-10-29 devnull s_append(s_restart(reply), errmsg);
688 5cdb1798 2005-10-29 devnull free(buf);
689 5cdb1798 2005-10-29 devnull return Retry;
690 5cdb1798 2005-10-29 devnull }
691 5cdb1798 2005-10-29 devnull if(n == 0)
692 5cdb1798 2005-10-29 devnull break;
693 5cdb1798 2005-10-29 devnull alarm(10*alarmscale);
694 5cdb1798 2005-10-29 devnull putcrnl(buf, n);
695 5cdb1798 2005-10-29 devnull nbytes += n;
696 5cdb1798 2005-10-29 devnull }
697 5cdb1798 2005-10-29 devnull }
698 5cdb1798 2005-10-29 devnull free(buf);
699 5cdb1798 2005-10-29 devnull if(!filter){
700 5cdb1798 2005-10-29 devnull if(last != '\n')
701 5cdb1798 2005-10-29 devnull dBprint("\r\n.\r\n");
702 5cdb1798 2005-10-29 devnull else
703 5cdb1798 2005-10-29 devnull dBprint(".\r\n");
704 5cdb1798 2005-10-29 devnull alarm(10*alarmscale);
705 5cdb1798 2005-10-29 devnull switch(getreply()){
706 5cdb1798 2005-10-29 devnull case 2:
707 5cdb1798 2005-10-29 devnull break;
708 5cdb1798 2005-10-29 devnull case 5:
709 5cdb1798 2005-10-29 devnull return Giveup;
710 5cdb1798 2005-10-29 devnull default:
711 5cdb1798 2005-10-29 devnull return Retry;
712 5cdb1798 2005-10-29 devnull }
713 5cdb1798 2005-10-29 devnull syslog(0, "smtp", "%s sent %d bytes to %s", s_to_c(from),
714 5cdb1798 2005-10-29 devnull nbytes, s_to_c(toline));/**/
715 5cdb1798 2005-10-29 devnull }
716 5cdb1798 2005-10-29 devnull return 0;
717 5cdb1798 2005-10-29 devnull }
718 5cdb1798 2005-10-29 devnull
719 5cdb1798 2005-10-29 devnull /*
720 5cdb1798 2005-10-29 devnull * we're leaving
721 5cdb1798 2005-10-29 devnull */
722 5cdb1798 2005-10-29 devnull void
723 5cdb1798 2005-10-29 devnull quit(char *rv)
724 5cdb1798 2005-10-29 devnull {
725 5cdb1798 2005-10-29 devnull /* 60 minutes to quit */
726 5cdb1798 2005-10-29 devnull quitting = 1;
727 5cdb1798 2005-10-29 devnull quitrv = rv;
728 5cdb1798 2005-10-29 devnull alarm(60*alarmscale);
729 5cdb1798 2005-10-29 devnull dBprint("QUIT\r\n");
730 5cdb1798 2005-10-29 devnull getreply();
731 5cdb1798 2005-10-29 devnull Bterm(&bout);
732 5cdb1798 2005-10-29 devnull Bterm(&bfile);
733 5cdb1798 2005-10-29 devnull }
734 5cdb1798 2005-10-29 devnull
735 5cdb1798 2005-10-29 devnull /*
736 5cdb1798 2005-10-29 devnull * read a reply into a string, return the reply code
737 5cdb1798 2005-10-29 devnull */
738 5cdb1798 2005-10-29 devnull int
739 5cdb1798 2005-10-29 devnull getreply(void)
740 5cdb1798 2005-10-29 devnull {
741 5cdb1798 2005-10-29 devnull char *line;
742 5cdb1798 2005-10-29 devnull int rv;
743 5cdb1798 2005-10-29 devnull
744 5cdb1798 2005-10-29 devnull reply = s_reset(reply);
745 5cdb1798 2005-10-29 devnull for(;;){
746 5cdb1798 2005-10-29 devnull line = getcrnl(reply);
747 5cdb1798 2005-10-29 devnull if(line == 0)
748 5cdb1798 2005-10-29 devnull return -1;
749 5cdb1798 2005-10-29 devnull if(!isdigit(line[0]) || !isdigit(line[1]) || !isdigit(line[2]))
750 5cdb1798 2005-10-29 devnull return -1;
751 5cdb1798 2005-10-29 devnull if(line[3] != '-')
752 5cdb1798 2005-10-29 devnull break;
753 5cdb1798 2005-10-29 devnull }
754 5cdb1798 2005-10-29 devnull if(debug)
755 5cdb1798 2005-10-29 devnull Bflush(&berr);
756 5cdb1798 2005-10-29 devnull rv = atoi(line)/100;
757 5cdb1798 2005-10-29 devnull return rv;
758 5cdb1798 2005-10-29 devnull }
759 5cdb1798 2005-10-29 devnull void
760 5cdb1798 2005-10-29 devnull addhostdom(String *buf, char *host)
761 5cdb1798 2005-10-29 devnull {
762 5cdb1798 2005-10-29 devnull s_append(buf, "@");
763 5cdb1798 2005-10-29 devnull s_append(buf, host);
764 5cdb1798 2005-10-29 devnull }
765 5cdb1798 2005-10-29 devnull
766 5cdb1798 2005-10-29 devnull /*
767 5cdb1798 2005-10-29 devnull * Convert from `bang' to `source routing' format.
768 5cdb1798 2005-10-29 devnull *
769 5cdb1798 2005-10-29 devnull * a.x.y!b.p.o!c!d -> @a.x.y:c!d@b.p.o
770 5cdb1798 2005-10-29 devnull */
771 5cdb1798 2005-10-29 devnull String *
772 5cdb1798 2005-10-29 devnull bangtoat(char *addr)
773 5cdb1798 2005-10-29 devnull {
774 5cdb1798 2005-10-29 devnull String *buf;
775 5cdb1798 2005-10-29 devnull register int i;
776 5cdb1798 2005-10-29 devnull int j, d;
777 5cdb1798 2005-10-29 devnull char *field[128];
778 5cdb1798 2005-10-29 devnull
779 5cdb1798 2005-10-29 devnull /* parse the '!' format address */
780 5cdb1798 2005-10-29 devnull buf = s_new();
781 5cdb1798 2005-10-29 devnull for(i = 0; addr; i++){
782 5cdb1798 2005-10-29 devnull field[i] = addr;
783 5cdb1798 2005-10-29 devnull addr = strchr(addr, '!');
784 5cdb1798 2005-10-29 devnull if(addr)
785 5cdb1798 2005-10-29 devnull *addr++ = 0;
786 5cdb1798 2005-10-29 devnull }
787 5cdb1798 2005-10-29 devnull if (i==1) {
788 5cdb1798 2005-10-29 devnull s_append(buf, field[0]);
789 5cdb1798 2005-10-29 devnull return buf;
790 5cdb1798 2005-10-29 devnull }
791 5cdb1798 2005-10-29 devnull
792 5cdb1798 2005-10-29 devnull /*
793 5cdb1798 2005-10-29 devnull * count leading domain fields (non-domains don't count)
794 5cdb1798 2005-10-29 devnull */
795 5cdb1798 2005-10-29 devnull for(d = 0; d<i-1; d++)
796 5cdb1798 2005-10-29 devnull if(strchr(field[d], '.')==0)
797 5cdb1798 2005-10-29 devnull break;
798 5cdb1798 2005-10-29 devnull /*
799 5cdb1798 2005-10-29 devnull * if there are more than 1 leading domain elements,
800 5cdb1798 2005-10-29 devnull * put them in as source routing
801 5cdb1798 2005-10-29 devnull */
802 5cdb1798 2005-10-29 devnull if(d > 1){
803 5cdb1798 2005-10-29 devnull addhostdom(buf, field[0]);
804 5cdb1798 2005-10-29 devnull for(j=1; j<d-1; j++){
805 5cdb1798 2005-10-29 devnull s_append(buf, ",");
806 5cdb1798 2005-10-29 devnull s_append(buf, "@");
807 5cdb1798 2005-10-29 devnull s_append(buf, field[j]);
808 5cdb1798 2005-10-29 devnull }
809 5cdb1798 2005-10-29 devnull s_append(buf, ":");
810 5cdb1798 2005-10-29 devnull }
811 5cdb1798 2005-10-29 devnull
812 5cdb1798 2005-10-29 devnull /*
813 5cdb1798 2005-10-29 devnull * throw in the non-domain elements separated by '!'s
814 5cdb1798 2005-10-29 devnull */
815 5cdb1798 2005-10-29 devnull s_append(buf, field[d]);
816 5cdb1798 2005-10-29 devnull for(j=d+1; j<=i-1; j++) {
817 5cdb1798 2005-10-29 devnull s_append(buf, "!");
818 5cdb1798 2005-10-29 devnull s_append(buf, field[j]);
819 5cdb1798 2005-10-29 devnull }
820 5cdb1798 2005-10-29 devnull if(d)
821 5cdb1798 2005-10-29 devnull addhostdom(buf, field[d-1]);
822 5cdb1798 2005-10-29 devnull return buf;
823 5cdb1798 2005-10-29 devnull }
824 5cdb1798 2005-10-29 devnull
825 5cdb1798 2005-10-29 devnull /*
826 5cdb1798 2005-10-29 devnull * convert header addresses to @ format.
827 5cdb1798 2005-10-29 devnull * if the address is a source address, and a domain is specified,
828 5cdb1798 2005-10-29 devnull * make sure it falls in the domain.
829 5cdb1798 2005-10-29 devnull */
830 5cdb1798 2005-10-29 devnull String*
831 5cdb1798 2005-10-29 devnull convertheader(String *from)
832 5cdb1798 2005-10-29 devnull {
833 5cdb1798 2005-10-29 devnull Field *f;
834 5cdb1798 2005-10-29 devnull Node *p, *lastp;
835 5cdb1798 2005-10-29 devnull String *a;
836 5cdb1798 2005-10-29 devnull
837 5cdb1798 2005-10-29 devnull if(!returnable(s_to_c(from))){
838 5cdb1798 2005-10-29 devnull from = s_new();
839 5cdb1798 2005-10-29 devnull s_append(from, "Postmaster");
840 5cdb1798 2005-10-29 devnull addhostdom(from, hostdomain);
841 5cdb1798 2005-10-29 devnull } else
842 5cdb1798 2005-10-29 devnull if(strchr(s_to_c(from), '@') == 0){
843 5cdb1798 2005-10-29 devnull a = username(from);
844 5cdb1798 2005-10-29 devnull if(a) {
845 5cdb1798 2005-10-29 devnull s_append(a, " <");
846 5cdb1798 2005-10-29 devnull s_append(a, s_to_c(from));
847 5cdb1798 2005-10-29 devnull addhostdom(a, hostdomain);
848 5cdb1798 2005-10-29 devnull s_append(a, ">");
849 5cdb1798 2005-10-29 devnull from = a;
850 5cdb1798 2005-10-29 devnull } else {
851 5cdb1798 2005-10-29 devnull from = s_copy(s_to_c(from));
852 5cdb1798 2005-10-29 devnull addhostdom(from, hostdomain);
853 5cdb1798 2005-10-29 devnull }
854 5cdb1798 2005-10-29 devnull } else
855 5cdb1798 2005-10-29 devnull from = s_copy(s_to_c(from));
856 5cdb1798 2005-10-29 devnull for(f = firstfield; f; f = f->next){
857 5cdb1798 2005-10-29 devnull lastp = 0;
858 5cdb1798 2005-10-29 devnull for(p = f->node; p; lastp = p, p = p->next){
859 5cdb1798 2005-10-29 devnull if(!p->addr)
860 5cdb1798 2005-10-29 devnull continue;
861 5cdb1798 2005-10-29 devnull a = bangtoat(s_to_c(p->s));
862 5cdb1798 2005-10-29 devnull s_free(p->s);
863 5cdb1798 2005-10-29 devnull if(strchr(s_to_c(a), '@') == 0)
864 5cdb1798 2005-10-29 devnull addhostdom(a, hostdomain);
865 5cdb1798 2005-10-29 devnull else if(*s_to_c(a) == '@')
866 5cdb1798 2005-10-29 devnull a = fixrouteaddr(a, p->next, lastp);
867 5cdb1798 2005-10-29 devnull p->s = a;
868 5cdb1798 2005-10-29 devnull }
869 5cdb1798 2005-10-29 devnull }
870 5cdb1798 2005-10-29 devnull return from;
871 5cdb1798 2005-10-29 devnull }
872 5cdb1798 2005-10-29 devnull /*
873 5cdb1798 2005-10-29 devnull * ensure route addr has brackets around it
874 5cdb1798 2005-10-29 devnull */
875 5cdb1798 2005-10-29 devnull String*
876 5cdb1798 2005-10-29 devnull fixrouteaddr(String *raddr, Node *next, Node *last)
877 5cdb1798 2005-10-29 devnull {
878 5cdb1798 2005-10-29 devnull String *a;
879 5cdb1798 2005-10-29 devnull
880 5cdb1798 2005-10-29 devnull if(last && last->c == '<' && next && next->c == '>')
881 5cdb1798 2005-10-29 devnull return raddr; /* properly formed already */
882 5cdb1798 2005-10-29 devnull
883 5cdb1798 2005-10-29 devnull a = s_new();
884 5cdb1798 2005-10-29 devnull s_append(a, "<");
885 5cdb1798 2005-10-29 devnull s_append(a, s_to_c(raddr));
886 5cdb1798 2005-10-29 devnull s_append(a, ">");
887 5cdb1798 2005-10-29 devnull s_free(raddr);
888 5cdb1798 2005-10-29 devnull return a;
889 5cdb1798 2005-10-29 devnull }
890 5cdb1798 2005-10-29 devnull
891 5cdb1798 2005-10-29 devnull /*
892 5cdb1798 2005-10-29 devnull * print out the parsed header
893 5cdb1798 2005-10-29 devnull */
894 5cdb1798 2005-10-29 devnull int
895 5cdb1798 2005-10-29 devnull printheader(void)
896 5cdb1798 2005-10-29 devnull {
897 5cdb1798 2005-10-29 devnull int n, len;
898 5cdb1798 2005-10-29 devnull Field *f;
899 5cdb1798 2005-10-29 devnull Node *p;
900 5cdb1798 2005-10-29 devnull char *cp;
901 5cdb1798 2005-10-29 devnull char c[1];
902 5cdb1798 2005-10-29 devnull
903 5cdb1798 2005-10-29 devnull n = 0;
904 5cdb1798 2005-10-29 devnull for(f = firstfield; f; f = f->next){
905 5cdb1798 2005-10-29 devnull for(p = f->node; p; p = p->next){
906 5cdb1798 2005-10-29 devnull if(p->s)
907 5cdb1798 2005-10-29 devnull n += dBprint("%s", s_to_c(p->s));
908 5cdb1798 2005-10-29 devnull else {
909 5cdb1798 2005-10-29 devnull c[0] = p->c;
910 5cdb1798 2005-10-29 devnull putcrnl(c, 1);
911 5cdb1798 2005-10-29 devnull n++;
912 5cdb1798 2005-10-29 devnull }
913 5cdb1798 2005-10-29 devnull if(p->white){
914 5cdb1798 2005-10-29 devnull cp = s_to_c(p->white);
915 5cdb1798 2005-10-29 devnull len = strlen(cp);
916 5cdb1798 2005-10-29 devnull putcrnl(cp, len);
917 5cdb1798 2005-10-29 devnull n += len;
918 5cdb1798 2005-10-29 devnull }
919 5cdb1798 2005-10-29 devnull uneaten = p->end;
920 5cdb1798 2005-10-29 devnull }
921 5cdb1798 2005-10-29 devnull putcrnl("\n", 1);
922 5cdb1798 2005-10-29 devnull n++;
923 5cdb1798 2005-10-29 devnull uneaten++; /* skip newline */
924 5cdb1798 2005-10-29 devnull }
925 5cdb1798 2005-10-29 devnull return n;
926 5cdb1798 2005-10-29 devnull }
927 5cdb1798 2005-10-29 devnull
928 5cdb1798 2005-10-29 devnull /*
929 5cdb1798 2005-10-29 devnull * add a domain onto an name, return the new name
930 5cdb1798 2005-10-29 devnull */
931 5cdb1798 2005-10-29 devnull char *
932 5cdb1798 2005-10-29 devnull domainify(char *name, char *domain)
933 5cdb1798 2005-10-29 devnull {
934 5cdb1798 2005-10-29 devnull static String *s;
935 5cdb1798 2005-10-29 devnull char *p;
936 5cdb1798 2005-10-29 devnull
937 5cdb1798 2005-10-29 devnull if(domain==0 || strchr(name, '.')!=0)
938 5cdb1798 2005-10-29 devnull return name;
939 5cdb1798 2005-10-29 devnull
940 5cdb1798 2005-10-29 devnull s = s_reset(s);
941 5cdb1798 2005-10-29 devnull s_append(s, name);
942 5cdb1798 2005-10-29 devnull p = strchr(domain, '.');
943 5cdb1798 2005-10-29 devnull if(p == 0){
944 5cdb1798 2005-10-29 devnull s_append(s, ".");
945 5cdb1798 2005-10-29 devnull p = domain;
946 5cdb1798 2005-10-29 devnull }
947 5cdb1798 2005-10-29 devnull s_append(s, p);
948 5cdb1798 2005-10-29 devnull return s_to_c(s);
949 5cdb1798 2005-10-29 devnull }
950 5cdb1798 2005-10-29 devnull
951 5cdb1798 2005-10-29 devnull /*
952 5cdb1798 2005-10-29 devnull * print message observing '.' escapes and using \r\n for \n
953 5cdb1798 2005-10-29 devnull */
954 5cdb1798 2005-10-29 devnull void
955 5cdb1798 2005-10-29 devnull putcrnl(char *cp, int n)
956 5cdb1798 2005-10-29 devnull {
957 5cdb1798 2005-10-29 devnull int c;
958 5cdb1798 2005-10-29 devnull
959 5cdb1798 2005-10-29 devnull for(; n; n--, cp++){
960 5cdb1798 2005-10-29 devnull c = *cp;
961 5cdb1798 2005-10-29 devnull if(c == '\n')
962 5cdb1798 2005-10-29 devnull dBputc('\r');
963 5cdb1798 2005-10-29 devnull else if(c == '.' && last=='\n')
964 5cdb1798 2005-10-29 devnull dBputc('.');
965 5cdb1798 2005-10-29 devnull dBputc(c);
966 5cdb1798 2005-10-29 devnull last = c;
967 5cdb1798 2005-10-29 devnull }
968 5cdb1798 2005-10-29 devnull }
969 5cdb1798 2005-10-29 devnull
970 5cdb1798 2005-10-29 devnull /*
971 5cdb1798 2005-10-29 devnull * Get a line including a crnl into a string. Convert crnl into nl.
972 5cdb1798 2005-10-29 devnull */
973 5cdb1798 2005-10-29 devnull char *
974 5cdb1798 2005-10-29 devnull getcrnl(String *s)
975 5cdb1798 2005-10-29 devnull {
976 5cdb1798 2005-10-29 devnull int c;
977 5cdb1798 2005-10-29 devnull int count;
978 5cdb1798 2005-10-29 devnull
979 5cdb1798 2005-10-29 devnull count = 0;
980 5cdb1798 2005-10-29 devnull for(;;){
981 5cdb1798 2005-10-29 devnull c = Bgetc(&bin);
982 5cdb1798 2005-10-29 devnull if(debug)
983 5cdb1798 2005-10-29 devnull Bputc(&berr, c);
984 5cdb1798 2005-10-29 devnull switch(c){
985 5cdb1798 2005-10-29 devnull case -1:
986 5cdb1798 2005-10-29 devnull s_append(s, "connection closed unexpectedly by remote system");
987 5cdb1798 2005-10-29 devnull s_terminate(s);
988 5cdb1798 2005-10-29 devnull return 0;
989 5cdb1798 2005-10-29 devnull case '\r':
990 5cdb1798 2005-10-29 devnull c = Bgetc(&bin);
991 5cdb1798 2005-10-29 devnull if(c == '\n'){
992 5cdb1798 2005-10-29 devnull s_putc(s, c);
993 5cdb1798 2005-10-29 devnull if(debug)
994 5cdb1798 2005-10-29 devnull Bputc(&berr, c);
995 5cdb1798 2005-10-29 devnull count++;
996 5cdb1798 2005-10-29 devnull s_terminate(s);
997 5cdb1798 2005-10-29 devnull return s->ptr - count;
998 5cdb1798 2005-10-29 devnull }
999 5cdb1798 2005-10-29 devnull Bungetc(&bin);
1000 5cdb1798 2005-10-29 devnull s_putc(s, '\r');
1001 5cdb1798 2005-10-29 devnull if(debug)
1002 5cdb1798 2005-10-29 devnull Bputc(&berr, '\r');
1003 5cdb1798 2005-10-29 devnull count++;
1004 5cdb1798 2005-10-29 devnull break;
1005 5cdb1798 2005-10-29 devnull default:
1006 5cdb1798 2005-10-29 devnull s_putc(s, c);
1007 5cdb1798 2005-10-29 devnull count++;
1008 5cdb1798 2005-10-29 devnull break;
1009 5cdb1798 2005-10-29 devnull }
1010 5cdb1798 2005-10-29 devnull }
1011 5cdb1798 2005-10-29 devnull return 0;
1012 5cdb1798 2005-10-29 devnull }
1013 5cdb1798 2005-10-29 devnull
1014 5cdb1798 2005-10-29 devnull /*
1015 5cdb1798 2005-10-29 devnull * print out a parsed date
1016 5cdb1798 2005-10-29 devnull */
1017 5cdb1798 2005-10-29 devnull int
1018 5cdb1798 2005-10-29 devnull printdate(Node *p)
1019 5cdb1798 2005-10-29 devnull {
1020 5cdb1798 2005-10-29 devnull int n, sep = 0;
1021 5cdb1798 2005-10-29 devnull
1022 5cdb1798 2005-10-29 devnull n = dBprint("Date: %s,", s_to_c(p->s));
1023 5cdb1798 2005-10-29 devnull for(p = p->next; p; p = p->next){
1024 5cdb1798 2005-10-29 devnull if(p->s){
1025 5cdb1798 2005-10-29 devnull if(sep == 0) {
1026 5cdb1798 2005-10-29 devnull dBputc(' ');
1027 5cdb1798 2005-10-29 devnull n++;
1028 5cdb1798 2005-10-29 devnull }
1029 5cdb1798 2005-10-29 devnull if (p->next)
1030 5cdb1798 2005-10-29 devnull n += dBprint("%s", s_to_c(p->s));
1031 5cdb1798 2005-10-29 devnull else
1032 5cdb1798 2005-10-29 devnull n += dBprint("%s", rewritezone(s_to_c(p->s)));
1033 5cdb1798 2005-10-29 devnull sep = 0;
1034 5cdb1798 2005-10-29 devnull } else {
1035 5cdb1798 2005-10-29 devnull dBputc(p->c);
1036 5cdb1798 2005-10-29 devnull n++;
1037 5cdb1798 2005-10-29 devnull sep = 1;
1038 5cdb1798 2005-10-29 devnull }
1039 5cdb1798 2005-10-29 devnull }
1040 5cdb1798 2005-10-29 devnull n += dBprint("\r\n");
1041 5cdb1798 2005-10-29 devnull return n;
1042 5cdb1798 2005-10-29 devnull }
1043 5cdb1798 2005-10-29 devnull
1044 5cdb1798 2005-10-29 devnull char *
1045 5cdb1798 2005-10-29 devnull rewritezone(char *z)
1046 5cdb1798 2005-10-29 devnull {
1047 5cdb1798 2005-10-29 devnull int mindiff;
1048 5cdb1798 2005-10-29 devnull char s;
1049 5cdb1798 2005-10-29 devnull Tm *tm;
1050 5cdb1798 2005-10-29 devnull static char x[7];
1051 5cdb1798 2005-10-29 devnull
1052 5cdb1798 2005-10-29 devnull tm = localtime(time(0));
1053 5cdb1798 2005-10-29 devnull mindiff = tm->tzoff/60;
1054 5cdb1798 2005-10-29 devnull
1055 5cdb1798 2005-10-29 devnull /* if not in my timezone, don't change anything */
1056 5cdb1798 2005-10-29 devnull if(strcmp(tm->zone, z) != 0)
1057 5cdb1798 2005-10-29 devnull return z;
1058 5cdb1798 2005-10-29 devnull
1059 5cdb1798 2005-10-29 devnull if(mindiff < 0){
1060 5cdb1798 2005-10-29 devnull s = '-';
1061 5cdb1798 2005-10-29 devnull mindiff = -mindiff;
1062 5cdb1798 2005-10-29 devnull } else
1063 5cdb1798 2005-10-29 devnull s = '+';
1064 5cdb1798 2005-10-29 devnull
1065 5cdb1798 2005-10-29 devnull sprint(x, "%c%.2d%.2d", s, mindiff/60, mindiff%60);
1066 5cdb1798 2005-10-29 devnull return x;
1067 5cdb1798 2005-10-29 devnull }
1068 5cdb1798 2005-10-29 devnull
1069 5cdb1798 2005-10-29 devnull /*
1070 5cdb1798 2005-10-29 devnull * stolen from libc/port/print.c
1071 5cdb1798 2005-10-29 devnull */
1072 5cdb1798 2005-10-29 devnull #define SIZE 4096
1073 5cdb1798 2005-10-29 devnull int
1074 5cdb1798 2005-10-29 devnull dBprint(char *fmt, ...)
1075 5cdb1798 2005-10-29 devnull {
1076 5cdb1798 2005-10-29 devnull char buf[SIZE], *out;
1077 5cdb1798 2005-10-29 devnull va_list arg;
1078 5cdb1798 2005-10-29 devnull int n;
1079 5cdb1798 2005-10-29 devnull
1080 5cdb1798 2005-10-29 devnull va_start(arg, fmt);
1081 5cdb1798 2005-10-29 devnull out = vseprint(buf, buf+SIZE, fmt, arg);
1082 5cdb1798 2005-10-29 devnull va_end(arg);
1083 5cdb1798 2005-10-29 devnull if(debug){
1084 5cdb1798 2005-10-29 devnull Bwrite(&berr, buf, (long)(out-buf));
1085 5cdb1798 2005-10-29 devnull Bflush(&berr);
1086 5cdb1798 2005-10-29 devnull }
1087 5cdb1798 2005-10-29 devnull n = Bwrite(&bout, buf, (long)(out-buf));
1088 5cdb1798 2005-10-29 devnull Bflush(&bout);
1089 5cdb1798 2005-10-29 devnull return n;
1090 5cdb1798 2005-10-29 devnull }
1091 5cdb1798 2005-10-29 devnull
1092 5cdb1798 2005-10-29 devnull int
1093 5cdb1798 2005-10-29 devnull dBputc(int x)
1094 5cdb1798 2005-10-29 devnull {
1095 5cdb1798 2005-10-29 devnull if(debug)
1096 5cdb1798 2005-10-29 devnull Bputc(&berr, x);
1097 5cdb1798 2005-10-29 devnull return Bputc(&bout, x);
1098 5cdb1798 2005-10-29 devnull }
1099 5cdb1798 2005-10-29 devnull
1100 5cdb1798 2005-10-29 devnull char*
1101 5cdb1798 2005-10-29 devnull expand_addr(char* a)
1102 5cdb1798 2005-10-29 devnull {
1103 5cdb1798 2005-10-29 devnull Ndb *db;
1104 5cdb1798 2005-10-29 devnull Ndbs s;
1105 5cdb1798 2005-10-29 devnull char *sys, *ret, *proto, *host;
1106 5cdb1798 2005-10-29 devnull
1107 5cdb1798 2005-10-29 devnull proto = strtok(a,"!");
1108 5cdb1798 2005-10-29 devnull if ( strcmp(proto,"net") != 0 ) {
1109 5cdb1798 2005-10-29 devnull fprint(2,"unknown proto %s\n",proto);
1110 5cdb1798 2005-10-29 devnull }
1111 5cdb1798 2005-10-29 devnull host = strtok(0,"!");
1112 5cdb1798 2005-10-29 devnull if ( strcmp(host,"$smtp") == 0 ) {
1113 5cdb1798 2005-10-29 devnull sys = sysname();
1114 5cdb1798 2005-10-29 devnull db = ndbopen(unsharp("#9/ndb/local"));
1115 5cdb1798 2005-10-29 devnull host = ndbgetvalue(db, &s, "sys", sys, "smtp", nil);
1116 5cdb1798 2005-10-29 devnull }
1117 5cdb1798 2005-10-29 devnull ret = malloc(strlen(proto)+strlen(host)+2);
1118 5cdb1798 2005-10-29 devnull sprint(ret,"%s!%s",proto,host);
1119 5cdb1798 2005-10-29 devnull
1120 5cdb1798 2005-10-29 devnull return ret;
1121 5cdb1798 2005-10-29 devnull
1122 5cdb1798 2005-10-29 devnull }