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