]> Pileus Git - ~andy/fetchmail/commitdiff
Added autoprobe logic.
authorEric S. Raymond <esr@thyrsus.com>
Mon, 26 Aug 1996 23:19:04 +0000 (23:19 -0000)
committerEric S. Raymond <esr@thyrsus.com>
Mon, 26 Aug 1996 23:19:04 +0000 (23:19 -0000)
svn path=/trunk/; revision=66

NEWS
README
fetchmail.c
fetchmail.man
imap.c
pop2.c
pop3.c
rcfile_l.l
rcfile_y.y

diff --git a/NEWS b/NEWS
index 3e16d0659bfeac96028aeeb55685e52a05fc64c8..1733edf2dd36cf46efbd5b67876a813255e60eb2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,9 @@ S/key for secure challenge-response.
 
 * We have IMAP2bis/IMAP4 suppport.
 
+* Code now autoprobes for a POP3, IMAP, or POP2 server if no protocol is
+  specified.
+
 3.05:
 
 * Experimental support for RFC1725-compliant POP servers with the UIDL
diff --git a/README b/README
index 098e8f394a1be79f12ca79378dad9c2da15a1956..3e8dc07c3da36c18bbd6a5e5bafde83833b68b4c 100644 (file)
--- a/README
+++ b/README
@@ -10,7 +10,8 @@ You can find the latest version of popclient from Eric's home page
 
 Features of POP include:
 
-       * POP2, POP3, APOP and IMAP support
+       * POP2, POP3, APOP and IMAP support with auto-probing for a server
+         on the host if no protocol is specified.
 
        * Easy configuration via command line or free-format .poprc file.
 
index 15d966b385907ae0bc8794afad455822a4d3ddcc..bee75d160185e22425fed2d1e84317048bd57caa 100644 (file)
@@ -90,213 +90,256 @@ main (argc,argv)
 int argc;
 char **argv;
 { 
-  int mboxfd, st;
-  struct hostrec cmd_opts, def_opts;
-  int parsestatus;
-  char *servername; 
-  FILE *tmpfp;
-  pid_t pid;
+    int mboxfd, st;
+    struct hostrec cmd_opts, def_opts;
+    int parsestatus;
+    char *servername; 
+    FILE       *tmpfp;
+    pid_t pid;
 
-  if (setdefaults(&def_opts) != 0)
-    exit(PS_UNDEFINED);
+    if (setdefaults(&def_opts) != 0)
+       exit(PS_UNDEFINED);
 
-  if ((parsestatus = parsecmdline(argc,argv,&cmd_opts)) < 0)
-    exit(PS_SYNTAX);
+    if ((parsestatus = parsecmdline(argc,argv,&cmd_opts)) < 0)
+       exit(PS_SYNTAX);
 
-  if (versioninfo)
-    showversioninfo();
+    if (versioninfo)
+       showversioninfo();
 
-  if (prc_parse_file(poprcfile) != 0)
-    exit(PS_SYNTAX);
+    if (prc_parse_file(poprcfile) != 0)
+       exit(PS_SYNTAX);
 
-  if (optind >= argc)
-    append_server_names(&argc, argv);
+    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;
+    /* build in-core data list on all hosts */
+    while ((servername = getnextserver(argc, argv, &parsestatus)) != (char *)0)
+    {
+       if (strcmp(servername, "defaults") == 0)
+           continue;
 
-    hostp = (struct hostrec *)xmalloc(sizeof(struct hostrec));
+       hostp = (struct hostrec *)xmalloc(sizeof(struct hostrec));
 
-    prc_mergeoptions(servername, &cmd_opts, &def_opts, hostp);
-    strcpy(hostp->servername, servername);
-    parseMDAargs(hostp);
-    hostp->lastid[0] = '\0';
+       prc_mergeoptions(servername, &cmd_opts, &def_opts, hostp);
+       strcpy(hostp->servername, servername);
+       parseMDAargs(hostp);
+       hostp->lastid[0] = '\0';
 
-    hostp->next = hostlist;
-    hostlist = hostp;
-  }
+       hostp->next = hostlist;
+       hostlist = hostp;
+    }
 
