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>
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;
35 5cdb1798 2005-10-29 devnull #define Retry "Retry, Temporary Failure"
36 5cdb1798 2005-10-29 devnull #define Giveup "Permanent Failure"
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;
60 5cdb1798 2005-10-29 devnull usage(void)
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);
67 5cdb1798 2005-10-29 devnull timeout(void *x, char *msg)
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);
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);
83 5cc53af9 2006-02-12 devnull threadexitsall(Retry);
85 5cdb1798 2005-10-29 devnull return 0;
89 5cdb1798 2005-10-29 devnull removenewline(char *p)
91 5cdb1798 2005-10-29 devnull int n = strlen(p)-1;
93 5cdb1798 2005-10-29 devnull if(n < 0)
95 5cdb1798 2005-10-29 devnull if(p[n] == '\n')
96 5cdb1798 2005-10-29 devnull p[n] = 0;
100 5cc53af9 2006-02-12 devnull exitcode(char *s)
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;
108 5cdb1798 2005-10-29 devnull threadmain(int argc, char **argv)
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;
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;
130 5cdb1798 2005-10-29 devnull case 'f':
131 5cdb1798 2005-10-29 devnull filter = 1;
133 5cdb1798 2005-10-29 devnull case 'd':
134 5cdb1798 2005-10-29 devnull debug = 1;
136 5cdb1798 2005-10-29 devnull case 'g':
137 5cdb1798 2005-10-29 devnull gdomain = ARGF();
139 5cdb1798 2005-10-29 devnull case 'h':
140 5cdb1798 2005-10-29 devnull host = ARGF();
142 5cdb1798 2005-10-29 devnull case 'i':
143 5cdb1798 2005-10-29 devnull insecure = 1;
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;
149 5cdb1798 2005-10-29 devnull case 's':
150 5cdb1798 2005-10-29 devnull trysecure = 1;
152 5cdb1798 2005-10-29 devnull case 'u':
153 5cdb1798 2005-10-29 devnull user = ARGF();
155 5cdb1798 2005-10-29 devnull default:
156 5cdb1798 2005-10-29 devnull usage();
158 5cdb1798 2005-10-29 devnull }ARGEND;
160 5cdb1798 2005-10-29 devnull Binit(&berr, 2, OWRITE);
161 5cdb1798 2005-10-29 devnull Binit(&bfile, 0, OREAD);
164 5cdb1798 2005-10-29 devnull * get domain and add to host name
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--;
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));
177 5cdb1798 2005-10-29 devnull * get destination address
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;
187 5cdb1798 2005-10-29 devnull * get sender's machine.
188 5cdb1798 2005-10-29 devnull * get sender in internet style. domainify if necessary.
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++));
194 5cdb1798 2005-10-29 devnull fromm = s_clone(sender);
195 5cdb1798 2005-10-29 devnull rv = strrchr(s_to_c(fromm), '!');
197 5cdb1798 2005-10-29 devnull *rv = 0;
199 5cdb1798 2005-10-29 devnull *s_to_c(fromm) = 0;
200 5cdb1798 2005-10-29 devnull from = bangtoat(s_to_c(sender));
203 5cdb1798 2005-10-29 devnull * send the mail
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);
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);
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;
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 {
238 5cdb1798 2005-10-29 devnull errs[rcvrs] = 0;
240 5cdb1798 2005-10-29 devnull rcvrs++;
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;
247 5cdb1798 2005-10-29 devnull if(ping){
248 5cdb1798 2005-10-29 devnull quit(0);
249 5cc53af9 2006-02-12 devnull threadexitsall(0);
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);
260 5cdb1798 2005-10-29 devnull * here when some but not all rcvrs failed
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]);
269 5cc53af9 2006-02-12 devnull threadexitsall(Giveup);
272 5cdb1798 2005-10-29 devnull * here when all rcvrs failed
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);
286 5cdb1798 2005-10-29 devnull * connect to the remote host
288 5cdb1798 2005-10-29 devnull static char *
289 5cdb1798 2005-10-29 devnull connect(char* net)
291 5cdb1798 2005-10-29 devnull char buf[256];
294 5cdb1798 2005-10-29 devnull fd = mxdial(net, ddomain, gdomain);
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;
305 5cdb1798 2005-10-29 devnull return Retry;
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;
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";
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.
321 5cdb1798 2005-10-29 devnull static char *
322 5cdb1798 2005-10-29 devnull dotls(char *me)
324 5cdb1798 2005-10-29 devnull TLSconn *c;
325 5cdb1798 2005-10-29 devnull Thumbprint *goodcerts;
326 5cdb1798 2005-10-29 devnull char *h;
328 5cdb1798 2005-10-29 devnull uchar hash[SHA1dlen];
330 5cc53af9 2006-02-12 devnull return Giveup;
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;
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;
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;
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 */
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);
368 5cdb1798 2005-10-29 devnull return Giveup; /* how to recover? TLS is started */
370 5cdb1798 2005-10-29 devnull freeThumbprints(goodcerts);
371 5cdb1798 2005-10-29 devnull Bterm(&bin);
372 5cdb1798 2005-10-29 devnull Bterm(&bout);
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.
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);
382 5cdb1798 2005-10-29 devnull syslog(0, "smtp", "started TLS to %q", ddomain);
383 5cdb1798 2005-10-29 devnull return(hello(me, 1));
386 5cdb1798 2005-10-29 devnull static char *
387 5cdb1798 2005-10-29 devnull doauth(char *methods)
389 5cdb1798 2005-10-29 devnull char *buf, *base64;
392 5cdb1798 2005-10-29 devnull UserPasswd *p;
394 5cdb1798 2005-10-29 devnull dial_string_parse(ddomain, &ds);
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);
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;
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;
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;
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;
428 5cdb1798 2005-10-29 devnull free(base64);
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 */
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;
448 5cdb1798 2005-10-29 devnull return "No supported AUTH method";
449 5cdb1798 2005-10-29 devnull return(0);
453 5cdb1798 2005-10-29 devnull hello(char *me, int encrypted)
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;
459 5cdb1798 2005-10-29 devnull if (!encrypted)
460 5cdb1798 2005-10-29 devnull switch(getreply()){
464 5cdb1798 2005-10-29 devnull return Giveup;
465 5cdb1798 2005-10-29 devnull default:
466 5cdb1798 2005-10-29 devnull return Retry;
469 5cdb1798 2005-10-29 devnull ehlo = 1;
470 de43b162 2018-11-14 rsc encrypted = 1;
472 5cdb1798 2005-10-29 devnull if(ehlo)
473 5cdb1798 2005-10-29 devnull dBprint("EHLO %s\r\n", me);
475 5cdb1798 2005-10-29 devnull dBprint("HELO %s\r\n", me);
476 5cdb1798 2005-10-29 devnull switch (getreply()) {
480 5cdb1798 2005-10-29 devnull if(ehlo){
481 5cdb1798 2005-10-29 devnull ehlo = 0;
482 5cdb1798 2005-10-29 devnull goto Again;
484 5cdb1798 2005-10-29 devnull return Giveup;
485 5cdb1798 2005-10-29 devnull default:
486 5cdb1798 2005-10-29 devnull return Retry;
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 */
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));
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;
511 5cdb1798 2005-10-29 devnull s_free(r);
512 5cdb1798 2005-10-29 devnull return 0;
516 5cdb1798 2005-10-29 devnull * report sender to remote
519 5cdb1798 2005-10-29 devnull mailfrom(char *from)
521 5cdb1798 2005-10-29 devnull if(!returnable(from))
522 5cdb1798 2005-10-29 devnull dBprint("MAIL FROM:<>\r\n");
524 5cdb1798 2005-10-29 devnull if(strchr(from, '@'))
525 5cdb1798 2005-10-29 devnull dBprint("MAIL FROM:<%s>\r\n", from);
527 5cdb1798 2005-10-29 devnull dBprint("MAIL FROM:<%s@%s>\r\n", from, hostdomain);
528 5cdb1798 2005-10-29 devnull switch(getreply()){
532 5cdb1798 2005-10-29 devnull return Giveup;
533 5cdb1798 2005-10-29 devnull default:
534 5cdb1798 2005-10-29 devnull return Retry;
536 5cdb1798 2005-10-29 devnull return 0;
540 5cdb1798 2005-10-29 devnull * report a recipient to remote
543 5cdb1798 2005-10-29 devnull rcptto(char *to)
545 5cdb1798 2005-10-29 devnull String *s;
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();
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));
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);
560 5cdb1798 2005-10-29 devnull alarm(10*alarmscale);
561 5cdb1798 2005-10-29 devnull switch(getreply()){
565 5cdb1798 2005-10-29 devnull return Giveup;
566 5cdb1798 2005-10-29 devnull default:
567 5cdb1798 2005-10-29 devnull return Retry;
569 5cdb1798 2005-10-29 devnull return 0;
572 5cdb1798 2005-10-29 devnull static char hex[] = "0123456789abcdef";
575 5cdb1798 2005-10-29 devnull * send the damn thing
578 5cdb1798 2005-10-29 devnull data(String *from, Biobuf *b)
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];
587 5cdb1798 2005-10-29 devnull * input the header.
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;
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;
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;
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 */
614 5cdb1798 2005-10-29 devnull buf[n] = 0;
615 5cdb1798 2005-10-29 devnull bufsize = n;
618 5cdb1798 2005-10-29 devnull * parse the header, turn all addresses into @ format
620 5cdb1798 2005-10-29 devnull yyinit(buf, n);
621 5cdb1798 2005-10-29 devnull yyparse();
624 5cdb1798 2005-10-29 devnull * print message observing '.' escapes and using \r\n for \n
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()){
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;
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
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;
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];
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);
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));
666 5cdb1798 2005-10-29 devnull s_free(fromline);
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));
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);
688 5cdb1798 2005-10-29 devnull * send body
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;
702 5cdb1798 2005-10-29 devnull if(n == 0)
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;
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");
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()){
720 5cdb1798 2005-10-29 devnull return Giveup;
721 5cdb1798 2005-10-29 devnull default:
722 5cdb1798 2005-10-29 devnull return Retry;
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));/**/
727 5cdb1798 2005-10-29 devnull return 0;
731 5cdb1798 2005-10-29 devnull * we're leaving
734 5cdb1798 2005-10-29 devnull quit(char *rv)
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);
747 5cdb1798 2005-10-29 devnull * read a reply into a string, return the reply code
750 5cdb1798 2005-10-29 devnull getreply(void)
752 5cdb1798 2005-10-29 devnull char *line;
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] != '-')
767 5cdb1798 2005-10-29 devnull rv = atoi(line)/100;
768 5cdb1798 2005-10-29 devnull return rv;
771 5cdb1798 2005-10-29 devnull addhostdom(String *buf, char *host)
773 5cdb1798 2005-10-29 devnull s_append(buf, "@");
774 5cdb1798 2005-10-29 devnull s_append(buf, host);
778 5cdb1798 2005-10-29 devnull * Convert from `bang' to `source routing' format.
780 5cdb1798 2005-10-29 devnull * a.x.y!b.p.o!c!d -> @a.x.y:c!d@b.p.o
782 5cdb1798 2005-10-29 devnull String *
783 5cdb1798 2005-10-29 devnull bangtoat(char *addr)
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];
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;
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;
804 5cdb1798 2005-10-29 devnull * count leading domain fields (non-domains don't count)
806 5cdb1798 2005-10-29 devnull for(d = 0; d<i-1; d++)
807 5cdb1798 2005-10-29 devnull if(strchr(field[d], '.')==0)
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
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]);
820 5cdb1798 2005-10-29 devnull s_append(buf, ":");
824 5cdb1798 2005-10-29 devnull * throw in the non-domain elements separated by '!'s
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]);
832 5cdb1798 2005-10-29 devnull addhostdom(buf, field[d-1]);
833 5cdb1798 2005-10-29 devnull return buf;
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.
842 5cdb1798 2005-10-29 devnull convertheader(String *from)
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;
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);
853 5cdb1798 2005-10-29 devnull if(strchr(s_to_c(from), '@') == 0){
854 5cdb1798 2005-10-29 devnull a = username(from);
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);
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;
881 5cdb1798 2005-10-29 devnull return from;
884 5cdb1798 2005-10-29 devnull * ensure route addr has brackets around it
887 5cdb1798 2005-10-29 devnull fixrouteaddr(String *raddr, Node *next, Node *last)
889 5cdb1798 2005-10-29 devnull String *a;
891 5cdb1798 2005-10-29 devnull if(last && last->c == '<' && next && next->c == '>')
892 5cdb1798 2005-10-29 devnull return raddr; /* properly formed already */
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;
903 5cdb1798 2005-10-29 devnull * print out the parsed header
906 5cdb1798 2005-10-29 devnull printheader(void)
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];
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));
920 5cdb1798 2005-10-29 devnull c[0] = p->c;
921 5cdb1798 2005-10-29 devnull putcrnl(c, 1);
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;
930 5cdb1798 2005-10-29 devnull uneaten = p->end;
932 5cdb1798 2005-10-29 devnull putcrnl("\n", 1);
934 5cdb1798 2005-10-29 devnull uneaten++; /* skip newline */
936 5cdb1798 2005-10-29 devnull return n;
940 5cdb1798 2005-10-29 devnull * add a domain onto an name, return the new name
943 5cdb1798 2005-10-29 devnull domainify(char *name, char *domain)
945 5cdb1798 2005-10-29 devnull static String *s;
946 5cdb1798 2005-10-29 devnull char *p;
948 5cdb1798 2005-10-29 devnull if(domain==0 || strchr(name, '.')!=0)
949 5cdb1798 2005-10-29 devnull return name;
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;
958 5cdb1798 2005-10-29 devnull s_append(s, p);
959 5cdb1798 2005-10-29 devnull return s_to_c(s);
963 5cdb1798 2005-10-29 devnull * print message observing '.' escapes and using \r\n for \n
966 5cdb1798 2005-10-29 devnull putcrnl(char *cp, int n)
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;
982 5cdb1798 2005-10-29 devnull * Get a line including a crnl into a string. Convert crnl into nl.
985 5cdb1798 2005-10-29 devnull getcrnl(String *s)
988 5cdb1798 2005-10-29 devnull int count;
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;
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++;
1017 5cdb1798 2005-10-29 devnull default:
1018 5cdb1798 2005-10-29 devnull s_putc(s, c);
1019 5cdb1798 2005-10-29 devnull count++;
1023 5cdb1798 2005-10-29 devnull return 0;
1027 5cdb1798 2005-10-29 devnull * print out a parsed date
1030 5cdb1798 2005-10-29 devnull printdate(Node *p)
1032 5cdb1798 2005-10-29 devnull int n, sep = 0;
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(' ');
1041 5cdb1798 2005-10-29 devnull if (p->next)
1042 5cdb1798 2005-10-29 devnull n += dBprint("%s", s_to_c(p->s));
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);
1049 5cdb1798 2005-10-29 devnull sep = 1;
1052 5cdb1798 2005-10-29 devnull n += dBprint("\r\n");
1053 5cdb1798 2005-10-29 devnull return n;
1057 5cdb1798 2005-10-29 devnull rewritezone(char *z)
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];
1064 5cdb1798 2005-10-29 devnull tm = localtime(time(0));
1065 5cdb1798 2005-10-29 devnull mindiff = tm->tzoff/60;
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;
1071 5cdb1798 2005-10-29 devnull if(mindiff < 0){
1072 5cdb1798 2005-10-29 devnull s = '-';
1073 5cdb1798 2005-10-29 devnull mindiff = -mindiff;
1075 5cdb1798 2005-10-29 devnull s = '+';
1077 5cdb1798 2005-10-29 devnull sprint(x, "%c%.2d%.2d", s, mindiff/60, mindiff%60);
1078 5cdb1798 2005-10-29 devnull return x;
1082 5cdb1798 2005-10-29 devnull * stolen from libc/port/print.c
1084 5cdb1798 2005-10-29 devnull #define SIZE 4096
1086 5cdb1798 2005-10-29 devnull dBprint(char *fmt, ...)
1088 5cdb1798 2005-10-29 devnull char buf[SIZE], *out;
1089 5cdb1798 2005-10-29 devnull va_list arg;
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);
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;
1105 5cdb1798 2005-10-29 devnull dBputc(int x)
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);
1113 5cc53af9 2006-02-12 devnull expand_addr(char *addr)
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;
1120 5cc53af9 2006-02-12 devnull p = strchr(addr, '!');
1122 5cc53af9 2006-02-12 devnull q = strchr(p+1, '!');
1123 5cc53af9 2006-02-12 devnull name = p+1;
1125 5cc53af9 2006-02-12 devnull name = addr;
1126 5cc53af9 2006-02-12 devnull q = nil;
1129 5cc53af9 2006-02-12 devnull if(name[0] != '$')
1130 5cc53af9 2006-02-12 devnull return addr;
1131 5cc53af9 2006-02-12 devnull name++;
1133 5cc53af9 2006-02-12 devnull *q = 0;
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);
1141 5cc53af9 2006-02-12 devnull *q = '!';
1142 5cc53af9 2006-02-12 devnull return addr;
1145 5cc53af9 2006-02-12 devnull *(name-1) = 0;
1147 5cc53af9 2006-02-12 devnull *q = '!';
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;