Blame


1 ba97b2d7 2024-03-20 stsp /*
2 ba97b2d7 2024-03-20 stsp * Copyright (c) 2024 Stefan Sperling <stsp@openbsd.org>
3 15ff48f3 2024-05-10 stsp * Copyright (c) 2008, 2012 Gilles Chehade <gilles@poolp.org>
4 ba97b2d7 2024-03-20 stsp *
5 ba97b2d7 2024-03-20 stsp * Permission to use, copy, modify, and distribute this software for any
6 ba97b2d7 2024-03-20 stsp * purpose with or without fee is hereby granted, provided that the above
7 ba97b2d7 2024-03-20 stsp * copyright notice and this permission notice appear in all copies.
8 ba97b2d7 2024-03-20 stsp *
9 ba97b2d7 2024-03-20 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 ba97b2d7 2024-03-20 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 ba97b2d7 2024-03-20 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 ba97b2d7 2024-03-20 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 ba97b2d7 2024-03-20 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 ba97b2d7 2024-03-20 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 ba97b2d7 2024-03-20 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 ba97b2d7 2024-03-20 stsp */
17 ba97b2d7 2024-03-20 stsp
18 ba97b2d7 2024-03-20 stsp #include <sys/types.h>
19 ba97b2d7 2024-03-20 stsp #include <sys/socket.h>
20 ba97b2d7 2024-03-20 stsp
21 939d3016 2024-04-23 op #include <ctype.h>
22 2c1b1780 2024-04-23 op #include <err.h>
23 39910b63 2024-03-20 op #include <errno.h>
24 2c1b1780 2024-04-23 op #include <netdb.h>
25 09486e84 2024-03-21 op #include <poll.h>
26 2c1b1780 2024-04-23 op #include <pwd.h>
27 2c1b1780 2024-04-23 op #include <stdarg.h>
28 2c1b1780 2024-04-23 op #include <stdint.h>
29 ba97b2d7 2024-03-20 stsp #include <stdio.h>
30 ba97b2d7 2024-03-20 stsp #include <stdlib.h>
31 ba97b2d7 2024-03-20 stsp #include <string.h>
32 7e03b468 2024-04-19 stsp #include <syslog.h>
33 ba97b2d7 2024-03-20 stsp #include <time.h>
34 ba97b2d7 2024-03-20 stsp #include <unistd.h>
35 ba97b2d7 2024-03-20 stsp
36 7e03b468 2024-04-19 stsp #include "log.h"
37 7e03b468 2024-04-19 stsp
38 ba97b2d7 2024-03-20 stsp #include "got_error.h"
39 ba97b2d7 2024-03-20 stsp
40 ba97b2d7 2024-03-20 stsp #include "got_lib_poll.h"
41 ba97b2d7 2024-03-20 stsp
42 09486e84 2024-03-21 op #define SMTP_LINE_MAX 65535
43 09486e84 2024-03-21 op
44 100d3e4b 2024-03-20 op static int smtp_timeout = 60; /* in seconds */
45 09486e84 2024-03-21 op static char smtp_buf[SMTP_LINE_MAX];
46 09486e84 2024-03-21 op static size_t smtp_buflen;
47 ba97b2d7 2024-03-20 stsp
48 ba97b2d7 2024-03-20 stsp __dead static void
49 ba97b2d7 2024-03-20 stsp usage(void)
50 ba97b2d7 2024-03-20 stsp {
51 dfa6ae4c 2024-03-20 op fprintf(stderr, "usage: %s [-f sender] [-r responder] "
52 ba97b2d7 2024-03-20 stsp "[-s subject] [-h hostname] [-p port] recipient\n", getprogname());
53 ba97b2d7 2024-03-20 stsp exit(1);
54 ba97b2d7 2024-03-20 stsp }
55 ba97b2d7 2024-03-20 stsp
56 39910b63 2024-03-20 op static int
57 39910b63 2024-03-20 op dial(const char *host, const char *port)
58 39910b63 2024-03-20 op {
59 39910b63 2024-03-20 op struct addrinfo hints, *res, *res0;
60 39910b63 2024-03-20 op const char *cause = NULL;
61 39910b63 2024-03-20 op int s, error, save_errno;
62 39910b63 2024-03-20 op
63 39910b63 2024-03-20 op memset(&hints, 0, sizeof(hints));
64 39910b63 2024-03-20 op hints.ai_family = AF_UNSPEC;
65 39910b63 2024-03-20 op hints.ai_socktype = SOCK_STREAM;
66 39910b63 2024-03-20 op error = getaddrinfo(host, port, &hints, &res0);
67 39910b63 2024-03-20 op if (error)
68 7e03b468 2024-04-19 stsp fatalx("failed to resolve %s:%s: %s", host, port,
69 39910b63 2024-03-20 op gai_strerror(error));
70 39910b63 2024-03-20 op
71 39910b63 2024-03-20 op s = -1;
72 39910b63 2024-03-20 op for (res = res0; res; res = res->ai_next) {
73 39910b63 2024-03-20 op s = socket(res->ai_family, res->ai_socktype,
74 39910b63 2024-03-20 op res->ai_protocol);
75 39910b63 2024-03-20 op if (s == -1) {
76 39910b63 2024-03-20 op cause = "socket";
77 39910b63 2024-03-20 op continue;
78 39910b63 2024-03-20 op }
79 39910b63 2024-03-20 op
80 39910b63 2024-03-20 op if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
81 39910b63 2024-03-20 op cause = "connect";
82 39910b63 2024-03-20 op save_errno = errno;
83 39910b63 2024-03-20 op close(s);
84 39910b63 2024-03-20 op errno = save_errno;
85 39910b63 2024-03-20 op s = -1;
86 39910b63 2024-03-20 op continue;
87 39910b63 2024-03-20 op }
88 39910b63 2024-03-20 op
89 39910b63 2024-03-20 op break;
90 39910b63 2024-03-20 op }
91 39910b63 2024-03-20 op
92 39910b63 2024-03-20 op freeaddrinfo(res0);
93 39910b63 2024-03-20 op if (s == -1)
94 50ccbcd9 2024-05-11 stsp fatal("%s %s:%s", cause, host, port);
95 39910b63 2024-03-20 op return s;
96 39910b63 2024-03-20 op }
97 39910b63 2024-03-20 op
98 ba97b2d7 2024-03-20 stsp static char *
99 ba97b2d7 2024-03-20 stsp set_default_fromaddr(void)
100 ba97b2d7 2024-03-20 stsp {
101 ba97b2d7 2024-03-20 stsp struct passwd *pw = NULL;
102 ba97b2d7 2024-03-20 stsp char *s;
103 ba97b2d7 2024-03-20 stsp char hostname[255];
104 ba97b2d7 2024-03-20 stsp
105 ba97b2d7 2024-03-20 stsp pw = getpwuid(getuid());
106 ba97b2d7 2024-03-20 stsp if (pw == NULL) {
107 7e03b468 2024-04-19 stsp fatalx("my UID %d was not found in password database",
108 ba97b2d7 2024-03-20 stsp getuid());
109 ba97b2d7 2024-03-20 stsp }
110 8bffa129 2024-04-09 op
111 ba97b2d7 2024-03-20 stsp if (gethostname(hostname, sizeof(hostname)) == -1)
112 7e03b468 2024-04-19 stsp fatal("gethostname");
113 ba97b2d7 2024-03-20 stsp
114 ba97b2d7 2024-03-20 stsp if (asprintf(&s, "%s@%s", pw->pw_name, hostname) == -1)
115 7e03b468 2024-04-19 stsp fatal("asprintf");
116 ba97b2d7 2024-03-20 stsp
117 ba97b2d7 2024-03-20 stsp return s;
118 ba97b2d7 2024-03-20 stsp }
119 ba97b2d7 2024-03-20 stsp
120 ba97b2d7 2024-03-20 stsp static int
121 ba97b2d7 2024-03-20 stsp read_smtp_code(int s, const char *code)
122 ba97b2d7 2024-03-20 stsp {
123 ba97b2d7 2024-03-20 stsp const struct got_error *error;
124 09486e84 2024-03-21 op char *endl;
125 09486e84 2024-03-21 op size_t linelen;
126 09486e84 2024-03-21 op ssize_t r;
127 ba97b2d7 2024-03-20 stsp
128 09486e84 2024-03-21 op for (;;) {
129 09486e84 2024-03-21 op endl = memmem(smtp_buf, smtp_buflen, "\r\n", 2);
130 09486e84 2024-03-21 op if (endl != NULL)
131 09486e84 2024-03-21 op break;
132 ba97b2d7 2024-03-20 stsp
133 09486e84 2024-03-21 op if (smtp_buflen == sizeof(smtp_buf))
134 7e03b468 2024-04-19 stsp fatalx("line too long");
135 ba97b2d7 2024-03-20 stsp
136 09486e84 2024-03-21 op error = got_poll_fd(s, POLLIN, smtp_timeout);
137 ba97b2d7 2024-03-20 stsp if (error)
138 7e03b468 2024-04-19 stsp fatalx("poll: %s", error->msg);
139 09486e84 2024-03-21 op
140 09486e84 2024-03-21 op r = read(s, smtp_buf + smtp_buflen,
141 09486e84 2024-03-21 op sizeof(smtp_buf) - smtp_buflen);
142 09486e84 2024-03-21 op if (r == -1)
143 7e03b468 2024-04-19 stsp fatal("read");
144 09486e84 2024-03-21 op if (r == 0)
145 7e03b468 2024-04-19 stsp fatalx("unexpected EOF");
146 09486e84 2024-03-21 op smtp_buflen += r;
147 ba97b2d7 2024-03-20 stsp }
148 ba97b2d7 2024-03-20 stsp
149 09486e84 2024-03-21 op linelen = endl - smtp_buf;
150 09486e84 2024-03-21 op if (linelen < 3)
151 7e03b468 2024-04-19 stsp fatalx("invalid SMTP response");
152 09486e84 2024-03-21 op
153 09486e84 2024-03-21 op if (strncmp(code, smtp_buf, 3) != 0) {
154 09486e84 2024-03-21 op smtp_buf[3] = '\0';
155 7e03b468 2024-04-19 stsp log_warnx("unexpected SMTP message code: %s", smtp_buf);
156 09486e84 2024-03-21 op return -1;
157 09486e84 2024-03-21 op }
158 09486e84 2024-03-21 op
159 09486e84 2024-03-21 op /*
160 09486e84 2024-03-21 op * Normally we would get just one reply, but the regress doesn't
161 09486e84 2024-03-21 op * use a real SMTP server and queues all the replies upfront.
162 09486e84 2024-03-21 op */
163 09486e84 2024-03-21 op linelen += 2;
164 09486e84 2024-03-21 op memmove(smtp_buf, smtp_buf + linelen, smtp_buflen - linelen);
165 09486e84 2024-03-21 op smtp_buflen -= linelen;
166 09486e84 2024-03-21 op
167 09486e84 2024-03-21 op return 0;
168 ba97b2d7 2024-03-20 stsp }
169 ba97b2d7 2024-03-20 stsp
170 ba97b2d7 2024-03-20 stsp static int
171 ba97b2d7 2024-03-20 stsp send_smtp_msg(int s, const char *fmt, ...)
172 ba97b2d7 2024-03-20 stsp {
173 ba97b2d7 2024-03-20 stsp const struct got_error *error;
174 ba97b2d7 2024-03-20 stsp char buf[512];
175 ba97b2d7 2024-03-20 stsp int len;
176 ba97b2d7 2024-03-20 stsp va_list ap;
177 ba97b2d7 2024-03-20 stsp
178 ba97b2d7 2024-03-20 stsp va_start(ap, fmt);
179 ba97b2d7 2024-03-20 stsp len = vsnprintf(buf, sizeof(buf), fmt, ap);
180 ba97b2d7 2024-03-20 stsp va_end(ap);
181 ba97b2d7 2024-03-20 stsp if (len < 0) {
182 7e03b468 2024-04-19 stsp log_warn("vsnprintf");
183 ba97b2d7 2024-03-20 stsp return -1;
184 ba97b2d7 2024-03-20 stsp }
185 ba97b2d7 2024-03-20 stsp if (len >= sizeof(buf)) {
186 7e03b468 2024-04-19 stsp log_warnx("%s: buffer too small for message '%s...'",
187 ba97b2d7 2024-03-20 stsp __func__, buf);
188 ba97b2d7 2024-03-20 stsp return -1;
189 ba97b2d7 2024-03-20 stsp }
190 ba97b2d7 2024-03-20 stsp
191 ba97b2d7 2024-03-20 stsp error = got_poll_write_full(s, buf, len);
192 ba97b2d7 2024-03-20 stsp if (error) {
193 7e03b468 2024-04-19 stsp log_warnx("write: %s", error->msg);
194 ba97b2d7 2024-03-20 stsp return -1;
195 ba97b2d7 2024-03-20 stsp }
196 ba97b2d7 2024-03-20 stsp
197 ba97b2d7 2024-03-20 stsp return 0;
198 ba97b2d7 2024-03-20 stsp }
199 ba97b2d7 2024-03-20 stsp
200 939d3016 2024-04-23 op static const struct got_error *
201 939d3016 2024-04-23 op print_date(int s, char *date, int shortfmt)
202 939d3016 2024-04-23 op {
203 939d3016 2024-04-23 op const struct got_error *error;
204 939d3016 2024-04-23 op struct tm tm;
205 939d3016 2024-04-23 op char *t, datebuf[26];
206 939d3016 2024-04-23 op const char *errstr;
207 939d3016 2024-04-23 op time_t ts;
208 939d3016 2024-04-23 op
209 939d3016 2024-04-23 op date[strcspn(date, " \n")] = '\0';
210 939d3016 2024-04-23 op
211 939d3016 2024-04-23 op ts = strtonum(date, INT64_MIN, INT64_MAX, &errstr);
212 939d3016 2024-04-23 op if (errstr)
213 939d3016 2024-04-23 op return got_error_set_errno(EINVAL, errstr);
214 939d3016 2024-04-23 op if (gmtime_r(&ts, &tm) == NULL)
215 939d3016 2024-04-23 op return got_error_set_errno(EINVAL, "gmtime_r");
216 939d3016 2024-04-23 op
217 939d3016 2024-04-23 op if (!shortfmt) {
218 939d3016 2024-04-23 op t = asctime_r(&tm, datebuf);
219 939d3016 2024-04-23 op if (t == NULL)
220 939d3016 2024-04-23 op return got_error_set_errno(EINVAL, "invalid timestamp");
221 939d3016 2024-04-23 op t[strcspn(t, "\n")] = '\0';
222 939d3016 2024-04-23 op error = got_poll_write_full(s, t, strlen(t));
223 939d3016 2024-04-23 op if (error)
224 939d3016 2024-04-23 op return error;
225 939d3016 2024-04-23 op return got_poll_write_full(s, " UTC\n", 5);
226 939d3016 2024-04-23 op }
227 939d3016 2024-04-23 op
228 283939fb 2024-04-23 op if (strftime(datebuf, sizeof(datebuf), "%F ", &tm) == 0)
229 939d3016 2024-04-23 op return got_error_set_errno(EINVAL, "invalid timestamp");
230 939d3016 2024-04-23 op return got_poll_write_full(s, datebuf, strlen(datebuf));
231 15ff48f3 2024-05-10 stsp }
232 15ff48f3 2024-05-10 stsp
233 15ff48f3 2024-05-10 stsp /* from usr.sbin/smtpd/util.c */
234 15ff48f3 2024-05-10 stsp static int
235 15ff48f3 2024-05-10 stsp bsnprintf(char *str, size_t size, const char *format, ...)
236 15ff48f3 2024-05-10 stsp {
237 15ff48f3 2024-05-10 stsp int ret;
238 15ff48f3 2024-05-10 stsp va_list ap;
239 15ff48f3 2024-05-10 stsp
240 15ff48f3 2024-05-10 stsp va_start(ap, format);
241 15ff48f3 2024-05-10 stsp ret = vsnprintf(str, size, format, ap);
242 15ff48f3 2024-05-10 stsp va_end(ap);
243 15ff48f3 2024-05-10 stsp if (ret < 0 || (size_t)ret >= size)
244 15ff48f3 2024-05-10 stsp return 0;
245 15ff48f3 2024-05-10 stsp
246 15ff48f3 2024-05-10 stsp return 1;
247 15ff48f3 2024-05-10 stsp }
248 15ff48f3 2024-05-10 stsp
249 15ff48f3 2024-05-10 stsp /* based on usr.sbin/smtpd/to.c */
250 15ff48f3 2024-05-10 stsp static const char *
251 15ff48f3 2024-05-10 stsp time_to_text(time_t when, char *buf, size_t buf_size)
252 15ff48f3 2024-05-10 stsp {
253 15ff48f3 2024-05-10 stsp struct tm *lt;
254 15ff48f3 2024-05-10 stsp const char *day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
255 15ff48f3 2024-05-10 stsp const char *month[] = {"Jan","Feb","Mar","Apr","May","Jun",
256 15ff48f3 2024-05-10 stsp "Jul","Aug","Sep","Oct","Nov","Dec"};
257 15ff48f3 2024-05-10 stsp const char *tz;
258 15ff48f3 2024-05-10 stsp long offset;
259 15ff48f3 2024-05-10 stsp
260 15ff48f3 2024-05-10 stsp lt = gmtime(&when);
261 15ff48f3 2024-05-10 stsp if (lt == NULL || when == 0)
262 15ff48f3 2024-05-10 stsp fatalx("time_to_text: localtime");
263 15ff48f3 2024-05-10 stsp
264 15ff48f3 2024-05-10 stsp offset = lt->tm_gmtoff;
265 15ff48f3 2024-05-10 stsp tz = lt->tm_zone;
266 15ff48f3 2024-05-10 stsp
267 15ff48f3 2024-05-10 stsp /* We do not use strftime because it is subject to locale substitution*/
268 15ff48f3 2024-05-10 stsp if (!bsnprintf(buf, buf_size,
269 15ff48f3 2024-05-10 stsp "%s, %d %s %d %02d:%02d:%02d %c%02d%02d (%s)",
270 15ff48f3 2024-05-10 stsp day[lt->tm_wday], lt->tm_mday, month[lt->tm_mon],
271 15ff48f3 2024-05-10 stsp lt->tm_year + 1900,
272 15ff48f3 2024-05-10 stsp lt->tm_hour, lt->tm_min, lt->tm_sec,
273 15ff48f3 2024-05-10 stsp offset >= 0 ? '+' : '-',
274 15ff48f3 2024-05-10 stsp abs((int)offset / 3600),
275 15ff48f3 2024-05-10 stsp abs((int)offset % 3600) / 60,
276 15ff48f3 2024-05-10 stsp tz))
277 15ff48f3 2024-05-10 stsp fatalx("time_to_text: bsnprintf");
278 15ff48f3 2024-05-10 stsp
279 15ff48f3 2024-05-10 stsp return buf;
280 ba97b2d7 2024-03-20 stsp }
281 ba97b2d7 2024-03-20 stsp
282 ba97b2d7 2024-03-20 stsp static void
283 39910b63 2024-03-20 op send_email(int s, const char *myfromaddr, const char *fromaddr,
284 ba97b2d7 2024-03-20 stsp const char *recipient, const char *replytoaddr,
285 39910b63 2024-03-20 op const char *subject)
286 ba97b2d7 2024-03-20 stsp {
287 ba97b2d7 2024-03-20 stsp const struct got_error *error;
288 ba97b2d7 2024-03-20 stsp char *line = NULL;
289 ba97b2d7 2024-03-20 stsp size_t linesize = 0;
290 ba97b2d7 2024-03-20 stsp ssize_t linelen;
291 939d3016 2024-04-23 op int firstline = 1, shortfmt = 0;
292 15ff48f3 2024-05-10 stsp char datebuf[40];
293 15ff48f3 2024-05-10 stsp const char *datestr;
294 ba97b2d7 2024-03-20 stsp
295 15ff48f3 2024-05-10 stsp datestr = time_to_text(time(NULL), datebuf, sizeof(datebuf));
296 ba97b2d7 2024-03-20 stsp
297 ba97b2d7 2024-03-20 stsp if (read_smtp_code(s, "220"))
298 7e03b468 2024-04-19 stsp fatalx("unexpected SMTP greeting received");
299 ba97b2d7 2024-03-20 stsp
300 ba97b2d7 2024-03-20 stsp if (send_smtp_msg(s, "HELO localhost\r\n"))
301 7e03b468 2024-04-19 stsp fatalx("could not send HELO");
302 ba97b2d7 2024-03-20 stsp if (read_smtp_code(s, "250"))
303 7e03b468 2024-04-19 stsp fatalx("unexpected SMTP response received");
304 ba97b2d7 2024-03-20 stsp
305 ba97b2d7 2024-03-20 stsp if (send_smtp_msg(s, "MAIL FROM:<%s>\r\n", myfromaddr))
306 7e03b468 2024-04-19 stsp fatalx("could not send MAIL FROM");
307 ba97b2d7 2024-03-20 stsp if (read_smtp_code(s, "250"))
308 7e03b468 2024-04-19 stsp fatalx("unexpected SMTP response received");
309 ba97b2d7 2024-03-20 stsp
310 ba97b2d7 2024-03-20 stsp if (send_smtp_msg(s, "RCPT TO:<%s>\r\n", recipient))
311 7e03b468 2024-04-19 stsp fatalx("could not send MAIL FROM");
312 ba97b2d7 2024-03-20 stsp if (read_smtp_code(s, "250"))
313 7e03b468 2024-04-19 stsp fatalx("unexpected SMTP response received");
314 ba97b2d7 2024-03-20 stsp
315 ba97b2d7 2024-03-20 stsp if (send_smtp_msg(s, "DATA\r\n"))
316 7e03b468 2024-04-19 stsp fatalx("could not send MAIL FROM");
317 ba97b2d7 2024-03-20 stsp if (read_smtp_code(s, "354"))
318 7e03b468 2024-04-19 stsp fatalx("unexpected SMTP response received");
319 ba97b2d7 2024-03-20 stsp
320 ba97b2d7 2024-03-20 stsp if (send_smtp_msg(s, "From: %s\r\n", fromaddr))
321 7e03b468 2024-04-19 stsp fatalx("could not send From header");
322 ba97b2d7 2024-03-20 stsp if (send_smtp_msg(s, "To: %s\r\n", recipient))
323 7e03b468 2024-04-19 stsp fatalx("could not send To header");
324 ba97b2d7 2024-03-20 stsp if (replytoaddr) {
325 ba97b2d7 2024-03-20 stsp if (send_smtp_msg(s, "Reply-To: %s\r\n", replytoaddr))
326 7e03b468 2024-04-19 stsp fatalx("could not send Reply-To header");
327 ba97b2d7 2024-03-20 stsp }
328 15ff48f3 2024-05-10 stsp if (send_smtp_msg(s, "Date: %s\r\n", datestr))
329 7e03b468 2024-04-19 stsp fatalx("could not send Date header");
330 ba97b2d7 2024-03-20 stsp
331 ba97b2d7 2024-03-20 stsp if (send_smtp_msg(s, "Subject: %s\r\n", subject))
332 7e03b468 2024-04-19 stsp fatalx("could not send Subject header");
333 ba97b2d7 2024-03-20 stsp
334 ba97b2d7 2024-03-20 stsp if (send_smtp_msg(s, "\r\n"))
335 7e03b468 2024-04-19 stsp fatalx("could not send body delimiter");
336 ba97b2d7 2024-03-20 stsp
337 ba97b2d7 2024-03-20 stsp while ((linelen = getline(&line, &linesize, stdin)) != -1) {
338 939d3016 2024-04-23 op if (firstline && isdigit((unsigned char)line[0]))
339 939d3016 2024-04-23 op shortfmt = 1;
340 939d3016 2024-04-23 op firstline = 0;
341 939d3016 2024-04-23 op
342 ba97b2d7 2024-03-20 stsp if (line[0] == '.') { /* dot stuffing */
343 ba97b2d7 2024-03-20 stsp error = got_poll_write_full(s, ".", 1);
344 ba97b2d7 2024-03-20 stsp if (error)
345 7e03b468 2024-04-19 stsp fatalx("write: %s", error->msg);
346 ba97b2d7 2024-03-20 stsp }
347 939d3016 2024-04-23 op
348 939d3016 2024-04-23 op if (shortfmt) {
349 939d3016 2024-04-23 op char *t;
350 939d3016 2024-04-23 op t = strchr(line, ' ');
351 939d3016 2024-04-23 op if (t != NULL) {
352 939d3016 2024-04-23 op *t++ = '\0';
353 939d3016 2024-04-23 op error = print_date(s, line, shortfmt);
354 939d3016 2024-04-23 op if (error)
355 939d3016 2024-04-23 op fatalx("write: %s", error->msg);
356 939d3016 2024-04-23 op error = got_poll_write_full(s, t, strlen(t));
357 939d3016 2024-04-23 op continue;
358 939d3016 2024-04-23 op }
359 939d3016 2024-04-23 op }
360 939d3016 2024-04-23 op
361 939d3016 2024-04-23 op if (!shortfmt && !strncmp(line, "date: ", 6)) {
362 939d3016 2024-04-23 op error = got_poll_write_full(s, line, 6);
363 939d3016 2024-04-23 op if (error)
364 939d3016 2024-04-23 op fatalx("write: %s", error->msg);
365 939d3016 2024-04-23 op error = print_date(s, line + 6, shortfmt);
366 939d3016 2024-04-23 op if (error)
367 939d3016 2024-04-23 op fatalx("write: %s", error->msg);
368 939d3016 2024-04-23 op continue;
369 939d3016 2024-04-23 op }
370 939d3016 2024-04-23 op
371 ba97b2d7 2024-03-20 stsp error = got_poll_write_full(s, line, linelen);
372 ba97b2d7 2024-03-20 stsp if (error)
373 7e03b468 2024-04-19 stsp fatalx("write: %s", error->msg);
374 ba97b2d7 2024-03-20 stsp }
375 ba97b2d7 2024-03-20 stsp
376 ba97b2d7 2024-03-20 stsp if (send_smtp_msg(s, "\r\n.\r\n"))
377 7e03b468 2024-04-19 stsp fatalx("could not send data terminator");
378 ba97b2d7 2024-03-20 stsp if (read_smtp_code(s, "250"))
379 7e03b468 2024-04-19 stsp fatalx("unexpected SMTP response received");
380 ba97b2d7 2024-03-20 stsp
381 ba97b2d7 2024-03-20 stsp if (send_smtp_msg(s, "QUIT\r\n"))
382 7e03b468 2024-04-19 stsp fatalx("could not send QUIT");
383 ba97b2d7 2024-03-20 stsp
384 ba97b2d7 2024-03-20 stsp if (read_smtp_code(s, "221"))
385 7e03b468 2024-04-19 stsp fatalx("unexpected SMTP response received");
386 ba97b2d7 2024-03-20 stsp
387 ba97b2d7 2024-03-20 stsp close(s);
388 ba97b2d7 2024-03-20 stsp free(line);
389 ba97b2d7 2024-03-20 stsp }
390 ba97b2d7 2024-03-20 stsp
391 ba97b2d7 2024-03-20 stsp int
392 ba97b2d7 2024-03-20 stsp main(int argc, char *argv[])
393 ba97b2d7 2024-03-20 stsp {
394 ba97b2d7 2024-03-20 stsp char *default_fromaddr = NULL;
395 ba97b2d7 2024-03-20 stsp const char *fromaddr = NULL, *recipient = NULL, *replytoaddr = NULL;
396 ba97b2d7 2024-03-20 stsp const char *subject = "gotd notification";
397 ba97b2d7 2024-03-20 stsp const char *hostname = "127.0.0.1";
398 ba97b2d7 2024-03-20 stsp const char *port = "25";
399 ba97b2d7 2024-03-20 stsp const char *errstr;
400 ba97b2d7 2024-03-20 stsp char *timeoutstr;
401 39910b63 2024-03-20 op int ch, s;
402 ba97b2d7 2024-03-20 stsp
403 7e03b468 2024-04-19 stsp log_init(0, LOG_DAEMON);
404 ba97b2d7 2024-03-20 stsp while ((ch = getopt(argc, argv, "f:r:s:h:p:")) != -1) {
405 ba97b2d7 2024-03-20 stsp switch (ch) {
406 ba97b2d7 2024-03-20 stsp case 'h':
407 ba97b2d7 2024-03-20 stsp hostname = optarg;
408 ba97b2d7 2024-03-20 stsp break;
409 ba97b2d7 2024-03-20 stsp case 'f':
410 ba97b2d7 2024-03-20 stsp fromaddr = optarg;
411 ba97b2d7 2024-03-20 stsp break;
412 ba97b2d7 2024-03-20 stsp case 'p':
413 ba97b2d7 2024-03-20 stsp port = optarg;
414 ba97b2d7 2024-03-20 stsp break;
415 ba97b2d7 2024-03-20 stsp case 'r':
416 ba97b2d7 2024-03-20 stsp replytoaddr = optarg;
417 ba97b2d7 2024-03-20 stsp break;
418 ba97b2d7 2024-03-20 stsp case 's':
419 ba97b2d7 2024-03-20 stsp subject = optarg;
420 ba97b2d7 2024-03-20 stsp break;
421 ba97b2d7 2024-03-20 stsp default:
422 ba97b2d7 2024-03-20 stsp usage();
423 ba97b2d7 2024-03-20 stsp /* NOTREACHED */
424 ba97b2d7 2024-03-20 stsp break;
425 ba97b2d7 2024-03-20 stsp }
426 ba97b2d7 2024-03-20 stsp }
427 ba97b2d7 2024-03-20 stsp
428 ba97b2d7 2024-03-20 stsp argc -= optind;
429 ba97b2d7 2024-03-20 stsp argv += optind;
430 ba97b2d7 2024-03-20 stsp
431 ba97b2d7 2024-03-20 stsp if (argc != 1)
432 ba97b2d7 2024-03-20 stsp usage();
433 ba97b2d7 2024-03-20 stsp
434 ba97b2d7 2024-03-20 stsp /* used by the regression test suite */
435 ba97b2d7 2024-03-20 stsp timeoutstr = getenv("GOT_NOTIFY_EMAIL_TIMEOUT");
436 ba97b2d7 2024-03-20 stsp if (timeoutstr) {
437 8bffa129 2024-04-09 op smtp_timeout = strtonum(timeoutstr, 0, 600, &errstr);
438 ba97b2d7 2024-03-20 stsp if (errstr != NULL)
439 7e03b468 2024-04-19 stsp fatalx("timeout in seconds is %s: %s",
440 ba97b2d7 2024-03-20 stsp errstr, timeoutstr);
441 ba97b2d7 2024-03-20 stsp }
442 ba97b2d7 2024-03-20 stsp
443 ba97b2d7 2024-03-20 stsp #ifndef PROFILE
444 ba97b2d7 2024-03-20 stsp if (pledge("stdio dns inet getpw", NULL) == -1)
445 ba97b2d7 2024-03-20 stsp err(1, "pledge");
446 ba97b2d7 2024-03-20 stsp #endif
447 ba97b2d7 2024-03-20 stsp default_fromaddr = set_default_fromaddr();
448 ba97b2d7 2024-03-20 stsp
449 ba97b2d7 2024-03-20 stsp #ifndef PROFILE
450 ba97b2d7 2024-03-20 stsp if (pledge("stdio dns inet", NULL) == -1)
451 ba97b2d7 2024-03-20 stsp err(1, "pledge");
452 ba97b2d7 2024-03-20 stsp #endif
453 ba97b2d7 2024-03-20 stsp
454 ba97b2d7 2024-03-20 stsp recipient = argv[0];
455 ba97b2d7 2024-03-20 stsp if (fromaddr == NULL)
456 ba97b2d7 2024-03-20 stsp fromaddr = default_fromaddr;
457 ba97b2d7 2024-03-20 stsp
458 39910b63 2024-03-20 op s = dial(hostname, port);
459 ba97b2d7 2024-03-20 stsp
460 39910b63 2024-03-20 op #ifndef PROFILE
461 39910b63 2024-03-20 op if (pledge("stdio", NULL) == -1)
462 39910b63 2024-03-20 op err(1, "pledge");
463 39910b63 2024-03-20 op #endif
464 39910b63 2024-03-20 op
465 39910b63 2024-03-20 op send_email(s, default_fromaddr, fromaddr, recipient, replytoaddr,
466 39910b63 2024-03-20 op subject);
467 39910b63 2024-03-20 op
468 ba97b2d7 2024-03-20 stsp free(default_fromaddr);
469 ba97b2d7 2024-03-20 stsp return 0;
470 ba97b2d7 2024-03-20 stsp }