* For license terms, see the file COPYING in this directory.
*/
-#include <config.h>
+#include "config.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
+#if defined(HAVE_SYS_WAIT_H)
#include <sys/wait.h>
+#endif
#include <sys/stat.h>
#include <errno.h>
#if defined(STDC_HEADERS)
#endif
#include <string.h>
+#if defined(__CYGWIN__)
+#include <sys/cygwin.h>
+#endif /* __CYGWIN__ */
+
#include "fetchmail.h"
+#include "i18n.h"
+
+/* parser reads these */
+char *rcfile; /* path name of rc file */
+struct query cmd_opts; /* where to put command-line info */
-struct query cmd_opts; /* where to put command-line info */
+/* parser sets these */
struct query *querylist; /* head of server list (globally visible) */
-int yydebug; /* in case we didn't generate with -- debug */
+int yydebug; /* in case we didn't generate with -- debug */
-static struct query current; /* current server record */
+static struct query current; /* current server record */
static int prc_errflag;
+static struct hostdata *leadentry;
+static flag trailer;
-static void record_current();
-static void user_reset();
-static int reset_server(char *name, int skip);
+static void record_current(void);
+static void user_reset(void);
+static void reset_server(const char *name, int skip);
+
+/* these should be of size PATH_MAX */
+char currentwd[1024] = "", rcfiledir[1024] = "";
/* using Bison, this arranges that yydebug messages will show actual tokens */
extern char * yytext;
char *sval;
}
-%token DEFAULTS POLL SKIP AKA LOCALDOMAINS PROTOCOL
-%token AUTHENTICATE TIMEOUT KPOP KERBEROS4
-%token ENVELOPE USERNAME PASSWORD FOLDER SMTPHOST MDA PRECONNECT LIMIT
-%token IS HERE THERE TO MAP WILDCARD
-%token SET BATCHLIMIT FETCHLIMIT LOGFILE DAEMON SYSLOG INTERFACE MONITOR
-%token <proto> PROTO
+%token DEFAULTS POLL SKIP VIA AKA LOCALDOMAINS PROTOCOL
+%token AUTHENTICATE TIMEOUT KPOP SDPS ENVELOPE QVIRTUAL
+%token USERNAME PASSWORD FOLDER SMTPHOST FETCHDOMAINS MDA BSMTP LMTP
+%token SMTPADDRESS SMTPNAME SPAMRESPONSE PRECONNECT POSTCONNECT LIMIT WARNINGS
+%token INTERFACE MONITOR PLUGIN PLUGOUT
+%token IS HERE THERE TO MAP
+%token BATCHLIMIT FETCHLIMIT FETCHSIZELIMIT FASTUIDL EXPUNGE PROPERTIES
+%token SET LOGFILE DAEMON SYSLOG IDFILE PIDFILE INVISIBLE POSTMASTER BOUNCEMAIL
+%token SPAMBOUNCE SOFTBOUNCE SHOWDOTS
+%token BADHEADER ACCEPT REJECT_
+%token <proto> PROTO AUTHTYPE
%token <sval> STRING
%token <number> NUMBER
-%token NO KEEP FLUSH FETCHALL REWRITE FORCECR STRIPCR DNS PORT UIDL INTERVAL
+%token NO KEEP FLUSH LIMITFLUSH FETCHALL REWRITE FORCECR STRIPCR PASS8BITS
+%token DROPSTATUS DROPDELIVERED
+%token DNS SERVICE PORT UIDL INTERVAL MIMEDECODE IDLE CHECKALIAS
+%token SSL SSLKEY SSLCERT SSLPROTO SSLCERTCK SSLCERTFILE SSLCERTPATH SSLCOMMONNAME SSLFINGERPRINT
+%token PRINCIPAL ESMTPNAME ESMTPPASSWORD
+%token TRACEPOLLS
+
+%expect 2
+
+%destructor { free ($$); } STRING
%%
| statement_list statement
;
-/* future global options should also have the form SET <name> <value> */
-statement : SET LOGFILE MAP STRING {logfile = xstrdup($4);}
- | SET DAEMON NUMBER {poll_interval = $3;}
- | SET SYSLOG {use_syslog = TRUE;}
+optmap : MAP | /* EMPTY */;
+
+/* future global options should also have the form SET <name> optmap <value> */
+statement : SET LOGFILE optmap STRING {run.logfile = prependdir ($4, rcfiledir); free($4);}
+ | SET IDFILE optmap STRING {run.idfile = prependdir ($4, rcfiledir); free($4);}
+ | SET PIDFILE optmap STRING {run.pidfile = prependdir ($4, rcfiledir); free($4);}
+ | SET DAEMON optmap NUMBER {run.poll_interval = $4;}
+ | SET POSTMASTER optmap STRING {run.postmaster = $4;}
+ | SET BOUNCEMAIL {run.bouncemail = TRUE;}
+ | SET NO BOUNCEMAIL {run.bouncemail = FALSE;}
+ | SET SPAMBOUNCE {run.spambounce = TRUE;}
+ | SET NO SPAMBOUNCE {run.spambounce = FALSE;}
+ | SET SOFTBOUNCE {run.softbounce = TRUE;}
+ | SET NO SOFTBOUNCE {run.softbounce = FALSE;}
+ | SET PROPERTIES optmap STRING {run.properties = $4;}
+ | SET SYSLOG {run.use_syslog = TRUE;}
+ | SET NO SYSLOG {run.use_syslog = FALSE;}
+ | SET INVISIBLE {run.invisible = TRUE;}
+ | SET NO INVISIBLE {run.invisible = FALSE;}
+ | SET SHOWDOTS {run.showdots = FLAG_TRUE;}
+ | SET NO SHOWDOTS {run.showdots = FLAG_FALSE;}
/*
* The way the next two productions are written depends on the fact that
*/
| define_server serverspecs {record_current();}
| define_server serverspecs userspecs
+
+/* detect and complain about the most common user error */
+ | define_server serverspecs userspecs serv_option
+ {yyerror(GT_("server option after user options"));}
;
-define_server : POLL STRING {
- if (!reset_server($2, FALSE))
- {
- yyerror("duplicate entry name not allowed");
- YYERROR;
- }
- }
- | SKIP STRING {
- if (!reset_server($2, TRUE))
- {
- yyerror("duplicate entry name not allowed");
- YYERROR;
- }
- }
- | DEFAULTS {
- if (!reset_server("defaults", FALSE))
- {
- yyerror("can't have two default entries");
- YYERROR;
- }
- }
+define_server : POLL STRING {reset_server($2, FALSE); free($2);}
+ | SKIP STRING {reset_server($2, TRUE); free($2);}
+ | DEFAULTS {reset_server("defaults", FALSE);}
;
serverspecs : /* EMPTY */
| serverspecs serv_option
;
-alias_list : STRING {save_str(¤t.server.names,-1,$1);}
- | alias_list STRING {save_str(¤t.server.names,-1,$2);}
+alias_list : STRING {save_str(¤t.server.akalist,$1,0); free($1);}
+ | alias_list STRING {save_str(¤t.server.akalist,$2,0); free($2);}
;
-domain_list : STRING {save_str(¤t.server.localdomains,-1,$1);}
- | domain_list STRING {save_str(¤t.server.localdomains,-1,$2);}
+domain_list : STRING {save_str(¤t.server.localdomains,$1,0); free($1);}
+ | domain_list STRING {save_str(¤t.server.localdomains,$2,0); free($2);}
;
serv_option : AKA alias_list
+ | VIA STRING {current.server.via = $2;}
| LOCALDOMAINS domain_list
| PROTOCOL PROTO {current.server.protocol = $2;}
| PROTOCOL KPOP {
current.server.protocol = P_POP3;
- current.server.authenticate = A_KERBEROS_V4;
- current.server.port = KPOP_PORT;
+
+ if (current.server.authenticate == A_PASSWORD)
+#ifdef KERBEROS_V5
+ current.server.authenticate = A_KERBEROS_V5;
+#else
+ current.server.authenticate = A_KERBEROS_V4;
+#endif /* KERBEROS_V5 */
+ current.server.service = KPOP_PORT;
+ }
+ | PRINCIPAL STRING {current.server.principal = $2;}
+ | ESMTPNAME STRING {current.server.esmtp_name = $2;}
+ | ESMTPPASSWORD STRING {current.server.esmtp_password = $2;}
+ | PROTOCOL SDPS {
+#ifdef SDPS_ENABLE
+ current.server.protocol = P_POP3;
+ current.server.sdps = TRUE;
+#else
+ yyerror(GT_("SDPS not enabled."));
+#endif /* SDPS_ENABLE */
}
| UIDL {current.server.uidl = FLAG_TRUE;}
| NO UIDL {current.server.uidl = FLAG_FALSE;}
- | PORT NUMBER {current.server.port = $2;}
- | INTERVAL NUMBER {current.server.interval = $2;}
- | AUTHENTICATE PASSWORD {current.server.authenticate = A_PASSWORD;}
- | AUTHENTICATE KERBEROS4 {current.server.authenticate = A_KERBEROS_V4;}
- | TIMEOUT NUMBER {current.server.timeout = $2;}
- | ENVELOPE STRING {current.server.envelope = xstrdup($2);}
+ | CHECKALIAS {current.server.checkalias = FLAG_TRUE;}
+ | NO CHECKALIAS {current.server.checkalias = FLAG_FALSE;}
+ | SERVICE STRING {
+ current.server.service = $2;
+ }
+ | SERVICE NUMBER {
+ int port = $2;
+ char buf[10];
+ snprintf(buf, sizeof buf, "%d", port);
+ current.server.service = xstrdup(buf);
+ }
+ | PORT NUMBER {
+ int port = $2;
+ char buf[10];
+ snprintf(buf, sizeof buf, "%d", port);
+ current.server.service = xstrdup(buf);
+ }
+ | INTERVAL NUMBER
+ {current.server.interval = $2;}
+ | AUTHENTICATE AUTHTYPE
+ {current.server.authenticate = $2;}
+ | TIMEOUT NUMBER
+ {current.server.timeout = $2;}
+ | ENVELOPE NUMBER STRING
+ {
+ current.server.envelope = $3;
+ current.server.envskip = $2;
+ }
+ | ENVELOPE STRING
+ {
+ current.server.envelope = $2;
+ current.server.envskip = 0;
+ }
+
+ | QVIRTUAL STRING {current.server.qvirtual = $2;}
| INTERFACE STRING {
-#ifdef linux
+#ifdef CAN_MONITOR
interface_parse($2, ¤t.server);
#else
- fprintf(stderr, "fetchmail: interface option is only supported under Linux\n");
-#endif /* linux */
+ fprintf(stderr, GT_("fetchmail: interface option is only supported under Linux (without IPv6) and FreeBSD\n"));
+#endif
+ free($2);
}
| MONITOR STRING {
-#ifdef linux
- current.server.monitor = xstrdup($2);
+#ifdef CAN_MONITOR
+ current.server.monitor = $2;
#else
- fprintf(stderr, "fetchmail: monitor option is only supported under Linux\n");
-#endif /* linux */
+ fprintf(stderr, GT_("fetchmail: monitor option is only supported under Linux (without IPv6) and FreeBSD\n"));
+ free($2);
+#endif
}
+ | PLUGIN STRING { current.server.plugin = $2; }
+ | PLUGOUT STRING { current.server.plugout = $2; }
| DNS {current.server.dns = FLAG_TRUE;}
| NO DNS {current.server.dns = FLAG_FALSE;}
| NO ENVELOPE {current.server.envelope = STRING_DISABLED;}
+ | TRACEPOLLS {current.server.tracepolls = FLAG_TRUE;}
+ | NO TRACEPOLLS {current.server.tracepolls = FLAG_FALSE;}
+ | BADHEADER ACCEPT {current.server.badheader = BHACCEPT;}
+ | BADHEADER REJECT_ {current.server.badheader = BHREJECT;}
;
-/*
- * The first and only the first user spec may omit the USERNAME part.
- * This is a backward-compatibility kluge to allow old popclient files
- * to keep working.
- */
userspecs : user1opts {record_current(); user_reset();}
- | user1opts explicits
- {
- record_current(); user_reset();
- fprintf(stderr, "Warning: user entry with no `user' keyword\n");
- }
| explicits
;
explicitdef : userdef user0opts
;
-userdef : USERNAME STRING {current.remotename = xstrdup($2);}
+userdef : USERNAME STRING {current.remotename = $2;}
| USERNAME mapping_list HERE
- | USERNAME STRING THERE {current.remotename = xstrdup($2);}
+ | USERNAME STRING THERE {current.remotename = $2;}
;
user0opts : /* EMPTY */
| user1opts user_option
;
-localnames : WILDCARD {current.wildcard = TRUE;}
- | mapping_list {current.wildcard = FALSE;}
- | mapping_list WILDCARD {current.wildcard = TRUE;}
- ;
-
mapping_list : mapping
| mapping_list mapping
;
-mapping : STRING
- {save_str_pair(¤t.localnames, $1, NULL);}
- | STRING MAP STRING
- {save_str_pair(¤t.localnames, $1, $3);}
+mapping : STRING {if (0 == strcmp($1, "*")) {
+ current.wildcard = TRUE;
+ } else {
+ save_str_pair(¤t.localnames, $1, NULL);
+ }
+ free($1);}
+ | STRING MAP STRING {save_str_pair(¤t.localnames, $1, $3); free($1); free($3);}
;
-folder_list : STRING {save_str(¤t.mailboxes,-1,$1);}
- | folder_list STRING {save_str(¤t.mailboxes,-1,$2);}
+folder_list : STRING {save_str(¤t.mailboxes,$1,0); free($1);}
+ | folder_list STRING {save_str(¤t.mailboxes,$2,0); free($2);}
;
-smtp_list : STRING {save_str(¤t.smtphunt, -1, $1);}
- | smtp_list STRING {save_str(¤t.smtphunt, -1, $2);}
+smtp_list : STRING {save_str(¤t.smtphunt, $1,TRUE); free($1);}
+ | smtp_list STRING {save_str(¤t.smtphunt, $2,TRUE); free($2);}
;
-user_option : TO localnames HERE
- | TO localnames
- | IS localnames HERE
- | IS localnames
+fetch_list : STRING {save_str(¤t.domainlist, $1,TRUE); free($1);}
+ | fetch_list STRING {save_str(¤t.domainlist, $2,TRUE); free($2);}
+ ;
+
+num_list : NUMBER
+ {
+ struct idlist *id;
+ id = save_str(¤t.antispam,STRING_DUMMY,0);
+ id->val.status.num = $1;
+ }
+ | num_list NUMBER
+ {
+ struct idlist *id;
+ id = save_str(¤t.antispam,STRING_DUMMY,0);
+ id->val.status.num = $2;
+ }
+ ;
- | IS STRING THERE {current.remotename = xstrdup($2);}
- | PASSWORD STRING {current.password = xstrdup($2);}
+user_option : TO mapping_list HERE
+ | TO mapping_list
+ | IS mapping_list HERE
+ | IS mapping_list
+
+ | IS STRING THERE {current.remotename = $2;}
+ | PASSWORD STRING {current.password = $2;}
| FOLDER folder_list
| SMTPHOST smtp_list
- | MDA STRING {current.mda = xstrdup($2);}
- | PRECONNECT STRING {current.preconnect = xstrdup($2);}
-
- | KEEP {current.keep = FLAG_TRUE;}
- | FLUSH {current.flush = FLAG_TRUE;}
- | FETCHALL {current.fetchall = FLAG_TRUE;}
- | REWRITE {current.rewrite = FLAG_TRUE;}
- | FORCECR {current.forcecr = FLAG_TRUE;}
- | STRIPCR {current.stripcr = FLAG_TRUE;}
-
- | NO KEEP {current.keep = FLAG_FALSE;}
- | NO FLUSH {current.flush = FLAG_FALSE;}
- | NO FETCHALL {current.fetchall = FLAG_FALSE;}
- | NO REWRITE {current.rewrite = FLAG_FALSE;}
- | NO FORCECR {current.forcecr = FLAG_FALSE;}
- | NO STRIPCR {current.stripcr = FLAG_FALSE;}
-
- | LIMIT NUMBER {current.limit = $2;}
- | FETCHLIMIT NUMBER {current.fetchlimit = $2;}
- | BATCHLIMIT NUMBER {current.batchlimit = $2;}
+ | FETCHDOMAINS fetch_list
+ | SMTPADDRESS STRING {current.smtpaddress = $2;}
+ | SMTPNAME STRING {current.smtpname = $2;}
+ | SPAMRESPONSE num_list
+ | MDA STRING {current.mda = $2;}
+ | BSMTP STRING {current.bsmtp = prependdir ($2, rcfiledir); free($2);}
+ | LMTP {current.listener = LMTP_MODE;}
+ | PRECONNECT STRING {current.preconnect = $2;}
+ | POSTCONNECT STRING {current.postconnect = $2;}
+
+ | KEEP {current.keep = FLAG_TRUE;}
+ | FLUSH {current.flush = FLAG_TRUE;}
+ | LIMITFLUSH {current.limitflush = FLAG_TRUE;}
+ | FETCHALL {current.fetchall = FLAG_TRUE;}
+ | REWRITE {current.rewrite = FLAG_TRUE;}
+ | FORCECR {current.forcecr = FLAG_TRUE;}
+ | STRIPCR {current.stripcr = FLAG_TRUE;}
+ | PASS8BITS {current.pass8bits = FLAG_TRUE;}
+ | DROPSTATUS {current.dropstatus = FLAG_TRUE;}
+ | DROPDELIVERED {current.dropdelivered = FLAG_TRUE;}
+ | MIMEDECODE {current.mimedecode = FLAG_TRUE;}
+ | IDLE {current.idle = FLAG_TRUE;}
+
+ | SSL {
+#ifdef SSL_ENABLE
+ current.use_ssl = FLAG_TRUE;
+#else
+ yyerror(GT_("SSL is not enabled"));
+#endif
+ }
+ | SSLKEY STRING {current.sslkey = prependdir ($2, rcfiledir); free($2);}
+ | SSLCERT STRING {current.sslcert = prependdir ($2, rcfiledir); free($2);}
+ | SSLPROTO STRING {current.sslproto = $2;}
+ | SSLCERTCK {current.sslcertck = FLAG_TRUE;}
+ | SSLCERTFILE STRING {current.sslcertfile = prependdir($2, rcfiledir); free($2);}
+ | SSLCERTPATH STRING {current.sslcertpath = prependdir($2, rcfiledir); free($2);}
+ | SSLCOMMONNAME STRING {current.sslcommonname = $2;}
+ | SSLFINGERPRINT STRING {current.sslfingerprint = $2;}
+
+ | NO KEEP {current.keep = FLAG_FALSE;}
+ | NO FLUSH {current.flush = FLAG_FALSE;}
+ | NO LIMITFLUSH {current.limitflush = FLAG_FALSE;}
+ | NO FETCHALL {current.fetchall = FLAG_FALSE;}
+ | NO REWRITE {current.rewrite = FLAG_FALSE;}
+ | NO FORCECR {current.forcecr = FLAG_FALSE;}
+ | NO STRIPCR {current.stripcr = FLAG_FALSE;}
+ | NO PASS8BITS {current.pass8bits = FLAG_FALSE;}
+ | NO DROPSTATUS {current.dropstatus = FLAG_FALSE;}
+ | NO DROPDELIVERED {current.dropdelivered = FLAG_FALSE;}
+ | NO MIMEDECODE {current.mimedecode = FLAG_FALSE;}
+ | NO IDLE {current.idle = FLAG_FALSE;}
+
+ | NO SSL {current.use_ssl = FLAG_FALSE;}
+
+ | LIMIT NUMBER {current.limit = NUM_VALUE_IN($2);}
+ | WARNINGS NUMBER {current.warnings = NUM_VALUE_IN($2);}
+ | FETCHLIMIT NUMBER {current.fetchlimit = NUM_VALUE_IN($2);}
+ | FETCHSIZELIMIT NUMBER {current.fetchsizelimit = NUM_VALUE_IN($2);}
+ | FASTUIDL NUMBER {current.fastuidl = NUM_VALUE_IN($2);}
+ | BATCHLIMIT NUMBER {current.batchlimit = NUM_VALUE_IN($2);}
+ | EXPUNGE NUMBER {current.expunge = NUM_VALUE_IN($2);}
+
+ | PROPERTIES STRING {current.properties = $2;}
;
%%
void yyerror (const char *s)
/* report a syntax error */
{
- error_at_line( 0, 0, rcfile, prc_lineno, "%s at %s", s,
- (yytext && yytext[0]) ? yytext : "end of input");
+ report_at_line(stderr, 0, rcfile, prc_lineno, GT_("%s at %s"), s,
+ (yytext && yytext[0]) ? yytext : GT_("end of input"));
prc_errflag++;
}
-int prc_filecheck(pathname)
-/* check that a configuration file is secure */
-const char *pathname; /* pathname for the configuration file */
+/** check that a configuration file is secure, returns PS_* status codes */
+int prc_filecheck(const char *pathname,
+ const flag securecheck /** shortcuts permission, filetype and uid tests if false */)
{
+#ifndef __EMX__
struct stat statbuf;
errno = 0;
- /* special cases useful for debugging purposes */
- if (strcmp("/dev/null", pathname) == 0 || versioninfo)
- return(0);
+ /* special case useful for debugging purposes */
+ if (strcmp("/dev/null", pathname) == 0)
+ return(PS_SUCCESS);
+
+ /* pass through the special name for stdin */
+ if (strcmp("-", pathname) == 0)
+ return(PS_SUCCESS);
/* the run control file must have the same uid as the REAL uid of this
process, it must have permissions no greater than 600, and it must not
be a symbolic link. We check these conditions here. */
- if (lstat(pathname, &statbuf) < 0) {
+ if (stat(pathname, &statbuf) < 0) {
if (errno == ENOENT)
- return(0);
+ return(PS_SUCCESS);
else {
- error(0, errno, "lstat: %s", pathname);
+ report(stderr, "lstat: %s: %s\n", pathname, strerror(errno));
return(PS_IOERR);
}
}
- if ((statbuf.st_mode & S_IFLNK) == S_IFLNK) {
- fprintf(stderr, "File %s must not be a symbolic link.\n", pathname);
- return(PS_AUTHFAIL);
+ if (!securecheck) return PS_SUCCESS;
+
+ if (!S_ISREG(statbuf.st_mode))
+ {
+ fprintf(stderr, GT_("File %s must be a regular file.\n"), pathname);
+ return(PS_IOERR);
}
- if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE)) {
- fprintf(stderr, "File %s must have no more than -rw------ (0600) permissions.\n",
+#ifndef __BEOS__
+#ifdef __CYGWIN__
+ if (cygwin_internal(CW_CHECK_NTSEC, pathname))
+#endif /* __CYGWIN__ */
+ if (statbuf.st_mode & (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | S_IXOTH))
+ {
+ fprintf(stderr, GT_("File %s must have no more than -rwx------ (0700) permissions.\n"),
pathname);
- return(PS_AUTHFAIL);
+ return(PS_IOERR);
}
+#endif /* __BEOS__ */
- if (statbuf.st_uid != getuid()) {
- fprintf(stderr, "File %s must be owned by you.\n", pathname);
- return(PS_AUTHFAIL);
+#ifdef HAVE_GETEUID
+ if (statbuf.st_uid != geteuid())
+#else
+ if (statbuf.st_uid != getuid())
+#endif /* HAVE_GETEUID */
+ {
+ fprintf(stderr, GT_("File %s must be owned by you.\n"), pathname);
+ return(PS_IOERR);
}
-
- return(0);
+#endif
+ return(PS_SUCCESS);
}
-int prc_parse_file (pathname)
+int prc_parse_file (const char *pathname, const flag securecheck)
/* digest the configuration into a linked list of host records */
-const char *pathname; /* pathname for the configuration file */
{
prc_errflag = 0;
querylist = hosttail = (struct query *)NULL;
+ errno = 0;
+
/* Check that the file is secure */
- if ((prc_errflag = prc_filecheck(pathname)) != 0)
+ if ( (prc_errflag = prc_filecheck(pathname, securecheck)) != 0 )
return(prc_errflag);
- if (errno == ENOENT)
- return(0);
-
- /* Open the configuration and feed it to the lexer. */
- if ((yyin = fopen(pathname,"r")) == (FILE *)NULL) {
- error(0, errno, "open: %s", pathname);
+ /*
+ * Croak if the configuration directory does not exist.
+ * This probably means an NFS mount failed and we can't
+ * see a configuration file that ought to be there.
+ * Question: is this a portable check? It's not clear
+ * that all implementations of lstat() will return ENOTDIR
+ * rather than plain ENOENT in this case...
+ */
+ if (errno == ENOTDIR)
+ return(PS_IOERR);
+ else if (errno == ENOENT)
+ return(PS_SUCCESS);
+
+ /* Open the configuration file and feed it to the lexer. */
+ if (strcmp(pathname, "-") == 0)
+ yyin = stdin;
+ else if ((yyin = fopen(pathname,"r")) == (FILE *)NULL) {
+ report(stderr, "open: %s: %s\n", pathname, strerror(errno));
return(PS_IOERR);
}
yyparse(); /* parse entire file */
- fclose(yyin);
+ fclose(yyin); /* not checking this should be safe, file mode was r */
if (prc_errflag)
return(PS_SYNTAX);
else
- return(0);
+ return(PS_SUCCESS);
}
-static int reset_server(char *name, int skip)
+static void reset_server(const char *name, int skip)
/* clear the entire global record and initialize it with a new name */
{
- struct query *ctl;
-
- /* don't allow name collisions, this screws up the data structures */
- for (ctl = querylist; ctl; ctl = ctl->next)
- if (strcmp(name, ctl->server.names->id) == 0)
- return(FALSE);
-
+ trailer = FALSE;
memset(¤t,'\0',sizeof(current));
current.smtp_socket = -1;
- save_str(¤t.server.names, -1, name);
+ current.server.pollname = xstrdup(name);
current.server.skip = skip;
- return(TRUE);
+ current.server.principal = (char *)NULL;
}
static void user_reset(void)
-/* clear the global current record (server parameters) used by the parser */
+/* clear the global current record (user parameters) used by the parser */
{
struct hostdata save;
current.server = save;
}
-struct query *hostalloc(init)
-/* append a host record to the host list */
-struct query *init; /* pointer to block containing initial values */
+/** append a host record to the host list */
+struct query *hostalloc(struct query *init /** pointer to block containing
+ initial values */)
{
struct query *node;
node = (struct query *) xmalloc(sizeof(struct query));
/* initialize it */
- memcpy(node, init, sizeof(struct query));
+ if (init)
+ memcpy(node, init, sizeof(struct query));
+ else
+ {
+ memset(node, '\0', sizeof(struct query));
+ node->smtp_socket = -1;
+ }
/* append to end of list */
if (hosttail != (struct query *) 0)
else
querylist = node; /* list is empty */
hosttail = node;
+
+ if (trailer)
+ node->server.lead_server = leadentry;
+ else
+ {
+ node->server.lead_server = NULL;
+ leadentry = &node->server;
+ }
+
return(node);
}
static void record_current(void)
/* register current parameters and append to the host list */
{
-#define FLAG_FORCE(fld) if (cmd_opts.fld) current.fld = cmd_opts.fld
- FLAG_FORCE(server.protocol);
- FLAG_FORCE(server.port);
- FLAG_FORCE(server.interval);
- FLAG_FORCE(server.authenticate);
- FLAG_FORCE(server.timeout);
- FLAG_FORCE(server.envelope);
- FLAG_FORCE(server.skip);
- FLAG_FORCE(server.dns);
-
-#ifdef linux
- FLAG_FORCE(server.interface);
- FLAG_FORCE(server.monitor);
- FLAG_FORCE(server.interface_pair);
-#endif /* linux */
-
- FLAG_FORCE(remotename);
- FLAG_FORCE(password);
- if (cmd_opts.mailboxes)
- save_str(¤t.mailboxes, -1, cmd_opts.mailboxes->id);
- if (cmd_opts.smtphunt)
- save_str(¤t.smtphunt, -1, cmd_opts.smtphunt->id);
- FLAG_FORCE(mda);
- FLAG_FORCE(preconnect);
-
- FLAG_FORCE(keep);
- FLAG_FORCE(flush);
- FLAG_FORCE(fetchall);
- FLAG_FORCE(rewrite);
- FLAG_FORCE(forcecr);
- FLAG_FORCE(stripcr);
- FLAG_FORCE(limit);
- FLAG_FORCE(fetchlimit);
- FLAG_FORCE(batchlimit);
-
-#undef FLAG_FORCE
-
(void) hostalloc(¤t);
+ trailer = TRUE;
}
-void optmerge(struct query *h2, struct query *h1)
-/* merge two options records; empty fields in h2 are filled in from h1 */
+char *prependdir (const char *file, const char *dir)
+/* if a filename is relative to dir, convert it to an absolute path */
{
- append_str_list(&h2->server.localdomains, &h1->server.localdomains);
- append_str_list(&h2->localnames, &h1->localnames);
- append_str_list(&h2->mailboxes, &h1->mailboxes);
- append_str_list(&h2->smtphunt, &h1->smtphunt);
-
-#define FLAG_MERGE(fld) if (!h2->fld) h2->fld = h1->fld
- FLAG_MERGE(server.protocol);
- FLAG_MERGE(server.port);
- FLAG_MERGE(server.interval);
- FLAG_MERGE(server.authenticate);
- FLAG_MERGE(server.timeout);
- FLAG_MERGE(server.envelope);
- FLAG_MERGE(server.skip);
- FLAG_MERGE(server.dns);
-
-#ifdef linux
- FLAG_MERGE(server.interface);
- FLAG_MERGE(server.monitor);
- FLAG_MERGE(server.interface_pair);
-#endif /* linux */
-
- FLAG_MERGE(remotename);
- FLAG_MERGE(password);
- FLAG_MERGE(mda);
- FLAG_MERGE(preconnect);
-
- FLAG_MERGE(keep);
- FLAG_MERGE(flush);
- FLAG_MERGE(fetchall);
- FLAG_MERGE(rewrite);
- FLAG_MERGE(forcecr);
- FLAG_MERGE(stripcr);
- FLAG_MERGE(limit);
- FLAG_MERGE(fetchlimit);
- FLAG_MERGE(batchlimit);
-#undef FLAG_MERGE
+ char *newfile;
+ if (!file[0] || /* null path */
+ file[0] == '/' || /* absolute path */
+ strcmp(file, "-") == 0 || /* stdin/stdout */
+ !dir[0]) /* we don't HAVE_GETCWD */
+ return xstrdup (file);
+ newfile = (char *)xmalloc (strlen (dir) + 1 + strlen (file) + 1);
+ if (dir[strlen(dir) - 1] != '/')
+ sprintf (newfile, "%s/%s", dir, file);
+ else
+ sprintf (newfile, "%s%s", dir, file);
+ return newfile;
}
-/* easier to do this than cope with variations in where the library lives */
-int yywrap(void) {return 1;}
-
/* rcfile_y.y ends here */