/*
#ident "@(#)smail/src:RELEASE-3_2_0_121:pathto.c,v 1.24 2005/08/26 19:59:40 woods Exp"
*/
/*
* Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
* Copyright (C) 1992 Ronald S. Karr
*
* See the file COPYING, distributed with smail, for restriction
* and warranty information.
*/
/*
* main.c:
* process arguments, configure environment and process
* messages.
*
* external functions: main, initialize_state, process_args,
* deliver_mail
*/
#include "defs.h"
#include <sys/types.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif
#ifdef HAVE_STRING_H
# if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
# include <memory.h>
# endif
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "smail.h"
#include "main.h"
#include "parse.h"
#include "addr.h"
#include "route.h"
#include "alloc.h"
#include "list.h"
#include "smailstring.h"
#include "dys.h"
#include "transport.h"
#include "exitcodes.h"
#include "error.h"
#include "extern.h"
#include "debug.h"
#include "smailport.h"
/* variables local to this file */
static int bang_paths_only;
static int disable_smarthost;
static int direct_and_route;
static int show_transport;
/* functions local to this file */
static void print_pathto_addr __P((struct addr *));
static void pathto_direct_and_route __P((char **, struct addr **, struct addr **, struct addr **));
static char **pathto_setup __P((int, char **, char *, void(*)(void)));
static struct addr *pathto_route __P((char *, char **));
static void pathto_usage __P((void));
static void uupath_usage __P((void));
/*
* pathto - return paths to the given addresses.
*/
void
pathto(argc, argv)
int argc;
char **argv; /* generally, argv from main */
{
struct addr *addr;
char *error;
argv = pathto_setup(argc, argv, "vdnstD:", pathto_usage);
if (direct_and_route) {
struct addr *okay; /* list of routed addrs */
struct addr *defer; /* list of temp failed addrs */
struct addr *fail; /* list of failed addrs */
pathto_direct_and_route(argv, &okay, &defer, &fail);
while (defer) {
if (defer->error->info&ERR_CONFERR) {
(void) fprintf(stderr, "%s: %s ... config error: %s\n",
program, defer->in_addr,
defer->error->message);
} else {
(void) fprintf(stderr, "%s: %s ... temp error: %s\n",
program, defer->in_addr,
defer->error->message);
}
defer = defer->succ;
}
while (fail) {
(void) fprintf(stderr, "%s: %s ... failed: %s\n",
program, fail->in_addr, fail->error->message);
fail = fail->succ;
}
while (okay) {
print_pathto_addr(okay);
okay = okay->succ;
}
} else {
for (; *argv; argv++) {
if ((addr = pathto_route(*argv, &error)) == NULL) {
if (error) {
(void) fprintf(stderr, "%s: %s: %s\n",
program, *argv, error);
}
continue;
} else {
if (addr->next_host == NULL) {
addr->next_addr = addr->remainder;
}
print_pathto_addr(addr);
}
}
}
exit(EX_OK);
}
/*
* pathto_direct_and_route - take an array of address strings and
* return a list of resolved addresses
*/
static void
pathto_direct_and_route(addr_strings, okay, defer, fail)
char **addr_strings; /* input address strings */
struct addr **okay; /* successfully routed addrs */
struct addr **defer; /* temp routing failures */
struct addr **fail; /* unresolvable addrs */
{
register struct addr *addr = NULL;
*okay = NULL;
*defer = NULL;
*fail = NULL;
while (*addr_strings) {
register struct addr *new = alloc_addr();
char *error;
new->in_addr = *addr_strings;
new->work_addr = preparse_address(new->in_addr, &error);
if (new->work_addr == NULL) {
new->error = note_error(ERR_111,
xprintf("parse error: %s", error));
new->succ = *fail;
*fail = new;
} else {
if (disable_smarthost) {
new->flags |= ADDR_SMARTUSER|ADDR_SMARTHOST;
}
new->succ = addr;
addr = new;
}
addr_strings++;
}
/* resolve all of the addresses, removing duplicates */
resolve_addr_list(addr, okay, defer, fail, TRUE);
}
/*
* print_pathto_addr - output the given addr structure as an address
*/
static void
print_pathto_addr(addr)
register struct addr *addr;
{
if (show_transport) {
printf("%-11s ", addr->transport? addr->transport->name: "local");
}
if (addr->next_host == NULL) {
if (direct_and_route) {
(void) printf("%s\n", addr->next_addr);
} else if (bang_paths_only) {
(void) printf("%s!%s\n", uucp_name, addr->next_addr);
} else {
(void) printf("%s@%s\n", addr->next_addr, primary_name);
}
} else if (bang_paths_only) {
char *error;
char *path = build_uucp_route(addr->next_addr, &error,
addr->parseflags);
if (path == NULL) {
putchar('\n');
(void) fprintf(stderr, "%s: %s: %s\n",
program, addr->in_addr, error);
return;
} else {
(void) printf("%s!%s\n", addr->next_host, path);
}
} else {
printf("%s :: %s\n", addr->next_host, addr->next_addr);
}
return;
}
/*
* optto - return more optimal paths to the given addresses.
*/
/*ARGSUSED*/
void
optto(argc, argv)
int argc __attribute__((unused));
char **argv __attribute__((unused));
{
(void) fprintf(stderr, "%s: optto not currently supported\n", program);
exit(EX_UNAVAILABLE);
}
/*
* uupath - return paths to the given host.
*/
void
uupath(argc, argv)
int argc;
char **argv; /* generally, argv from main */
{
struct addr *addr;
char *error;
for (argv = pathto_setup(argc, argv, "vstD:", uupath_usage); *argv; argv++) {
char *host_path = build_uucp_route(*argv, &error, 0);
char *in_addr;
if (host_path == NULL) {
(void) fprintf(stderr, "%s: %s: %s\n", program, *argv, error);
continue;
}
in_addr = xmalloc(strlen(host_path) + sizeof("!~~user~~"));
(void) sprintf(in_addr, "%s!~~user~~", host_path);
if ((addr = pathto_route(in_addr, &error)) == NULL) {
if (error) {
(void) fprintf(stderr, "%s: %s: %s\n", program, *argv, error);
}
continue;
}
if (show_transport) {
printf("%-11s ", addr->transport? addr->transport->name: "local");
}
if (addr->next_host == NULL) {
(void) printf("%%s\n");
} else {
char *last_part;
char *path = build_uucp_route(addr->next_addr, &error,
addr->parseflags);
if (path == NULL) {
(void) fprintf(stderr, "%s: %s: %s\n",
program, *argv, error);
} else {
last_part = strrchr(path, '!');
if (last_part == NULL) {
(void) printf("%s\n", addr->next_host);
} else {
*last_part = '\0'; /* chop off the ~~user~~ */
(void) printf("%s!%s\n", addr->next_host, path);
}
}
}
}
exit(EX_OK);
}
/*
* pathto_setup - standard setup for the various pathto routines
*/
static char **
pathto_setup(argc, argv, oargs, usage)
int argc;
char **argv;
char *oargs;
void (*usage) __P((void));
{
extern char *optarg;
extern int optind;
int c;
char **argp;
--argv; /* go back to program name */
disable_smarthost = TRUE;
bang_paths_only = TRUE;
direct_and_route = FALSE;
show_transport = FALSE;
while ((c = getopt(argc, argv, oargs)) != EOF) {
switch (c) {
case 'd':
direct_and_route = TRUE;
break;
case 'n':
bang_paths_only = FALSE;
break;
case 't':
show_transport = TRUE;
break;
case 's':
disable_smarthost = FALSE;
break;
case 'v':
if (! debug)
debug = 1; /* turn on debugging */
break;
case 'D':
debug = atoi(optarg); /* set debugging level */
break;
default:
(*usage)();
exit(EX_USAGE);
}
}
if (argv[optind] == NULL) {
(*usage)();
exit(EX_USAGE);
}
for (argp = &argv[optind]; *argp; argp++) {
strip_rfc822_comments(*argp); /* XXX should we really do this!?!?! */
strip_rfc822_whitespace(*argp);
}
/* setup all of the hostname information */
build_host_strings();
return &argv[optind];
}
static struct addr *
pathto_route(in_addr, error)
char *in_addr;
char **error;
{
struct addr *cur = alloc_addr();
struct addr *defer = NULL;
struct addr *fail = NULL;
struct addr *done = NULL;
int form = PARSE_ERROR;
cur->in_addr = in_addr;
if (disable_smarthost) {
/*
* state we have already used the smarthost router to
* prevent its being used at all
*/
cur->flags |= ADDR_SMARTHOST;
}
if ((cur->work_addr = preparse_address(in_addr, error)) == NULL) {
return NULL;
}
while (cur &&
(form = parse_address(cur->work_addr, &cur->target,
&cur->remainder, &cur->parseflags)
) != FAIL && form != PARSE_ERROR && form != LOCAL)
{
struct addr *retry;
cur->flags &= ~ADDR_FORM_MASK;
cur->flags |= form;
if (islocalhost(cur->target)) {
cur->work_addr = cur->remainder;
continue;
}
done = NULL;
defer = NULL;
fail = NULL;
retry = NULL;
route_remote_addrs(cur, &done, &retry, &defer, &fail);
cur = retry;
}
/* note if route_remote_addrs returned an error */
if (defer) {
*error = defer->error->message;
return NULL;
}
if (fail) {
*error = fail->error->message;
return NULL;
}
/* nope, no error from route_remote_addrs */
switch (form) {
case PARSE_ERROR:
case FAIL:
*error = cur->remainder;
return NULL;
case LOCAL:
cur->next_host = NULL;
break;
default:
if (done) {
cur = done;
} else {
*error = NULL;
return NULL;
}
break;
}
return cur;
}
static void
pathto_usage()
{
(void) fprintf(stderr, "usage: %s [-vdsnt] addr ...\n", program);
}
static void
uupath_usage()
{
(void) fprintf(stderr, "usage: %s [-vst] addr ...\n", program);
}
/*
* Local Variables:
* c-file-style: "smail"
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1