-  /* perhaps we just want to check options? */
-  if (versioninfo) {
-    printf("Taking options from command line and %s\n", poprcfile);
-    for (hostp = hostlist; hostp; hostp = hostp->next) {
-      printf("Options for host %s:\n", hostp->servername);
-      dump_params(hostp);
+    /* perhaps we just want to check options? */
+    if (versioninfo) {
+       printf("Taking options from command line and %s\n", poprcfile);
+       for (hostp = hostlist; hostp; hostp = hostp->next) {
+           printf("Options for host %s:\n", hostp->servername);
+           dump_params(hostp);
+       }
+       if (hostlist == NULL)
+           (void) printf("No mailservers set up -- perhaps %s is missing?\n",
+                         poprcfile);
+       exit(0);
+    }
+    else if (hostlist == NULL) {
+       (void) fputs("popclient: no mailservers have been specified.\n", stderr);
+       exit(PS_SYNTAX);
     }
-    if (hostlist == NULL)
-       (void) printf("No mailservers set up -- perhaps %s is missing?\n",
-                     poprcfile);
-    exit(0);
-  }
-  else if (hostlist == NULL) {
-    (void) fputs("popclient: no mailservers have been specified.\n", stderr);
-    exit(PS_SYNTAX);
-  }
-
-  /* set up to do lock protocol */
-  umask(0077);
-  if ((lockfile = (char *) malloc( strlen(getenv("HOME")) + strlen("/.lockfetch-") + HOSTLEN)) == NULL) {
-    fprintf(stderr,"popclient: cannot allocate memory for .lockfetch, exiting.\n");
-    exit(PS_EXCLUDE);
-  }
-  strcpy(lockfile, getenv("HOME"));
-  strcat(lockfile,"/.lockfetch-");
-  gethostname(lockfile+strlen(lockfile),HOSTLEN);
-
-  /* perhaps user asked us to remove a lock */
-  if (quitmode)
+
+    /* set up to do lock protocol */
+    umask(0077);
+    if ((lockfile = (char *) malloc( strlen(getenv("HOME")) + strlen("/.lockfetch-") + HOSTLEN)) == NULL) {
+       fprintf(stderr,"popclient: cannot allocate memory for .lockfetch, exiting.\n");
+       exit(PS_EXCLUDE);
+    }
+    strcpy(lockfile, getenv("HOME"));
+    strcat(lockfile,"/.lockfetch-");
+    gethostname(lockfile+strlen(lockfile),HOSTLEN);
+
+    /* perhaps user asked us to remove a lock */
+    if (quitmode)
     {
-      FILE* fp;
+       FILE* fp;
 
-      if ( (fp = fopen(lockfile, "r")) == NULL ) {
-       fprintf(stderr,"popclient: no other popclient is running\n");
-       return(PS_EXCLUDE);
-      }
+       if ( (fp = fopen(lockfile, "r")) == NULL ) {
+           fprintf(stderr,"popclient: no other popclient is running\n");
+           return(PS_EXCLUDE);
+       }
   
-      fscanf(fp,"%d",&pid);
-      fprintf(stderr,"popclient: killing popclient at PID %d\n",pid);
-      if ( kill(pid,SIGTERM) < 0 )
-       fprintf(stderr,"popclient: error killing the process %d.\n",pid);
-      else
-       fprintf(stderr,"popclient: popclient at %d is dead.\n", pid);
+       fscanf(fp,"%d",&pid);
+       fprintf(stderr,"popclient: killing popclient at PID %d\n",pid);
+       if ( kill(pid,SIGTERM) < 0 )
+           fprintf(stderr,"popclient: error killing the process %d.\n",pid);
+       else
+           fprintf(stderr,"popclient: popclient at %d is dead.\n", pid);
   
-      fclose(fp);
-      remove(lockfile);
-      exit(0);
+       fclose(fp);
+       remove(lockfile);
+       exit(0);
+    }
+
+
+    /* beyond here we don't want more than one popclient running per user */
+    if ( (tmpfp = fopen(lockfile, "r")) != NULL ) {
+       fscanf(tmpfp,"%d",&pid);
+       fprintf(stderr,"Another session appears to be running at pid %d.\nIf you are sure that this is incorrect, remove %s file.\n",pid,lockfile);
+       fclose(tmpfp);
+       return(PS_EXCLUDE);
+    }
+
+    /* let's get stored message IDs from previous transactions */
+    if ((st = prc_filecheck(idfile)) != 0) {
+       return (st);
+    } else if ((tmpfp = fopen(idfile, "r")) != (FILE *)NULL) {
+       char buf[POPBUFSIZE+1], host[HOSTLEN+1], id[IDLEN+1];
+
+       while (fgets(buf, POPBUFSIZE, tmpfp) != (char *)NULL) {
+           if ((st = sscanf(buf, "%s %s\n", host, id)) == 2) {
+               for (hostp = hostlist; hostp; hostp = hostp->next) {
+                   if (strcmp(host, hostp->servername) == 0)
+                       strcpy(hostp->lastid, id);
+               }
+           }
+       }
+       fclose(tmpfp);
+    }
+
+    /*
+     * Maybe time to go to demon mode...
+     */
+    if (poll_interval)
+       daemonize(logfile, termhook);
+
+    /* if not locked, assert a lock */
+    signal(SIGABRT, termhook);
+    signal(SIGINT, termhook);
+    signal(SIGTERM, termhook);
+    signal(SIGALRM, termhook);
+    signal(SIGHUP, termhook);
+    signal(SIGPIPE, termhook);
+    signal(SIGQUIT, termhook);
+    if ( (tmpfp = fopen(lockfile,"w")) != NULL ) {
+       fprintf(tmpfp,"%d",getpid());
+       fclose(tmpfp);
     }
 
+    /*
+     * 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);
+       }
+
+       sleep(poll_interval);
+    } while
+                                                    (poll_interval);
 
-  /* beyond here we don't want more than one popclient running per user */
-  if ( (tmpfp = fopen(lockfile, "r")) != NULL ) {
-    fscanf(tmpfp,"%d",&pid);
-    fprintf(stderr,"Another session appears to be running at pid %d.\nIf you are sure that this is incorrect, remove %s file.\n",pid,lockfile);
-    fclose(tmpfp);
-    return(PS_EXCLUDE);
-  }
-
-  /* let's get stored message IDs from previous transactions */
-  if ((st = prc_filecheck(idfile)) != 0) {
-      return (st);
-  } else if ((tmpfp = fopen(idfile, "r")) != (FILE *)NULL) {
-     char buf[POPBUFSIZE+1], host[HOSTLEN+1], id[IDLEN+1];
-
-     while (fgets(buf, POPBUFSIZE, tmpfp) != (char *)NULL) {
-       if ((st = sscanf(buf, "%s %s\n", host, id)) == 2) {
-         for (hostp = hostlist; hostp; hostp = hostp->next) {
-           if (strcmp(host, hostp->servername) == 0)
-              strcpy(hostp->lastid, id);
-         }
-       }
-     }
-     fclose(tmpfp);
-  }
-
-  /*
-   * Maybe time to go to demon mode...
-   */
-  if (poll_interval)
-    daemonize(logfile, termhook);
-
-  /* if not locked, assert a lock */
-  signal(SIGABRT, termhook);
-  signal(SIGINT, termhook);
-  signal(SIGTERM, termhook);
-  signal(SIGALRM, termhook);
-  signal(SIGHUP, termhook);
-  signal(SIGPIPE, termhook);
-  signal(SIGQUIT, termhook);
-  if ( (tmpfp = fopen(lockfile,"w")) != NULL ) {
-      fprintf(tmpfp,"%d",getpid());
-      fclose(tmpfp);
-  }
-
-  /*
-   * 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);
-      }
-
-      sleep(poll_interval);
-  } while
-      (poll_interval);
-
-  if (outlevel == O_VERBOSE)
-      fprintf(stderr, "normal termination\n");
-
-  termhook(0);
-  exit(popstatus);
+    if (outlevel == O_VERBOSE)
+       fprintf(stderr, "normal termination\n");
+
+    termhook(0);
+    exit(popstatus);
 }
 
 void termhook(int sig)
 {
-  FILE *tmpfp;
-  int idcount = 0;
-
-  if (sig != 0)
-      fprintf(stderr, "terminated with signal %d\n", sig);
+    FILE *tmpfp;
+    int idcount = 0;
 
-  for (hostp = hostlist; hostp; hostp = hostp->next) {
-    if (hostp->lastid[0])
-       idcount++;
-  }
+    if (sig != 0)
+       fprintf(stderr, "terminated with signal %d\n", sig);
 
-  /* write updated last-seen IDs */
-  if (!idcount)
-     unlink(idfile);
-  else if ((tmpfp = fopen(idfile, "w")) != (FILE *)NULL) {
     for (hostp = hostlist; hostp; hostp = hostp->next) {
-      if (hostp->lastid[0])
-        fprintf(tmpfp, "%s %s\n", hostp->servername, hostp->lastid);
+       if (hostp->lastid[0])
+           idcount++;
     }
-    fclose(tmpfp);
-  }
 
-  unlink(lockfile);
-  exit(popstatus);
+    /* write updated last-seen IDs */
+    if (!idcount)
+       unlink(idfile);
+    else if ((tmpfp = fopen(idfile, "w")) != (FILE *)NULL) {
+       for (hostp = hostlist; hostp; hostp = hostp->next) {
+           if (hostp->lastid[0])
+               fprintf(tmpfp, "%s %s\n", hostp->servername, hostp->lastid);
+       }
+       fclose(tmpfp);
+    }
+
+    unlink(lockfile);
+    exit(popstatus);
 }
 
