diff options
-rw-r--r-- | NEWS | 8 | ||||
-rw-r--r-- | driver.c | 33 | ||||
-rw-r--r-- | fetchmail.c | 15 | ||||
-rw-r--r-- | fetchmail.h | 2 | ||||
-rw-r--r-- | fetchmail.man | 9 | ||||
-rw-r--r-- | imap.c | 33 | ||||
-rw-r--r-- | options.c | 19 | ||||
-rw-r--r-- | pop2.c | 1 | ||||
-rw-r--r-- | pop3.c | 35 | ||||
-rw-r--r-- | rcfile_l.l | 1 | ||||
-rw-r--r-- | rcfile_y.y | 5 |
11 files changed, 149 insertions, 12 deletions
@@ -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 @@ -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 @@ -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 */ @@ -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); @@ -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 */ @@ -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 */ @@ -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 */} @@ -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(¤t); @@ -315,6 +317,7 @@ struct hostrec *h2; FLAG_MERGE(port); FLAG_MERGE(authenticate); FLAG_MERGE(timeout); + FLAG_MERGE(limit); #undef FLAG_MERGE } |