aboutsummaryrefslogtreecommitdiff
path: root/mfd/savclt.c
diff options
context:
space:
mode:
Diffstat (limited to 'mfd/savclt.c')
-rw-r--r--mfd/savclt.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/mfd/savclt.c b/mfd/savclt.c
new file mode 100644
index 00000000..447f6857
--- /dev/null
+++ b/mfd/savclt.c
@@ -0,0 +1,275 @@
1/* This file is part of Mailfromd.
2 Copyright (C) 2005, 2006, 2007, 2008, 2009 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#define MF_SOURCE_NAME MF_SOURCE_SAVCLT
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29#include <netdb.h>
30
31#include "mailfromd.h"
32
33struct sockaddr *callout_server_sa;
34socklen_t callout_server_sa_len;
35time_t savclt_timeout = 3;
36
37/* Ideally, I'd want to use smtp_io functions here. But they are
38 based on Mailutils' TCP streams, which so far do not support
39 UNIX sockets. So, for the time being, I use the straightforward
40 I/O approach. */
41int
42savclt_getline(int fd, char **pbuf, size_t *pbufsize)
43{
44 char *buf = *pbuf;
45 size_t bufsize = *pbufsize;
46 int off = 0;
47#define DELTA 128
48 time_t start = time(NULL);
49
50 if (buf == NULL) {
51 bufsize = DELTA;
52 buf = xmalloc(bufsize);
53 }
54
55 do {
56 struct timeval tv;
57 int rc, flags;
58 time_t diff = time(NULL) - start;
59
60 if (diff > savclt_timeout) {
61 errno = ETIMEDOUT;
62 return -1;
63 }
64
65 tv.tv_sec = savclt_timeout - diff;
66 tv.tv_usec = 0;
67 flags = MU_STREAM_READY_RD;
68 rc = mu_fd_wait(fd, &flags, &tv);
69 if (rc) {
70 debug1(1, "mu_fd_wait: %s", mu_strerror(rc));
71 errno = rc;
72 return -1;
73 }
74 if (!(flags & MU_STREAM_READY_RD)) {
75 errno = ETIMEDOUT;
76 return -1;
77 }
78
79 if (off + 1 == bufsize) {
80 bufsize += DELTA;
81 buf = xrealloc(buf, bufsize);
82 }
83
84 rc = read(fd, buf + off, 1);
85 if (rc == -1)
86 return -1;
87 if (rc == 0)
88 break;
89 off++;
90 } while (buf[off - 1] != '\n');
91
92 if (off + 1 == bufsize) {
93 bufsize++;
94 buf = xrealloc(buf, bufsize);
95 }
96 buf[off] = 0;
97 *pbuf = buf;
98 *pbufsize = bufsize;
99 transcript("savclt", "RECV:", buf);
100 return off;
101}
102
103static int
104send_line(int fd, const char *txt, size_t len)
105{
106 time_t start = time(NULL);
107
108 while (len) {
109 struct timeval tv;
110 int rc, flags;
111 time_t diff = time(NULL) - start;
112
113 if (diff > savclt_timeout) {
114 errno = ETIMEDOUT;
115 return -1;
116 }
117
118 tv.tv_sec = savclt_timeout - diff;
119 tv.tv_usec = 0;
120 flags = MU_STREAM_READY_WR;
121 rc = mu_fd_wait(fd, &flags, &tv);
122 if (rc) {
123 debug1(1, "mu_fd_wait: %s", mu_strerror(rc));
124 errno = rc;
125 return -1;
126 }
127 if (!(flags & MU_STREAM_READY_WR)) {
128 errno = ETIMEDOUT;
129 return -1;
130 }
131
132 rc = write(fd, txt, len);
133 if (rc <= 0) {
134 if (errno == EAGAIN)
135 continue;
136 return -1;
137 }
138 txt += rc;
139 len -= rc;
140 }
141 return 0;
142}
143
144int
145savclt_wrtline(int fd, char **pbuf, size_t *pbufsize,
146 const char *fmt, ...)
147{
148 int rc;
149 va_list ap;
150
151 va_start(ap, fmt);
152 rc = mu_vasnprintf(pbuf, pbufsize, fmt, ap);
153 va_end(ap);
154 if (rc == 0) {
155 transcript("savclt", "SEND:", *pbuf);
156 rc = send_line(fd, *pbuf, strlen(*pbuf));
157 }
158 return rc;
159}
160
161
162static int
163connect_callout_server()
164{
165 int fd;
166 int flags;
167 int rc;
168
169 if (!callout_server_sa)
170 return -1;
171 fd = socket(callout_server_sa->sa_family, SOCK_STREAM, 0);
172 if (fd == -1) {
173 mu_error("schedule_callout: socket: %s",
174 mu_strerror(errno));
175 return -1;
176 }
177
178 flags = fcntl(fd, F_GETFL);
179 flags |= O_NONBLOCK;
180 fcntl(fd, F_SETFL, flags);
181
182 rc = connect(fd, callout_server_sa, callout_server_sa_len);
183 if (rc == -1) {
184 if (errno == EINPROGRESS) {
185 struct timeval tv;
186
187 tv.tv_sec = savclt_timeout;
188 tv.tv_usec = 0;
189 flags = MU_STREAM_READY_WR;
190 rc = mu_fd_wait(fd, &flags, &tv);
191 if (rc) {
192 debug1(1, "mu_fd_wait: %s", mu_strerror(rc));
193 close(fd);
194 return -1;
195 }
196
197 if (flags & MU_STREAM_READY_WR) {
198 socklen_t len = sizeof(flags);
199 rc = getsockopt(fd, SOL_SOCKET, SO_ERROR,
200 &flags, &len);
201 if (rc) {
202 mu_error("getsockopt: %s",
203 mu_strerror(rc));
204 close(fd);
205 return -1;
206 }
207 } else
208 flags = ETIMEDOUT;
209 } else
210 flags = errno;
211
212 if (flags) {
213 mu_error("connect: %s", mu_strerror(flags));
214 close(fd);
215 return -1;
216 }
217 }
218
219 if (rc) {
220 close(fd);
221 return -1;
222 }
223
224 return fd;
225}
226
227enum callout_server_state {
228 css_init,
229 css_send,
230 css_quit,
231};
232
233void
234schedule_callout(const char *email, const char *ehlo, const char *mailfrom,
235 const char *client_addr)
236{
237 size_t size = 0;
238 char *buf = NULL;
239 int fd = connect_callout_server();
240 enum callout_server_state state = css_init;
</