+/*********************************************************************
+  function:      showproto
+  description:   protocol index to name mapping
+  arguments:
+    proto        protocol index
+  return value:  string name of protocol
+  calls:         none.
+  globals:       none.
+ *********************************************************************/
+
+char *showproto(proto)
+int proto;
+{
+    switch (proto)
+    {
+    case P_AUTO: return("auto"); break;
+    case P_POP2: return("POP2"); break;
+    case P_POP3: return("POP3"); break;
+    case P_IMAP: return("IMAP"); break;
+    case P_APOP: return("APOP"); break;
+    case P_RPOP: return("RPOP"); break;
+    default: return("unknown?!?"); break;
+    }
+}
+
+/*
+ * Sequence of protocols to try when autoprobing
+ */
+static const int autoprobe[] = {P_POP3, P_IMAP, P_POP2};
+
 int query_host(queryctl)
 /* perform fetch transaction with single host */
 struct hostrec *queryctl;
 {
-  if (outlevel != O_SILENT)
-  {
-    time_t now;
-
-    time(&now);
-    fprintf(stderr, "popclient: querying %s at %s",
-           queryctl->servername, ctime(&now));
-  }
-  switch (queryctl->protocol) {
-  case P_POP2:
-    return(doPOP2(queryctl));
-    break;
-  case P_POP3:
-  case P_APOP:
-    return(doPOP3(queryctl));
-    break;
-  case P_IMAP:
-    return(doIMAP(queryctl));
-    break;
-  default:
-    fprintf(stderr,"popclient: unsupported protocol selected.\n");
-    return(PS_PROTOCOL);
-  }
+    int i, st;
+
+    if (outlevel != O_SILENT)
+    {
+       time_t now;
+
+       time(&now);
+       fprintf(stderr, "popclient: querying %s (protocol %s) at %s",
+           queryctl->servername, showproto(queryctl->protocol), ctime(&now));
+    }
+    switch (queryctl->protocol) {
+    case P_AUTO:
+       for (i = 0; i < sizeof(autoprobe)/sizeof(autoprobe[0]); i++)
+       {
+           queryctl->protocol = autoprobe[i];
+           if ((st = query_host(queryctl)) == PS_SUCCESS || st == PS_NOMAIL)
+               break;
+       }
+       queryctl->protocol = P_AUTO;
+       return(st);
+       break;
+    case P_POP2:
+       return(doPOP2(queryctl));
+       break;
+    case P_POP3:
+    case P_APOP:
+       return(doPOP3(queryctl));
+       break;
+    case P_IMAP:
+       return(doIMAP(queryctl));
+       break;
+    default:
+       fprintf(stderr,"popclient: unsupported protocol selected.\n");
+       return(PS_PROTOCOL);
+    }
 }
  
 /*********************************************************************
@@ -310,7 +353,7 @@ struct hostrec *queryctl;
 
 int showversioninfo()
 {
-  printf("This is popclient release %s\n",RELEASE_TAG);
+    printf("This is popclient release %s\n",RELEASE_TAG);
 }
 
 /*********************************************************************
@@ -327,70 +370,60 @@ int showversioninfo()
 int dump_params (queryctl)
 struct hostrec *queryctl;
 {
-  char *cp;
-
-  printf("  Username = '%s'\n", queryctl->remotename);
-  printf("  Password = '%s'\n", queryctl->password);
-
-  printf("  Protocol is ");
-  switch (queryctl->protocol)
-  {
-  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",
-        queryctl->keep ? "" : " not",
-        queryctl->keep ? "on" : "off");
-  printf("  %s messages will be retrieved (--all %s).\n",
-        queryctl->fetchall ? "All" : "Only new",
-         queryctl->fetchall ? "on" : "off");
-  printf("  Old messages will%s be flushed before message retrieval (--flush %s).\n",
-        queryctl->flush ? "" : " not",
-         queryctl->flush ? "on" : "off");
-
-  switch(queryctl->output)
-  {
-  case TO_FOLDER:
-    printf("  Messages will be appended to '%s'\n", queryctl->userfolder);
-    break;
-  case TO_MDA:
-    printf("  Messages will be delivered with");
-    for (cp = queryctl->mda; *cp; cp += strlen(cp) + 1) {
-       printf(" %s", cp);
-    }
-    putchar('\n');
-    break;
-  case TO_STDOUT:
-    printf("  Messages will be dumped to standard output\n");
-  default:
-    printf("  Message destination unknown?!?\n");
-  }
-  if (outlevel == O_VERBOSE)
+    char *cp;
+
+    printf("  Username = '%s'\n", queryctl->remotename);
+    printf("  Password = '%s'\n", queryctl->password);
+    printf("  Protocol is %s\n", showproto(queryctl->protocol));
+
+    printf("  Fetched messages will%s be kept on the server (--keep %s).\n",
+          queryctl->keep ? "" : " not",
+          queryctl->keep ? "on" : "off");
+    printf("  %s messages will be retrieved (--all %s).\n",
+          queryctl->fetchall ? "All" : "Only new",
+          queryctl->fetchall ? "on" : "off");
+    printf("  Old messages will%s be flushed before message retrieval (--flush %s).\n",
+          queryctl->flush ? "" : " not",
+          queryctl->flush ? "on" : "off");
+
+    switch(queryctl->output)
     {
-      if (queryctl->output != TO_FOLDER)
-       printf("  (Mail folder would have been '%s')\n", queryctl->userfolder);
-      if (queryctl->output != TO_MDA)
-      {
-       printf("  (MDA would have been");
+    case TO_FOLDER:
+       printf("  Messages will be appended to '%s'\n", queryctl->userfolder);
+       break;
+    case TO_MDA:
+       printf("  Messages will be delivered with");
        for (cp = queryctl->mda; *cp; cp += strlen(cp) + 1) {
-         printf(" %s", cp);
+           printf(" %s", cp);
+       }
+       putchar('\n');
+       break;
+    case TO_STDOUT:
+       printf("  Messages will be dumped to standard output\n");
+    default:
+       printf("  Message destination unknown?!?\n");
+    }
+    if (outlevel == O_VERBOSE)
+    {
+       if (queryctl->output != TO_FOLDER)
+           printf("  (Mail folder would have been '%s')\n", queryctl->userfolder);
+       if (queryctl->output != TO_MDA)
+       {
+           printf("  (MDA would have been");
+           for (cp = queryctl->mda; *cp; cp += strlen(cp) + 1) {
+               printf(" %s", cp);
+           }
+           printf(")\n");
        }
-       printf(")\n");
-      }
     }
 
-  if (linelimit == 0)
-    printf("  No limit on retrieved message length.\n");
-  else
-    printf("  Text retrieved per message will be at most %d bytes.\n",
-          linelimit);
-  if (queryctl->lastid[0])
-    printf("  ID of last message retrieved %s\n", queryctl->lastid);
+    if (linelimit == 0)
+       printf("  No limit on retrieved message length.\n");
+    else
+       printf("  Text retrieved per message will be at most %d bytes.\n",
+              linelimit);
+    if (queryctl->lastid[0])
+       printf("  ID of last message retrieved %s\n", queryctl->lastid);
 }
 
 /*********************************************************************
@@ -410,25 +443,25 @@ struct hostrec *queryctl;
 int openuserfolder (queryctl)
 struct hostrec *queryctl;
 {
-  int fd;
+    int fd;
 
-  if (queryctl->output == TO_STDOUT)
-    return(1);
-  else    /* queryctl->output == TO_FOLDER */
-    if ((fd = open(queryctl->userfolder,O_CREAT|O_WRONLY|O_APPEND,0600)) >= 0) {
+    if (queryctl->output == TO_STDOUT)
+       return(1);
+    else    /* queryctl->output == TO_FOLDER */
+       if ((fd = open(queryctl->userfolder,O_CREAT|O_WRONLY|O_APPEND,0600)) >= 0) {
 #ifdef HAVE_FLOCK
-      if (flock(fd, LOCK_EX) == -1)
-       {
-         close(fd);
-         fd = -1;
-       }
+           if (flock(fd, LOCK_EX) == -1)
+           {
+               close(fd);
+               fd = -1;
+           }
 #endif /* HAVE_FLOCK */
-      return(fd);
-    }
-    else {
-      perror("popclient: openuserfolder: open()");
-      return(-1);
-    }
+           return(fd);
+       }
+       else {
+           perror("popclient: openuserfolder: open()");
+           return(-1);
+       }
   
 }
 
