/*
** ali.c -- list nmh mail aliases
**
** This code is Copyright (c) 2002, by the authors of nmh.  See the
** COPYRIGHT file in the root directory of the nmh distribution for
** complete copyright information.
*/

#include <h/mh.h>
#include <h/addrsbr.h>
#include <h/aliasbr.h>
#include <h/utils.h>
#include <locale.h>
#include <sysexits.h>

/*
** maximum number of names
*/
#define NVEC 50

static struct swit switches[] = {
#define FILESW     0
	{ "file aliasfile", 0 },
#define LISTSW     1
	{ "list", 0 },
#define NLISTSW    2
	{ "nolist", 2 },
#define NORMSW     3
	{ "normalize", 0 },
#define NNORMSW    4
	{ "nonormalize", 2 },
#define USERSW     5
	{ "user", 0 },
#define NUSERSW    6
	{ "nouser", 2 },
#define VERSIONSW  7
	{ "Version", 0 },
#define HELPSW     8
	{ "help", 0 },
	{ NULL, 0 }
};

char *version=VERSION;

static int pos = 1;

extern struct aka *akahead;

/*
** prototypes
*/
static void print_aka(char *, int, int);
static void print_usr(char *, int, int);


int
main(int argc, char **argv)
{
	int i, vecp = 0, inverted = 0, list = 0;
	int deffiles = 1, normalize = AD_NHST;
	char *cp, **ap, **argp, buf[BUFSIZ];
	char *vec[NVEC], **arguments;
	struct aka *ak;

	setlocale(LC_ALL, "");
	invo_name = mhbasename(argv[0]);

	/* read user profile/context */
	context_read();

	arguments = getarguments(invo_name, argc, argv, 1);
	argp = arguments;

	while ((cp = *argp++)) {
		if (*cp == '-') {
			switch (smatch(++cp, switches)) {
			case AMBIGSW:
				ambigsw(cp, switches);
				exit(EX_USAGE);
			case UNKWNSW:
				adios(EX_USAGE, NULL, "-%s unknown", cp);

			case HELPSW:
				snprintf(buf, sizeof(buf), "%s [switches] aliases ...",
					invo_name);
				print_help(buf, switches, 1);
				exit(argc == 2 ? EX_OK : EX_USAGE);
			case VERSIONSW:
				print_version(invo_name);
				exit(argc == 2 ? EX_OK : EX_USAGE);

			case FILESW:
				if (!(cp = *argp++) || *cp == '-') {
					adios(EX_USAGE, NULL, "missing argument to %s", argp[-2]);
				}
				if ((i = alias(cp)) != AK_OK)
					adios(EX_USAGE, NULL, "aliasing error in %s: %s", cp, akerror(i));
				deffiles = 0;
				continue;

			case LISTSW:
				list++;
				continue;
			case NLISTSW:
				list = 0;
				continue;

			case NORMSW:
				normalize = AD_HOST;
				continue;
			case NNORMSW:
				normalize = AD_NHST;
				continue;

			case USERSW:
				inverted++;
				continue;
			case NUSERSW:
				inverted = 0;
				continue;
			}
		}
		vec[vecp++] = cp;
	}

	/* process default Aliasfile: profile entry */
	if (deffiles && (cp = context_find("Aliasfile"))) {
		char *dp = NULL;

		for (ap = brkstring(dp=mh_xstrdup(cp), " ", "\n");
				ap && *ap; ap++) {
			if ((i = alias(etcpath(*ap))) != AK_OK) {
				adios(EX_DATAERR, NULL, "aliasing error in %s: %s",
						*ap, akerror(i));
			}
		}
		if (dp) {
			mh_free0(&dp);
		}
	}

	/*
	** If -user is specified
	*/
	if (inverted) {
		if (vecp == 0)
			adios(EX_USAGE, NULL, "usage: %s -user addresses ...  (you forgot the addresses)",
				   invo_name);

		for (i = 0; i < vecp; i++)
			print_usr(vec[i], list, normalize);

		exit(EX_OK);
	}

	if (vecp) {
		/* print specified aliases */
		for (i = 0; i < vecp; i++)
			print_aka(akvalue(vec[i]), list, 0);
	} else {
		/* print them all */
		for (ak = akahead; ak; ak = ak->ak_next) {
			printf("%s: ", ak->ak_name);
			pos += strlen(ak->ak_name) + 1;
			print_aka(akresult(ak), list, pos);
		}
	}

	return EX_OK;
}

static void
print_aka(char *p, int list, int margin)
{
	char c;

	if (p == NULL) {
		printf("<empty>\n");
		return;
	}

	while ((c = *p++)) {
		switch (c) {
		case ',':
			if (*p) {
				if (list)
					printf("\n%*s", margin, "");
				else {
					if (pos >= 68) {
						printf(",\n ");
						pos = 2;
					} else {
						printf(", ");
						pos += 2;
					}
				}
			}

		case 0:
			break;

		default:
			pos++;
			putchar(c);
		}
	}

	putchar('\n');
	pos = 1;
}

static void
print_usr(char *s, int list, int norm)
{
	char *cp, *pp, *vp;
	struct aka *ak;
	struct mailname *mp, *np;

	if ((pp = getname(s)) == NULL)
		adios(EX_DATAERR, NULL, "no address in \"%s\"", s);
	if ((mp = getm(pp, NULL, 0, norm, NULL)) == NULL)
		adios(EX_DATAERR, NULL, "bad address \"%s\"", s);
	while (getname(""))
		continue;

	vp = NULL;
	for (ak = akahead; ak; ak = ak->ak_next) {
		pp = akresult(ak);
		while ((cp = getname(pp))) {
			if ((np = getm(cp, NULL, 0, norm, NULL)) == NULL)
				continue;
			if (!mh_strcasecmp(mp->m_host, np->m_host)
					&& !mh_strcasecmp(mp->m_mbox, np->m_mbox)) {
				vp = vp ? add(ak->ak_name, add(",", vp))
					: mh_xstrdup(ak->ak_name);
				mnfree(np);
				while (getname(""))
					continue;
				break;
			}
			mnfree(np);
		}
	}
	mnfree(mp);

	print_aka(vp ? vp : s, list, 0);

	if (vp)
		mh_free0(&vp);
}
