aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--driver.c4
-rw-r--r--etrn.c8
-rw-r--r--fetchmail.c11
-rw-r--r--fetchmail.h3
-rw-r--r--fetchmail.man21
-rw-r--r--imap.c57
-rw-r--r--options.c25
-rw-r--r--pop2.c8
-rw-r--r--pop3.c8
-rw-r--r--rcfile_l.l5
-rw-r--r--rcfile_y.y6
-rw-r--r--sample.rcfile1
13 files changed, 120 insertions, 38 deletions
diff --git a/NEWS b/NEWS
index 518c02d5..b7c2252c 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,7 @@ fetchmail-4.2.8 ()
* Only emit length-mismatch messages in verbose mode.
* POP3 lock busy error is now treated as authorization failure (Greg Stark)
* Kerberos error is now treated as authorization failure (Greg Stark)
+* New --expunge option allows you to better control resource use under IMAP.
There are 284 people on the fetchmail-friends list.
diff --git a/driver.c b/driver.c
index 33c85c76..796574d4 100644
--- a/driver.c
+++ b/driver.c
@@ -1848,7 +1848,7 @@ const struct method *proto; /* protocol method table */
no_error:
set_timeout(ctl->server.timeout);
- ok = gen_transact(sock, protocol->exit_cmd);
+ ok = (protocol->logout_cmd)(sock, ctl);
if (ok == 0)
ok = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
set_timeout(0);
@@ -1858,7 +1858,7 @@ const struct method *proto; /* protocol method table */
cleanUp:
set_timeout(ctl->server.timeout);
if (ok != 0 && ok != PS_SOCKET)
- gen_transact(sock, protocol->exit_cmd);
+ (protocol->logout_cmd)(sock, ctl);
set_timeout(0);
close(sock);
}
diff --git a/etrn.c b/etrn.c
index 59ce2fee..534e3425 100644
--- a/etrn.c
+++ b/etrn.c
@@ -105,6 +105,12 @@ static int etrn_getrange(int sock, struct query *ctl, char *id, int *countp,
return(0);
}
+static int etrn_logout(int sock, struct query *ctl)
+/* send logout command */
+{
+ return(gen_transact(sock, "QUIT"));
+}
+
const static struct method etrn =
{
"ETRN", /* ESMTP ETRN extension */
@@ -120,7 +126,7 @@ const static struct method etrn =
NULL, /* no way to fetch body */
NULL, /* no message trailer */
NULL, /* how to delete a message */
- "QUIT", /* the ETRN exit command */
+ etrn_logout, /* log out, we're done */
};
int doETRN (struct query *ctl)
diff --git a/fetchmail.c b/fetchmail.c
index 54dc45c6..c255530e 100644
--- a/fetchmail.c
+++ b/fetchmail.c
@@ -527,6 +527,7 @@ static int load_params(int argc, char **argv, int optind)
def_opts.remotename = user;
save_str(&def_opts.smtphunt, TRUE, fetchmailhost);
save_str(&def_opts.smtphunt, FALSE, "localhost");
+ def_opts.expunge = 1;
/* this builds the host list */
if (prc_parse_file(rcfile, !versioninfo) != 0)
@@ -928,7 +929,12 @@ void dump_params (struct query *ctl)
if (ctl->batchlimit > 0)
printf(" SMTP message batch limit is %d.\n", ctl->batchlimit);
else if (outlevel == O_VERBOSE)
- printf(" No SMTP message batch limit.\n");
+ printf(" No SMTP message batch limit (--batchlimit 0).\n");
+ if (ctl->server.protocol == P_IMAP)
+ if (ctl->expunge > 0)
+ printf(" Max deletions between expunges is %d (--expunge %d).\n", ctl->expunge, ctl->expunge);
+ else if (outlevel == O_VERBOSE)
+ printf(" No deletion limit between expunges (--expunge 0).\n");
if (ctl->mda)
printf(" Messages will be delivered with '%s.'\n", visbuf(ctl->mda));
else
@@ -979,7 +985,8 @@ void dump_params (struct query *ctl)
if (ctl->server.envelope == STRING_DISABLED)
printf(" Envelope-address routing is disabled\n");
else
- printf(" Envelope header is assumed to be: %s\n", ctl->server.envelope);
+ printf(" Envelope header is assumed to be: %s\n",
+ ctl->server.envelope ? ctl->server.envelope : "Received");
}
#ifdef linux
if (ctl->server.interface)
diff --git a/fetchmail.h b/fetchmail.h
index da9c050e..df817234 100644
--- a/fetchmail.h
+++ b/fetchmail.h
@@ -138,6 +138,7 @@ struct query
int limit; /* limit size of retrieved messages */
int fetchlimit; /* max # msgs to get in single poll */
int batchlimit; /* max # msgs to pass in single SMTP session */
+ int expunge; /* max # msgs to pass between expunges */
/* unseen, previous state of mailbox (initially from .fetchids) */
struct idlist *oldsaved, *newsaved;
@@ -169,7 +170,7 @@ struct method
int (*fetch_body)(); /* fetch a given message */
int (*trail)(); /* eat trailer of a message */
int (*delete)(); /* delete method */
- char *exit_cmd; /* exit command */
+ int (*logout_cmd)(); /* logout command */
};
#define TAGLEN 6
diff --git a/fetchmail.man b/fetchmail.man
index c627fdce..5b794fb5 100644
--- a/fetchmail.man
+++ b/fetchmail.man
@@ -245,6 +245,24 @@ Limit the number of messages accepted from a given server in a single
poll. By default there is no limit. An explicit --fetchlimit of 0
overrides any limits set in your run control file.
This option does not work with ETRN.
+.TP
+.B -e, --expunge
+(keyword: expunge)
+When talking to an IMAP server,
+.I fetchmail
+normally issues an EXPUNGE command after each deletion in order to
+force the deletion to be done immediately. This is safest when your
+connection to the server is flaky and expensive, as it avoids
+resending duplicate mail after a line hit. However, on large
+mailboxes the overhead of re-indexing after every message can slam the
+server pretty hard, so if your connection is reliable it is good to do
+expunges less frequently. If you specify this option to an integer N,
+it tells
+.I fetchmail
+to only issue expunges on every Nth delete. An argument
+of zero suppresses expunges entirely (so no expunges at all will be
+done until the end of run).
+This option does not work with ETRN, POP2, or POP3.
.SS Authentication Options
.TP
.B \-u name, --username name
@@ -817,6 +835,9 @@ T}
fetchlimit -B T{
Max # messages to forward in single connect
T}
+expunge -e T{
+Perform an expunge on every #th message (IMAP only)
+T}
syslog \& T{
Do error logging through syslog(3).
T}
diff --git a/imap.c b/imap.c
index ef4df99c..ce30d121 100644
--- a/imap.c
+++ b/imap.c
@@ -33,7 +33,7 @@ extern char *strstr(); /* needed on sysV68 R3V7.1. */
#define IMAP4 0 /* IMAP4 rev 0, RFC1730 */
#define IMAP4rev1 1 /* IMAP4 rev 1, RFC2060 */
-static int count, seen, recent, unseen, deletecount, imap_version;
+static int count, seen, recent, unseen, deletions, expunged, imap_version;
int imap_ok(int sock, char *argbuf)
/* parse command response */
@@ -441,7 +441,7 @@ static int imap_getrange(int sock,
else
*newp = -1; /* should never happen, RECENT is mandatory */
- deletecount = 0;
+ expunged = deletions = 0;
return(PS_SUCCESS);
}
@@ -474,8 +474,8 @@ static int imap_is_old(int sock, struct query *ctl, int number)
{
int ok;
- /* expunges change the fetch numbers */
- number -= deletecount;
+ /* expunged change the fetch numbers */
+ number -= expunged;
if ((ok = gen_transact(sock, "FETCH %d FLAGS", number)) != 0)
return(PS_ERROR);
@@ -489,8 +489,8 @@ static int imap_fetch_headers(int sock, struct query *ctl,int number,int *lenp)
char buf [POPBUFSIZE+1];
int num;
- /* expunges change the fetch numbers */
- number -= deletecount;
+ /* expunged change the fetch numbers */
+ number -= expunged;
/*
* This is blessed by RFC 1176, RFC1730, RFC2060.
@@ -519,8 +519,8 @@ static int imap_fetch_body(int sock, struct query *ctl, int number, int *lenp)
char buf [POPBUFSIZE+1], *cp;
int num;
- /* expunges change the fetch numbers */
- number -= deletecount;
+ /* expunged change the fetch numbers */
+ number -= expunged;
/*
* If we're using IMAP4, we can fetch the message without setting its
@@ -577,8 +577,8 @@ static int imap_fetch_body(int sock, struct query *ctl, int number, int *lenp)
static int imap_trail(int sock, struct query *ctl, int number)
/* discard tail of FETCH response after reading message text */
{
- /* expunges change the fetch numbers */
- /* number -= deletecount; */
+ /* expunged change the fetch numbers */
+ /* number -= expunged; */
for (;;)
{
@@ -601,8 +601,8 @@ static int imap_delete(int sock, struct query *ctl, int number)
{
int ok;
- /* expunges change the fetch numbers */
- number -= deletecount;
+ /* expunged change the fetch numbers */
+ number -= expunged;
/*
* Use SILENT if possible as a minor throughput optimization.
@@ -616,18 +616,37 @@ static int imap_delete(int sock, struct query *ctl, int number)
return(ok);
/*
- * We do an expunge after each message, rather than just before quit,
- * so that a line hit during a long session won't result in lots of
- * messages being fetched again during the next session.
+ * We do an expunge after ctl->expunge messages, rather than
+ * just before quit, so that a line hit during a long session
+ * won't result in lots of messages being fetched again during
+ * the next session.
*/
- if ((ok = gen_transact(sock, "EXPUNGE")))
- return(ok);
+ if (ctl->expunge > 0 && (++deletions % ctl->expunge) == 0)
+ {
+ if ((ok = gen_transact(sock, "EXPUNGE")))
+ return(ok);
- deletecount++;
+ expunged = deletions;;
+ }
return(PS_SUCCESS);
}
+static int imap_logout(int sock, struct query *ctl)
+/* send logout command */
+{
+ /* if expunges after deletion have been suppressed, ship one now */
+ if (ctl->expunge <= 0 && deletions)
+ {
+ int ok;
+
+ if ((ok = gen_transact(sock, "EXPUNGE")))
+ return(ok);
+ }
+
+ return(gen_transact(sock, "LOGOUT"));
+}
+
const static struct method imap =
{
"IMAP", /* Internet Message Access Protocol */
@@ -643,7 +662,7 @@ const static struct method imap =
imap_fetch_body, /* request given message body */
imap_trail, /* eat message trailer */
imap_delete, /* delete the message */
- "LOGOUT", /* the IMAP exit command */
+ imap_logout, /* expunge and exit */
};
int doIMAP(struct query *ctl)
diff --git a/options.c b/options.c
index 4d9515cd..fc610f6b 100644
--- a/options.c
+++ b/options.c
@@ -45,14 +45,15 @@
#define LA_SMTPHOST 27
#define LA_BATCHLIMIT 28
#define LA_FETCHLIMIT 29
-#define LA_MDA 30
-#define LA_INTERFACE 31
-#define LA_MONITOR 32
-#define LA_YYDEBUG 33
+#define LA_EXPUNGE 30
+#define LA_MDA 31
+#define LA_INTERFACE 32
+#define LA_MONITOR 33
+#define LA_YYDEBUG 34
-/* options still left: CDegGhHjJoOqQRTUwWxXYzZ */
+/* options still left: CDgGhHjJoOqQRTUwWxXYzZ */
static const char *shortoptions =
- "?Vcsvd:NqL:f:i:p:UP:A:t:E:u:akKFnl:r:S:b:B:m:I:M:y";
+ "?Vcsvd:NqL:f:i:p:UP:A:t:E:u:akKFnl:r:S:b:B:e:m:I:M:y";
static const struct option longoptions[] = {
/* this can be const because all flag fields are 0 and will never get set */
@@ -91,6 +92,7 @@ static const struct option longoptions[] = {
{"smtphost", required_argument, (int *) 0, LA_SMTPHOST },
{"batchlimit",required_argument, (int *) 0, LA_BATCHLIMIT },
{"fetchlimit",required_argument, (int *) 0, LA_FETCHLIMIT },
+ {"expunge", required_argument, (int *) 0, LA_EXPUNGE },
{"mda", required_argument, (int *) 0, LA_MDA },
#ifdef linux
@@ -105,8 +107,8 @@ static const struct option longoptions[] = {
int parsecmdline (argc, argv, ctl)
/* parse and validate the command line options */
-int argc; /* argument count */
-char **argv; /* argument strings */
+int argc; /* argument count */
+char **argv; /* argument strings */
struct query *ctl; /* option record to be initialized */
{
/*
@@ -298,6 +300,12 @@ struct query *ctl; /* option record to be initialized */
if (ctl->fetchlimit == 0)
ctl->fetchlimit = -1;
break;
+ case 'e':
+ case LA_EXPUNGE:
+ ctl->expunge = atoi(optarg);
+ if (ctl->expunge == 0)
+ ctl->expunge = -1;
+ break;
case 'm':
case LA_MDA:
ctl->mda = xstrdup(optarg);
@@ -375,6 +383,7 @@ struct query *ctl; /* option record to be initialized */
fputs(" -S, --smtphost set SMTP forwarding host\n", stderr);
fputs(" -b, --batchlimit set batch limit for SMTP connections\n", stderr);
fputs(" -B, --fetchlimit set fetch limit for server connections\n", stderr);
+ fputs(" -e, --expunge set max deletions between expunges\n", stderr);
fputs(" -r, --folder specify remote folder name\n", stderr);
return(-1);
}
diff --git a/pop2.c b/pop2.c
index c3a4b650..db34cc32 100644
--- a/pop2.c
+++ b/pop2.c
@@ -114,6 +114,12 @@ static int pop2_trail(int sock, struct query *ctl, int number)
return(gen_transact(sock, ctl->keep ? "ACKS" : "ACKD"));
}
+static int pop2_logout(int sock, struct query *ctl)
+/* send logout command */
+{
+ return(gen_transact(sock, "QUIT"));
+}
+
const static struct method pop2 =
{
"POP2", /* Post Office Protocol v2 */
@@ -129,7 +135,7 @@ const static struct method pop2 =
NULL, /* no way to fetch body alone */
pop2_trail, /* eat message trailer */
NULL, /* no POP2 delete method */
- "QUIT", /* the POP2 exit command */
+ pop2_logout, /* log out, we're done */
};
int doPOP2 (struct query *ctl)
diff --git a/pop3.c b/pop3.c
index 2f1c2a65..d219f7d0 100644
--- a/pop3.c
+++ b/pop3.c
@@ -443,6 +443,12 @@ static int pop3_delete(int sock, struct query *ctl, int number)
return(gen_transact(sock, "DELE %d", number));
}
+static int pop3_logout(int sock, struct query *ctl)
+/* send logout command */
+{
+ return(gen_transact(sock, "QUIT"));
+}
+
const static struct method pop3 =
{
"POP3", /* Post Office Protocol v3 */
@@ -458,7 +464,7 @@ const static struct method pop3 =
NULL, /* no way to fetch body alone */
NULL, /* no message trailer */
pop3_delete, /* how to delete a message */
- "QUIT", /* the POP3 exit command */
+ pop3_logout, /* log out, we're done */
};
int doPOP3 (struct query *ctl)
diff --git a/rcfile_l.l b/rcfile_l.l
index 95df5e90..a751f6fc 100644
--- a/rcfile_l.l
+++ b/rcfile_l.l
@@ -21,8 +21,6 @@ int prc_lineno = 1;
%%
set { return SET; }
-batchlimit { return BATCHLIMIT; }
-fetchlimit { return FETCHLIMIT; }
logfile { return LOGFILE; }
daemon { return DAEMON; }
syslog { return SYSLOG; }
@@ -52,6 +50,9 @@ pre(connect)? { return PRECONNECT; }
post(connect)? { return POSTCONNECT; }
interface { return INTERFACE; }
monitor { return MONITOR; }
+batchlimit { return BATCHLIMIT; }
+fetchlimit { return FETCHLIMIT; }
+expunge { return EXPUNGE; }
is { return IS; }
here { return HERE; }
diff --git a/rcfile_y.y b/rcfile_y.y
index 63a4543d..29a64b0e 100644
--- a/rcfile_y.y
+++ b/rcfile_y.y
@@ -59,7 +59,8 @@ extern char * yytext;
%token ENVELOPE USERNAME PASSWORD FOLDER SMTPHOST MDA
%token PRECONNECT POSTCONNECT LIMIT
%token IS HERE THERE TO MAP WILDCARD
-%token SET BATCHLIMIT FETCHLIMIT LOGFILE DAEMON SYSLOG INTERFACE MONITOR
+%token BATCHLIMIT FETCHLIMIT EXPUNGE
+%token SET LOGFILE DAEMON SYSLOG INTERFACE MONITOR
%token <proto> PROTO
%token <sval> STRING
%token <number> NUMBER
@@ -229,6 +230,7 @@ user_option : TO localnames HERE
| LIMIT NUMBER {current.limit = $2;}
| FETCHLIMIT NUMBER {current.fetchlimit = $2;}
| BATCHLIMIT NUMBER {current.batchlimit = $2;}
+ | EXPUNGE NUMBER {current.expunge = $2;}
;
%%
@@ -425,6 +427,7 @@ static void record_current(void)
FLAG_FORCE(limit);
FLAG_FORCE(fetchlimit);
FLAG_FORCE(batchlimit);
+ FLAG_FORCE(expunge);
#undef FLAG_FORCE
@@ -475,6 +478,7 @@ void optmerge(struct query *h2, struct query *h1)
FLAG_MERGE(limit);
FLAG_MERGE(fetchlimit);
FLAG_MERGE(batchlimit);
+ FLAG_MERGE(expunge);
#undef FLAG_MERGE
}
diff --git a/sample.rcfile b/sample.rcfile
index 01b3349d..45bcc2ff 100644
--- a/sample.rcfile
+++ b/sample.rcfile
@@ -66,6 +66,7 @@
# limit -- must be followed by numeric size limit
# fetchlimit -- must be followed by numeric msg fetch limit
# batchlimit -- must be followed by numeric SMTP batch limit
+# expunge -- must be followed by numeric delete count
#
# Legal protocol identifiers are
# pop2 (or POP2)