@@ -449,39 +482,39 @@ struct hostrec *queryctl;
 int openmailpipe (queryctl)
 struct hostrec *queryctl;
 {
-  int pipefd [2];
-  int childpid;
-  char binmailargs [80];
-
-  if (pipe(pipefd) < 0) {
-    perror("popclient: openmailpipe: pipe");
-    return(-1);
-  }
-  if ((childpid = fork()) < 0) {
-    perror("popclient: openmailpipe: fork");
-    return(-1);
-  }
-  else if (childpid == 0) {
-
-    /* in child process space */
-    close(pipefd[1]);  /* close the 'write' end of the pipe */
-    close(0);          /* get rid of inherited stdin */
-    if (dup(pipefd[0]) != 0) {
-      fputs("popclient: openmailpipe: dup() failed\n",stderr);
-      exit(1);
+    int pipefd [2];
+    int childpid;
+    char binmailargs [80];
+
+    if (pipe(pipefd) < 0) {
+       perror("popclient: openmailpipe: pipe");
+       return(-1);
+    }
+    if ((childpid = fork()) < 0) {
+       perror("popclient: openmailpipe: fork");
+       return(-1);
     }
+    else if (childpid == 0) {
+
+       /* in child process space */
+       close(pipefd[1]);  /* close the 'write' end of the pipe */
+       close(0);          /* get rid of inherited stdin */
+       if (dup(pipefd[0]) != 0) {
+           fputs("popclient: openmailpipe: dup() failed\n",stderr);
+           exit(1);
+       }
 
-    execv(queryctl->mda, mda_argv+1);
+       execv(queryctl->mda, mda_argv+1);
 
-    /* if we got here, an error occurred */
-    perror("popclient: openmailpipe: exec");
-    return(-1);
+       /* if we got here, an error occurred */
+       perror("popclient: openmailpipe: exec");
+       return(-1);
 
-  }
+    }
 
-  /* in the parent process space */
-  close(pipefd[0]);  /* close the 'read' end of the pipe */
-  return(pipefd[1]);
+    /* in the parent process space */
+    close(pipefd[0]);  /* close the 'read' end of the pipe */
+    return(pipefd[1]);
 }
 
 
@@ -500,18 +533,18 @@ struct hostrec *queryctl;
 int closeuserfolder(fd)
 int fd;
 {
-  int err;
+    int err;
 
-  if (fd != 1) {   /* not stdout */
-    err = close(fd);
-  }   
-  else
-    err = 0;
+    if (fd != 1) {   /* not stdout */
+       err = close(fd);
+    }   
+    else
+       err = 0;
   
-  if (err)
-    perror("popclient: closeuserfolder: close");
+    if (err)
+       perror("popclient: closeuserfolder: close");
 
-  return(err);
+    return(err);
 }
 
 
@@ -531,25 +564,25 @@ int fd;
 int closemailpipe (fd)
 int fd;
 {
-  int err;
-  int childpid;
+    int err;
+    int childpid;
 
-  if (outlevel == O_VERBOSE)
-      fprintf(stderr, "about to close pipe %d\n", fd);
+    if (outlevel == O_VERBOSE)
+       fprintf(stderr, "about to close pipe %d\n", fd);
 
-  err = close(fd);
+    err = close(fd);
 #if defined(STDC_HEADERS)
-  childpid = wait(NULL);
+    childpid = wait(NULL);
 #else
-  childpid = wait((int *) 0);
+    childpid = wait((int *) 0);
 #endif
-  if (err)
-    perror("popclient: closemailpipe: close");
+    if (err)
+       perror("popclient: closemailpipe: close");
 
-  if (outlevel == O_VERBOSE)
-    fprintf(stderr, "closed pipe %d\n", fd);
+    if (outlevel == O_VERBOSE)
+       fprintf(stderr, "closed pipe %d\n", fd);
   
-  return(err);
+    return(err);
 }
 
 
@@ -569,33 +602,33 @@ int fd;
 int parseMDAargs (queryctl)
 struct hostrec *queryctl;
 {
-  int argi;
-  char *argp;
+    int argi;
+    char *argp;
 
-  /* first put the last segment of the MDA pathname in argv[0] */
-  argp = strrchr(queryctl->mda, '/');
-  mda_argv[0] = argp ? (argp + 1) : queryctl->mda;
+    /* first put the last segment of the MDA pathname in argv[0] */
+    argp = strrchr(queryctl->mda, '/');
+    mda_argv[0] = argp ? (argp + 1) : queryctl->mda;
   
-  argp = queryctl->mda;
-  while (*argp != '\0' && isspace(*argp))      /* skip null first arg */
-    argp++;                                    
+    argp = queryctl->mda;
+    while (*argp != '\0' && isspace(*argp))    /* skip null first arg */
+       argp++;                                 
 
-  /* now punch nulls into the delimiting whitespace in the args */
-  for (argi = 1;  
-       *argp != '\0';
-       argi++) {
+    /* now punch nulls into the delimiting whitespace in the args */
+    for (argi = 1;  
+        *argp != '\0';
+        argi++) {
 
-    mda_argv[argi] = argp;     /* store pointer to this argument */
+       mda_argv[argi] = argp;     /* store pointer to this argument */
 
-    /* find end of this argument */
-    while (!(*argp == '\0' || isspace(*argp)))
-      argp++;
+       /* find end of this argument */
+       while (!(*argp == '\0' || isspace(*argp)))
+           argp++;
 
-    /* punch in a null terminator */
-    if (*argp != '\0')
-      *(argp++) = '\0';  
-   }
-  mda_argv[argi] = (char *) 0;
+       /* punch in a null terminator */
+       if (*argp != '\0')
+           *(argp++) = '\0';  
+    }
+    mda_argv[argi] = (char *) 0;
 
 }
 
@@ -618,87 +651,87 @@ void reply_hack(buf, host)
 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';
+    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 955b75d77987b2aaba7f58e5318fc9d0ee32a215..db79f303cdd9fdb9c570920614f1fc28b20157d9 100644 (file)
@@ -112,7 +112,10 @@ machine.  Some possible MDAs are "/usr/formail", "/usr/bin/deliver %s",
 .TP
 .B \--protocol proto
 Specify the protocol to used when communicating with the remote 
-mailserver.  
+mailserver.  If no protocol is specified,
+.I popclient
+will try each of the supported protocols in turn, terminating after
+any successful attempt.
 .I proto 
 may be one of the following:
 .RS
@@ -403,6 +406,7 @@ Legal keywords are:
 .PP
 Legal protocol identifiers are
 
+    auto (or AUTO)
     pop2 (or POP2)
     pop3 (or POP3)
     imap (or IMAP)
diff --git a/imap.c b/imap.c
index bc7884ecc8aefcf41b15871fc0aeaec5843b292f..0e06115292cc641cebe1e55c616efef7df9ad388 100644 (file)
--- a/imap.c
+++ b/imap.c
@@ -98,7 +98,7 @@ struct hostrec *queryctl;
 
     /* print the greeting */
     if (outlevel > O_SILENT && outlevel < O_VERBOSE) 
-       fprintf(stderr,"%s\n",buf);
+       fprintf(stderr,"IMAP greeting: %s\n",buf);
 
     /* try to get authorized */
     ok = IMAP_cmd(socket,
diff --git a/pop2.c b/pop2.c
index 54d2939dd1b9c872cd6d57e3fa310823bd15f532..50c619c9456383c86ed347ac073fa440f6d98b0f 100644 (file)
--- a/pop2.c
+++ b/pop2.c
@@ -312,7 +312,7 @@ int socket;
 
     /* echo the server's greeting to the user */
     if (outlevel > O_SILENT)
-      fprintf(stderr,"%s\n",buf);
+      fprintf(stderr,"POP2 greeting: %s\n",buf);
     else
       ;
     /* is the greeting in the correct format? */
diff --git a/pop3.c b/pop3.c
index 5926389eddd3b70009a2a1c2f7984f77271dba0c..f5623cfd20cac958a6a3dc48601efa498cc399a2 100644 (file)
--- a/pop3.c
+++ b/pop3.c
@@ -93,7 +93,7 @@ struct hostrec *queryctl;
 
   /* print the greeting */
   if (outlevel > O_SILENT && outlevel < O_VERBOSE) 
-    fprintf(stderr,"%s\n",buf);
+    fprintf(stderr,"pop3 greeting: %s\n",buf);
   else 
     ;
 
index d6c0d9ffaa6e7c7b58792b935858f038e2d62261..dfc45cfb217f81db317e36022709bed255a8c93c 100644 (file)
@@ -41,6 +41,7 @@ noflush               { yylval.flag = FALSE; return KW_FLUSH; }
 nofetchall     { yylval.flag = FALSE; return KW_FETCHALL; }
 norewrite      { yylval.flag = FALSE; return KW_REWRITE; }
 
+(auto)|(AUTO)  { yylval.proto = P_AUTO;  return PROTO_AUTO; }
 (pop2)|(POP2)  { yylval.proto = P_POP2;  return PROTO_POP2; }
 (pop3)|(POP3)  { yylval.proto = P_POP3;  return PROTO_POP3; }
 (imap)|(IMAP)  { yylval.proto = P_IMAP;  return PROTO_IMAP; }
index 5b48feee7098716b32e721c2f4eb4e77153a3dec..7232dbaa6ddfe14cf49930c469770a9943261d59 100644 (file)
@@ -31,7 +31,7 @@ int yydebug;  /* in case we didn't generate with -- debug */
 
 %token KW_SERVER KW_PROTOCOL KW_USERNAME KW_PASSWORD
 %token KW_REMOTEFOLDER KW_LOCALFOLDER KW_MDA KW_EOL KW_DEFAULTS
-%token <proto> PROTO_POP2 PROTO_POP3 PROTO_IMAP PROTO_APOP PROTO_RPOP
+%token <proto> PROTO_AUTO PROTO_POP2 PROTO_POP3 PROTO_IMAP PROTO_APOP PROTO_RPOP
 %token <sval> PARAM_STRING
 %token <flag> KW_KEEP KW_FLUSH KW_FETCHALL KW_REWRITE
 %type <proto> proto;