Here is another patch to test.

It is against the 20030101 release qmail-reply.c and includes the patches
sent to this list.

The db file is now written to a temp file. So the file is not truncated or
corrupted but it is possible that a sender recieves more than one mail.
This solution is the most robust and fails not horribly over nfs.
 
-- 
:wq Claudio
Index: qmail-reply.c
===================================================================
RCS file: /home/cvs-qmail-ldap/CVS/qmail-ldap/qmail-reply.c,v
retrieving revision 1.18
diff -u -r1.18 qmail-reply.c
--- qmail-reply.c       6 Jan 2003 14:22:46 -0000       1.18
+++ qmail-reply.c       22 Jan 2003 13:57:58 -0000
@@ -30,7 +30,6 @@
 void temp_rewind() { strerr_die2x(111, FATAL, "Unable to rewind message."); }
 void temp_fork() { strerr_die2sys(111, FATAL, "Unable to fork: "); }
 
-
 void usage(void)
 {
        strerr_die1x(100,
@@ -211,7 +210,6 @@
 }
 
 stralloc rs = {0}; /* recent sender */
-int rsmatch = 0;
 datetime_sec timeout;
 #ifndef REPLY_TIMEOUT
 #define REPLY_TIMEOUT 1209600 /* 2 weeks */
@@ -235,16 +233,16 @@
        }
 
        slen = rs.len; s = rs.s;
-       for (i = 0; i < slen; i += str_len(s+i)) {
+       for (i = 0; i < slen; i += str_len(s+i) + 1) {
                if (case_diffb(buf, len, s+i) == 0) {
                        /* match found, look at timeval */
-                       rsmatch = i; i += len;
+                       i += len;
                        if (s[i++] != ':')
                                strerr_die2x(100, FATAL,
                                    "db file .qmail-reply.db corrupted");
                        last = get_stamp(s+i);
-                       if (last + timeout > now()) return 1;
-                       else return 0;
+                       if (last + timeout < now()) return 0;
+                       else return 1;
                }
        }
 
@@ -252,10 +250,10 @@
 }
 
 char rsoutbuf[SUBSTDIO_OUTSIZE];
-char fntmptph[32 + FMT_ULONG * 2];
+char fntmptph[32 + FMT_ULONG];
 
-void tryunlinktmp() { unlink(fntmptph); }
-void sigalrm()
+void tryunlinktmp(void) { unlink(fntmptph); }
+void sigalrm(void)
 {
        tryunlinktmp();
        strerr_die2x(111, FATAL, "timeout while writing db file");
@@ -263,35 +261,44 @@
 
 void recent_update(char *buf, int len)
 {
-       char *s, *t;
        struct stat st;
-       unsigned long pid, time;
-       int fd, loop, size, slen, i;
        substdio ss;
+       char *s, *t;
+       datetime_sec time, last;
+       unsigned long pid;
+       unsigned int slen, i, n;
+       int fd, loop;
 
        s = rs.s; slen = rs.len;
-       size = slen + len + 10;
-       for(; size > MAX_SIZE; ) {
+       n = slen + len + 10;
+       for(; n > MAX_SIZE; ) {
                i = str_len(s) + 1;
-               size -= i;
+               n -= i;
                slen -= i;
                s += i;
        }
 
        pid = getpid();
+       time = now();
+       t = fntmptph;
+       t += fmt_str(t, ".qmail-reply.tmp.");
+       t += fmt_ulong(t, pid);
+       *t++ = 0;
+       
        for (loop = 0;;++loop) {
-               time = now();
-               t = fntmptph;
-               t += fmt_str(t, ".qmail-reply.tmp.");
-               t += fmt_ulong(t, time); *t++ = '.';
-               t += fmt_ulong(t, pid);
-               *t++ = 0;
-               if (stat(fntmptph, &st) == -1) if (errno == error_noent) break;
+               if (stat(fntmptph, &st) == -1) if (errno == error_noent)
+                       break;
                /* really should never get to this point */
-               if (loop == 2) _exit(1);
+               if (st.st_mtime + 900 < time) {
+                       /* stale tmp file */
+                       tryunlinktmp();
+               }
+               if (loop == 2)
+                       strerr_die2x(111, FATAL,
+                           "could not open tmp file.");
                sleep(2);
        }
-       
+
        sig_alarmcatch(sigalrm);
        alarm(600); /* give up after 10 min */
        fd = open_excl(fntmptph);
@@ -301,7 +308,11 @@
        substdio_fdbuf(&ss, write, fd, rsoutbuf, sizeof(rsoutbuf));
 
        for (i = 0; i < slen; i += str_len(s+i) + 1) {
-               if (rs.s+rsmatch == s+i) continue;
+               n = byte_chr(s+i, slen, ':');
+               if (n++ != slen) {
+                       last = get_stamp(s + i + n);
+                       if (last + timeout < time) continue;
+               } /* else file corrupted */
                if (substdio_puts(&ss, s+i) == -1) goto fail;
                if (substdio_put(&ss, "\n", 1) == -1) goto fail;
        }
@@ -314,7 +325,6 @@
        if (close(fd) == -1) goto fail; /* NFS dorks */
 
        if (unlink(".qmail-reply.db") == -1 && errno != error_noent) goto fail;
-       
        if (link(fntmptph, ".qmail-reply.db") == -1) goto fail;
        /* if it was error_exist, almost certainly successful; i hate NFS */
 
@@ -322,6 +332,7 @@
        return;
 
 fail:
+       strerr_warn2(WARN, "db update failed: ", &strerr_sys);
        tryunlinktmp(); /* failed somewhere, giving up */
        return;
 }
@@ -489,8 +500,11 @@
        do {
                for(i = 0;;) {
                        i += byte_chr(s + i, len - i, '\n');
-                       if (++i >= len)
-                               strerr_die2x(100, FATAL, "parser error");
+                       if (++i >= len) {
+                               /* last line ends without a newline. */
+                               i = len;
+                               break;
+                       }
                        if (s[i] == ' ' || s[i] == '\t')
                                continue;
                        break;
@@ -581,7 +595,9 @@
 next:
                s += i;
                len -= i;
-       } while (header == 1);
+               if (len == 0 && header != 0)
+                       strerr_die2sys(100, FATAL, "parser error");
+       } while (header != 0);
 
        if (resubject.s == (char *)0) {
                if (!stralloc_copys(&resubject, "[Auto-Reply] "))
@@ -618,10 +634,14 @@
                qmail_puts(&qqt, REPLY_CTE);
        /* '\n' already written */
        /* X-Mailer: qmail-reply */
-       qmail_puts(&qqt, "X-Mailer: qmail-reply\n\n");
+       qmail_puts(&qqt, "X-Mailer: qmail-reply\n");
+       /* end of header marker */
+       qmail_puts(&qqt, "\n");
 
        /* body */
        qmail_put(&qqt, s, len);
+       /* add a empty newline */
+       qmail_puts(&qqt, "\n");
        qmail_from(&qqt, from.s);
        qmail_to(&qqt, to.s);
        qqx = qmail_close(&qqt);

Reply via email to