mail.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 */