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