mixmaster

mixmaster 3.0 patched for libressl
git clone git://parazyd.org/mixmaster.git
Log | Files | Refs | README

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