aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS8
-rw-r--r--driver.c33
-rw-r--r--fetchmail.c15
-rw-r--r--fetchmail.h2
-rw-r--r--fetchmail.man9
-rw-r--r--imap.c33
-rw-r--r--options.c19
-rw-r--r--pop2.c1
-rw-r--r--pop3.c35
-rw-r--r--rcfile_l.l1
-rw-r--r--rcfile_y.y5
11 files changed, 149 insertions, 12 deletions
diff --git a/NEWS b/NEWS
index 717a5300..87989779 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,14 @@ features --
lists and multidrop mailboxes. See the man page for details (and note
the caveat in the BUGS AND KNOWN PROBLEMS section).
+* It is possible to specify a size limit for retrieved messages. I resisted
+ doing this because I don't want fetchmail to be in the filtering game, but
+ too many Europeans begged for it because their telecomms monopolies are
+ price-gouging them on per-second phone charges. I will ignore, or be
+ extremely rude to, anyone who takes this feature as a license to beg me
+ for kill files or any other form of content-based filtering. Use
+ procmail on your server if you want that.
+
* If you use an MDA, the internal changes to support multi-drop mailboxes
require that you *remove* the %s at the end of your MDA string. Local
delivery addresses will be appended to the end of the command in the
diff --git a/driver.c b/driver.c
index 0a34bbd9..be0a73f1 100644
--- a/driver.c
+++ b/driver.c
@@ -760,6 +760,15 @@ struct method *proto; /* protocol method table */
return(PS_SYNTAX);
}
}
+ if (!proto->getsizes && queryctl->limit)
+ {
+ fprintf(stderr,
+ "Option --limit is not supported with %s\n",
+ proto->name);
+ alarm(0);
+ signal(SIGALRM, sigsave);
+ return(PS_SYNTAX);
+ }
protocol = proto;
tagnum = 0;
@@ -773,7 +782,7 @@ struct method *proto; /* protocol method table */
else
{
char buf [POPBUFSIZE+1], host[HOSTLEN+1];
- int socket, len, num, count, new, deletions = 0;
+ int *msgsizes, socket, len, num, count, new, deletions = 0;
alarm(queryctl->timeout);
@@ -830,6 +839,12 @@ struct method *proto; /* protocol method table */
queryctl->servername);
}
+ /* we may need to get sizes in order to check message limits */
+ msgsizes = (int *)NULL;
+ if (!queryctl->fetchall && proto->getsizes && queryctl->limit)
+ if ((msgsizes = (proto->getsizes)(socket, count)) == (int *)NULL)
+ return(PS_ERROR);
+
if (check_only)
{
if (new == -1 || queryctl->fetchall)
@@ -853,12 +868,20 @@ struct method *proto; /* protocol method table */
/* read, forward, and delete messages */
for (num = 1; num <= count; num++)
{
+ int toolarge = msgsizes && msgsizes[num-1]>queryctl->limit;
int fetch_it = queryctl->fetchall ||
- !(protocol->is_old && (protocol->is_old)(socket,queryctl,num));
+ (!(protocol->is_old && (protocol->is_old)(socket,queryctl,num)) && !toolarge);
/* we may want to reject this message if it's old */
if (!fetch_it)
- fprintf(stderr, "skipping message %d ", num);
+ {
+ if (outlevel > O_SILENT)
+ {
+ fprintf(stderr, "skipping message %d", num);
+ if (toolarge)
+ fprintf(stderr, " (oversized, %d bytes)", msgsizes[num-1]);
+ }
+ }
else
{
/* request a message */
@@ -910,13 +933,13 @@ struct method *proto; /* protocol method table */
&& (fetch_it ? !queryctl->keep : queryctl->flush))
{
deletions++;
- if (outlevel > O_SILENT && outlevel < O_VERBOSE)
+ if (outlevel > O_SILENT)
fprintf(stderr, " flushed\n", num);
ok = (protocol->delete)(socket, queryctl, num);
if (ok != 0)
goto cleanUp;
}
- else if (outlevel > O_SILENT && outlevel < O_VERBOSE)
+ else if (outlevel > O_SILENT)
{
/* nuke it from the unseen-messages list */
delete_uid(&queryctl->newsaved, num);
diff --git a/fetchmail.c b/fetchmail.c
index 369bc63f..e2a82e5e 100644
--- a/fetchmail.c
+++ b/fetchmail.c
@@ -188,9 +188,20 @@ char **argv;
/* merge in defaults */
optmerge(hostp, &def_opts);
+ /* keep lusers from shooting themselves in the foot :-) */
+ if (poll_interval && hostp->limit)
+ {
+ fprintf(stderr,"fetchmail: you'd never see large messages!\n");
+ exit(PS_SYNTAX);
+ }
+
/* check that delivery is going to a real local user */
if ((pw = getpwnam(user)) == (struct passwd *)NULL)
+ {
+ fprintf(stderr,
+ "fetchmail: can't default delivery to %s\n", user);
exit(PS_SYNTAX); /* has to be from bad rc file */
+ }
else
hostp->uid = pw->pw_uid;
@@ -607,6 +618,10 @@ struct hostrec *queryctl; /* query parameter block */
printf(" Rewrite of server-local addresses is %sabled (--norewrite %s).\n",
queryctl->norewrite ? "dis" : "en",
queryctl->norewrite ? "on" : "off");
+ if (queryctl->limit)
+ printf(" Message size limit is %d bytes\n", queryctl->limit);
+ else if (outlevel == O_VERBOSE)
+ printf(" No message size limit\n");
if (queryctl->mda[0])
{
char **cp;
diff --git a/fetchmail.h b/fetchmail.h
index 1c2a5e21..eac06c99 100644
--- a/fetchmail.h
+++ b/fetchmail.h
@@ -72,6 +72,7 @@ struct hostrec
int port;
int authenticate;
int timeout;
+ int limit;
/* MDA arguments */
int mda_argcount;
@@ -106,6 +107,7 @@ struct method
int (*parse_response)(); /* response_parsing function */
int (*getauth)(); /* authorization fetcher */
int (*getrange)(); /* get message range to fetch */
+ int *(*getsizes)(); /* get sizes of messages */
int (*is_old)(); /* check for old message */
int (*fetch)(); /* fetch a given message */
int (*trail)(); /* eat trailer of a message */
diff --git a/fetchmail.man b/fetchmail.man
index 7c9f35e2..3bfe5b9a 100644
--- a/fetchmail.man
+++ b/fetchmail.man
@@ -62,6 +62,15 @@ Note that POP2 retrieval, and POP3 retrieval on servers without the
LAST command, behaves as though --all is always on (see RETRIEVAL
FAILURE MODES below).
.TP
+.B \-l, --limit
+Takes a maximum octet size argument. Messages larger than this size
+will not be fetched, not be marked seen, and will be left on the
+server (in foreground sessions, the progress messages will note that
+they are "oversized"). The --all option overrides this one. This
+option is intended for those need to strictly control fetch time
+in interactive mode. It may not be used with daemon mode,
+as users would never receive a notification that messages were waiting.
+.TP
.B \-S host, --smtphost host
Specify an host to forward mail to (other than localhost).
.TP
diff --git a/imap.c b/imap.c
index 22f8db7c..c1dac5c8 100644
--- a/imap.c
+++ b/imap.c
@@ -111,6 +111,38 @@ int *countp, *newp;
return(0);
}
+static int *imap_getsizes(socket, count)
+/* capture the sizes of all messages */
+int socket;
+int count;
+{
+ int ok, *sizes;
+
+ if ((sizes = (int *)malloc(sizeof(int) * count)) == (int *)NULL)
+ return((int *)NULL);
+ else
+ {
+ char buf [POPBUFSIZE+1];
+
+ gen_send(socket, "FETCH 1:%d RFC822.SIZE", count);
+ while (SockGets(socket, buf, sizeof(buf)) >= 0)
+ {
+ int num, size;
+
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"%s\n",buf);
+ if (strstr(buf, "OK"))
+ break;
+ else if (sscanf(buf, "* %d FETCH (RFC822.SIZE %d)", &num, &size) == 2)
+ sizes[num - 1] = size;
+ else
+ sizes[num - 1] = -1;
+ }
+
+ return(sizes);
+ }
+}
+
static imap_is_old(socket, queryctl, num)
int socket;
struct hostrec *queryctl;
@@ -181,6 +213,7 @@ const static struct method imap =
imap_ok, /* parse command response */
imap_getauth, /* get authorization */
imap_getrange, /* query range of messages */
+ imap_getsizes, /* grab message sizes */
imap_is_old, /* no UID check */
imap_fetch, /* request given message */
imap_trail, /* eat message trailer */
diff --git a/options.c b/options.c
index f6899e11..57d7f427 100644
--- a/options.c
+++ b/options.c
@@ -31,12 +31,13 @@
#define LA_KEEP 18
#define LA_FLUSH 19
#define LA_NOREWRITE 20
-#define LA_REMOTEFILE 21
-#define LA_SMTPHOST 22
-#define LA_MDA 23
-#define LA_YYDEBUG 24
+#define LA_LIMIT 21
+#define LA_REMOTEFILE 22
+#define LA_SMTPHOST 23
+#define LA_MDA 24
+#define LA_YYDEBUG 25
-static char *shortoptions = "?Vcsvd:qL:f:i:p:P:A:t:u:akKFnr:S:m:y";
+static char *shortoptions = "?Vcsvd:qL:f:i:p:P:A:t:u:akKFnl:r:S:m:y";
static struct option longoptions[] = {
{"help", no_argument, (int *) 0, LA_HELP },
{"version", no_argument, (int *) 0, LA_VERSION },
@@ -63,6 +64,7 @@ static struct option longoptions[] = {
{"keep", no_argument, (int *) 0, LA_KEEP },
{"flush", no_argument, (int *) 0, LA_FLUSH },
{"norewrite", no_argument, (int *) 0, LA_NOREWRITE },
+ {"limit", required_argument, (int *) 0, LA_LIMIT },
{"remote", required_argument, (int *) 0, LA_REMOTEFILE },
{"smtphost", required_argument, (int *) 0, LA_SMTPHOST },
@@ -202,6 +204,10 @@ struct hostrec *queryctl; /* option record to be initialized */
case LA_NOREWRITE:
queryctl->norewrite = TRUE;
break;
+ case 'l':
+ case LA_LIMIT:
+ queryctl->limit = atoi(optarg);
+ break;
case 'r':
case LA_REMOTEFILE:
strncpy(queryctl->mailbox,optarg,sizeof(queryctl->mailbox)-1);
@@ -260,7 +266,8 @@ struct hostrec *queryctl; /* option record to be initialized */
fputs(" -K, --kill delete new messages after retrieval\n", stderr);
fputs(" -k, --keep save new messages after retrieval\n", stderr);
fputs(" -F, --flush delete old messages from server\n", stderr);
- fputs(" -n, --norewrite don't rewrite header addresses\n", stderr);
+ fputs(" -n, --norewrite don't rewrite header addresses\n", stderr);
+ fputs(" -l, --limit don't fetch messages over given size\n", stderr);
fputs(" -S, --smtphost set SMTP forwarding host\n", stderr);
fputs(" -r, --remote specify remote folder name\n", stderr);
diff --git a/pop2.c b/pop2.c
index 1d373778..887f529c 100644
--- a/pop2.c
+++ b/pop2.c
@@ -130,6 +130,7 @@ const static struct method pop2 =
pop2_ok, /* parse command response */
pop2_getauth, /* get authorization */
pop2_getrange, /* query range of messages */
+ NULL, /* no way to get sizes */
NULL, /* messages are always new */
pop2_fetch, /* request given message */
pop2_trail, /* eat message trailer */
diff --git a/pop3.c b/pop3.c
index c3b2da60..b898986b 100644
--- a/pop3.c
+++ b/pop3.c
@@ -186,7 +186,41 @@ int *countp, *newp;
return(0);
}
+static int *pop3_getsizes(socket, count)
+/* capture the sizes of all messages */
+int socket;
+int count;
+{
+ int ok, *sizes;
+
+ if ((ok = gen_transact(socket, "LIST")) != 0)
+ return((int *)NULL);
+ else if ((sizes = (int *)malloc(sizeof(int) * count)) == (int *)NULL)
+ return((int *)NULL);
+ else
+ {
+ char buf [POPBUFSIZE+1];
+
+ while (SockGets(socket, buf, sizeof(buf)) >= 0)
+ {
+ int num, size;
+
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"%s\n",buf);
+ if (buf[0] == '.')
+ break;
+ else if (sscanf(buf, "%d %d", &num, &size) == 2)
+ sizes[num - 1] = size;
+ else
+ sizes[num - 1] = -1;
+ }
+
+ return(sizes);
+ }
+}
+
static int pop3_is_old(socket, queryctl, num)
+/* is the goiven message old? */
int socket;
struct hostrec *queryctl;
int num;
@@ -240,6 +274,7 @@ const static struct method pop3 =
pop3_ok, /* parse command response */
pop3_getauth, /* get authorization */
pop3_getrange, /* query range of messages */
+ pop3_getsizes, /* we can get a list of sizes */
pop3_is_old, /* how do we tell a message is old? */
pop3_fetch, /* request given message */
NULL, /* no message trailer */
diff --git a/rcfile_l.l b/rcfile_l.l
index 701edd57..6c71aedf 100644
--- a/rcfile_l.l
+++ b/rcfile_l.l
@@ -46,6 +46,7 @@ noflush { yylval.flag = FLAG_FALSE; return FLUSH; }
nofetchall { yylval.flag = FLAG_FALSE; return FETCHALL; }
norewrite { yylval.flag = FLAG_TRUE; return REWRITE; }
noskip { yylval.flag = FLAG_FALSE; return SKIP; }
+limit { return LIMIT; }
with {/* EMPTY */}
and {/* EMPTY */}
diff --git a/rcfile_y.y b/rcfile_y.y
index 6582a31c..ef0ba68c 100644
--- a/rcfile_y.y
+++ b/rcfile_y.y
@@ -31,7 +31,7 @@ static int prc_errflag;
}
%token DEFAULTS SERVER PROTOCOL AUTHENTICATE TIMEOUT KPOP KERBEROS
-%token USERNAME PASSWORD FOLDER SMTPHOST MDA IS HERE THERE TO MAP
+%token USERNAME PASSWORD FOLDER SMTPHOST MDA IS HERE THERE TO MAP LIMIT
%token <proto> PROTO
%token <sval> STRING
%token <number> NUMBER
@@ -127,6 +127,7 @@ user_option : TO mapping_list HERE
| FLUSH {current.flush = ($1==FLAG_TRUE);}
| FETCHALL {current.fetchall = ($1==FLAG_TRUE);}
| REWRITE {current.norewrite = ($1==FLAG_TRUE);}
+ | LIMIT NUMBER {current.limit = $2;}
;
%%
@@ -283,6 +284,7 @@ int prc_register()
FLAG_FORCE(port);
FLAG_FORCE(authenticate);
FLAG_FORCE(timeout);
+ FLAG_FORCE(limit);
#undef FLAG_FORCE
(void) hostalloc(&current);
@@ -315,6 +317,7 @@ struct hostrec *h2;
FLAG_MERGE(port);
FLAG_MERGE(authenticate);
FLAG_MERGE(timeout);
+ FLAG_MERGE(limit);
#undef FLAG_MERGE
}