aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS3
-rw-r--r--README3
-rw-r--r--fetchmail.c837
-rw-r--r--fetchmail.man6
-rw-r--r--imap.c2
-rw-r--r--pop2.c2
-rw-r--r--pop3.c2
-rw-r--r--rcfile_l.l1
-rw-r--r--rcfile_y.y2
9 files changed, 450 insertions, 408 deletions
diff --git a/NEWS b/NEWS
index 3e16d065..1733edf2 100644
--- 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 098e8f39..3e8dc07c 100644
--- 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.
diff --git a/fetchmail.c b/fetchmail.c
index 15d966b3..bee75d16 100644
--- a/fetchmail.c
+++ b/fetchmail.c
@@ -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';
}
diff --git a/fetchmail.man b/fetchmail.man
index 955b75d7..db79f303 100644
--- a/fetchmail.man
+++ b/fetchmail.man
@@ -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 bc7884ec..0e061152 100644
--- 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 54d2939d..50c619c9 100644
--- 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 5926389e..f5623cfd 100644
--- 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
;
diff --git a/rcfile_l.l b/rcfile_l.l
index d6c0d9ff..dfc45cfb 100644
--- a/rcfile_l.l
+++ b/rcfile_l.l
@@ -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; }
diff --git a/rcfile_y.y b/rcfile_y.y
index 5b48feee..7232dbaa 100644
--- a/rcfile_y.y
+++ b/rcfile_y.y
@@ -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;