From d98d211d8b8832c01d8ccccb501fd419b8f430e1 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Wed, 26 Jun 1996 19:09:01 +0000 Subject: [PATCH] This is what I sent Harris. svn path=/trunk/; revision=9 --- Makefile.in | 33 ++++- README | 91 +++++++++++++ configure.in | 78 ++++++----- daemon.c | 27 ++-- fetchmail.c | 349 +++++++++++++++++++++++++++++++++++++++++--------- fetchmail.h | 42 ++++-- fetchmail.man | 236 ++++++++++++++++++++++++++++------ options.c | 72 ++++++----- pop2.c | 31 +++-- pop3.c | 66 ++++++---- rcfile_l.l | 18 ++- rcfile_y.y | 16 ++- sample.rcfile | 10 ++ 13 files changed, 841 insertions(+), 228 deletions(-) diff --git a/Makefile.in b/Makefile.in index 7f061806..83171e55 100644 --- a/Makefile.in +++ b/Makefile.in @@ -3,6 +3,9 @@ # Carl Harris, ceharris@mal.com # # $Log: Makefile.in,v $ +# Revision 1.2 1996/06/26 19:08:55 esr +# This is what I sent Harris. +# # Revision 1.1 1996/06/25 14:29:44 esr # Initial revision # @@ -97,16 +100,14 @@ ETAGS = etags -tw CTAGS = ctags -tw objs = socket.o getpass.o pop2.o pop3.o popclient.o options.o \ - poprc_l.o poprc_y.o poprc.o xmalloc.o \ + poprc_l.o poprc_y.o poprc.o daemon.o xmalloc.o \ $(EXTRAOBJ) $(extras) srcs = $(srcdir)/socket.c $(srcdir)/getpass.c $(srcdir)/pop2.c \ $(srcdir)/pop3.c $(srcdir)/popclient.c $(srcdir)/options.c \ - $(srcdir)/poprc_l.c $(srcdir)/poprc_y.c $(srcdir)/poprc.c \ - $(srcdir)/xmalloc.c \ + $(srcdir)/poprc.c $(srcdir)/daemon.c $(srcdir)/xmalloc.c \ $(EXTRASRC) - .SUFFIXES: .SUFFIXES: .o .c .h .y .l .ps .dvi .info .texi @@ -160,7 +161,7 @@ MAKE = make FORCE: -tagsrcs = $(srcs) +tagsrcs = $(srcs) $(srcdir)/poprc_l.c $(srcdir)/poprc_y.c TAGS: $(tagsrcs) $(ETAGS) $(tagsrcs) tags: $(tagsrcs) @@ -200,7 +201,7 @@ $(mandir)/$(instname).$(manext): popclient.man .PHONY: clean realclean distclean mostlyclean clean: -rm -f popclient *.o core popclient.dvi \ - poprc_l.c poprc_y.h poprc_y.c + poprc_l.c poprc_y.h poprc_y.c popclient.tar popclient.tar.gz distclean: clean -rm -f Makefile config.h @@ -232,6 +233,26 @@ configure: configure.in $(srcdir)/poprc_l.c: $(srcdir)/poprc_l.l $(srcdir)/poprc_y.c: $(srcdir)/poprc_y.y +parser = $(srcdir)/poprc_l.l $(srcdir)/poprc_y.y +headers = $(srcdir)/popclient.h $(srcdir)/socket.h $(srcdir)/poproto.h +extra = $(srcdir)/alloca.c $(srcdir)/bzero.[ch] $(srcdir)/errorcodes \ + $(srcdir)/getopt.[ch] $(srcdir)/getopt1.c $(srcdir)/md5*.[ch] \ + $(srcdir)/strcasecmp.c $(srcdir)/strdup.c +docs = $(srcdir)/README $(srcdir)/INSTALL $(srcdir)/RFC/*.txt \ + $(srcdir)/*.man $(srcdir)/*.texi $(srcdir)/*.info \ + $(srcdir)/sample.poprc $(srcdir)/TODO +config = $(srcdir)/Makefile.in $(srcdir)/configure.in $(srcdir)/config.guess \ + $(srcdir)/config.h.in $(srcdir)/config.sub +scripts = $(srcdir)/install.sh $(srcdir)/mkinstalldirs +all = $(docs) $(config) $(srcs) $(parser) $(headers) $(extra) $(scripts) + +manifest: + @echo $(all) | tr "[ \t]" '\n' | sort + +popclient.tar: $(all) + tar -cf popclient.tar $(all) +popclient.tar.gz: popclient.tar + gzip -f popclient.tar # The automatically generated dependencies below may omit config.h # because it is included with ``#include '' rather than diff --git a/README b/README index fa94f5d1..c2894ba9 100644 --- a/README +++ b/README @@ -1,6 +1,9 @@ Popclient README $Log: README,v $ + Revision 1.2 1996/06/26 19:08:55 esr + This is what I sent Harris. + Revision 1.1 1996/06/26 15:27:06 esr Initial revision @@ -19,6 +22,94 @@ be a "developer/tester" release only. Release History +3.0b7: + +Eric S. Raymond hacked on 3.0b6. Here are his change notes: + +CONFIGURATION AND BUILDING + +* The autoconfigure script incorrectly assumed that all Linuxes use + /usr/bin/deliver. Under Linux it now checks for both /usr/bin/delivermail + and /bin/mail. + +* I added a distribution-maker production to Makefile.in. + +OPTIONS AND COMMAND LINE + +* I have removed the -p command-line option. Given that there's a .poprc + facility there is no excuse for encouraging users to put plaintext passwords + in scripts which might be readable. + +* Calling popclient with no arguments now causes it to query or operate + on every host in the .poprc file. + +* I have made --version more useful by having it dump the computed + connection options for each server specified. + +* The user can now explicitly set an MDA (such as procmail) with the + new option -m or -mda. Various possible MDAs are listed on the man page. + +POPRC FILE SYNTAX + +* The .poprc lexer now supports "-enclosed strings which may contain + whitespace. + +* I added a --yydebug option to enable .poprc parser debugging at runtime + if the parser was generated with --debug. It's not documented. + +* You may now have a `defaults' entry in .poprc which sets overrideable + values for other entries. See the man page for details. + +* It is now possible to set keep, flush and fetchall in your .poprc file. + +* Fixed incorrect numbering of source lines in .poprc parse error messages. + +* The configure.in specification no longer uses the obsolete AC_TRY_COMPILE + macro (it uses AC_TRY_LINK instead). + +MAILBOX LOCKING + +* I have added mandatory locking of mailbox files where supported. + This will cover Linux systems, in particular. + +* The default behavior is now to do lock-protected append on the user's + system mailbox rather than using delivermail or some other MDA. + (This is a performance hack.) + +* The autoconfigure script now looks for standard mail locations. The + default mail delivery agent is used only if it can't find a mail spool + directory in the standard places. + +FUNCTIONAL ENHANCEMENTS + +* When using POP3, message headers are edited so that replies won't foo up. + Anything that looks like a mail ID local to the POP host gets @ and the + pop servername attached to it before being appended to the user's + mailbox or passed to an MDA. + +* I have implemented daemon mode. + +DOCUMENTATION + +* All changes and feature additions have been tested in actual use and are + documented on the man page. + +* I have turned the comments in the sample.poprc into a new manual + section documenting the .poprc format. + +MISCELLANEOUS BUG FIXES + +* I fixed some de-initialization bugs in pop2.c and pop3.c that led to + fd leaks (these became painfully obvious when I tested daemon mode!). + +* I've fixed the flaky parser error messages. They turned out to be due + to a misdeclaration of yytext. + +There's only one feature I haven't been able to add successfully. I +want a --logfile option that redirects the daemon-mode output to a +given file, but the code (in daemon.c near 200) unaccountably doesn't +work (so I haven't documented it yet). + 3.0b5 o "From " header fix in pop2.c and pop3.c o Surpress "..." output when --stdout option specified in pop3.c diff --git a/configure.in b/configure.in index 35e14591..6b4d1ccf 100644 --- a/configure.in +++ b/configure.in @@ -4,6 +4,9 @@ dnl dnl Process this file with autoconf to produce a configure script. dnl dnl $Log: configure.in,v $ +dnl Revision 1.2 1996/06/26 19:08:56 esr +dnl This is what I sent Harris. +dnl dnl Revision 1.1 1996/06/24 20:43:13 esr dnl Initial revision dnl @@ -51,43 +54,56 @@ test -z "$LDFLAGS" && LDFLAGS=-g AC_SUBST(LDFLAGS) AC_CANONICAL_HOST +AC_MSG_CHECKING(system mailbox directory) +if test -d /var/mail +then + AC_DEFINE(USERFOLDER, "/var/mail/%s") + userfolder='/var/mail/$u' +elif test -d /usr/mail +then + AC_DEFINE(USERFOLDER, "/usr/mail/%s") + userfolder='/usr/mail/$u' +elif test -d /usr/spool/mail +then + AC_DEFINE(USERFOLDER, "/usr/spool/mail/%s") + userfolder='/usr/spool/mail/$u' +elif test -d /var/spool/mail +then + AC_DEFINE(USERFOLDER, "/var/spool/mail/%s") + userfolder='/var/mail/$u' +else + userfolder="can't find one, will fall back on system MDA." +fi +AC_MSG_RESULT($userfolder) + AC_MSG_CHECKING(delivery agent for $host) case $host in *-*-*bsd*) - AC_DEFINE(MDA_PATH,"/usr/libexec/mail.local") - AC_DEFINE(MDA_ALIAS,"mail.local") - AC_DEFINE(MDA_ARGS,"$u") + AC_DEFINE(DEF_MDA,"/usr/libexec/mail.local %s") mdacmd="/usr/libexec/mail.local \$u" ;; - *-*-linux*) - AC_DEFINE(MDA_PATH,"/usr/bin/deliver") - AC_DEFINE(MDA_ALIAS,"deliver") - AC_DEFINE(MDA_ARGS,"$u") - mdacmd="/usr/bin/deliver \$u" - ;; - *-*-aix*) - AC_DEFINE(MDA_PATH,"/usr/bin/bellmail") - AC_DEFINE(MDA_ALIAS,"bellmail") - AC_DEFINE(MDA_ARGS,"$u") + AC_DEFINE(DEF_MDA,"/usr/bin/bellmail %s") mdacmd="/usr/bin/bellmail \$u" ;; *-*-hpux*) - AC_DEFINE(MDA_PATH,"/bin/rmail") - AC_DEFINE(MDA_ALIAS,"rmail") - AC_DEFINE(MDA_ARGS,"-d $u") + AC_DEFINE(DEF_MDA,"/bin/rmail -d %s") mdacmd="/bin/rmail -d \$u" ;; - # default case assumes /bin/mail is an MDA -- may LOSE mail on - # systems where it is not an MDA. *) - AC_DEFINE(MDA_PATH,"/bin/mail") - AC_DEFINE(MDA_ALIAS,"mail") - AC_DEFINE(MDA_ARGS,"-d $u") - mdacmd="/bin/mail -d \$u" + if test -x "/usr/bin/deliver %s" + then + AC_DEFINE(DEF_MDA,"/usr/bin/deliver %s") + mdacmd="/usr/bin/deliver \$u" + else + # default case assumes /bin/mail is an MDA -- may LOSE mail on + # systems where it is not an MDA. + AC_DEFINE(DEF_MDA,"/bin/mail -d %s") + mdacmd="/bin/mail -d \$u" + fi ;; esac AC_MSG_RESULT($mdacmd) @@ -156,7 +172,7 @@ dnl All AC_CHECK_FUNCs must precede the following AC_SUBSTs AC_SUBST(EXTRASRC) AC_SUBST(EXTRAOBJ) -AC_CHECK_FUNCS(dup2 strerror tcsetattr stty setsid) +AC_CHECK_FUNCS(dup2 strerror tcsetattr stty setsid flock) dnl AC_FUNC_SETVBUF_REVERSED @@ -183,7 +199,8 @@ AC_TRY_COMPILE([], dnl Check out the wait reality. AC_CHECK_HEADERS(sys/wait.h) AC_CHECK_FUNCS(waitpid wait3) -AC_COMPILE_CHECK(union wait, [#include +AC_MSG_CHECKING(for union wait); +AC_TRY_LINK([#include #include ], [union wait status; int pid; pid = wait (&status); #ifdef WEXITSTATUS @@ -197,19 +214,20 @@ if (WEXITSTATUS (status) != 0) pid = -1; pid = waitpid (-1, &status, 0); #endif ], - AC_DEFINE(HAVE_UNION_WAIT)) + [AC_DEFINE(HAVE_UNION_WAIT) AC_MSG_RESULT(yes)], + AC_MSG_RESULT(no)) -AC_COMPILE_CHECK(sys_siglist declaration in signal.h or unistd.h, - [#include +AC_MSG_CHECKING(sys_siglist declaration in signal.h or unistd.h) +AC_TRY_LINK([#include /* NetBSD declares sys_siglist in . */ #ifdef HAVE_UNISTD_H #include #endif], [char *msg = *(sys_siglist + 1);], - AC_DEFINE(SYS_SIGLIST_DECLARED)) - + [AC_DEFINE(SYS_SIGLIST_DECLARED) AC_MSG_RESULT(yes)], + AC_MSG_RESULT(no)) # The presence of the following is not meant to imply -# that necessarily works on those systems. +# that popclient necessarily works on those systems. dnl AC_DYNIX_SEQ dnl AC_XENIX_DIR dnl AC_IRIX_SUN diff --git a/daemon.c b/daemon.c index 56aab4ef..cdfb35f9 100644 --- a/daemon.c +++ b/daemon.c @@ -25,6 +25,9 @@ BSD systems. $Log: daemon.c,v $ + Revision 1.2 1996/06/26 19:08:57 esr + This is what I sent Harris. + Revision 1.1 1996/06/25 14:32:01 esr Initial revision @@ -98,7 +101,7 @@ sigchld_handler () become process group leader of our own process group, and set up to catch child process termination signals. arguments: - options command-line options. + logfile file to direct stdout and stderr to, if non-NULL. ret. value: none. globals: refers to the address of sigchld_handler(). @@ -106,12 +109,12 @@ sigchld_handler () *****************************************************************/ int -daemonize (options) -struct optrec *options; +daemonize (logfile) +const char *logfile; { int fd; pid_t childpid; - RETSIGTYPE sigchild_handler(); + RETSIGTYPE sigchld_handler(); /* if we are started by init (process 1) via /etc/inittab we needn't bother to detach from our process group context */ @@ -195,13 +198,15 @@ nottyDetach: return(PS_IOERR); } - - if (dup(fd) < 0) { /* stdout */ - log_perror("dup"); - return(PS_IOERR); - } + if (logfile) + open(logfile, O_CREAT|O_WRONLY, 0777); /* stdout */ + else + if (dup(fd) < 0) { /* stdout */ + perror("dup"); + return(PS_IOERR); + } if (dup(fd) < 0) { /* stderr */ - log_perror("dup"); + perror("dup"); return(PS_IOERR); } @@ -216,6 +221,6 @@ nottyDetach: #endif /* set up to catch child process termination signals */ - signal(SIGCLD, sigchild_handler); + signal(SIGCLD, sigchld_handler); } diff --git a/fetchmail.c b/fetchmail.c index 7a04ca2c..10bff927 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -22,6 +22,9 @@ description: main driver module for popclient $Log: fetchmail.c,v $ + Revision 1.2 1996/06/26 19:08:59 esr + This is what I sent Harris. + Revision 1.1 1996/06/24 18:32:00 esr Initial revision @@ -89,23 +92,30 @@ /* release info */ #define RELEASE_TAG "3.0b6" +struct hostrec { + char *servername; + struct optrec options; + struct hostrec *next; +}; + #ifdef HAVE_PROTOTYPES /* prototypes for internal functions */ int showoptions (struct optrec *options); int parseMDAargs (struct optrec *options); int showversioninfo (void); +int dump_options (struct optrec *options); +int query_host(char *servername, struct optrec *options); #endif /* Controls the detail of status/progress messages written to stderr */ -int outlevel; /* see the O_.* constants in popclient.h */ +int outlevel; /* see the O_.* constants in popclient.h */ -/* args for the MDA, parsed out in the usual fashion by parseMDAargs() */ -#ifdef MDA_ARGS -char *mda_argv [MDA_ARGCOUNT + 2]; -#else -char *mda_argv [2]; -#endif +/* Daemon-mode control */ +int poll_interval; /* polling interval for daemon mode */ +char *logfile; /* logfile to ship progress reports to */ +/* args for the MDA, parsed out in the usual fashion by parseMDAargs() */ +char *mda_argv [32]; /********************************************************************* function: main @@ -129,49 +139,99 @@ char **argv; int popstatus; int parsestatus; char *servername; + struct hostrec *hostp, *hostlist = (struct hostrec *)NULL; - parsestatus = parsecmdline(argc,argv,&cmd_opts); - if (parsestatus >= 0) { - setoutlevel(&cmd_opts); - if (!cmd_opts.versioninfo) - if (setdefaults(&def_opts) == 0) { - if (prc_parse_file(prc_getpathname(&cmd_opts,&def_opts)) == 0) { - while ((servername = getnextserver(argc, argv, &parsestatus)) - != (char *) 0) { - if (outlevel != O_SILENT) - fprintf(stderr, "querying %s\n", servername); - else - ; - prc_mergeoptions(servername, &cmd_opts, &def_opts, &merged_opts); - parseMDAargs(&merged_opts); - switch (merged_opts.whichpop) { - case P_POP2: - popstatus = doPOP2(servername, &merged_opts); - break; - case P_POP3: - case P_APOP: - popstatus = doPOP3(servername, &merged_opts); - break; - default: - fprintf(stderr,"unsupported protocol selected.\n"); - } - } - } - else - popstatus = PS_SYNTAX; - } - else - popstatus = PS_UNDEFINED; - else - showversioninfo(); + if ((parsestatus = parsecmdline(argc,argv,&cmd_opts)) < 0) + exit(PS_SYNTAX); + + setoutlevel(&cmd_opts); + if (cmd_opts.versioninfo) + showversioninfo(); + + if (setdefaults(&def_opts) != 0) + exit(PS_UNDEFINED); + + if (prc_parse_file(prc_getpathname(&cmd_opts,&def_opts)) != 0) + exit(PS_SYNTAX); + + if (optind >= argc) + append_server_names(&argc, argv); + + /* build in-core data list on all hosts */ + while ((servername = getnextserver(argc, argv, &parsestatus)) != (char *)0) { + if (strcmp(servername, "defaults") == 0) + continue; + + prc_mergeoptions(servername, &cmd_opts, &def_opts, &merged_opts); + parseMDAargs(&merged_opts); + + hostp = (struct hostrec *)xmalloc(sizeof(struct hostrec)); + hostp->servername = strdup(servername); + memcpy(&hostp->options, &merged_opts, sizeof(struct optrec)); + + hostp->next = hostlist; + hostlist = hostp; } - else - popstatus = PS_SYNTAX; + + /* perhaps we just want to check options? */ + if (cmd_opts.versioninfo) { + printf("Taking options from command line and %s\n", prc_pathname); + for (hostp = hostlist; hostp; hostp = hostp->next) { + printf("Options for host %s:\n", hostp->servername); + dump_options(&hostp->options); + } + if (hostlist == NULL) + (void) printf("No mailservers set up -- perhaps %s is missing?\n", + prc_pathname); + exit(0); + } + else if (hostlist == NULL) { + (void) fputs("popclient: no mailservers have been specified.\n", stderr); + exit(PS_SYNTAX); + } + + /* + * Maybe time to go to demon mode... + */ + if (poll_interval) + daemonize(logfile); + + /* + * Query all hosts. If there's only one, the error return will + * reflect the status of that transaction. + */ + do { + for (hostp = hostlist; hostp; hostp = hostp->next) { + popstatus = query_host(hostp->servername, &hostp->options); + } + + sleep(poll_interval); + } while + (poll_interval); exit(popstatus); } - +int query_host(servername, options) +/* perform fetch transaction with single host */ +char *servername; +struct optrec *options; +{ + if (outlevel != O_SILENT) + fprintf(stderr, "querying %s\n", servername); + switch (options->whichpop) { + case P_POP2: + return(doPOP2(servername, options)); + break; + case P_POP3: + case P_APOP: + return(doPOP3(servername, options)); + break; + default: + fprintf(stderr,"unsupported protocol selected.\n"); + return(PS_PROTOCOL); + } +} /********************************************************************* function: showversioninfo @@ -184,11 +244,77 @@ char **argv; int showversioninfo() { - printf("popclient release %s\n",RELEASE_TAG); + printf("This is popclient release %s\n",RELEASE_TAG); } +/********************************************************************* + function: dump_options + description: display program options in English + arguments: + options merged options + return value: none. + calls: none. + globals: none. +*********************************************************************/ +int dump_options (options) +struct optrec *options; +{ + if (!options->loginid[0]) + printf(" No password set\n"); + else + printf(" Username = '%s'\n", options->loginid); + printf(" Password = '%s'\n", options->password); + + printf(" Protocol is "); + switch (options->whichpop) + { + case P_POP2: printf("POP2\n"); break; + case P_POP3: printf("POP3\n"); break; + case P_IMAP: printf("IMAP\n"); break; + case P_APOP: printf("APOP\n"); break; + case P_RPOP: printf("RPOP\n"); break; + default: printf("unknown?!?\n"); break; + } + + printf(" Fetched messages will%s be kept on the server (--keep %s).\n", + options->keep ? "" : " not", + options->keep ? "on" : "off"); + printf(" %s messages will be retrieved (--all %s).\n", + options->fetchall ? "All" : "Only new", + options->fetchall ? "on" : "off"); + printf(" Old messages will%s be flushed before message retrieval (--flush %s).\n", + options->flush ? "" : " not", + options->flush ? "on" : "off"); + + switch(options->output) + { + case TO_FOLDER: + printf(" Messages will be appended to '%s'\n", options->userfolder); + break; + case TO_MDA: + printf(" Messages will be delivered with %s\n", options->mda); + break; + case TO_STDOUT: + printf(" Messages will be dumped to standard output\n"); + default: + printf(" Message destination unknown?!?\n"); + } + if (options->verbose) + { + if (options->output != TO_FOLDER) + printf(" (Mail folder would have been '%s')\n", options->userfolder); + if (options->output != TO_MDA) + printf(" (MDA would have been '%s')\n", options->mda); + } + + if (options->limit == 0) + printf(" No limit on retrieved message length.\n"); + else + printf(" Text retrieved per message will be at most %d bytes.\n", + options->limit); +} /****************************************************************** function: setoutlevel @@ -217,8 +343,7 @@ struct optrec *options; /********************************************************************* function: openuserfolder description: open the file to which the retrieved messages will - be appended. Do NOT call when options->foldertype - is OF_SYSMBOX. + be appended. Write-lock the folder if possible. arguments: options fully-determined options (i.e. parsed, defaults invoked, @@ -234,10 +359,17 @@ struct optrec *options; { int fd; - if (options->foldertype == OF_STDOUT) + if (options->output == TO_STDOUT) return(1); - else /* options->foldertype == OF_USERMBOX */ + else /* options->output == TO_FOLDER */ if ((fd = open(options->userfolder,O_CREAT|O_WRONLY|O_APPEND,0600)) >= 0) { +#ifdef HAVE_FLOCK + if (flock(fd, LOCK_EX) == -1) + { + close(fd); + fd = -1; + } +#endif /* HAVE_FLOCK */ return(fd); } else { @@ -286,7 +418,7 @@ struct optrec *options; exit(1); } - execv(MDA_PATH,mda_argv); + execv(options->mda,mda_argv); /* if we got here, an error occurred */ perror("popclient: openmailpipe: exec"); @@ -365,7 +497,7 @@ int fd; /********************************************************************* function: parseMDAargs - description: parse the argument string given in MDA_ARGS into + description: parse the argument string given in agent option into a regular *argv[] array. arguments: options fully-determined options record pointer. @@ -381,14 +513,11 @@ struct optrec *options; int argi; char *argp; - /* first put the MDA alias in as argv[0] */ - mda_argv[0] = MDA_ALIAS; - -#ifdef MDA_ARGS - - /* make a writeable copy of MDA_ARGS */ - argp = strcpy((char *) malloc(strlen(MDA_ARGS)+1), MDA_ARGS); + /* first put the last segment of the MDA pathname in argv[0] */ + argp = strrchr(options->mda, '/'); + mda_argv[0] = argp ? (argp + 1) : options->mda; + argp = options->mda; while (*argp != '\0' && isspace(*argp)) /* skip null first arg */ argp++; @@ -417,10 +546,108 @@ struct optrec *options; } mda_argv[argi] = (char *) 0; -#else +} - mda_argv[1] = (char *) 0; +/********************************************************************* + function: + description: hack message headers so replies will work properly -#endif + arguments: + after where to put the hacked header + before header to hack + host name of the pop header + + return value: none. + calls: none. + globals: writes mda_argv. + *********************************************************************/ +void reply_hack(buf, host) +/* hack local mail IDs -- code by Eric S. Raymond 20 Jun 1996 */ +char *buf; +const char *host; +{ + const char *from; + int state = 0; + char mycopy[POPBUFSIZE]; + + if (strncmp("From: ", buf, 6) + && strncmp("To: ", buf, 4) + && strncmp("Reply-", buf, 6) + && strncmp("Cc: ", buf, 4) + && strncmp("Bcc: ", buf, 5)) { + return; + } + + strcpy(mycopy, buf); + for (from = mycopy; *from; from++) + { + switch (state) + { + case 0: /* before header colon */ + if (*from == ':') + state = 1; + break; + + case 1: /* we've seen the colon, we're looking for addresses */ + if (*from == '"') + state = 2; + else if (*from == '(') + state = 3; + else if (*from == '<' || isalnum(*from)) + state = 4; + break; + + case 2: /* we're in a quoted human name, copy and ignore */ + if (*from == '"') + state = 1; + break; + + case 3: /* we're in a parenthesized human name, copy and ignore */ + if (*from == ')') + state = 1; + break; + + case 4: /* the real work gets done here */ + /* + * We're in something that might be an address part, + * either a bare unquoted/unparenthesized text or text + * enclosed in <> as per RFC822. + */ + /* if the address part contains an @, don't mess with it */ + if (*from == '@') + state = 5; + + /* If the address token is not properly terminated, ignore it. */ + else if (*from == ' ' || *from == '\t') + state = 1; + + /* + * On proper termination with no @, insert hostname. + * Case '>' catches <>-enclosed mail IDs. Case ',' catches + * comma-separated bare IDs. Cases \r and \n catch the case + * of a single ID alone on the line. + */ + else if (strchr(">,\r\n", *from)) + { + strcpy(buf, "@"); + strcat(buf, host); + buf += strlen(buf); + state = 1; + } + + /* everything else, including alphanumerics, just passes through */ + break; + + case 5: /* we're in a remote mail ID, no need to append hostname */ + if (*from == '>' || *from == ',' || isspace(*from)) + state = 1; + break; + } + + /* all characters from the old buffer get copied to the new one */ + *buf++ = *from; + } + *buf++ = '\0'; } + diff --git a/fetchmail.h b/fetchmail.h index 63b8ca70..814605ad 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -23,6 +23,9 @@ description: global constant, type, and variable definitions. $Log: fetchmail.h,v $ + Revision 1.2 1996/06/26 19:08:59 esr + This is what I sent Harris. + Revision 1.1 1996/06/24 18:14:08 esr Initial revision @@ -67,10 +70,11 @@ #define POPBUFSIZE 512 /* per RFC 937 */ #define MSGBUFSIZE 1024 /* size of message read buffer */ #define HOSTLEN 128 /* max hostname length */ -#define USERIDLEN 32 /* max user-length */ +#define USERNAMELEN 32 /* max user-length */ #define PASSWORDLEN MAX_PASSWORD_LENGTH #define FOLDERLEN 256 /* max folder name length */ #define DIGESTLEN 33 /* length of MD5 digest */ +#define MDALEN 33 /* length of delivery agent command */ /* exit code values */ #define PS_SUCCESS 0 /* successful receipt of messages */ @@ -88,10 +92,10 @@ #define O_NORMAL 1 /* user-friendly */ #define O_VERBOSE 2 /* excessive */ -/* output folder type, used in options record */ -#define OF_SYSMBOX 1 /* use system default mailbox */ -#define OF_USERMBOX 2 /* use user's specified mailbox */ -#define OF_STDOUT 3 /* use stdout */ +/* output sink type */ +#define TO_FOLDER 1 /* use a mailbox */ +#define TO_STDOUT 2 /* use stdout */ +#define TO_MDA 3 /* use agent */ /* Command-line arguments are passed in this structure type */ struct optrec { @@ -103,16 +107,17 @@ struct optrec { int limit; int fetchall; int flush; - int foldertype; - char loginid [USERIDLEN]; + int output; + char loginid [USERNAMELEN]; char *poprcfile; - char userid [USERIDLEN]; + char username [USERNAMELEN]; char password [PASSWORDLEN]; #if defined(HAVE_APOP_SUPPORT) char digest [DIGESTLEN]; #endif char userfolder [FOLDERLEN]; char remotefolder [FOLDERLEN]; + char mda [MDALEN]; }; @@ -123,12 +128,23 @@ struct prc_server { char *username; char *password; char *remotefolder; - char *localfolder; + char *userfolder; + char *mda; + int keep; + int flush; + int fetchall; }; /* Controls the detail of status/progress messages written to stderr */ -extern int outlevel; /* see the O_.* constants above */ +extern int outlevel; /* see the O_.* constants above */ +extern int yydebug; /* enable parse debugging */ + +/* daemon mode control */ +extern int poll_interval; /* poll interval in seconds */ +extern char *logfile; /* log file for daemon mode */ + +extern char *prc_pathname; /* path name of rc file */ #ifdef HAVE_PROTOTYPES @@ -145,12 +161,18 @@ int openmailpipe (struct optrec *options); int closemailpipe (int fd); char *MD5Digest (char *); char *prc_getpathname (struct optrec *cmd_opts, struct optrec *def_opts); +void reply_hack(char *buf, const char *host); +void append_server_names(int *pargc, char **argv); +int daemonize(const char *logfile); #else char *getnextserver(); char *MD5Digest (); char *prc_getpathname(); +void reply_hack (); +void append_server_names (); +int daemonize (); #endif diff --git a/fetchmail.man b/fetchmail.man index 03c3275f..46ee9f94 100644 --- a/fetchmail.man +++ b/fetchmail.man @@ -16,6 +16,9 @@ \. */ \. \. $Log: fetchmail.man,v $ +\. Revision 1.2 1996/06/26 19:09:00 esr +\. This is what I sent Harris. +\. \. Revision 1.1 1996/06/24 19:30:36 esr \. Initial revision \. @@ -38,7 +41,7 @@ popclient \- retrieve mail from a mailserver using Post Office Protocol. .SH SYNOPSIS .B popclient -[\fI options \fR] \fI server-host [server-host...]\fR +[\fI options \fR] \fI [server-host...]\fR .SH DESCRIPTION .I popclient is a Post Office Protocol compliant mail retrieval client which supports @@ -48,7 +51,7 @@ Typically, .I popclient will be used to download mail in batch from the remote mailserver specified by .I host -to a mail folder on the local disk. The retrieved mail will then be +to a mail folder on the local disk. The retrieved mail can then be manipulated using a local mail reader, such as .I mail or @@ -58,7 +61,20 @@ To facilitate the use of .I popclient in scripts, pipelines, etc, it returns an appropriate exit code upon termination -- see EXIT CODES below. +.PP +The behavior of +.I popclient +is controlled by comand-line options and a control file, +.I ~/.poprc +the syntax of which we describe below. Command-line options override +.I ~/.poprc +declarations. .SH OPTIONS +Each server name that you specify (following the options on the +command line) will be queried. If you don't specify any servers +on the command line, each server in your +.I ~/.poprc +file will be operated on. .TP .B \-2 Use Post Office Protocol version 2 (POP2). See also the @@ -116,15 +132,12 @@ option -- i.e. messages downloaded with the .B limit option remain on the remote mailserver. .TP -.B \-p string, --password string -Specifies the password -.I string -to be used when logging-in to the mailserver. The -appropriate password is both server and user dependent. If the -.B password -option is not used to specify a password, you will be prompted -for a password before the connection to the mailserver is established. -See USER AUTHENTICATION below for a complete description. +.B \-m mda, --mda mda +Specify a mail delivery agent to use. This can be used to pass +fetched mail to programs like procmail. If the MDA string contains +%s, that escape will be expanded into your username on the client +machine. Some possible MDAs are "/usr/formail", "/usr/bin/deliver %s", +"/usr/lib/sendmail -oem -t - -q %s". .TP .B \--protocol proto Specify the protocol to used when communicating with the remote @@ -193,9 +206,11 @@ to be modified or omitted. .B \-V, --version Displays the version information for your copy of .I popclient. -If you specify the -.B \version -option, all other options are ignored and no POP connection is made. +No POP connection is made. +Instead, for each server specified, all option information +that would be computed if +.I popclient. +were connecting to that server is displayed. .TP .PP .SH PROTOCOL SELECTION @@ -245,19 +260,11 @@ is to prompt you for your mailserver password before the POP connection is established. This is the safest way to use .I popclient and ensures that your password will not be compromised. You may also specify -your password using the -.B \-p -option. This is convenient when using -.I popclient -with automated scripts, but it may result in your password being exposed to -prying eyes \-\- be careful! Regardless of how your password is specified -it is never stored in shared memory segments, or left unencrypted in the core -image when +your password in your +.I ~/.poprc +file. This is convenient when using .I popclient -terminates. Continuing the preceding example, suppose your password on -\'mailgrunt' is 'Gr8PassWd'. The syntax would be: -.IP -popclient -u jsmith -p Gr8PassWd mailgrunt +with automated scripts. .PP On mailservers that do not provide ordinary user accounts, your user-id and password are usually assigned by the server administrator when you apply for @@ -273,10 +280,16 @@ to be used in conjunction with common mail readers like .I mail and .I elm. -The retrieved messages are normally appended to your default system mailbox -on the local disk, using the local Mail Delivery Agent (MDA), usually -/bin/mail(1), so that when you invoke your mail reader it can manipulate the -retrieved messages like any other mail you receive on the client machine. +The retrieved messages are normally appended to your default system +mailbox on the local disk, so that when you invoke your mail reader it +can manipulate the retrieved messages like any other mail you receive +on the client machine. If +.I popclient +doesn't know where your mailbox is, or can't modify it safely (e.g. because +your underlying operating system doesn't support mandatory file +locking), it will use the local Mail Delivery Agent +(MDA), usually +/bin/mail(1), .PP Using the .B \-o @@ -292,8 +305,7 @@ popclient \-o $HOME/mbox mailgrunt .PP Note that the folder specified with .B \-o -is not locked or otherwise protected from other processes writing to it -while popclient is writing to it. +is write-locked while popclient is writing to it, .PP .I popclient can be used in a shell pipeline by using the @@ -306,8 +318,10 @@ discards mail marked as 'Precedence: junk'. Suppose you've written an AWK script called 'dumpjunk.awk' to implement a junk mail filter. The appropriate syntax to retrieve your mail from 'mailgrunt', pass it through the filter, and write it to a folder called 'realmail' in your home directory would be: -.IP -popclient -c mailgrunt | awk -f dumpjunk.awk > $HOME/realmail + +.nf + popclient -c mailgrunt | awk -f dumpjunk.awk >$HOME/realmail +.fi .PP The progress/status messages written to stderr when the .B \-s @@ -322,15 +336,140 @@ option when using .B \-c to insure that your messages will not be lost if part of the shell pipeline does not function incorrectly. The safest bet would be something like: -.IP -popclient -k -c mailgrunt | myfilter > $HOME/filtered.mail + +.nf + popclient -k -c mailgrunt | myfilter >$HOME/filtered.mail +.fi .PP followed by -.IP -popclient -c mailgrunt > /dev/null + +.nf + popclient -c mailgrunt > /dev/null +.fi .PP when you're sure the messages were correctly processed by 'myfilter'. .PP +.SH DAEMON MODE +The +.B --daemon +or +.B -d +option runs +.I popmail +in daemon mode. You must specify a numeric argument which is a +polling interval in seconds. +.PP +In daemon mode, +.I popmail +puts itself in background and runs forever, querying each specified +host and then sleeping for the given polling interval. +.PP +Simply invoking +.IP +popmail -d 900 +.PP +will, therefore, poll the hosts described in your +.I ~/.poprc +file once every fifteen minutes. +.SH THE POPRC FILE +The preferred way to set up popclient (and the only way if you want to +specify a password) is to write a .poprc file in your home directory. +To protect the security of your passwords, your ~/.poprc may not have +more than u+r,u+w permissions; +.I popclient +will complain and exit otherwise. +.PP +Comments begin with a '#' and extend through the end of the line. +Otherwise the file consists of a series of server entries. +Blank lines between server entries are ignored. +Keywords and identifiers are case sensitive. +When there is a conflict between the command-line arguments and the +arguments in this file, the command-line arguments take precedence. +.PP +Legal keywords are: + + server + protocol (or proto) + username (or user) + password (or pass) + remotefolder (or remote) + localfolder (or local) + mda + keep + flush + fetchall + nokeep + noflush + nofetchall +.PP +Legal protocol identifiers are + + pop2 (or POP2) + pop3 (or POP3) + imap (or IMAP) + apop (or APOP) + rpop (or RPOP) +.PP +Basic format is: + +.nf + server SERVERNAME protocol PROTOCOL username NAME password PASSWORD +.fi +.PP +Example: + +.nf + server pop.provider.net protocol pop3 username jsmith password secret1 +.fi +.PP +Or, using some abbreviations: + +.nf + server pop.provider.net proto pop3 user jsmith password secret1 +.fi +.PP +Multiple servers may be listed: + +.nf + server pop.provider.net proto pop3 user jsmith pass secret1 + server other.provider.net proto pop2 user John.Smith pass My^Hat +.fi +.PP +Other possibilities (note use of \ to escape newline -- this is all +one server definition. + +.nf + server pop.provider.net \e + proto pop3 \e + user jsmith \e + pass secret1 \e + localfolder ~/mbox +.fi +If you need to include whitespace in a paramter string, enclose the +string in double quotes. Thus: + +.nf + server mail.provider.net \e + proto pop3 \e + user jsmith \e + pass secret1 \e + mda "/bin/mail -d %s" +.fi +Finally, you may have an initial server description headed by the keyword +`defaults' instead of `server' followed by a name. Such a record +is interpreted as defaults for all quries to use. It may be overwritten +by individual server descriptions. So, you could write: + +.nf + defaults \e + proto pop3 \e + user jsmith \e + mda "/bin/mail -d %s" + server pop.provider.net \e + pass secret1 \e + server mail.provider.net \e + pass secret2 \e +.fi .SH EXIT CODES To facilitate the use of .I popclient @@ -386,13 +525,28 @@ Something totally undefined occured. This is usually caused by a bug within .I popclient. Do let me know if this happens. .PP +When +.I popclient +queries more than one host, the returned status is that of the last +host queried. .SH AUTHOR .I popclient was written by Carl Harris at Virginia Polytechnic Institute and State -University (a.k.a. Virginia Tech). +University (a.k.a. Virginia Tech). Version 3.0 was extensively hacked +by Eric S. Raymond . .PP .SH BUGS -There are none! Well, maybe one or two. Send comments, bug reports, gripes, -and the like to ceharris@mal.com. +.PP +The --version option doesn't display MDA arguments. +.PP +No IMAP or RPOP support yet. +.PP +Send comments, bug reports, gripes, and the like to ceharris@mal.com. +.SH NOTE +The -p (--password) option of previous versions has been removed -- it +encouraged people to expose passwords in scripts. Passwords +must now be specified either manually or in your +.I ~/.poprc +file. .SH SEE ALSO mail(1), binmail(1), sendmail(8), popd(8), RFC 937, RFC 1225. diff --git a/options.c b/options.c index f8bda4b2..47c92094 100644 --- a/options.c +++ b/options.c @@ -22,6 +22,9 @@ description: command-line option processing $Log: options.c,v $ + Revision 1.2 1996/06/26 19:08:57 esr + This is what I sent Harris. + Revision 1.1 1996/06/24 18:11:08 esr Initial revision @@ -80,12 +83,13 @@ #define LA_DAEMON 11 #define LA_POPRC 12 #define LA_USERNAME 13 -#define LA_PASSWORD 14 -#define LA_REMOTEFILE 15 -#define LA_LOCALFILE 16 - +#define LA_REMOTEFILE 14 +#define LA_LOCALFILE 15 +#define LA_MDA 16 +#define LA_LOGFILE 17 +#define LA_YYDEBUG 18 -static char *shortoptions = "23VaKkvscl:Fd:f:u:p:r:o:"; +static char *shortoptions = "23VaKkvscl:Fd:f:u:r:o:m:"; static struct option longoptions[] = { {"version", no_argument, (int *) 0, LA_VERSION }, {"all", no_argument, (int *) 0, LA_ALL }, @@ -102,9 +106,11 @@ static struct option longoptions[] = { {"poprc", required_argument, (int *) 0, LA_POPRC }, {"user", required_argument, (int *) 0, LA_USERNAME }, {"username", required_argument, (int *) 0, LA_USERNAME }, - {"password", required_argument, (int *) 0, LA_PASSWORD }, {"remote", required_argument, (int *) 0, LA_REMOTEFILE }, {"local", required_argument, (int *) 0, LA_LOCALFILE }, + {"mda", required_argument, (int *) 0, LA_MDA }, + {"logfile", required_argument, (int *) 0, LA_LOGFILE }, + {"yydebug", no_argument, (int *) 0, LA_YYDEBUG }, {(char *) 0, no_argument, (int *) 0, 0 } }; @@ -187,7 +193,7 @@ struct optrec *options; errflag++; else { fflag++; - options->foldertype = OF_STDOUT; + options->output = TO_STDOUT; } break; case 'l': @@ -221,7 +227,7 @@ struct optrec *options; break; case 'd': case LA_DAEMON: - fprintf(stderr,"Got daemonize option with argument '%s'\n",optarg); + poll_interval = atoi(optarg); break; case 'f': case LA_POPRC: @@ -230,13 +236,7 @@ struct optrec *options; break; case 'u': case LA_USERNAME: - strncpy(options->userid,optarg,sizeof(options->userid)-1); - break; - case 'p': - case LA_PASSWORD: - strncpy(options->password,optarg,sizeof(options->password)-1); - for (i = strlen(options->password)-1; i >= 0; i--) - argv[optind-1][i] = '*'; + strncpy(options->username,optarg,sizeof(options->username)-1); break; case 'o': case LA_LOCALFILE: @@ -244,7 +244,7 @@ struct optrec *options; errflag++; else { fflag++; - options->foldertype = OF_USERMBOX; + options->output = TO_FOLDER; strncpy(options->userfolder,optarg,sizeof(options->userfolder)-1); } break; @@ -252,24 +252,25 @@ struct optrec *options; case LA_REMOTEFILE: strncpy(options->remotefolder,optarg,sizeof(options->remotefolder)-1); break; + case 'm': + case LA_MDA: + strncpy(options->mda,optarg,sizeof(options->mda)-1); + break; + case 'L': + case LA_LOGFILE: + logfile = optarg; + break; + case LA_YYDEBUG: + yydebug = 1; + break; default: errflag++; } } - if (!options->versioninfo) - /* if options don't obviate the need, we must have server name(s) - left on the command line. */ - if (optind >= argc) - errflag++; - else - ; - else - optind = 0; - if (errflag) { /* squawk if syntax errors were detected */ - fputs("usage: popclient [options] server [server ...]\n", stderr); + fputs("usage: popclient [options] [server ...]\n", stderr); fputs(" options\n",stderr); fputs(" -2 use POP2 protocol\n", stderr); fputs(" -3 use POP3 protocol\n", stderr); @@ -281,15 +282,16 @@ struct optrec *options; fputs(" -K, --kill delete new messages after retrieval\n", stderr); fputs(" -k, --keep save new messages after retrieval\n", stderr); fputs(" -l, --limit retrieve at most n message lines\n", stderr); + fputs(" -m, --mda set mail user agent to pass to\n", stderr); fputs(" -s, --silent work silently\n", stderr); fputs(" -v, --verbose work noisily (diagnostic output)\n", stderr); - fputs(" -d, --daemon run as a daemon\n", stderr); + fputs(" -d, --daemon run as a daemon once per n seconds\n", stderr); fputs(" -f, --poprc specify alternate config file\n", stderr); fputs(" -u, --username specify server user ID\n", stderr); - fputs(" -p, --password specify server password\n", stderr); fputs(" -c, --stdout write received mail to stdout\n", stderr); fputs(" -o, --local specify filename for received mail\n", stderr); fputs(" -r, --remote specify remote folder name\n", stderr); + fputs(" -L, --logfile specify logfile name\n", stderr); return(-1); } else { @@ -332,7 +334,6 @@ struct optrec *options; strcpy(options->loginid,pw->pw_name); options->whichpop = DEF_PROTOCOL; - options->foldertype = OF_SYSMBOX; #if defined(KEEP_IS_DEFAULT) options->keep = 1; @@ -340,7 +341,16 @@ struct optrec *options; options->keep = 0; #endif - strcpy(options->userid,pw->pw_name); + strcpy(options->username,pw->pw_name); + +#if defined(USERFOLDER) && defined(HAVE_FLOCK) + options->output = TO_FOLDER; + sprintf(options->userfolder, USERFOLDER, options->username); +#else + options->output = TO_MDA; +#endif + + (void) sprintf(options->mda, DEF_MDA, options->username); options->poprcfile = (char *) xmalloc(strlen(pw->pw_dir)+strlen(POPRC_NAME)+2); diff --git a/pop2.c b/pop2.c index 3323fda1..3709d8e8 100644 --- a/pop2.c +++ b/pop2.c @@ -23,6 +23,9 @@ description: POP2 client code. $Log: pop2.c,v $ + Revision 1.2 1996/06/26 19:08:57 esr + This is what I sent Harris. + Revision 1.1 1996/06/24 19:00:51 esr Initial revision @@ -142,21 +145,23 @@ struct optrec *options; } /* open/lock the folder if it is a user folder or stdout */ - if (options->foldertype != OF_SYSMBOX) + if (options->output == TO_FOLDER) if ((mboxfd = openuserfolder(options)) < 0) return(PS_IOERR); /* wait for the POP2 greeting */ if (POP2_stateGREET(socket) != 0) { POP2_quit(socket); - return(PS_PROTOCOL); + status = PS_PROTOCOL; + goto closeUp; } /* log the user onto the server */ - POP2_sendHELO(options->userid,options->password,socket); + POP2_sendHELO(options->username,options->password,socket); if ((number = POP2_stateNMBR(socket)) < 0) { POP2_quit(socket); - return(PS_AUTHFAIL); + status = PS_AUTHFAIL; + goto closeUp; } /* set the remote folder if selected */ @@ -164,7 +169,8 @@ struct optrec *options; POP2_sendFOLD(options->remotefolder,socket); if ((number = POP2_stateNMBR(socket)) < 0) { POP2_quit(socket); - return(PS_PROTOCOL); + status = PS_PROTOCOL; + goto closeUp; } } @@ -182,7 +188,7 @@ struct optrec *options; while (msgsize > 0) { /* open the pipe */ - if (options->foldertype == OF_SYSMBOX) + if (options->output == TO_MDA) if ((mboxfd = openmailpipe(options)) < 0) { POP2_quit(socket); return(PS_IOERR); @@ -190,7 +196,7 @@ struct optrec *options; POP2_sendcmd("RETR",socket); actsize = POP2_stateXFER(msgsize,socket,mboxfd, - options->foldertype == OF_SYSMBOX); + options->output == TO_MDA); if (actsize == msgsize) if (options->keep) POP2_sendcmd("ACKS",socket); @@ -200,14 +206,16 @@ struct optrec *options; POP2_sendcmd("NACK",socket); else { POP2_quit(socket); - return(PS_SOCKET); + status = PS_SOCKET; + goto closeUp; } /* close the pipe */ - if (options->foldertype == OF_SYSMBOX) + if (options->output == TO_MDA) if (closemailpipe(mboxfd) < 0) { POP2_quit(socket); - return(PS_IOERR); + status = PS_IOERR; + goto closeUp; } msgsize = POP2_stateSIZE(socket); @@ -220,7 +228,8 @@ struct optrec *options; status = PS_NOMAIL; } - if (options->foldertype != OF_SYSMBOX) +closeUp: + if (options->output == TO_FOLDER) closeuserfolder(mboxfd); return(status); diff --git a/pop3.c b/pop3.c index 514edab8..4eb8870e 100644 --- a/pop3.c +++ b/pop3.c @@ -23,6 +23,9 @@ description: POP3 client code. $Log: pop3.c,v $ + Revision 1.2 1996/06/26 19:08:58 esr + This is what I sent Harris. + Revision 1.1 1996/06/24 18:56:35 esr Initial revision @@ -86,7 +89,7 @@ int POP3_sendSTAT (int *msgcount, int socket); int POP3_sendRETR (int msgnum, int socket); int POP3_sendDELE (int msgnum, int socket); int POP3_sendLAST (int *last, int socket); -int POP3_readmsg (int socket, int mboxfd, int topipe); +int POP3_readmsg (int socket, int mboxfd, char *host, int topipe); int POP3_BuildDigest (char *buf, struct optrec *options); #endif @@ -118,15 +121,16 @@ struct optrec *options; int first,number,count; - /* open the folder if we're not using the system mailbox */ - if (options->foldertype != OF_SYSMBOX) + /* open/lock the folder if we're using a mailbox */ + if (options->output == TO_FOLDER) if ((mboxfd = openuserfolder(options)) < 0) return(PS_IOERR); /* open the socket and get the greeting */ if ((socket = Socket(servername,POP3_PORT)) < 0) { perror("doPOP3: socket"); - return(PS_SOCKET); + ok = PS_SOCKET; + goto closeUp; } ok = POP3_OK(buf,socket); @@ -134,7 +138,7 @@ struct optrec *options; if (ok != PS_SOCKET) POP3_sendQUIT(socket); close(socket); - return(ok); + goto closeUp; } /* print the greeting */ @@ -146,9 +150,10 @@ struct optrec *options; #if defined(HAVE_APOP_SUPPORT) /* build MD5 digest from greeting timestamp + password */ if (options->whichpop == P_APOP) - if (POP3_BuildDigest(buf,options) != 0) - return(PS_AUTHFAIL); - else + if (POP3_BuildDigest(buf,options) != 0) { + ok = PS_AUTHFAIL; + goto closeUp; + } else ; else ; /* not using APOP protocol this time */ @@ -193,8 +198,8 @@ struct optrec *options; number <= count; number++) { - /* open the mail pipe if we're using the system mailbox */ - if (options->foldertype == OF_SYSMBOX + /* open the mail pipe if we're using an MDA */ + if (options->output == TO_MDA && (options->fetchall || number >= first)) { ok = (mboxfd = openmailpipe(options)) < 0 ? -1 : 0; if (ok != 0) @@ -211,7 +216,7 @@ struct optrec *options; goto cleanUp; if (number >= first || options->fetchall) - ok = POP3_readmsg(socket,mboxfd,options->foldertype == OF_SYSMBOX); + ok = POP3_readmsg(socket,mboxfd,servername,options->output == TO_MDA); else ok = 0; if (ok != 0) @@ -230,7 +235,7 @@ struct optrec *options; ; /* message is kept */ /* close the mail pipe if we're using the system mailbox */ - if (options->foldertype == OF_SYSMBOX + if (options->output == TO_MDA && (options->fetchall || number >= first)) { ok = closemailpipe(mboxfd); if (ok != 0) @@ -242,21 +247,22 @@ struct optrec *options; if (ok == 0) ok = PS_SUCCESS; close(socket); - return(ok); + goto closeUp; } else { ok = POP3_sendQUIT(socket); if (ok == 0) ok = PS_NOMAIL; close(socket); - return(ok); + goto closeUp; } cleanUp: if (ok != 0 && ok != PS_SOCKET) POP3_sendQUIT(socket); - if (options->foldertype != OF_SYSMBOX) +closeUp: + if (options->output == TO_FOLDER) if (closeuserfolder(mboxfd) < 0 && ok == 0) ok = PS_IOERR; @@ -342,9 +348,9 @@ int socket; switch (options->whichpop) { case P_POP3: - SockPrintf(socket,"USER %s\r\n",options->userid); + SockPrintf(socket,"USER %s\r\n",options->username); if (outlevel == O_VERBOSE) - fprintf(stderr,"> USER %s\n",options->userid); + fprintf(stderr,"> USER %s\n",options->username); if (POP3_OK(buf,socket) != 0) goto badAuth; @@ -359,9 +365,9 @@ int socket; #if defined(HAVE_APOP_SUPPORT) case P_APOP: SockPrintf(socket,"APOP %s %s\r\n", - options->userid, options->digest); + options->username, options->digest); if (outlevel == O_VERBOSE) - fprintf(stderr,"> APOP %s %s\n",options->userid, options->digest); + fprintf(stderr,"> APOP %s %s\n",options->username, options->digest); if (POP3_OK(buf,socket) != 0) goto badAuth; break; @@ -369,11 +375,11 @@ int socket; #if defined(HAVE_RPOP_SUPPORT) case P_RPOP: - SockPrintf(socket, "RPOP %s\r\n", options->userid); + SockPrintf(socket, "RPOP %s\r\n", options->username); if (POP3_OK(buf,socket) != 0) goto badAuth; if (outlevel == O_VERBOSE) - fprintf(stderr,"> RPOP %s %s\n",options->userid); + fprintf(stderr,"> RPOP %s %s\n",options->username); break; #endif /* HAVE_RPOP_SUPPORT */ @@ -573,7 +579,8 @@ int socket; arguments: socket ... to which the server is connected. mboxfd open file descriptor to which the retrieved message will - be written. + be written. + pophost name of the POP host topipe true if we're writing to the system mailbox pipe. return value: zero if success else PS_* return code. @@ -581,9 +588,10 @@ int socket; globals: reads outlevel. *********************************************************************/ -int POP3_readmsg (socket,mboxfd,topipe) +int POP3_readmsg (socket,mboxfd,pophost,topipe) int socket; int mboxfd; +char *pophost; int topipe; { char buf [MSGBUFSIZE]; @@ -591,6 +599,7 @@ int topipe; char savec; char fromBuf[MSGBUFSIZE]; int needFrom; + int inheaders; int lines,sizeticker; time_t now; /* This keeps the retrieved message count for display purposes */ @@ -609,12 +618,15 @@ int topipe; ; /* read the message content from the server */ + inheaders = 1; lines = 0; sizeticker = MSGBUFSIZE; while (1) { if (SockGets(socket,buf,sizeof(buf)) < 0) return(PS_SOCKET); bufp = buf; + if (buf[0] == '\r' || buf[0] == '\n') + inheaders = 0; if (*bufp == '.') { bufp++; if (*bufp == 0) @@ -622,7 +634,7 @@ int topipe; } strcat(bufp,"\n"); - /* Check for Unix 'From' header, and a bogus one if it's not + /* Check for Unix 'From' header, and add a bogus one if it's not present -- only if not using an MDA. XXX -- should probably parse real From: header and use its address field instead of bogus 'POPmail' string. @@ -646,6 +658,12 @@ int topipe; } } + /* + * Edit some headers so that replies will work properly. + */ + if (inheaders) + reply_hack(bufp, pophost); + /* write this line to the file */ if (write(mboxfd,bufp,strlen(bufp)) < 0) { perror("POP3_readmsg: write"); diff --git a/rcfile_l.l b/rcfile_l.l index 9b37da55..6d932015 100644 --- a/rcfile_l.l +++ b/rcfile_l.l @@ -25,6 +25,9 @@ description: .poprc lexer $Log: rcfile_l.l,v $ + Revision 1.2 1996/06/26 19:09:01 esr + This is what I sent Harris. + Revision 1.1 1996/06/24 18:16:08 esr Initial revision @@ -60,18 +63,26 @@ #include "poproto.h" #include "poprc_y.h" -int prc_lineno = 0; +int prc_lineno = 1; %} %% +defaults { return KW_DEFAULTS; } server { return KW_SERVER; } proto(col)? { return KW_PROTOCOL; } user(name)? { return KW_USERNAME; } pass(word)? { return KW_PASSWORD; } remote(folder)? { return KW_REMOTEFOLDER; } local(folder)? { return KW_LOCALFOLDER; } +mda { return KW_MDA; } +keep { yylval.flag = 1; return KW_KEEP; } +flush { yylval.flag = 1; return KW_FLUSH; } +fetchall { yylval.flag = 1; return KW_FETCHALL; } +nokeep { yylval.flag = -1; return KW_KEEP; } +noflush { yylval.flag = -1; return KW_FLUSH; } +nofetchall { yylval.flag = -1; return KW_FETCHALL; } (pop2)|(POP2) { yylval.proto = P_POP2; return PROTO_POP2; } (pop3)|(POP3) { yylval.proto = P_POP3; return PROTO_POP3; } @@ -84,6 +95,11 @@ local(folder)? { return KW_LOCALFOLDER; } (#.*)?\n { prc_lineno++; return KW_EOL; } [^ \t\r\n#]+ { yylval.sval = (char *) strdup(yytext); return PARAM_STRING; } +\"[^\"]*\"` { + yytext[strlen(yytext)-1] = '\0'; + yylval.sval = (char *) strdup(yytext+1); + return PARAM_STRING; + } [ \t\r]+ ; /* whitespace */ diff --git a/rcfile_y.y b/rcfile_y.y index f3adc0e8..07d773ce 100644 --- a/rcfile_y.y +++ b/rcfile_y.y @@ -24,6 +24,9 @@ description: .poprc parser $Log: rcfile_y.y,v $ + Revision 1.2 1996/06/26 19:09:01 esr + This is what I sent Harris. + Revision 1.1 1996/06/24 18:17:24 esr Initial revision @@ -60,18 +63,22 @@ extern char *prc_pathname; extern int prc_lineno; extern int prc_errflag; -extern char yytext[]; +extern char *yytext; + +int yydebug; /* in case we didn't generate with -- debug */ %} %union { int proto; + int flag; char *sval; } %token KW_SERVER KW_PROTOCOL KW_USERNAME KW_PASSWORD -%token KW_REMOTEFOLDER KW_LOCALFOLDER KW_EOL +%token KW_REMOTEFOLDER KW_LOCALFOLDER KW_MDA KW_EOL KW_DEFAULTS %token PROTO_POP2 PROTO_POP3 PROTO_IMAP PROTO_APOP PROTO_RPOP %token PARAM_STRING +%token KW_KEEP KW_FLUSH KW_FETCHALL %type proto; %% @@ -89,6 +96,7 @@ statement: define_server: KW_SERVER PARAM_STRING server_options {prc_setserver($2);} | KW_SERVER PARAM_STRING {prc_setserver($2);} + | KW_DEFAULTS server_options {prc_setserver("defaults");} ; server_options: serv_option_clause @@ -101,6 +109,10 @@ serv_option_clause: | KW_PASSWORD PARAM_STRING {prc_setpassword($2);} | KW_REMOTEFOLDER PARAM_STRING {prc_setremote($2);} | KW_LOCALFOLDER PARAM_STRING {prc_setlocal($2);} + | KW_MDA PARAM_STRING {prc_setmda($2);} + | KW_KEEP {prc_setkeep($1);} + | KW_FLUSH {prc_setflush($1);} + | KW_FETCHALL {prc_setfetchall($1);} ; proto: PROTO_POP2 diff --git a/sample.rcfile b/sample.rcfile index 9d81b38f..a6973156 100644 --- a/sample.rcfile +++ b/sample.rcfile @@ -1,6 +1,9 @@ # .poprc sample # # $Log: sample.rcfile,v $ +# Revision 1.2 1996/06/26 19:09:01 esr +# This is what I sent Harris. +# # Revision 1.1 1996/06/25 16:50:31 esr # Initial revision # @@ -53,6 +56,13 @@ # password (or pass) # remotefolder (or remote) # localfolder (or local) +# mda +# keep +# flush +# fetchall +# nokeep +# noflush +# nofetchall # # Legal protocol identifiers are # pop2 (or POP2) -- 2.43.2