Ssmtp presumes a temporary lack of data on STDIN means it can send the message off.

# (seq 1 10; sleep 1; seq 11 20; sleep 1; seq 21 30) | /usr/sbin/sendmail 
[EMAIL PROTECTED]
1
2
3
4
5
6
7
8
9
10
# echo no good
no good

A delay in stdin, such as e.g. the popularity-contest script output, causes ssmtp to send the message incomplete, ignoring the rest of the data.

Either the fcntl is reverted and ssmtp uses blocking pipes like John Eikenberry proposed above (patch 1) - this is a quick fix;

... or the code is fixed by applying Aidas Kasparas' code which is nicer to non-blocking pipes (patch 2). I added a timeout and corrected a typo somewhere else in the code.

Please, someone test these patches, choose the best solution, apply it, and close this over 3 months old bug... hopefully in time for the next update.


Thanks,

  Wouter Van Hemel
--- ssmtp-2.61/ssmtp.c  2005-09-04 18:05:20.000000000 +0200
+++ ssmtp-2.61-wvh/ssmtp.c      2005-09-04 20:01:14.000000000 +0200
@@ -1530,7 +1530,7 @@
 
        /*prevent blocking on pipes, we really shouldnt be using
          stdio functions like fgets in the first place */
-       fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK);
+       /* fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK); */
 
        while(fgets(buf, sizeof(buf), stdin)) {
                /* Trim off \n, double leading .'s */
--- ssmtp-2.61/ssmtp.c  2005-09-04 18:05:20.000000000 +0200
+++ ssmtp-2.61-wvh/ssmtp.c      2005-09-05 01:32:55.000000000 +0200
@@ -1319,6 +1319,7 @@
        struct passwd *pw;
        int i, sock;
        uid_t uid;
+       int timeout = 0;
 
        outbytes = 0;
 
@@ -1532,7 +1533,15 @@
          stdio functions like fgets in the first place */
        fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK);
 
-       while(fgets(buf, sizeof(buf), stdin)) {
+       /* don't hang forever when reading from stdin */
+       while(!feof(stdin) && timeout < MEDWAIT) {
+               if (!fgets(buf, sizeof(buf), stdin)) {
+                       /* if nothing was received, then no transmission
+                       * over smtp should be done */
+                       sleep(1);
+                       timeout++;
+                       continue;
+               }
                /* Trim off \n, double leading .'s */
                standardise(buf);
 
@@ -1542,6 +1551,11 @@
        }
        /* End of body */
 
+       if (timeout >= MEDWAIT) {
+               log_event(LOG_ERR, "killed: timeout on stdin while reading body 
-- message saved to dead.letter.");
+               die("Timeout on stdin while reading body");
+       }
+
        outbytes += smtp_write(sock, ".");
        (void)alarm((unsigned) MAXWAIT);
 
@@ -1549,7 +1563,7 @@
                die("%s", buf);
        }
 
-       /* Close conection */
+       /* Close connection */
        (void)signal(SIGALRM, SIG_IGN);
 
        outbytes += smtp_write(sock, "QUIT");

Reply via email to