]> Pileus Git - ~andy/fetchmail/commitdiff
This is what I sent Harris.
authorEric S. Raymond <esr@thyrsus.com>
Wed, 26 Jun 1996 19:09:01 +0000 (19:09 -0000)
committerEric S. Raymond <esr@thyrsus.com>
Wed, 26 Jun 1996 19:09:01 +0000 (19:09 -0000)
svn path=/trunk/; revision=9

13 files changed:
Makefile.in
README
configure.in
daemon.c
fetchmail.c
fetchmail.h
fetchmail.man
options.c
pop2.c
pop3.c
rcfile_l.l
rcfile_y.y
sample.rcfile

index 7f061806a1bcde524a87eac2d7e94d31674e31e6..83171e55d6883fbb11bbe6fed9a520b7681bd572 100644 (file)
@@ -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 <config.h>'' rather than
diff --git a/README b/README
index fa94f5d14a0d50867738b429b7f0aa5c041c1b83..c2894ba9e7fd7fe4ec7f62ad8ece2c015eb7b305 100644 (file)
--- 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 <esr@thyrsus.com> 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
index 35e14591bb3093fa8b6b5bcb786e447a49b5604d..6b4d1ccf826f6884aa4757dfdf4bebd745828b58 100644 (file)
@@ -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 <sys/types.h>
+AC_MSG_CHECKING(for union wait);
+AC_TRY_LINK([#include <sys/types.h>
 #include <sys/wait.h>],
                 [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 <signal.h>
+AC_MSG_CHECKING(sys_siglist declaration in signal.h or unistd.h)
+AC_TRY_LINK([#include <signal.h>
 /* NetBSD declares sys_siglist in <unistd.h>.  */
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #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
index 56aab4ef0b80d6d11f2c1cce662e336577b93e8a..cdfb35f91c0df36c5f505ec81a90fcbdbf57d0ad 100644 (file)
--- 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); 
 
 }
index 7a04ca2c4bace710d427c0e41e3d3b119a0b45a5..10bff927feccb9b369d9411eca2e7d048514af2d 100644 (file)
@@ -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
 
 /* 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';
 }
+
index 63b8ca700897d5b7710917d7799e85c0d6cfc864..814605adcaa10aff3ae0a115bb22df9b448348c3 100644 (file)
@@ -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
 
 #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 */
 #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
 
index 03c3275f249f1ad2f596cf7e0b7740166fc709ae..46ee9f94c9c210e93c86ccd0054c5eea38a7b0cd 100644 (file)
@@ -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 <esr@snark.thyrsus.com>.
 .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.
index f8bda4b275df433031000ef6e755b4e93929ed2a..47c920940823cc508ade24c949e43f3c9095a6f3 100644 (file)
--- 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
 
 #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 3323fda1f72e9ae034cec96bce6c1c82d5e88ecf..3709d8e8876d3f8412a7a081b66218ff1acec5d1 100644 (file)
--- 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 514edab88d6a664df01b96ba1e7228590488172b..4eb8870e58f27e1ed11f4a6d16da05d3471f07a0 100644 (file)
--- 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");
index 9b37da558f0d76005c4b8d70cfd9c80063c71ef6..6d93201537b81288f0eeddef1c4b80c941df11fd 100644 (file)
@@ -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
 
 #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 */
 
index f3adc0e894be0c2a809bbbef86be328d992de5f9..07d773ce933810c9dc81fe2a56e8f96f46d625e5 100644 (file)
@@ -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
 
 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> PROTO_POP2 PROTO_POP3 PROTO_IMAP PROTO_APOP PROTO_RPOP
 %token <sval> PARAM_STRING
+%token <flag> KW_KEEP KW_FLUSH KW_FETCHALL
 %type <proto> 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
index 9d81b38f2a378c99a5f437a9a2b0971347287f11..a6973156e832786a5e7768a90084ab6a481e4888 100644 (file)
@@ -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
 #
 #   password (or pass)
 #   remotefolder (or remote)
 #   localfolder (or local)
+#   mda
+#   keep
+#   flush
+#   fetchall
+#   nokeep
+#   noflush
+#   nofetchall
 #
 # Legal protocol identifiers are
 #   pop2 (or POP2)