]> Pileus Git - ~andy/fetchmail/blob - fetchmail.c
39f70074c6b28b4bba5a90824956aad5e9223c31
[~andy/fetchmail] / fetchmail.c
1 /*
2  * fetchmail.c -- main driver module for fetchmail
3  *
4  * For license terms, see the file COPYING in this directory.
5  */
6
7 #include <config.h>
8
9 #include <stdio.h>
10 #include <ctype.h>
11 #if defined(STDC_HEADERS)
12 #include <stdlib.h>
13 #endif
14 #if defined(HAVE_UNISTD_H)
15 #include <unistd.h>
16 #endif
17 #if defined(HAVE_ALLOCA_H)
18 #include <alloca.h>
19 #endif
20 #include <string.h>
21 #include <signal.h>
22 #if defined(HAVE_SYSLOG)
23 #include <syslog.h>
24 #endif
25 #include <pwd.h>
26 #include <errno.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/wait.h>
31
32 #ifdef HAVE_GETHOSTBYNAME
33 #include <netdb.h>
34 #endif /* HAVE_GETHOSTBYNAME */
35
36 #include "fetchmail.h"
37 #include "tunable.h"
38 #include "smtp.h"
39 #include "getopt.h"
40 #include "netrc.h"
41
42 #define DROPDEAD        6       /* maximum bad socket opens */
43
44 /* prototypes for internal functions */
45 static int load_params(int, char **, int);
46 static void dump_params (struct query *);
47 static int query_host(struct query *);
48 static char *visbuf(const char *);
49
50 /* controls the detail level of status/progress messages written to stderr */
51 int outlevel;           /* see the O_.* constants above */
52 int yydebug;            /* enable parse debugging */
53
54 /* daemon mode control */
55 int poll_interval;      /* poll interval in seconds */
56 int nodetach;           /* if TRUE, don't detach daemon process */
57 char *logfile;          /* log file for daemon mode */
58 int use_syslog;         /* if --syslog was set */
59 int quitmode;           /* if --quit was set */
60 int check_only;         /* if --probe was set */
61 char *cmd_logfile;      /* if --logfile was set */
62
63 /* miscellaneous global controls */
64 char *rcfile;           /* path name of rc file */
65 char *idfile;           /* UID list file */
66 int versioninfo;        /* emit only version info */
67 char *user;             /* the name of the invoking user */
68 char *program_name;     /* the name to prefix error messages with */
69
70 static char *lockfile;          /* name of lockfile */
71 static int querystatus;         /* status of query */
72 static int lastsig;             /* last signal received */
73
74 static void termhook();         /* forward declaration of exit hook */
75
76 RETSIGTYPE donothing(sig) int sig; {signal(sig, donothing); lastsig = sig;}
77
78 static void unlockit(void)
79 /* must-do actions for exit (but we can't count on being able to do malloc) */
80 {
81     unlink(lockfile);
82 }
83
84 int main (int argc, char **argv)
85 {
86     int st, bkgd = FALSE;
87     int parsestatus, implicitmode;
88     char *home, *tmpdir, tmpbuf[BUFSIZ]; 
89     struct passwd *pw;
90     struct query *ctl;
91     FILE        *lockfp;
92     netrc_entry *netrc_list;
93     char *netrc_file;
94     pid_t pid;
95
96     if ((program_name = strrchr(argv[0], '/')) != NULL)
97         ++program_name;
98     else
99         program_name = argv[0];
100
101     if ((user = getenv("USER")) == (char *)NULL)
102         user = getenv("LOGNAME");
103
104     if ((user == (char *)NULL) || (home = getenv("HOME")) == (char *)NULL)
105     {
106         if ((pw = getpwuid(getuid())) != NULL)
107         {
108             user = pw->pw_name;
109             home = pw->pw_dir;
110         }
111         else
112         {
113             fprintf(stderr,"fetchmail: can't find your name and home directory!\n");
114             exit(PS_UNDEFINED);
115         }
116     }
117
118     /*
119      * Backward-compatibility hack.  If we're called by the name of the
120      * ancestral popclient, look for .poprc.  This will actually work 
121      * for popclient files that don't use the removed keywords.
122      */
123     if (strcmp("popclient", argv[0]) == 0)
124         tmpdir = ".poprc";
125     else
126         tmpdir = ".fetchmailrc";
127
128     rcfile = (char *) xmalloc(strlen(home)+strlen(tmpdir)+2);
129     strcpy(rcfile, home);
130     strcat(rcfile, "/");
131     strcat(rcfile, tmpdir);
132
133 #define IDFILE_NAME     ".fetchids"
134     idfile = (char *) xmalloc(strlen(home)+strlen(IDFILE_NAME)+2);
135     strcpy(idfile, home);
136     strcat(idfile, "/");
137     strcat(idfile, IDFILE_NAME);
138   
139     outlevel = O_NORMAL;
140
141     if ((parsestatus = parsecmdline(argc,argv,&cmd_opts)) < 0)
142         exit(PS_SYNTAX);
143
144     /* this hint to stdio should help messages come out in the right order */
145     setvbuf(stdout, NULL, _IOLBF, POPBUFSIZE);
146
147     if (versioninfo)
148         printf("This is fetchmail release %s pl %s\n", RELEASE_ID, PATCHLEVEL);
149
150     /* avoid parsing the config file if all we're doing is killing a daemon */ 
151     if (!quitmode)
152         implicitmode = load_params(argc, argv, optind);
153
154     /* set up to do lock protocol */
155     if (!getuid())
156         strcpy(tmpbuf, "/var/run/fetchmail.pid");
157     else {
158         strcpy(tmpbuf, home);
159         strcat(tmpbuf, "/.fetchmail");
160     }
161
162     /* perhaps we just want to check options? */
163     if (versioninfo) {
164         printf("Taking options from command line");
165         if (access(rcfile, 0))
166             printf("\n");
167         else
168             printf(" and %s\n", rcfile);
169         if (outlevel == O_VERBOSE)
170             printf("Lockfile at %s\n", tmpbuf);
171         for (ctl = querylist; ctl; ctl = ctl->next) {
172             if (ctl->active && !(implicitmode && ctl->server.skip))
173                 dump_params(ctl);
174         }
175         if (querylist == NULL)
176             (void) fprintf(stderr,
177                 "No mailservers set up -- perhaps %s is missing?\n", rcfile);
178         exit(0);
179     }
180     else if (!quitmode && querylist == NULL) {
181         (void) fputs("fetchmail: no mailservers have been specified.\n", stderr);
182         exit(PS_SYNTAX);
183     }
184
185     /* check for another fetchmail running concurrently */
186     pid = -1;
187     if ((lockfile = (char *) malloc(strlen(tmpbuf) + 1)) == NULL)
188     {
189         fprintf(stderr,"fetchmail: cannot allocate memory for lock name.\n");
190         exit(PS_EXCLUDE);
191     }
192     else
193         (void) strcpy(lockfile, tmpbuf);
194     if ((lockfp = fopen(lockfile, "r")) != NULL )
195     {
196         bkgd = (fscanf(lockfp,"%d %d", &pid, &st) == 2);
197
198         if (kill(pid, 0) == -1) {
199             fprintf(stderr,"fetchmail: removing stale lockfile\n");
200             pid = -1;
201             bkgd = FALSE;
202             unlink(lockfile);
203         }
204         fclose(lockfp);
205     }
206
207     /* perhaps user asked us to kill the other fetchmail */
208     if (quitmode)
209     {
210         if (pid == -1) 
211         {
212             fprintf(stderr,"fetchmail: no other fetchmail is running\n");
213             exit(PS_EXCLUDE);
214         }
215         else if (kill(pid, SIGTERM) < 0)
216         {
217             fprintf(stderr,"fetchmail: error killing %s fetchmail at %d.\n",
218                     bkgd ? "background" : "foreground", pid);
219             exit(PS_EXCLUDE);
220         }
221         else
222         {
223             fprintf(stderr,"fetchmail: %s fetchmail at %d killed.\n",
224                     bkgd ? "background" : "foreground", pid);
225             unlink(lockfile);
226             exit(0);
227         }
228     }
229
230     /* another fetchmail is running -- wake it up or die */
231     if (pid != -1)
232     {
233         if (check_only)
234         {
235             fprintf(stderr,
236                  "fetchmail: can't check mail while another fetchmail to same host is running.");
237             return(PS_EXCLUDE);
238         }
239         else if (!implicitmode)
240         {
241             fprintf(stderr,
242                  "fetchmail: can't poll specified hosts with another fetchmail running at %d.\n",
243                  pid);
244                 return(PS_EXCLUDE);
245         }
246         else if (!bkgd)
247         {
248             fprintf(stderr,
249                  "fetchmail: another foreground fetchmail is running at %d.\n",
250                  pid);
251                 return(PS_EXCLUDE);
252         }
253         else if (kill(pid, SIGUSR1) == 0)
254         {
255             fprintf(stderr,
256                     "fetchmail: background fetchmail at %d awakened.\n",
257                     pid);
258             return(0);
259         }
260         else
261         {
262             /*
263              * Should never happen -- possible only if a background fetchmail
264              * croaks after the first kill probe above but before the SIGUSR1/SIGHUP
265              * transmission.
266              */
267             fprintf(stderr,
268                     "fetchmail: elder sibling at %d died mysteriously.\n",
269                     pid);
270             return(PS_UNDEFINED);
271         }
272     }
273
274     /* parse the ~/.netrc file, for future password lookups. */
275     netrc_file = (char *) xmalloc (strlen (home) + 8);
276     strcpy (netrc_file, home);
277     strcat (netrc_file, "/.netrc");
278
279     netrc_list = parse_netrc (netrc_file);
280
281     /* pick up interactively any passwords we need but don't have */ 
282     for (ctl = querylist; ctl; ctl = ctl->next)
283         if (ctl->active && !(implicitmode && ctl->server.skip) && !ctl->password)
284         {
285             if (ctl->server.authenticate == A_KERBEROS)
286                 /* Server won't care what the password is, but there
287                    must be some non-null string here.  */
288                 ctl->password = ctl->remotename;
289             else
290             {
291                 /* Look up the host and account in the .netrc file. */
292                 netrc_entry *p = search_netrc(netrc_list,ctl->server.names->id);
293                 while (p && strcmp (p->account, ctl->remotename))
294                     p = search_netrc (p->next, ctl->remotename);
295
296                 if (p)
297                 {
298                     /* We found the entry, so use the password. */
299                     ctl->password = xstrdup(p->password);
300                 }
301             }
302
303             if (!ctl->password)
304             {
305                 (void) sprintf(tmpbuf, "Enter password for %s@%s: ",
306                                ctl->remotename, ctl->server.names->id);
307                 ctl->password = xstrdup((char *)getpassword(tmpbuf));
308             }
309         }
310
311     /*
312      * Maybe time to go to demon mode...
313      */
314 #if defined(HAVE_SYSLOG)
315     if (use_syslog)
316         openlog(program_name, LOG_PID, LOG_MAIL);
317 #endif
318
319     if (poll_interval && !nodetach)
320         daemonize(logfile, termhook);
321
322     /* beyond here we don't want more than one fetchmail running per user */
323     umask(0077);
324     signal(SIGABRT, termhook);
325     signal(SIGINT, termhook);
326     signal(SIGTERM, termhook);
327     signal(SIGALRM, termhook);
328     signal(SIGPIPE, termhook);
329     signal(SIGQUIT, termhook);
330
331     /*
332      * With this simple hack, we make it possible for a foreground 
333      * fetchmail to wake up one in daemon mode.  What we want is the
334      * side effect of interrupting any sleep that may be going on,
335      * forcing fetchmail to re-poll its hosts.
336      */
337     signal(SIGUSR1, donothing);
338
339     /* pacify people who think all system daemons wake up on SIGHUP */
340     if (poll_interval && !getuid())
341         signal(SIGHUP, donothing);
342
343     /* here's the exclusion lock */
344     if ( (lockfp = fopen(lockfile,"w")) != NULL ) {
345         fprintf(lockfp,"%d",getpid());
346         if (poll_interval)
347             fprintf(lockfp," %d", poll_interval);
348         fclose(lockfp);
349         atexit(unlockit);
350     }
351
352     /*
353      * Query all hosts. If there's only one, the error return will
354      * reflect the status of that transaction.
355      */
356     do {
357 #ifdef HAVE_RES_SEARCH
358         sethostent(TRUE);       /* use TCP/IP for mailserver queries */
359 #endif /* HAVE_RES_SEARCH */
360
361         batchcount = 0;
362         for (ctl = querylist; ctl; ctl = ctl->next)
363         {
364             if (ctl->active && !(implicitmode && ctl->server.skip))
365             {
366 #ifdef linux
367                 /* interface_approve() does its own error logging */
368                 if (!interface_approve(&ctl->server))
369                     continue;
370 #endif /* linux */
371
372 #ifdef HAVE_GETHOSTBYNAME
373                 /*
374                  * This functions partly as an optimization and partly
375                  * as a probe to make sure our nameserver is still up.
376                  * The multidrop case (especially) needs it.
377                  */
378                 if (ctl->server.authenticate == A_KERBEROS || MULTIDROP(ctl))
379                 {
380                     struct hostent      *namerec;
381
382                     /* compute the canonical name of the host */
383                     errno = 0;
384                     namerec = gethostbyname(ctl->server.names->id);
385                     if (namerec == (struct hostent *)NULL)
386                     {
387                         error(0, errno,
388                                 "skipping %s poll, ",
389                                 ctl->server.names->id);
390                         if (errno)
391                         {
392                             if (errno == ENETUNREACH)
393                                 break;  /* go to sleep */
394                         }
395 #ifdef HAVE_HERROR              /* NEXTSTEP doesn't */
396                         else
397                             herror("DNS error");
398 #endif /* HAVE_HERROR */
399                         continue;
400                     }
401                     else
402                     {
403                         free(ctl->server.canonical_name);
404                         ctl->server.canonical_name = xstrdup((char *)namerec->h_name);
405                     }
406                 }
407 #endif /* HAVE_GETHOSTBYNAME */
408
409                 querystatus = query_host(ctl);
410                 if (!check_only)
411                     update_str_lists(ctl);
412 #ifdef  linux
413                 if (ctl->server.monitor)
414                     {
415                         /* Allow some time for the link to quiesce.  One
416                          * second is usually sufficient, three is safe.
417                          * Note:  this delay is important - don't remove!
418                          */
419                         sleep(3);
420                         interface_note_activity(&ctl->server);
421                     }
422 #endif
423             }
424         }
425
426 #ifdef HAVE_RES_SEARCH
427         endhostent();           /* release TCP/IP connection to nameserver */
428 #endif /* HAVE_RES_SEARCH */
429
430         /*
431          * Close all SMTP delivery sockets.  For optimum performance
432          * we'd like to hold them open til end of run, but (1) this
433          * loses if our poll interval is longer than the MTA's inactivity
434          * timeout, and (2) some MTAs (like smail) don't deliver after
435          * each message, but rather queue up mail and wait to actually
436          * deliver it until the input socket is closed. 
437          */
438         for (ctl = querylist; ctl; ctl = ctl->next)
439             if (ctl->smtp_sockfp)
440             {
441                 SMTP_quit(ctl->smtp_sockfp);
442                 fclose(ctl->smtp_sockfp);
443                 ctl->smtp_sockfp = (FILE *)NULL;
444             }
445
446         /*
447          * OK, we've polled.  Now sleep.
448          */
449         if (poll_interval)
450         {
451             if (outlevel == O_VERBOSE)
452             {
453                 time_t  now;
454
455                 time(&now);
456                 fprintf(stderr, "fetchmail: sleeping at %s", ctime(&now));
457             }
458
459             /*
460              * We can't use sleep(3) here because we need an alarm(3)
461              * equivalent in order to implement server nonresponse timeout.
462              * We'll just assume setitimer(2) is available since fetchmail
463              * has to have a BSDoid socket layer to work at all.
464              */
465             {
466                 struct itimerval ntimeout;
467
468                 ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0;
469                 ntimeout.it_value.tv_sec  = poll_interval;
470                 ntimeout.it_value.tv_usec = 0;
471
472                 setitimer(ITIMER_REAL,&ntimeout,NULL);
473                 signal(SIGALRM, donothing);
474                 pause();
475                 signal(SIGALRM, SIG_IGN);
476                 if (lastsig == SIGUSR1
477                         || ((poll_interval && !getuid()) && lastsig == SIGHUP))
478                 {
479 #ifdef SYS_SIGLIST_DECLARED
480                     error(0, 0, "awakened by %s", sys_siglist[lastsig]);
481 #else
482                     error(0, 0, "awakened by signal %d", lastsig);
483 #endif
484                 }
485             }
486
487             if (outlevel == O_VERBOSE)
488             {
489                 time_t  now;
490
491                 time(&now);
492                 fprintf(stderr, "fetchmail: awakened at %s", ctime(&now));
493             }
494         }
495     } while
496         (poll_interval);
497
498     if (outlevel == O_VERBOSE)
499         fprintf(stderr,"fetchmail: normal termination, status %d\n",querystatus);
500
501     termhook(0);
502     exit(querystatus);
503 }
504
505 static int load_params(int argc, char **argv, int optind)
506 {
507     int implicitmode, st;
508     struct passwd *pw;
509     struct query def_opts, *ctl, *mp;
510
511     memset(&def_opts, '\0', sizeof(struct query));
512
513     def_opts.server.protocol = P_AUTO;
514     def_opts.server.timeout = CLIENT_TIMEOUT;
515     def_opts.remotename = user;
516     def_opts.smtphost = "localhost";
517
518     /* this builds the host list */
519     if (prc_parse_file(rcfile) != 0)
520         exit(PS_SYNTAX);
521
522     if ((implicitmode = (optind >= argc)))
523     {
524         for (ctl = querylist; ctl; ctl = ctl->next)
525             ctl->active = TRUE;
526     }
527     else
528         for (; optind < argc; optind++) 
529         {
530             /*
531              * If hostname corresponds to a host known from the rc file,
532              * simply declare it active.  Otherwise synthesize a host
533              * record from command line and defaults
534              */
535             for (ctl = querylist; ctl; ctl = ctl->next)
536                 if (str_in_list(&ctl->server.names, argv[optind]))
537                     goto foundit;
538
539             ctl = hostalloc(&cmd_opts);
540             save_str(&ctl->server.names, -1, argv[optind]);
541
542         foundit:
543             ctl->active = TRUE;
544         }
545
546     /* if there's a defaults record, merge it and lose it */ 
547     if (querylist && strcmp(querylist->server.names->id, "defaults") == 0)
548     {
549         for (ctl = querylist->next; ctl; ctl = ctl->next)
550             optmerge(ctl, querylist);
551         querylist = querylist->next;
552     }
553
554     /* don't allow a defaults record after the first */
555     for (ctl = querylist; ctl; ctl = ctl->next)
556         if (ctl != querylist && strcmp(ctl->server.names->id, "defaults") == 0)
557             exit(PS_SYNTAX);
558
559     /* merge in wired defaults, do sanity checks and prepare internal fields */
560     for (ctl = querylist; ctl; ctl = ctl->next)
561     {
562         if (ctl->active && !(implicitmode && ctl->server.skip))
563         {
564             /* merge in defaults */
565             optmerge(ctl, &def_opts);
566
567             /* keep lusers from shooting themselves in the foot :-) */
568             if (poll_interval && ctl->limit)
569             {
570                 fprintf(stderr,"fetchmail: you'd never see large messages!\n");
571                 exit(PS_SYNTAX);
572             }
573
574             /* make sure delivery will default to a real local user */
575             if ((pw = getpwnam(user)) == (struct passwd *)NULL)
576             {
577                 fprintf(stderr,
578                         "fetchmail: can't set up default delivery to %s\n", user);
579                 exit(PS_SYNTAX);        /* has to be from bad rc file */
580             }
581             else
582             {
583                 ctl->uid = pw->pw_uid;  /* for local delivery via MDA */
584                 if (!ctl->localnames)   /* for local delivery via SMTP */
585                     save_str_pair(&ctl->localnames, user, NULL);
586             }
587
588 #if !defined(HAVE_GETHOSTBYNAME) || !defined(HAVE_RES_SEARCH)
589             /* can't handle multidrop mailboxes unless we can do DNS lookups */
590             if (ctl->localnames && ctl->localnames->next)
591             {
592                 fputs("fetchmail: can't handle multidrop mailboxes without DNS\n",
593                         stderr);
594                 exit(PS_SYNTAX);
595             }
596 #endif /* !HAVE_GETHOSTBYNAME || !HAVE_RES_SEARCH */
597
598             /*
599              * Assign SMTP leaders.  We want to allow all query blocks
600              * sharing the same server/SMTP-host pair to use the same
601              * SMTP connection.  To accomplish this, we initialize
602              * each query block's leader field to point to the first
603              * block in the list with a matching server/SMTP-host pair.
604              *
605              * In the typical case, there will be only one SMTP host (the
606              * client machine) and thus just one SMTP leader (and one listener
607              * process) through the entire poll cycle.
608              */
609             if (!ctl->mda)
610             {
611                 ctl->smtp_sockfp = (FILE *)NULL;
612                 for (mp = querylist; mp && mp != ctl; mp = mp->next)
613                     if (!strcmp(mp->server.names->id, ctl->server.names->id)
614                         && !strcmp(mp->smtphost, ctl->smtphost))
615                     {
616                         ctl->lead_smtp = mp->lead_smtp;
617                         goto no_new_leader;
618                     }
619                 ctl->lead_smtp = ctl;
620             no_new_leader:;
621             }
622
623             /* similarly, compute server leaders for queries */
624             for (mp = querylist; mp && mp != ctl; mp = mp->next)
625                 if (strcmp(mp->server.names->id, ctl->server.names->id) == 0)
626                 {
627                     ctl->server.lead_server = mp->server.lead_server;
628                     goto no_new_server;
629                 }
630             ctl->server.lead_server = &(ctl->server);
631         no_new_server:;
632
633             /* if stripcr hasn't been set, default it asccording to MDA */
634             if (ctl->stripcr == -1)
635                 ctl->stripcr = (ctl->mda != (char *)NULL); 
636
637             /* plug in the semi-standard way of indicating a mail address */
638             if (ctl->server.envelope == (char *)NULL)
639                 ctl->server.envelope = "X-Envelope-To:";
640
641             /* sanity checks */
642             if (ctl->server.port < 0)
643             {
644                 (void) fprintf(stderr,
645                                "%s configuration invalid, port number cannot be negative",
646                                ctl->server.names->id);
647                 exit(PS_SYNTAX);
648             }
649             if (ctl->server.protocol == P_RPOP && ctl->server.port >= 1024)
650             {
651                 (void) fprintf(stderr,
652                                "%s configuration invalid, RPOP requires a privileged port",
653                                ctl->server.names->id);
654                 exit(PS_SYNTAX);
655             }
656         }
657     }
658
659     /* initialize UID handling */
660     if ((st = prc_filecheck(idfile)) != 0)
661         exit(st);
662     else
663         initialize_saved_lists(querylist, idfile);
664
665     /* if cmd_logfile was explicitly set, use it to override logfile */
666     if (cmd_logfile)
667         logfile = cmd_logfile;
668
669     return(implicitmode);
670 }
671
672 void termhook(int sig)
673 /* to be executed on normal or signal-induced termination */
674 {
675     struct query        *ctl;
676
677     /*
678      * Sending SMTP QUIT on signal is theoretically nice, but led to a 
679      * subtle bug.  If fetchmail was terminated by signal while it was 
680      * shipping message text, it would hang forever waiting for a
681      * command acknowledge.  In theory we could disable the QUIT
682      * only outside of the message send.  In practice, we don't
683      * care.  All mailservers hang up on a dropped TCP/IP connection
684      * anyway.
685      */
686
687     if (sig != 0)
688         error(0, 0, "terminated with signal %d", sig);
689     else
690         /* terminate all SMTP connections cleanly */
691         for (ctl = querylist; ctl; ctl = ctl->next)
692             if (ctl->lead_smtp == ctl && ctl->smtp_sockfp != (FILE *)NULL)
693                 SMTP_quit(ctl->smtp_sockfp);
694
695     if (!check_only)
696         write_saved_lists(querylist, idfile);
697
698     exit(querystatus);
699 }
700
701 static char *showproto(int proto)
702 /* protocol index to protocol name mapping */
703 {
704     switch (proto)
705     {
706     case P_AUTO: return("auto"); break;
707     case P_POP2: return("POP2"); break;
708     case P_POP3: return("POP3"); break;
709     case P_IMAP: return("IMAP"); break;
710     case P_APOP: return("APOP"); break;
711     case P_RPOP: return("RPOP"); break;
712     default: return("unknown?!?"); break;
713     }
714 }
715
716 /*
717  * Sequence of protocols to try when autoprobing, most capable to least.
718  */
719 static const int autoprobe[] = {P_IMAP, P_POP3, P_POP2};
720
721 static int query_host(struct query *ctl)
722 /* perform fetch transaction with single host */
723 {
724     int i, st;
725
726     if (outlevel == O_VERBOSE)
727     {
728         time_t now;
729
730         time(&now);
731         fprintf(stderr, "Querying %s (protocol %s) at %s",
732             ctl->server.names->id, showproto(ctl->server.protocol), ctime(&now));
733     }
734     switch (ctl->server.protocol) {
735     case P_AUTO:
736         for (i = 0; i < sizeof(autoprobe)/sizeof(autoprobe[0]); i++)
737         {
738             ctl->server.protocol = autoprobe[i];
739             if ((st = query_host(ctl)) == PS_SUCCESS || st == PS_NOMAIL || st == PS_AUTHFAIL)
740                 break;
741         }
742         ctl->server.protocol = P_AUTO;
743         return(st);
744         break;
745     case P_POP2:
746         return(doPOP2(ctl));
747         break;
748     case P_POP3:
749     case P_APOP:
750     case P_RPOP:
751         return(doPOP3(ctl));
752         break;
753     case P_IMAP:
754         return(doIMAP(ctl));
755         break;
756     default:
757         error(0, 0, "unsupported protocol selected.");
758         return(PS_PROTOCOL);
759     }
760 }
761
762 void dump_params (struct query *ctl)
763 /* display query parameters in English */
764 {
765     printf("Options for retrieving from %s@%s:\n",
766            ctl->remotename, visbuf(ctl->server.names->id));
767 #ifdef HAVE_GETHOSTBYNAME
768     if (ctl->server.canonical_name)
769         printf("  Canonical DNS name of server is %s.\n", ctl->server.canonical_name);
770 #endif /* HAVE_GETHOSTBYNAME */
771     if (ctl->server.names->next)
772     {
773         struct idlist *idp;
774
775         printf("  Predeclared mailserver aliases:");
776         for (idp = ctl->server.names->next; idp; idp = idp->next)
777             printf(" %s", idp->id);
778         putchar('\n');
779     }
780     if (ctl->server.skip || outlevel == O_VERBOSE)
781         printf("  This host will%s be queried when no host is specified.\n",
782                ctl->server.skip ? " not" : "");
783     if (!ctl->password)
784         printf("  Password will be prompted for.\n");
785     else if (outlevel == O_VERBOSE)
786         if (ctl->server.protocol == P_APOP)
787             printf("  APOP secret = '%s'.\n", visbuf(ctl->password));
788         else if (ctl->server.protocol == P_RPOP)
789             printf("  RPOP id = '%s'.\n", visbuf(ctl->password));
790         else
791             printf("  Password = '%s'.\n", visbuf(ctl->password));
792     if (ctl->server.protocol == P_POP3 
793                 && ctl->server.port == KPOP_PORT
794                 && ctl->server.authenticate == A_KERBEROS)
795         printf("  Protocol is KPOP");
796     else
797         printf("  Protocol is %s", showproto(ctl->server.protocol));
798     if (ctl->server.port)
799         printf(" (using port %d)", ctl->server.port);
800     else if (outlevel == O_VERBOSE)
801         printf(" (using default port)");
802     putchar('.');
803     putchar('\n');
804     if (ctl->server.authenticate == A_KERBEROS)
805             printf("  Kerberos authentication enabled.\n");
806     printf("  Server nonresponse timeout is %d seconds", ctl->server.timeout);
807     if (ctl->server.timeout ==  CLIENT_TIMEOUT)
808         printf(" (default).\n");
809     else
810         printf(".\n");
811     if (ctl->server.localdomains)
812     {
813         struct idlist *idp;
814
815         printf("  Local domains:");
816         for (idp = ctl->server.localdomains; idp; idp = idp->next)
817             printf(" %s", idp->id);
818         putchar('\n');
819     }
820
821     printf("  %s messages will be retrieved (--all %s).\n",
822            ctl->fetchall ? "All" : "Only new",
823            ctl->fetchall ? "on" : "off");
824     printf("  Fetched messages will%s be kept on the server (--keep %s).\n",
825            ctl->keep ? "" : " not",
826            ctl->keep ? "on" : "off");
827     printf("  Old messages will%s be flushed before message retrieval (--flush %s).\n",
828            ctl->flush ? "" : " not",
829            ctl->flush ? "on" : "off");
830     printf("  Rewrite of server-local addresses is %sabled (--norewrite %s).\n",
831            ctl->no_rewrite ? "dis" : "en",
832            ctl->no_rewrite ? "on" : "off");
833     printf("  Carriage-return stripping is %sabled (--stripcr %s).\n",
834            ctl->stripcr ? "en" : "dis",
835            ctl->stripcr ? "on" : "off");
836     if (ctl->limit)
837         printf("  Message size limit is %d bytes (--limit %d).\n", 
838                ctl->limit, ctl->limit);
839     else if (outlevel == O_VERBOSE)
840         printf("  No message size limit (--limit 0).\n");
841     if (ctl->fetchlimit)
842         printf("  Received-message limit is %d (--fetchlimit %d).\n",
843                ctl->fetchlimit, ctl->fetchlimit);
844     else if (outlevel == O_VERBOSE)
845         printf("  No received-message limit (--fetchlimit 0).\n");
846     if (ctl->batchlimit)
847         printf("  SMTP message batch limit is %d.\n", ctl->batchlimit);
848     else if (outlevel == O_VERBOSE)
849         printf("  No SMTP message batch limit.\n");
850     if (ctl->mda)
851         printf("  Messages will be delivered with '%s.'\n", visbuf(ctl->mda));
852     else
853         printf("  Messages will be SMTP-forwarded to '%s'.\n", visbuf(ctl->smtphost));
854     if (ctl->preconnect)
855         printf("  Server connection will be preinitialized with '%s.'\n", visbuf(ctl->preconnect));
856     else if (outlevel == O_VERBOSE)
857         printf("  No preinitialization command.\n");
858     if (!ctl->localnames)
859         printf("  No localnames declared for this host.\n");
860     else
861     {
862         struct idlist *idp;
863         int count = 0;
864
865         for (idp = ctl->localnames; idp; idp = idp->next)
866             ++count;
867
868         printf("  %d local name(s) recognized%s.\n",
869                count,
870                (count == 1 && !strcmp(ctl->localnames->id, user)) ? " (by default)" : "");
871         if (outlevel == O_VERBOSE)
872         {
873             for (idp = ctl->localnames; idp; idp = idp->next)
874                 if (idp->val.id2)
875                     printf("\t%s -> %s\n", idp->id, idp->val.id2);
876                 else
877                     printf("\t%s\n", idp->id);
878             if (ctl->wildcard)
879                 fputs("*\n", stdout);
880         }
881
882         printf("  DNS lookup for multidrop addresses is %sabled.\n",
883                ctl->server.no_dns ? "dis" : "en",
884                ctl->server.no_dns ? "on" : "off");
885
886         if (count > 1)
887             printf("  Envelope header is assumed to be: %s\n", ctl->server.envelope);
888     }
889 #ifdef  linux
890     if (ctl->server.interface)
891         printf("  Connection must be through interface %s.\n", ctl->server.interface);
892     else if (outlevel == O_VERBOSE)
893         printf("  No interface requirement specified.\n");
894     if (ctl->server.monitor)
895         printf("  Polling loop will monitor %s.\n", ctl->server.monitor);
896     else if (outlevel == O_VERBOSE)
897         printf("  No monitor interrface specified.\n");
898 #endif
899
900     if (ctl->server.protocol > P_POP2)
901         if (!ctl->oldsaved)
902             printf("  No UIDs saved from this host.\n");
903         else
904         {
905             struct idlist *idp;
906             int count = 0;
907
908             for (idp = ctl->oldsaved; idp; idp = idp->next)
909                 ++count;
910
911             printf("  %d UIDs saved.\n", count);
912             if (outlevel == O_VERBOSE)
913                 for (idp = ctl->oldsaved; idp; idp = idp->next)
914                     fprintf(stderr, "\t%s\n", idp->id);
915         }
916 }
917
918 /* helper functions for string interpretation and display */
919
920 void escapes(cp, tp)
921 /* process standard C-style escape sequences in a string */
922 const char      *cp;    /* source string with escapes */
923 char            *tp;    /* target buffer for digested string */
924 {
925     while (*cp)
926     {
927         int     cval = 0;
928
929         if (*cp == '\\' && strchr("0123456789xX", cp[1]))
930         {
931             char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
932             int dcount = 0;
933
934             if (*++cp == 'x' || *cp == 'X')
935                 for (++cp; (dp = strchr(hex, *cp)) && (dcount++ < 2); cp++)
936                     cval = (cval * 16) + (dp - hex) / 2;
937             else if (*cp == '0')
938                 while (strchr("01234567",*cp) != (char*)NULL && (dcount++ < 3))
939                     cval = (cval * 8) + (*cp++ - '0');
940             else
941                 while ((strchr("0123456789",*cp)!=(char*)NULL)&&(dcount++ < 3))
942                     cval = (cval * 10) + (*cp++ - '0');
943         }
944         else if (*cp == '\\')           /* C-style character escapes */
945         {
946             switch (*++cp)
947             {
948             case '\\': cval = '\\'; break;
949             case 'n': cval = '\n'; break;
950             case 't': cval = '\t'; break;
951             case 'b': cval = '\b'; break;
952             case 'r': cval = '\r'; break;
953             default: cval = *cp;
954             }
955             cp++;
956         }
957         else
958             cval = *cp++;
959         *tp++ = cval;
960     }
961     *tp = '\0';
962 }
963
964 static char *visbuf(const char *buf)
965 /* visibilize a given string */
966 {
967     static char vbuf[BUFSIZ];
968     char *tp = vbuf;
969
970     while (*buf)
971     {
972         if (isprint(*buf) || *buf == ' ')
973             *tp++ = *buf++;
974         else if (*buf == '\n')
975         {
976             *tp++ = '\\'; *tp++ = 'n';
977             buf++;
978         }
979         else if (*buf == '\r')
980         {
981             *tp++ = '\\'; *tp++ = 'r';
982             buf++;
983         }
984         else if (*buf == '\b')
985         {
986             *tp++ = '\\'; *tp++ = 'b';
987             buf++;
988         }
989         else if (*buf < ' ')
990         {
991             *tp++ = '\\'; *tp++ = '^'; *tp++ = '@' + *buf;
992             buf++;
993         }
994         else
995         {
996             (void) sprintf(tp, "\\0x%02x", *buf++);
997             tp += strlen(tp);
998         }
999     }
1000     *tp++ = '\0';
1001     return(vbuf);
1002 }
1003
1004 /* fetchmail.c ends here */