1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #ifndef WIN32
6 #include <unistd.h>
7 #else
8 #include <winsock2.h>
9 #endif
10
11 #include "config.h"
12 #include "sockio.h"
13 #include "variables.h"
14 #include "core.h"
15 #include "hooks.h"
16 #include "compat.h"
17 #include "mystring.h"
18
19 #define CAPS_MIME 0x01
20 #define CAPS_DSN 0x02
21
22
23
24 const char *cfg_user_notify = "DELAY,FAILURE";
25
26 LSOCKET my_socket = -1;
27 int servercaps;
28 int receipients;
29
30 int notify_type;
31
try_connect_EHLO(const char * hostname)32 int try_connect_EHLO(const char *hostname)
33 {
34 char dbg_hostname[BIG_BUF];
35 char dbg_version[BIG_BUF];
36 char buf[BIG_BUF];
37 char testme[BIG_BUF];
38 int read_data = 0;
39
40 if(my_socket != -1)
41 sock_close(my_socket);
42
43 log_printf(9, "Attempting to connect to %s\n", get_string("mailserver"));
44
45 if (sock_open(get_string("mailserver"), get_number("smtp-socket"), &my_socket))
46 return 0;
47
48 while(sock_readline(my_socket, buf, sizeof(buf)) != 0) {
49 int val;
50 char ch;
51
52 read_data = 1;
53 log_printf(9,"Server sent: %s\n", buf);
54
55 sscanf(buf, "%d%c%s %s", &val, &ch, &dbg_hostname[0], &dbg_version[0]);
56 if(val != 220) {
57 return 0;
58 }
59 if(ch != '-') {
60 log_printf(9, "Connected: %s (%s)\n", dbg_hostname, dbg_version);
61 break;
62 }
63 }
64 if(!read_data)
65 return 0;
66
67 sock_printf(my_socket, "EHLO %s\r\n", hostname);
68 if(sock_readline(my_socket, buf, sizeof(buf)) == 0)
69 return 0;
70
71 /* Check for valid response */
72 if(!sscanf(buf, "250-%s", testme))
73 return 0;
74
75 /* Okay, we have a valid ESMTP server. Read the server caps */
76 while(sock_readline(my_socket, buf, sizeof(buf)) != 0) {
77 int val;
78 char ch;
79
80 log_printf(9,"Server sent: %s\n", buf);
81
82 sscanf(buf, "%d%c%s", &val, &ch, testme);
83 if(val != 250) {
84 return 0;
85 }
86 if(ch != '-')
87 break;
88 else {
89 if (!strcmp(testme,"DSN")) {
90 servercaps &= CAPS_DSN;
91 log_printf(9, "Server caps: server supports DSN\n");
92 } else if (!strcmp(testme,"8BITMIME")) {
93 servercaps &= CAPS_MIME;
94 log_printf(9, "Server caps: server supports MIME\n");
95 }
96 }
97 }
98 return 1;
99 }
100
try_connect_HELO(const char * hostname)101 int try_connect_HELO(const char *hostname)
102 {
103 char dbg_hostname[BIG_BUF];
104 char dbg_version[BIG_BUF];
105 char buf[BIG_BUF];
106 char testme[BIG_BUF];
107
108 /* Try the HELO protocal */
109 if(my_socket != -1)
110 sock_close(my_socket);
111
112 if (sock_open(get_string("mailserver"), get_number("smtp-socket"), &my_socket))
113 return 0;
114
115 if (sock_readline(my_socket, buf, sizeof(buf)) == 0)
116 return 0;
117
118 if(!sscanf(buf,"220 %s %s", &dbg_hostname[0], &dbg_version[0]))
119 return 0;
120 log_printf(9, "Connected: %s (%s)\n", dbg_hostname, dbg_version);
121
122 sock_printf(my_socket, "HELO %s\r\n", hostname);
123 if(sock_readline(my_socket, buf, sizeof(buf)) == 0)
124 return 0;
125 if(!sscanf(buf, "250 %s", testme))
126 return 0;
127 return 1;
128 }
129
smtp_start(int notify)130 int smtp_start(int notify)
131 {
132 char hostname[BIG_BUF];
133
134 clean_var("smtp-last-error", VAR_TEMP);
135 notify_type = notify;
136
137 my_socket = -1;
138 servercaps = 0;
139 receipients = 0;
140
141 build_hostname(hostname,sizeof(hostname));
142
143 if(!try_connect_EHLO(hostname)) {
144 if(!try_connect_HELO(hostname)) {
145 if(my_socket != -1)
146 sock_close(my_socket);
147 my_socket = -1;
148 set_var("smtp-last-error", "Error connecting to SMTP server.", VAR_TEMP);
149 return 0;
150 }
151 }
152 return 1;
153 }
154
smtp_from(const char * fromaddy)155 int smtp_from(const char *fromaddy)
156 {
157 int result, final;
158 char buf[BIG_BUF];
159 int maxretries;
160
161 maxretries = get_number("max-rcpt-tries");
162 if (!maxretries) maxretries = 5;
163
164 clean_var("smtp-last-error", VAR_TEMP);
165 final = sock_printf(my_socket,"MAIL FROM:<%s>", fromaddy);
166
167 log_printf(9, "Mail from set to %s\n", fromaddy);
168
169 if (servercaps & CAPS_DSN) {
170 result = sock_printf(my_socket," RET=%s",
171 (notify_type ? "FULL" : "HDRS"));
172 final += result;
173 }
174
175 final += sock_printf(my_socket, "\r\n");
176 if (!final) {
177 set_var("smtp-last-error", "Error setting SMTP from address.", VAR_TEMP);
178 return 0;
179 }
180
181 if (!get_bool("smtp-blind-blast")) {
182 memset(buf, 0, sizeof(buf));
183 result = 0;
184 if (get_bool("smtp-retry-forever")) {
185
186 while (!result) {
187 result = sock_readline(my_socket, buf, sizeof(buf));
188 }
189 } else {
190 int tries = 0;
191
192 log_printf(9, "sock_readline maxretries=%d\n", maxretries);
193
194 while(!result && (tries < maxretries)) {
195 result = sock_readline(my_socket, buf, sizeof(buf));
196 tries++;
197 }
198 }
199
200 if (result) {
201 log_printf(9, "Response: %s\n", buf);
202
203 if (strncmp(buf,"250",3)) {
204 result = 0;
205 log_printf(9, "Sender '%s' rejected!\n", fromaddy);
206 set_var("smtp-last-error", buf, VAR_TEMP);
207 } else {
208 log_printf(9, "Sender '%s' accepted.\n", fromaddy);
209 }
210 } else {
211 log_printf(9,"IO Err: Read timeout on MAIL FROM.");
212 set_var("smtp-last-error", "Error setting SMTP from address.",
213 VAR_TEMP);
214 }
215 return (result != 0);
216 }
217 else return 1;
218 }
219
smtp_to(const char * toaddy)220 int smtp_to(const char *toaddy)
221 {
222 char buf[BIG_BUF];
223 int result, final;
224 int maxretries;
225
226 result = 0;
227 maxretries = get_number("max-rcpt-tries");
228 if (!maxretries) maxretries = 5;
229
230 clean_var("smtp-last-error", VAR_TEMP);
231 final = sock_printf(my_socket, "RCPT TO:<%s>", toaddy);
232
233 log_printf(9, "Mail sent to %s\n", toaddy);
234
235 if (servercaps & CAPS_DSN) {
236 result = sock_printf(my_socket, " NOTIFY=%s", cfg_user_notify);
237 final += result;
238
239 result = sock_printf(my_socket, " ORCPT=%s", toaddy);
240 final += result;
241 }
242
243 final += sock_printf(my_socket, "\r\n");
244
245 if (!final) {
246 set_var("smtp-last-error","Can't send to SMTP server (RCPT TO)", VAR_TEMP);
247 return 0;
248 }
249
250 if (!get_bool("smtp-blind-blast")) {
251 int tries;
252 int tryforever = 0;
253
254 tries = 0; result = 0;
255
256 while (!result && (tryforever ? 1 : tries < maxretries)) {
257 result = sock_readline(my_socket, buf, sizeof(buf));
258 }
259
260 if (result > 0) {
261 log_printf(9, "Response: %s\n", buf);
262
263 if (strncmp(buf,"25",2)) {
264 result = 0;
265 log_printf(9, "Receipient '%s' rejected!\n", toaddy);
266 set_var("smtp-last-error", buf, VAR_TEMP);
267 set_var("bounce-error", buf, VAR_TEMP);
268 set_var("bounce-address", toaddy, VAR_TEMP);
269 (void)do_hooks("LOCAL-BOUNCE");
270 } else {
271 receipients++;
272 log_printf(9, "Receipient '%s' accepted. (%d total)\n",
273 toaddy, receipients);
274 }
275 }
276 }
277
278 if (get_bool("sendmail-sleep")) {
279 int sleeplen;
280
281 sleeplen = get_seconds("sendmail-sleep-length");
282 do_sleep(sleeplen);
283 }
284
285 return (result != 0);
286 }
287
smtp_body_start()288 int smtp_body_start()
289 {
290 char buf[BIG_BUF];
291 int tryforever;
292 int maxretries;
293
294 maxretries = get_number("max-rcpt-tries");
295 if (!maxretries) maxretries = 5;
296
297 tryforever = get_bool("smtp-retry-forever");
298
299 clean_var("smtp-last-error", VAR_TEMP);
300 log_printf(9, "Data transmit starting.\n");
301 if (!sock_printf(my_socket,"DATA\r\n")) {
302 set_var("smtp-last-error", "Unable to write to SMTP server (DATA).", VAR_TEMP);
303 return 0;
304 }
305
306 if (!get_bool("smtp-blind-blast")) {
307 int result, tries;
308
309 tries = 0; result = 0;
310
311 while(!result && (tryforever ? 1 : tries < maxretries)) {
312 result = sock_readline(my_socket, buf, sizeof(buf));
313 tries++;
314 }
315
316 if (!result) {
317 set_var("smtp-last-error", "No response from SMTP server (DATA).", VAR_TEMP);
318 return 0;
319 }
320
321 log_printf(9, "Response: %s\n", buf);
322
323 if (strncmp(buf,"354",3)) {
324 log_printf(9, "Unable to start message body!\n");
325 set_var("smtp-last-error", buf, VAR_TEMP);
326 return 0;
327 }
328 }
329
330 return 1;
331 }
332
smtp_body_822bis(const char * src,char * dest,size_t size)333 void smtp_body_822bis(const char *src, char *dest, size_t size)
334 {
335 const char *ptr1;
336 char *ptr2, *end;
337 int lastcr;
338
339 lastcr = 0;
340
341 ptr1 = src;
342 ptr2 = dest;
343 end = dest + size - 2;
344
345 while(*ptr1 && ptr2 < end) {
346 if ((*ptr1 == '\n') && (!lastcr)) {
347 *ptr2++ = '\r';
348 } else if (*ptr1 == '\r') {
349 lastcr = 1;
350 } else if (*ptr1 == '.') {
351 /* Handle escaping of single periods on a line */
352 if((ptr2 == dest) || (*(ptr2-1) == '\n')) {
353 *ptr2++ = '.';
354 }
355 }
356
357 if (lastcr && (*ptr1 != '\r')) {
358 lastcr = 0;
359 }
360
361 *ptr2++ = *ptr1++;
362 }
363
364 *ptr2 = 0;
365 }
366
smtp_body_text(const char * line)367 int smtp_body_text(const char *line)
368 {
369 char buffer[HUGE_BUF];
370
371 smtp_body_822bis(line,&buffer[0], sizeof(buffer));
372
373 clean_var("smtp-last-error", VAR_TEMP);
374 if (!sock_printf(my_socket,"%s",buffer)) {
375 set_var("smtp-last-error", "Unable to write to SMTP server (message body).", VAR_TEMP);
376 return 0;
377 }
378
379 return 1;
380 }
381
smtp_body_line(const char * line)382 int smtp_body_line(const char *line)
383 {
384 char buffer[HUGE_BUF];
385 char buffer2[HUGE_BUF];
386
387 buffer_printf(buffer2, sizeof(buffer2) - 1, "%s\r\n", line);
388
389 smtp_body_822bis(buffer2,&buffer[0], sizeof(buffer));
390
391 clean_var("smtp-last-error", VAR_TEMP);
392 if (!sock_printf(my_socket,"%s",buffer)) {
393 set_var("smtp-last-error", "Unable to write to SMTP server (message body).", VAR_TEMP);
394 return 0;
395 }
396
397 return 1;
398 }
399
smtp_body_end()400 int smtp_body_end()
401 {
402 char buf[BIG_BUF], buf2[BIG_BUF];
403 int tryforever;
404 int maxretries;
405
406 maxretries = get_number("max-rcpt-tries");
407 if (!maxretries) maxretries = 5;
408
409 tryforever = get_bool("smtp-retry-forever");
410
411 clean_var("smtp-last-error", VAR_TEMP);
412 log_printf(9, "Data transmit ending.\n");
413 if (!sock_printf(my_socket,"\r\n.\r\n")) {
414 set_var("smtp-last-error", "Unable to write to SMTP server (message end).", VAR_TEMP);
415 return 0;
416 }
417
418 if (!get_bool("smtp-blind-blast")) {
419 int tries, result;
420
421 tries = 0; result = 0;
422
423 while(!result && (tryforever ? 1 : tries < maxretries)) {
424 result = sock_readline(my_socket, buf, sizeof(buf));
425 tries++;
426 }
427
428 if (!result) {
429 set_var("smtp-last-error", "No response from SMTP server. (message end)", VAR_TEMP);
430 return 0;
431 }
432
433 log_printf(9, "Response: %s\n", buf);
434
435 if (!strncmp(&buf[0],"250",3)) {
436 if (sscanf(buf, "250 %s Message accepted for delivery.", &buf2[0]) == 1)
437 log_printf(9, "Message accepted and queued as %s.\n", buf2);
438 } else {
439 log_printf(9, "Message rejected.\n");
440 set_var("smtp-last-error", buf, VAR_TEMP);
441 return 0;
442 }
443 }
444
445 return 1;
446 }
447
smtp_end()448 int smtp_end()
449 {
450 clean_var("smtp-last-error", VAR_TEMP);
451 log_printf(9, "Disconnecting.\n");
452 if (!sock_printf(my_socket, "QUIT\r\n")) {
453 set_var("smtp-last-error", "Unable to write to SMTP server (QUIT).", VAR_TEMP);
454 return 0;
455 }
456
457 sock_close(my_socket);
458 my_socket = -1;
459 log_printf(9, "Disconnected.\n");
460
461 return 1;
462 }
463