Hello,
the appended patch implements a different kind of "once" files. As of
exim 3.16, once files are DB files and grow as needed. While this
makes sure every sender only gets one answer, the file size may become
a problem and that can certainly be abused.
My patch adds the option "once_file_size". Like formail(1) caches,
a cyclic buffer is used. It differs from formail by using \n instead
of \0 as separator. The file won't grow by more than the length of a
single mail address beyond the given limit.
This patch is experimental and mostly untested. If you like it, then
give it a try. Note that its screws up the indentation a bit, but
otherwise the patch would not show which code is actually new.
Michael
----------------------------------------------------------------------
--- src/transports/autoreply.c.orig Thu Sep 14 12:31:37 2000
+++ src/transports/autoreply.c Tue Sep 19 14:37:03 2000
@@ -50,6 +50,8 @@
(void *)(offsetof(autoreply_transport_options_block, mode)) },
{ "once", opt_stringptr,
(void *)(offsetof(autoreply_transport_options_block, oncelog)) },
+ { "once_file_size", opt_int,
+ (void *)(offsetof(autoreply_transport_options_block, once_file_size)) },
{ "once_repeat", opt_time,
(void *)(offsetof(autoreply_transport_options_block, once_repeat)) },
{ "reply_to", opt_stringptr,
@@ -86,6 +88,7 @@
NULL, /* file */
NULL, /* logfile */
NULL, /* oncelog */
+ 0, /* once_file_size */
0600, /* mode */
0, /* once_repeat */
FALSE, /* file_expand */
@@ -188,8 +191,11 @@
BOOL file_expand, return_message;
char *from, *reply_to, *to, *cc, *bcc, *subject, *headers, *text, *file;
char *logfile, *oncelog;
+off_t once_file_size;
header_line *h;
EXIM_DB *dbm_file = NULL;
+FILE *idcache = NULL;
+off_t insoffs;
time_t now = time(NULL);
time_t once_repeat;
FILE *f;
@@ -223,6 +229,7 @@
file = addr->reply->file;
logfile = addr->reply->logfile;
oncelog = addr->reply->oncelog;
+ once_file_size = ob->once_file_size;
once_repeat = addr->reply->once_repeat;
file_expand = addr->reply->file_expand;
return_message = addr->reply->return_message;
@@ -241,6 +248,7 @@
file = ob->file;
logfile = ob->logfile;
oncelog = ob->oncelog;
+ once_file_size = ob->once_file_size;
once_repeat = ob->once_repeat;
file_expand = ob->file_expand;
return_message = ob->return_message;
@@ -289,6 +297,65 @@
if (oncelog != NULL && to != NULL)
{
+ if (once_file_size) /* circular buffer recipient cache */
+ {
+ int fd;
+
+ if ((fd=open(oncelog,O_CREAT|O_RDWR,ob->mode))==-1)
+ {
+ addr->transport_return = DEFER;
+ addr->message = string_sprintf("Failed to open file %s when sending "
+ "message from %s transport: %s", oncelog, tblock->name,
+ strerror(errno));
+ return;
+ }
+ insoffs = once_file_size;
+ if (!(idcache=fdopen(fd,"r+")))
+ {
+ addr->transport_return = DEFER;
+ addr->message = string_sprintf("Failed to fdopen file %s when sending "
+ "message from %s transport: %s", oncelog, tblock->name,
+ strerror(errno));
+ close(fd);
+ return;
+ }
+ do
+ {
+ int j,ch;
+ const char * p;
+
+ /* inspired by formail.c:elimdups() of <srb@???> */
+ for (p=to; j=fgetc(idcache),(j==*p && *p); ++p);
+ if (j=='\n')
+ {
+ if (*p=='\0')
+ {
+ char *ptr = log_buffer;
+ sprintf(ptr, "%s\n previously sent to %.200s\n", tod_stamp(tod_log),
+ to);
+ while(*ptr) ptr++;
+ write(log_fd, log_buffer, ptr - log_buffer);
+ fclose(idcache);
+ return;
+ }
+ if (p==to && insoffs==once_file_size)
+ {
+ insoffs=ftell(idcache)-1;
+ goto skipremaining;
+ }
+ }
+ else
+ skipremaining:
+ do
+ {
+ if ((ch=fgetc(idcache))==EOF) goto noluck;
+ } while (ch!='\n');
+ } while (ftell(idcache)<once_file_size);
+ noluck:
+ if (insoffs>=once_file_size) insoffs=0;
+ }
+ else /* DB recipient cache */
+ {
EXIM_DATUM key_datum, result_datum;
EXIM_DBOPEN(oncelog, O_RDWR|O_CREAT, ob->mode, &dbm_file);
if (dbm_file == NULL)
@@ -347,7 +414,7 @@
}
}
}
-
+ }
/* Ensure any requested file is available. */
@@ -470,6 +537,12 @@
/* Update the "sent to" log whatever the yield. This errs on the side of
missing out a message rather than risking sending more than one. */
+
+if (idcache != NULL)
+ {
+ fseek(idcache,insoffs,SEEK_SET); fputs(to,idcache); putc('\n',idcache); putc('\n',idcache);
+ fclose(idcache);
+ }
if (dbm_file != NULL)
{