tmail.c - mixmaster - mixmaster 3.0 patched for libressl
HTML git clone git://parazyd.org/mixmaster.git
DIR Log
DIR Files
DIR Refs
DIR README
---
tmail.c (20880B)
---
1 /* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
2
3 Mixmaster may be redistributed and modified under certain conditions.
4 This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
5 ANY KIND, either express or implied. See the file COPYRIGHT for
6 details.
7
8 Socket-based mail transport services
9 $Id: mail.c 934 2006-06-24 13:40:39Z rabbi $ */
10
11
12 #include "mix3.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #if defined(UNIX) && defined(USE_SOCK)
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <netdb.h>
24 #endif /* defined(UNIX) && defined(USE_SOCK) */
25
26 #include <fcntl.h>
27 #include <time.h>
28 #include <sys/stat.h>
29 #include <errno.h>
30
31
32 int sendinfofile(char *name, char *logname, BUFFER *address, BUFFER *header)
33 {
34 FILE *f = NULL, *log = NULL;
35 BUFFER *msg, *addr;
36 char line[LINELEN];
37 int ret = -1;
38
39 if (bufeq(address, ANONNAME))
40 return (0); /* don't reply to our own anon messages */
41 f = mix_openfile(name, "r");
42 if (f == NULL)
43 return (-1);
44
45 addr = buf_new();
46 rfc822_addr(address, addr);
47 if (addr->length == 0)
48 buf_set(addr, address), buf_nl(addr);
49
50 if (logname != NULL) {
51 if ((log = mix_openfile(logname, "r+")) != NULL) {
52 /* log recipients to prevent mail loop */
53 while (fgets(line, sizeof(line), log) != NULL)
54 if (strieq(line, addr->data))
55 goto end;
56 } else if ((log = mix_openfile(logname, "w")) == NULL) {
57 errlog(ERRORMSG, "Can't create %s.\n", logname);
58 ret = -1;
59 goto end;
60 }
61 fprintf(log, "%s", addr->data);
62 }
63 msg = buf_new();
64 if (header)
65 buf_cat(msg, header), buf_nl(msg);
66 while (fgets(line, sizeof(line), f) != NULL) {
67 if (streq(line, "DESTINATION-BLOCK\n"))
68 buf_appendf(msg, "destination-block %b", addr);
69 else
70 buf_appends(msg, line);
71 }
72 ret = sendmail(msg, REMAILERNAME, address);
73 buf_free(msg);
74 end:
75 if (f)
76 fclose(f);
77 if (log)
78 fclose(log);
79 buf_free(addr);
80 return (ret);
81 }
82
83 int smtpsend(BUFFER *head, BUFFER *message, char *from);
84
85
86 int sendmail_loop(BUFFER *message, char *from, BUFFER *address)
87 {
88 BUFFER *msg;
89 int err;
90
91 msg = buf_new();
92 buf_appendf(msg, "X-Loop: %s\n", REMAILERADDR);
93 buf_cat(msg, message);
94 err = sendmail(msg, from, address);
95 buf_free(msg);
96
97 return(err);
98 }
99
100 /* Returns true if more than one of the recipients in the
101 * rcpt buffer is a remailer
102 */
103 int has_more_than_one_remailer(BUFFER *rcpts)
104 {
105 BUFFER *newlinelist;
106 BUFFER *line;
107 int remailers = 0;
108 REMAILER type1[MAXREM];
109 REMAILER type2[MAXREM];
110 int num1;
111 int num2;
112 int i;
113
114 newlinelist = buf_new();
115 line = buf_new();
116
117 num1 = t1_rlist(type1, NULL);
118 num2 = mix2_rlist(type2, NULL);
119
120 rfc822_addr(rcpts, newlinelist);
121
122 while (buf_getline(newlinelist, line) != -1) {
123 int found = 0;
124 printf("%s\n", line->data);
125
126 for (i = 0; i < num2; i++)
127 if (strcmp(type2[i].addr, line->data) == 0) {
128 found = 1;
129 break;
130 }
131 if (!found)
132 for (i = 0; i < num1; i++)
133 if (strcmp(type1[i].addr, line->data) == 0) {
134 found = 1;
135 break;
136 }
137 if (found)
138 remailers++;
139 }
140 printf("found %d\n", remailers);
141
142 buf_free(newlinelist);
143 buf_free(line);
144
145 return(remailers > 1);
146 }
147
148 int sendmail(BUFFER *message, char *from, BUFFER *address)
149 {
150 /* returns: 0: ok 1: problem, try again -1: failed */
151
152 BUFFER *head, *block, *rcpt;
153 FILE *f;
154 int err = -1;
155 int rcpt_cnt;
156
157 head = buf_new();
158 rcpt = buf_new();
159
160 block = readdestblk( );
161 if ( !block ) block = buf_new( );
162
163 if (address != NULL &&
164 (address->length == 0 || doblock(address, block, 1) == -1))
165 goto end;
166
167 if (from != NULL) {
168 buf_setf(head, "From: %s", from);
169 hdr_encode(head, 255);
170 buf_nl(head);
171 }
172 if (address != NULL)
173 buf_appendf(head, "To: %b\n", address);
174
175 if (PRECEDENCE[0])
176 buf_appendf(head, "Precedence: %s\n", PRECEDENCE);
177
178 buf_rewind(message);
179
180 /* search recipient addresses */
181 if (address == NULL) {
182 BUFFER *field, *content;
183 field = buf_new();
184 content = buf_new();
185
186 rcpt_cnt = 0;
187 while (buf_getheader(message, field, content) == 0) {
188 if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) {
189 int thislinercpts = 1;
190 char *tmp = content->data;
191 while ((tmp = strchr(tmp+1, ',')))
192 thislinercpts ++;
193 rcpt_cnt += thislinercpts;
194
195 if ( rcpt->data[0] )
196 buf_appends(rcpt, ", ");
197 buf_cat(rcpt, content);
198 }
199 }
200 buf_free(field);
201 buf_free(content);
202 } else if (address->data[0]) {
203 char *tmp = address->data;
204 rcpt_cnt = 1;
205 while ((tmp = strchr(tmp+1, ',')))
206 rcpt_cnt ++;
207
208 buf_set(rcpt, address);
209 } else
210 rcpt_cnt = 0;
211
212 buf_rewind(message);
213
214 if ( ! rcpt_cnt ) {
215 errlog(NOTICE, "No recipients found.\n");
216 err = 0;
217 } else if ( rcpt_cnt > MAXRECIPIENTS ) {
218 errlog(NOTICE, "Too many recipients. Dropping message.\n");
219 err = 0;
220 } else if ( rcpt_cnt > 1 && has_more_than_one_remailer(rcpt) ) {
221 errlog(NOTICE, "Message is destined to more than one remailer. Dropping.\n");
222 err = 0;
223 } else if ( REMAIL && strcmp(REMAILERADDR, rcpt->data) == 0) {
224 buf_cat(head, message);
225 errlog(LOG, "Message loops back to us; storing in pool rather than sending it.\n");
226 err = pool_add(head, "inf");
227 } else if (SMTPRELAY[0])
228 err = smtpsend(head, message, from);
229 else if (strieq(SENDMAIL, "outfile")) {
230 char path[PATHMAX];
231 FILE *f = NULL;
232 #ifdef SHORTNAMES
233 int i;
234 for (i = 0; i < 10000; i++) {
235 snprintf(path, PATHMAX, "%s%cout%i.txt", POOLDIR, DIRSEP, i);
236 f = fopen(path, "r");
237 if (f)
238 fclose(f);
239 else
240 break;
241 }
242 f = fopen(path, "w");
243 #else /* end of SHORTNAMES */
244 static unsigned long namecounter = 0;
245 struct stat statbuf;
246 int count;
247 char hostname[64];
248
249 hostname[0] = '\0';
250 gethostname(hostname, 63);
251 hostname[63] = '\0';
252
253 /* Step 2: Stat the file. Wait for ENOENT as a response. */
254 for (count = 0;; count++) {
255 snprintf(path, PATHMAX, "%s%cout.%lu.%u_%lu.%s,S=%lu.txt",
256 POOLDIR, DIRSEP, time(NULL), getpid(), namecounter++, hostname, head->length + message->length);
257
258 if (stat(path, &statbuf) == 0)
259 errno = EEXIST;
260 else if (errno == ENOENT) { /* create the file (at least try) */
261 f = fopen(path, "w");
262 if (f != NULL)
263 break; /* we managed to open the file */
264 }
265 if (count > 5)
266 break; /* Too many retries - give up */
267 sleep(2); /* sleep and retry */
268 }
269 #endif /* else not SHORTNAMES */
270 if (f != NULL) {
271 err = buf_write(head, f);
272 err = buf_write(message, f);
273 fclose(f);
274 } else
275 errlog(ERRORMSG, "Can't create %s!\n", path);
276 } else {
277 if (SENDANONMAIL[0] != '\0' && (from == NULL || streq(from, ANONNAME)))
278 f = openpipe(SENDANONMAIL);
279 else
280 f = openpipe(SENDMAIL);
281 if (f != NULL) {
282 err = buf_write(head, f);
283 err = buf_write(message, f);
284 closepipe(f);
285 }
286 }
287 if (err != 0) {
288 errlog(ERRORMSG, "Unable to execute sendmail. Check path!\n");
289 err = 1; /* error while sending, retry later */
290 }
291
292 end:
293 buf_free(block);
294 buf_free(head);
295 buf_free(rcpt);
296 return (err);
297 }
298
299 /* socket communication **********************************************/
300
301 #ifdef USE_SOCK
302 #ifdef WIN32
303 WSADATA w;
304
305 int sock_init()
306 {
307 if (WSAStartup(MAKEWORD(2, 0), &w) != 0) {
308 errlog(ERRORMSG, "Unable to initialize WINSOCK.\n");
309 return 0;
310 }
311 return 1;
312 }
313
314 void sock_exit(void)
315 {
316 WSACleanup();
317 }
318 #endif /* WIN32 */
319
320 SOCKET opensocket(char *hostname, int port)
321 {
322 struct hostent *hp;
323 struct sockaddr_in server;
324 SOCKET s;
325
326 if ((hp = gethostbyname(hostname)) == NULL)
327 return (INVALID_SOCKET);
328
329 memset((char *) &server, 0, sizeof(server));
330 server.sin_family = AF_INET;
331 server.sin_addr.s_addr = *(unsigned long *) hp->h_addr;
332 server.sin_port = htons((unsigned short) port);
333
334 s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
335 if (s != INVALID_SOCKET)
336 if (connect(s, (struct sockaddr *) &server, sizeof(server)) < 0) {
337 closesocket(s);
338 return (INVALID_SOCKET);
339 }
340 return (s);
341 }
342
343 #ifndef WIN32
344 int closesocket(SOCKET s)
345 {
346 return (close(s));
347 }
348 #endif /* ifndef WIN32 */
349
350 int sock_getline(SOCKET s, BUFFER *line)
351 {
352 char c;
353 int ok;
354
355 buf_clear(line);
356 while ((ok = recv(s, &c, 1, 0)) > 0) {
357 if (c == '\n')
358 break;
359 if (c != '\r')
360 buf_appendc(line, c);
361 }
362 if (ok <= 0)
363 return (-1);
364 if (line->length == 0)
365 return (1);
366 return (0);
367 }
368
369 int sock_cat(SOCKET s, BUFFER *b)
370 {
371 int p = 0, n;
372
373 do {
374 n = send(s, b->data, b->length, 0);
375 if (n < 0)
376 return (-1);
377 p += n;
378 } while (p < b->length);
379 return (0);
380 }
381 #else /* end of USE_SOCK */
382 SOCKET opensocket(char *hostname, int port)
383 {
384 return (INVALID_SOCKET);
385 }
386
387 int closesocket(SOCKET s)
388 {
389 return (INVALID_SOCKET);
390 }
391
392 int sock_getline(SOCKET s, BUFFER *line)
393 {
394 return (-1);
395 }
396
397 int sock_cat(SOCKET s, BUFFER *b)
398 {
399 return (-1);
400 }
401 #endif /* else not USE_SOCK */
402
403 /* send messages by SMTP ************************************************/
404
405 static int sock_getsmtp(SOCKET s, BUFFER *response)
406 {
407 int ret;
408 BUFFER *line;
409 line = buf_new();
410
411 buf_clear(response);
412 do {
413 ret = sock_getline(s, line);
414 buf_cat(response, line);
415 } while (line->length >= 4 && line->data[3] == '-');
416 buf_free(line);
417 return (ret);
418 }
419
420 SOCKET smtp_open(void)
421 {
422 int s = INVALID_SOCKET;
423 int esmtp = 0;
424 BUFFER *line;
425
426 #ifdef USE_SOCK
427 if (SMTPRELAY[0] != '\0')
428 s = opensocket(SMTPRELAY, 25);
429 if (s != INVALID_SOCKET) {
430 line = buf_new();
431 sock_getsmtp(s, line);
432 if (bufifind(line, "ESMTP"))
433 esmtp = 1;
434 if (line->data[0] != '2') {
435 errlog(ERRORMSG, "SMTP relay not ready. %b\n", line);
436 closesocket(s);
437 s = INVALID_SOCKET;
438 } else {
439 errlog(DEBUGINFO, "Opening SMTP connection.\n");
440 if (esmtp)
441 buf_sets(line, "EHLO ");
442 else
443 buf_sets(line, "HELO ");
444 if (HELONAME[0])
445 buf_appends(line, HELONAME);
446 else if (strchr(ENVFROM, '@'))
447 buf_appends(line, strchr(ENVFROM, '@') + 1);
448 else {
449 struct sockaddr_in sa;
450 int len = sizeof(sa);
451 struct hostent *hp;
452
453 if (getsockname(s, (struct sockaddr *) &sa, &len) == 0 &&
454 (hp = gethostbyaddr((char *) &sa.sin_addr, sizeof(sa.sin_addr),
455 AF_INET)) != NULL)
456 buf_appends(line, (char *) hp->h_name);
457 else if (strchr(REMAILERADDR, '@'))
458 buf_appends(line, strchr(REMAILERADDR, '@') + 1);
459 else
460 buf_appends(line, SHORTNAME);
461 }
462 buf_chop(line);
463 buf_appends(line, "\r\n");
464 sock_cat(s, line);
465 sock_getsmtp(s, line);
466 if (line->data[0] != '2') {
467 errlog(ERRORMSG, "SMTP relay refuses HELO: %b\n", line);
468 closesocket(s);
469 s = INVALID_SOCKET;
470 } else if (SMTPUSERNAME[0] && esmtp && bufifind(line, "AUTH") && bufifind(line, "LOGIN")) {
471 buf_sets(line, "AUTH LOGIN\r\n");
472 sock_cat(s, line);
473 sock_getsmtp(s, line);
474 if (!bufleft(line, "334")) {
475 errlog(ERRORMSG, "SMTP AUTH fails: %b\n", line);
476 goto err;
477 }
478 buf_sets(line, SMTPUSERNAME);
479 encode(line, 0);
480 buf_appends(line, "\r\n");
481 sock_cat(s, line);
482 sock_getsmtp(s, line);
483 if (!bufleft(line, "334")) {
484 errlog(ERRORMSG, "SMTP username rejected: %b\n", line);
485 goto err;
486 }
487 buf_sets(line, SMTPPASSWORD);
488 encode(line, 0);
489 buf_appends(line, "\r\n");
490 sock_cat(s, line);
491 sock_getsmtp(s, line);
492 if (!bufleft(line, "235"))
493 errlog(ERRORMSG, "SMTP authentication failed: %b\n", line);
494 }
495 }
496 err:
497 buf_free(line);
498 }
499 #endif /* USE_SOCK */
500 return (s);
501 }
502
503 int smtp_close(SOCKET s)
504 {
505 BUFFER *line;
506 int ret = -1;
507
508 #ifdef USE_SOCK
509 line = buf_new();
510 buf_sets(line, "QUIT\r\n");
511 sock_cat(s, line);
512 if (sock_getsmtp(s, line) == 0 && line->data[0] == '2') {
513 errlog(DEBUGINFO, "Closing SMTP connection.\n");
514 ret = 0;
515 } else
516 errlog(WARNING, "SMTP quit failed: %b\n", line);
517 closesocket(s);
518 buf_free(line);
519 #endif /* USE_SOCK */
520 return (ret);
521 }
522
523 int smtp_send(SOCKET relay, BUFFER *head, BUFFER *message, char *from)
524 {
525 BUFFER *rcpt, *line, *field, *content;
526 int ret = -1;
527
528 #ifdef USE_SOCK
529 line = buf_new();
530 field = buf_new();
531 content = buf_new();
532 rcpt = buf_new();
533
534 while (buf_getheader(head, field, content) == 0)
535 if (bufieq(field, "to"))
536 #ifdef BROKEN_MTA
537 if (!bufifind(rcpt, content->data))
538 /* Do not add the same recipient twice.
539 Needed for brain-dead MTAs. */
540 #endif /* BROKEN_MTA */
541 rfc822_addr(content, rcpt);
542 buf_rewind(head);
543
544 while (buf_isheader(message) && buf_getheader(message, field, content) == 0) {
545 if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) {
546 #ifdef BROKEN_MTA
547 if (!bufifind(rcpt, content->data))
548 /* Do not add the same recipient twice.
549 Needed for brain-dead MTAs. */
550 #endif /* BROKEN_MTA */
551 rfc822_addr(content, rcpt);
552 }
553 if (!bufieq(field, "bcc"))
554 buf_appendheader(head, field, content);
555 }
556 buf_nl(head);
557
558 buf_clear(content);
559 if (from) {
560 buf_sets(line, from);
561 rfc822_addr(line, content);
562 buf_chop(content);
563 }
564 if (bufieq(content, REMAILERADDR) || bufieq(content, ANONADDR))
565 buf_clear(content);
566 if (content->length == 0)
567 buf_sets(content, ENVFROM[0] ? ENVFROM : ANONADDR);
568
569 buf_setf(line, "MAIL FROM:<%b>\r\n", content);
570 sock_cat(relay, line);
571 sock_getsmtp(relay, line);
572 if (!line->data[0] == '2') {
573 errlog(ERRORMSG, "SMTP relay does not accept mail: %b\n", line);
574 goto end;
575 }
576 while (buf_getline(rcpt, content) == 0) {
577 buf_setf(line, "RCPT TO:<%b>\r\n", content);
578 sock_cat(relay, line);
579 sock_getsmtp(relay, line);
580 if (bufleft(line, "421")) {
581 errlog(ERRORMSG, "SMTP relay error: %b\n", line);
582 goto end;
583 }
584 if (bufleft(line, "530")) {
585 errlog(ERRORMSG, "SMTP authentication required: %b\n", line);
586 goto end;
587 }
588 }
589
590 buf_sets(line, "DATA\r\n");
591 sock_cat(relay, line);
592 sock_getsmtp(relay, line);
593 if (!bufleft(line, "354")) {
594 errlog(WARNING, "SMTP relay does not accept message: %b\n", line);
595 goto end;
596 }
597 while (buf_getline(head, line) >= 0) {
598 buf_appends(line, "\r\n");
599 if (bufleft(line, ".")) {
600 buf_setf(content, ".%b", line);
601 buf_move(line, content);
602 }
603 sock_cat(relay, line);
604 }
605 while (buf_getline(message, line) >= 0) {
606 buf_appends(line, "\r\n");
607 if (bufleft(line, ".")) {
608 buf_setf(content, ".%b", line);
609 buf_move(line, content);
610 }
611 sock_cat(relay, line);
612 }
613 buf_sets(line, ".\r\n");
614 sock_cat(relay, line);
615 sock_getsmtp(relay, line);
616 if (bufleft(line, "2"))
617 ret = 0;
618 else
619 errlog(WARNING, "SMTP relay will not send message: %b\n", line);
620 end:
621 buf_free(line);
622 buf_free(field);
623 buf_free(content);
624 buf_free(rcpt);
625 #endif /* USE_SOCK */
626 return (ret);
627 }
628
629 static SOCKET sendmail_state = INVALID_SOCKET;
630
631 void sendmail_begin(void)
632 {
633 /* begin mail sending session */
634 if (sendmail_state == INVALID_SOCKET)
635 sendmail_state = smtp_open();
636 }
637 void sendmail_end(void)
638 {
639 /* end mail sending session */
640 if (sendmail_state != INVALID_SOCKET) {
641 smtp_close(sendmail_state);
642 sendmail_state = INVALID_SOCKET;
643 }
644 }
645
646 int smtpsend(BUFFER *head, BUFFER *message, char *from)
647 {
648 SOCKET s;
649 int ret = -1;
650
651 if (sendmail_state != INVALID_SOCKET)
652 ret = smtp_send(sendmail_state, head, message, from);
653 else {
654 s = smtp_open();
655 if (s != INVALID_SOCKET) {
656 ret = smtp_send(s, head, message, from);
657 smtp_close(s);
658 }
659 }
660 return (ret);
661 }
662
663 /* retrieve mail with POP3 **********************************************/
664 #ifdef USE_SOCK
665 int pop3_close(SOCKET s);
666
667 #define POP3_ANY 0
668 #define POP3_APOP 1
669 #define POP3_PASS 2
670
671 SOCKET pop3_open(char *user, char *host, char *pass, int auth)
672 {
673 SOCKET server = INVALID_SOCKET;
674 BUFFER *line;
675 int authenticated = 0;
676 char md[33];
677 int c;
678
679 line = buf_new();
680 server = opensocket(host, 110);
681 if (server == INVALID_SOCKET)
682 errlog(NOTICE, "Can't connect to POP3 server %s.\n", host);
683 else {
684 sock_getline(server, line);
685 if (!bufleft(line, "+")) {
686 errlog(WARNING, "No POP3 service at %s.\n", host);
687 closesocket(server);
688 server = INVALID_SOCKET;
689 }
690 }
691 if (server != INVALID_SOCKET) {
692 errlog(DEBUGINFO, "Opening POP3 connection to %s.\n", host);
693 do
694 c = buf_getc(line);
695 while (c != '<' && c != -1);
696 while (c != '>' && c != -1) {
697 buf_appendc(line, c);
698 c = buf_getc(line);
699 }
700 if (c == '>' && (auth == POP3_ANY || auth == POP3_APOP)) {
701 buf_appendc(line, c);
702 buf_appends(line, pass);
703 digest_md5(line, line);
704 id_encode(line->data, md);
705 buf_setf(line, "APOP %s %s\r\n", user, md);
706 sock_cat(server, line);
707 sock_getline(server, line);
708 if (bufleft(line, "+"))
709 authenticated = 1;
710 else {
711 errlog(auth == POP3_APOP ? ERRORMSG : NOTICE,
712 "POP3 APOP auth at %s failed: %b\n", host, line);
713 buf_sets(line, "QUIT\r\n");
714 sock_cat(server, line);
715 closesocket(server);
716 server = pop3_open(user, host, pass, POP3_PASS);
717 goto end;
718 }
719 }
720 if (!authenticated) {
721 buf_setf(line, "USER %s\r\n", user);
722 sock_cat(server, line);
723 sock_getline(server, line);
724 if (!bufleft(line, "+"))
725 errlog(ERRORMSG, "POP3 USER command at %s failed: %b\n", host, line);
726 else {
727 buf_setf(line, "PASS %s\r\n", pass);
728 sock_cat(server, line);
729 sock_getline(server, line);
730 if (bufleft(line, "+"))
731 authenticated = 1;
732 else
733 errlog(ERRORMSG, "POP3 auth at %s failed: %b\n", host, line);
734 }
735 }
736 if (!authenticated) {
737 pop3_close(server);
738 closesocket(server);
739 server = INVALID_SOCKET;
740 }
741 }
742 end:
743 buf_free(line);
744 return (server);
745 }
746
747 int pop3_close(SOCKET s)
748 {
749 BUFFER *line;
750 int ret = -1;
751
752 line = buf_new();
753 buf_sets(line, "QUIT\r\n");
754 sock_cat(s, line);
755 sock_getline(s, line);
756 if (bufleft(line, "+")) {
757 ret = 0;
758 errlog(DEBUGINFO, "Closing POP3 connection.\n");
759 } else
760 errlog(ERRORMSG, "POP3 QUIT failed:\n", line->data);
761 buf_free(line);
762 return (ret);
763 }
764
765 int pop3_stat(SOCKET s)
766 {
767 BUFFER *line;
768 int val = -1;
769
770 line = buf_new();
771 buf_sets(line, "STAT\r\n");
772 sock_cat(s, line);
773 sock_getline(s, line);
774 if (bufleft(line, "+"))
775 sscanf(line->data, "+%*s %d", &val);
776 buf_free(line);
777 return (val);
778 }
779
780 int pop3_list(SOCKET s, int n)
781 {
782 BUFFER *line;
783 int val = -1;
784
785 line = buf_new();
786 buf_setf(line, "LIST %d\r\n", n);
787 sock_cat(s, line);
788 sock_getline(s, line);
789 if (bufleft(line, "+"))
790 sscanf(line->data, "+%*s %d", &val);
791 buf_free(line);
792 return (val);
793 }
794
795 int pop3_dele(SOCKET s, int n)
796 {
797 BUFFER *line;
798 int ret = 0;
799
800 line = buf_new();
801 buf_setf(line, "DELE %d\r\n", n);
802 sock_cat(s, line);
803 sock_getline(s, line);
804 if (!bufleft(line, "+"))
805 ret = -1;
806 buf_free(line);
807 return (ret);
808 }
809
810 int pop3_retr(SOCKET s, int n, BUFFER *msg)
811 {
812 BUFFER *line;
813 int ret = -1;
814
815 line = buf_new();
816 buf_clear(msg);
817 buf_setf(line, "RETR %d\r\n", n);
818 sock_cat(s, line);
819 sock_getline(s, line);
820 if (bufleft(line, "+")) {
821 for (;;) {
822 if (sock_getline(s, line) == -1)
823 break;
824 if (bufeq(line, ".")) {
825 ret = 0;
826 break;
827 } else if (bufleft(line, ".")) {
828 buf_append(msg, line->data + 1, line->length - 1);
829 } else
830 buf_cat(msg, line);
831 buf_nl(msg);
832 }
833 }
834 buf_free(line);
835 return (ret);
836 }
837
838 void pop3get(void)
839 {
840 FILE *f;
841 char cfg[LINELEN], user[LINELEN], host[LINELEN], pass[LINELEN], auth[5];
842 SOCKET server;
843 BUFFER *line, *msg;
844 int i = 0, num = 0;
845
846 line = buf_new();
847 msg = buf_new();
848 f = mix_openfile(POP3CONF, "r");
849 if (f != NULL)
850 while (fgets(cfg, sizeof(cfg), f) != NULL) {
851 if (cfg[0] == '#')
852 continue;
853 if (strchr(cfg, '@'))
854 strchr(cfg, '@')[0] = ' ';
855 if (sscanf(cfg, "%127s %127s %127s %4s", user, host, pass, auth) < 3)
856 continue;
857 i = POP3_ANY;
858 if (strileft(auth, "apop"))
859 i = POP3_APOP;
860 if (strileft(auth, "pass"))
861 i = POP3_PASS;
862 server = pop3_open(user, host, pass, i);
863 if (server != INVALID_SOCKET) {
864 num = pop3_stat(server);
865 if (num < 0)
866 errlog(WARNING, "POP3 protocol error at %s.\n", host);
867 else if (num == 0)
868 errlog(DEBUGINFO, "No mail at %s.\n", host);
869 else
870 for (i = 1; i <= num; i++) {
871 if (POP3SIZELIMIT > 0 &&
872 pop3_list(server, i) > POP3SIZELIMIT * 1024) {
873 errlog(WARNING, "Over size message on %s.", host);
874 if (POP3DEL == 1)
875 pop3_dele(server, i);
876 } else {
877 if (pop3_retr(server, i, msg) == 0 &&
878 pool_add(msg, "inf") == 0)
879 pop3_dele(server, i);
880 else {
881 errlog(WARNING, "POP3 error while getting mail from %s.",
882 host);
883 closesocket(server);
884 goto end;
885 }
886 }
887 }
888 pop3_close(server);
889 closesocket(server);
890 }
891 }
892 end:
893 if (f != NULL)
894 fclose(f);
895 buf_free(line);
896 buf_free(msg);
897 }
898 #endif /* USE_SOCK */