/* * 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 #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; }