/*
 * Copyright (c) 2002-2005 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_IDSTR(id, "@(#)$Id: t-t2821-1.c,v 1.20 2007/11/14 06:01:06 ca Exp $")

#include "sm/debug.h"
#include "sm/heap.h"
#include "sm/rpool.h"
#include "sm/test.h"
#include "sm/rfc2821.h"
#include "sm/rfc2822.h"
#include "sm/net.h"
#include "sm/sysexits.h"

#include <stdio.h>

#if SM_HEAP_CHECK
# include "sm/io.h"
extern SM_DEBUG_T SmHeapCheck;
# define HEAP_CHECK (SmHeapCheck > 0)
#else /* SM_HEAP_CHECK */
# define HEAP_CHECK 0
#endif /* SM_HEAP_CHECK */

#define BUFLEN	512
#define MAXLEN	1024

static int
stripcr(char *buf)
{
	int n;

	n = strlen(buf);
	while (n > 0 && buf[n - 1] == '\n') {
	    buf[n - 1] = '\0';
	   --n;
	}
	return n;
}

static void
usage(const char *prg)
{
	fprintf(stderr, "usage: %s [options]\n", prg);
	fprintf(stderr, "Test whether addresses (read from stdin) conforms to RFC 2821\n");
	fprintf(stderr, "options:\n");
	fprintf(stderr, "-D    extract domain\n");
	fprintf(stderr, "-S c  specify delimiter\n");
	fprintf(stderr, "-d c  extract detail, using c as delimiter\n");
	fprintf(stderr, "-f n  set address parsing flags\n");
	fprintf(stderr, "-i    extract literal\n");
	fprintf(stderr, "-l    extract local part\n");
	fprintf(stderr, "-q    don't observe quotes\n");
	fprintf(stderr, "-r    use rpool\n");
	fprintf(stderr, "-s s  extract delimiter and detail, using s as delimiters\n");
}

#define XDETAIL_NONE	0
#define XDETAIL_ONLY	1
#define XDETAIL_INCL	2

