/*
* 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