int
main(int argc, char **argv)
{
	int n;
	int c, flags, delim;
	sm_ret_T r;
	bool xdomain, xlocal, xliteral, quoted;
	int xdetail;
	uchar *chdetail;
	sm_a2821_T addr, domain, local;
	sm_a2821_P pdomain, plocal;
	sm_str_P vp;
	sm_str_P out, detail;
	sm_rpool_P rpool;
	char *buf;

#if SM_HEAP_CHECK
	SmHeapCheck = 0;
#endif
	rpool = NULL;
	flags = R2821_STRICT;
	xdomain = true;
	xlocal = false;
	xliteral = false;
	xdetail = XDETAIL_NONE;
	quoted = true;
	delim = T2821_ENDTOK;
	chdetail = (uchar *)"\0";
	detail = NULL;
	while ((c = getopt(argc, argv, "Dd:f:H:ilrS:s:q")) != -1) {
		switch (c) {
		  case 'D':
			xdomain = false;
			break;
		  case 'd':
			xdetail = XDETAIL_ONLY;
			chdetail = (uchar *)strdup(optarg);
			break;
#if SM_HEAP_CHECK
		  case 'H':
			SmHeapCheck = atoi(optarg);
			break;
#endif
		  case 'f':
			flags = strtol(optarg, NULL, 0);
			break;
		  case 'i':
			xliteral = true;
			break;
		  case 'l':
			xlocal = true;
			break;
		  case 'r':
			rpool = sm_rpool_new(NULL);
			break;
		  case 'S':
			if (optarg != NULL)
				delim = (int) optarg[0];
			break;
		  case 's':
			xdetail = XDETAIL_INCL;
			chdetail = (uchar *)strdup(optarg);
			break;
		  case 'q':
			quoted = false;
			break;
		  default:
			usage(argv[0]);
			return(EX_USAGE);
		}
	}

	pdomain = &domain;
	plocal = &local;
	buf = sm_malloc(BUFLEN);
	SM_TEST(buf != NULL);
	if (NULL == buf)
		goto end;
	if (xdetail != XDETAIL_NONE) {
		detail = sm_str_new(NULL, BUFLEN, MAXLEN);
		SM_TEST(detail != NULL);
		if (NULL == detail)
			goto end;
	}

	while (fgets(buf, BUFLEN, stdin)) {
		n = getc(stdin);
		ungetc(n, stdin);
		if (n == ' ' || n == '\t') {
			n = strlen(buf);
			fgets(buf + n, BUFLEN - n, stdin);
		}
		n = stripcr(buf);
		if (n <= 0)
			goto end; /* bogus input, don't try to recover */

		vp = sm_str_scpy(NULL, buf, MAXLEN);
		SM_TEST(vp != NULL);
		if (!isatty(STDIN_FILENO)) {
			printf(">>>%s<<<\n", buf);
			fflush(stdout);
		}
		A2821_INIT_RP(&addr, rpool);
		r = t2821_scan((sm_rdstr_P) vp, &addr, 0);
		SM_TEST(sm_is_success(r));
		if (sm_is_success(r)) {
			r = t2821_parse(&addr, flags);
			SM_TEST(sm_is_success(r));
			if (!sm_is_success(r))
				printf("ERROR: %x\t>>>%s<<<\n", r, buf);
			else
				printf("OK\t>>>%s<<<\n", buf);
			out = sm_str_new(NULL, BUFLEN, MAXLEN);
			SM_TEST(out != NULL);
			r = t2821_str(&addr, out, 0);
			SM_TEST(sm_is_success(r));
			printf("%s\n", (char *)sm_str_getdata(out));
			if (sm_is_success(r)) {
				if (xdomain) {
					A2821_INIT_RP(&domain, rpool);
					r = t2821_extract_domain(rpool, &addr, &pdomain);
					SM_TEST(sm_is_success(r));
					sm_str_clr(out);
					r = t2821_str(pdomain, out, 0);
					SM_TEST(sm_is_success(r));
					printf("domain=%s\n", (char *)sm_str_getdata(out));
					if (xliteral && sm_str_rd_elem(out, 0) == '[') {
						ipv4_T ipv4;

						r = sm_inet_a2ipv4((const char *)sm_str_getdata(out),
							NULL, &ipv4);
						SM_TEST(sm_is_success(r));
						printf("ipv4=%x\n", (int) ntohl(ipv4));
					}
					a2821_free(pdomain);
				}
				if (xlocal) {
					A2821_INIT_RP(&local, rpool);
					r = t2821_extract_local(rpool, &addr, delim, &plocal);
					SM_TEST(sm_is_success(r));
					sm_str_clr(out);
					r = t2821_str(plocal, out, 0);
					SM_TEST(sm_is_success(r));
					printf("local=%s\n", (char *)sm_str_getdata(out));
					a2821_free(plocal);
				}
				if (xdetail != XDETAIL_NONE) {
					uchar fdelim;

					sm_str_clr(out);
					sm_str_clr(detail);
					r = t2821_parts(&addr, chdetail, quoted, out, detail, NULL
							, &fdelim);
					SM_TEST(sm_is_success(r));
					printf("local=%s, detail=%s",
						(char *)sm_str_getdata(out),
						(char *)sm_str_getdata(detail));
					if (xdetail == XDETAIL_INCL)
						printf(", delim=%c\n", (char)fdelim);
					else
						printf("\n");
				}
			}
			SM_STR_FREE(out);
		}
		else
			printf("FAILED\t>>>%s<<<\n", buf);
		a2821_free(&addr);
		SM_STR_FREE(vp);
		fflush(stdout);
	}
  end:
	if (buf != NULL)
		sm_free(buf);
	if (rpool != NULL)
		sm_rpool_delete(rpool);
	SM_STR_FREE(detail);
#if SM_HEAP_CHECK
	if (HEAP_CHECK) {
		sm_io_fprintf(smioout, "heap should be empty except for makebuf:\n");
		sm_heap_report(smioout, 3);
	}
#endif /* SM_HEAP_CHECK */
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1