#line 945 "../../src/builtin/snarf.m4"
/* -*- buffer-read-only: t -*- vi: set ro:
   THIS FILE IS GENERATED AUTOMATICALLY.  PLEASE DO NOT EDIT.
*/
#line 945
#ifdef HAVE_CONFIG_H
#line 945
# include <config.h>
#line 945
#endif
#line 945
#include <sys/types.h>
#line 945

#line 945
#include "mailfromd.h"
#line 945
#include "prog.h"
#line 945
#include "builtin.h"
#line 945

#line 945

#line 985 "../../src/builtin/snarf.m4"

/* End of snarf.m4 */
#line 1 "dns.bi"
/* This file is part of Mailfromd.             -*- c -*-
   Copyright (C) 2006-2020 Sergey Poznyakoff

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */



#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "srvcfg.h"
#include "global.h"

void
#line 26
bi_primitive_hostname(eval_environ_t env)
#line 26

#line 26

#line 26 "dns.bi"
{
#line 26
	
#line 26

#line 26

#line 26
char * MFL_DATASEG string;
#line 26
        
#line 26
get_string_arg(env, 0, &string);
#line 26
        
#line 26

#line 26
        adjust_stack(env, 1);
#line 26

#line 26

#line 26
	if (builtin_module_trace(BUILTIN_IDX_dns))
#line 26
		prog_trace(env, "primitive_hostname %s",string);;
#line 26

{
	char *hbuf;
	mf_status stat;

	stat = resolve_ipstr(string, &hbuf);
		if (!(stat == mf_success))
#line 32
		(
#line 32
	env_throw_bi(env, mf_status_to_exception(stat), "primitive_hostname", _("cannot resolve IP %s"),string)
#line 32
)
#line 35
;
	
	pushs(env, hbuf);
	free(hbuf);
}

#line 40
        env_function_cleanup_flush(env, NULL);
#line 40
	return;
#line 40
}

void
#line 42
bi_primitive_resolve(eval_environ_t env)
#line 42

#line 42

#line 42 "dns.bi"
{
#line 42
	
#line 42

#line 42
long __bi_argcnt;
#line 42
char * MFL_DATASEG string;
#line 42
        char * MFL_DATASEG domain;
#line 42
        
#line 42
get_string_arg(env, 1, &string);
#line 42
        get_string_arg(env, 2, &domain);
#line 42
        
#line 42
get_numeric_arg(env, 0, &__bi_argcnt);
#line 42
        adjust_stack(env, __bi_argcnt + 1);
#line 42

#line 42

#line 42
	if (builtin_module_trace(BUILTIN_IDX_dns))
#line 42
		prog_trace(env, "primitive_resolve %s %s",string, ((__bi_argcnt > 1) ? domain : ""));;
#line 42

{
	char *ipstr;
	mf_status stat;
	
	if (((__bi_argcnt > 1) ? domain : "")[0]) {
		stat = resolve_ipstr_domain(string, domain, &ipstr);
			if (!(stat == mf_success))
#line 49
		(
#line 49
	env_throw_bi(env, mf_status_to_exception(stat), "primitive_resolve", _("cannot resolve %s.%s"),string,domain)
#line 49
)
#line 51
;
	} else {
		stat = resolve_hostname(string, &ipstr);
			if (!(stat == mf_success))
#line 54
		(
#line 54
	env_throw_bi(env, mf_status_to_exception(stat), "primitive_resolve", _("cannot resolve %s"),string)
#line 54
)
#line 56
;
	}
	pushs(env, ipstr);
	free(ipstr);
}

#line 61
        env_function_cleanup_flush(env, NULL);
#line 61
	return;
#line 61
}

static int
ipaddr_cmp(const void *a, const void *b)
{
	GACOPYZ_UINT32_T ipa = ntohl(*(GACOPYZ_UINT32_T*)a);
	GACOPYZ_UINT32_T ipb = ntohl(*(GACOPYZ_UINT32_T*)b);
	if (ipa < ipb)
		return -1;
	if (ipa > ipb)
		return 1;
	return 0;
}

void
#line 75
bi_dns_getaddr(eval_environ_t env)
#line 75

#line 75

#line 75 "dns.bi"
{
#line 75
	
#line 75

#line 75

#line 75
char * MFL_DATASEG string;
#line 75
        
#line 75
get_string_arg(env, 0, &string);
#line 75
        
#line 75

#line 75
        adjust_stack(env, 1);
#line 75

#line 75

#line 75
	if (builtin_module_trace(BUILTIN_IDX_dns))
#line 75
		prog_trace(env, "dns_getaddr %s",string);;
#line 75

{
	size_t i;
	dns_status dnstat;
	struct dns_reply r;
	
	dnstat = a_lookup(string, &r);
	switch (dnstat) {
	case dns_success: {
		heap_obstack_begin(env);
		qsort(r.data.ip, r.count, sizeof r.data.ip[0], ipaddr_cmp);
		for (i = 0; i < r.count; i++) {
			struct in_addr addr;
			char *q;
			
			addr.s_addr = r.data.ip[i];
			q = inet_ntoa(addr);
			if (i > 0)
				do { char __c = ' '; heap_obstack_grow(env, &__c, 1); } while(0);
 			
#line 94
do {
#line 94
  char *__s = q;
#line 94
  heap_obstack_grow(env, __s, strlen(__s));
#line 94
} while (0);
		}
		dns_reply_free(&r);
		do { char __c = 0; heap_obstack_grow(env, &__c, 1); } while(0);
		
#line 98
do {
#line 98
  push(env, (STKVAL) (heap_obstack_finish(env)));
#line 98
  goto endlab;
#line 98
} while (0);
	}
	case dns_not_found:
		
#line 101
do {
#line 101
  pushs(env, "");
#line 101
  goto endlab;
#line 101
} while (0);
	default:
		(
#line 103
	env_throw_bi(env, mf_status_to_exception(dns_to_mf_status(dnstat)), "dns_getaddr", _("failed to get A record for %s"),string)
#line 103
);
#line 105
	}
}
endlab:
#line 107
        env_function_cleanup_flush(env, NULL);
#line 107
	return;
#line 107
}

static int
hostname_cmp(const void *a, const void *b)
{
	return strcmp(*(const char**) a, *(const char**) b);
}

void
#line 115
bi_dns_getname(eval_environ_t env)
#line 115

#line 115

#line 115 "dns.bi"
{
#line 115
	
#line 115

#line 115

#line 115
char * MFL_DATASEG ipstr;
#line 115
        
#line 115
get_string_arg(env, 0, &ipstr);
#line 115
        
#line 115

#line 115
        adjust_stack(env, 1);
#line 115

#line 115

#line 115
	if (builtin_module_trace(BUILTIN_IDX_dns))
#line 115
		prog_trace(env, "dns_getname %s",ipstr);;
#line 115

{
	dns_status dnstat;
	struct in_addr addr;
	struct dns_reply r;
	
		if (!(inet_aton(ipstr, &addr)))
#line 121
		(
#line 121
	env_throw_bi(env, mfe_invip, "dns_getname", _("invalid IP: %s"),ipstr)
#line 121
)
#line 123
;

	dnstat = ptr_lookup(addr, &r);
	switch (dnstat) {
	case dns_success: {
		size_t i;

		qsort(r.data.str, r.count, sizeof r.data.str[0], hostname_cmp);

		heap_obstack_begin(env);
		for (i = 0; i < r.count; i++) {
			if (i > 0)
				do { char __c = ' '; heap_obstack_grow(env, &__c, 1); } while(0);
			
#line 136
do {
#line 136
  char *__s = (char*)r.data.str[i];
#line 136
  heap_obstack_grow(env, __s, strlen(__s));
#line 136
} while (0);
		}
		do { char __c = 0; heap_obstack_grow(env, &__c, 1); } while(0);

		dns_reply_free(&r);
		
#line 141
do {
#line 141
  push(env, (STKVAL) (heap_obstack_finish(env)));
#line 141
  goto endlab;
#line 141
} while (0);
	}
	case dns_not_found:
		
#line 144
do {
#line 144
  pushs(env, "");
#line 144
  goto endlab;
#line 144
} while (0);
	default:
		(
#line 146
	env_throw_bi(env, mf_status_to_exception(dns_to_mf_status(dnstat)), "dns_getname", _("failed to get PTR record for %s"),ipstr)
#line 146
);
#line 148
	}
}
endlab:
#line 150
        env_function_cleanup_flush(env, NULL);
#line 150
	return;
#line 150
}

void
#line 152
bi_primitive_hasmx(eval_environ_t env)
#line 152

#line 152

#line 152 "dns.bi"
{
#line 152
	
#line 152

#line 152

#line 152
char *  string;
#line 152
        
#line 152
get_string_arg(env, 0, &string);
#line 152
        
#line 152

#line 152
        adjust_stack(env, 1);
#line 152

#line 152

#line 152
	if (builtin_module_trace(BUILTIN_IDX_dns))
#line 152
		prog_trace(env, "primitive_hasmx %s",string);;
#line 152

{
	struct dns_reply repl;
	mf_status mxstat;

	mxstat = dns_to_mf_status(mx_lookup(string, 0, &repl));
	
		if (!(mxstat == mf_success || mxstat == mf_not_found))
#line 159
		(
#line 159
	env_throw_bi(env, mf_status_to_exception(mxstat), "primitive_hasmx", _("cannot get MX records for %s"),string)
#line 159
)
#line 162
;
	dns_reply_free(&repl);
	if (mxstat == mf_success) {
		
#line 165
do {
#line 165
  push(env, (STKVAL)(mft_number)(1));
#line 165
  goto endlab;
#line 165
} while (0);
	}
	
#line 167
do {
#line 167
  push(env, (STKVAL)(mft_number)(0));
#line 167
  goto endlab;
#line 167
} while (0);
}
endlab:
#line 169
        env_function_cleanup_flush(env, NULL);
#line 169
	return;
#line 169
}

void
#line 171
bi_getmx(eval_environ_t env)
#line 171

#line 171

#line 171 "dns.bi"
{
#line 171
	
#line 171

#line 171
long __bi_argcnt;
#line 171
char * MFL_DATASEG domain;
#line 171
        long  resolve;
#line 171
        
#line 171
get_string_arg(env, 1, &domain);
#line 171
        get_numeric_arg(env, 2, &resolve);
#line 171
        
#line 171
get_numeric_arg(env, 0, &__bi_argcnt);
#line 171
        adjust_stack(env, __bi_argcnt + 1);
#line 171

#line 171

#line 171
	if (builtin_module_trace(BUILTIN_IDX_dns))
#line 171
		prog_trace(env, "getmx %s %lu",domain, ((__bi_argcnt > 1) ? resolve : 0));;
#line 171

{
	mf_status mxstat;
	struct dns_reply reply;
	int i;
	
	mxstat = dns_to_mf_status(mx_lookup(domain, ((__bi_argcnt > 1) ? resolve : 0),
					    &reply));
	if (!mf_resolved(mxstat)) {
		(
#line 180
	env_throw_bi(env, mf_status_to_exception(mxstat), "getmx", _("cannot get MX records for %s"),domain)
#line 180
);
#line 182
	}
	if (mxstat == mf_not_found) {
		
#line 184
do {
#line 184
  pushs(env, "");
#line 184
  goto endlab;
#line 184
} while (0);
	} else if (reply.type == dns_reply_ip) {
		heap_obstack_begin(env);
		for (i = 0; i < reply.count; i++) {
			struct in_addr s;
			s.s_addr = reply.data.ip[i];
			if (i > 0)
				do { char __c = ' '; heap_obstack_grow(env, &__c, 1); } while(0);
			
#line 192
do {
#line 192
  char *__s = inet_ntoa(s);
#line 192
  heap_obstack_grow(env, __s, strlen(__s));
#line 192
} while (0);
		}
	} else {
		heap_obstack_begin(env);
		for (i = 0; i < reply.count; i++) {
			if (i > 0)
				do { char __c = ' '; heap_obstack_grow(env, &__c, 1); } while(0);
			
#line 199
do {
#line 199
  char *__s = reply.data.str[i];
#line 199
  heap_obstack_grow(env, __s, strlen(__s));
#line 199
} while (0);
		}
	}
	do { char __c = 0; heap_obstack_grow(env, &__c, 1); } while(0);
	dns_reply_free(&reply);
	
#line 204
do {
#line 204
  push(env, (STKVAL) (heap_obstack_finish(env)));
#line 204
  goto endlab;
#line 204
} while (0);
}
endlab:
#line 206
        env_function_cleanup_flush(env, NULL);
#line 206
	return;
#line 206
}

static dns_status
resolve_host(const char *string, struct dns_reply *reply)
{
	struct in_addr addr;

	if (inet_aton(string, &addr)) {
		dns_reply_init(reply, dns_reply_ip, 1);
		reply->data.ip[0] = addr.s_addr;
		return dns_success;
	}
	return a_lookup(string, reply);
}

static int
dns_replies_intersect(struct dns_reply const *a, struct dns_reply const *b)
{
	int i, j;
	
	if (a->type == b->type && a->type == dns_reply_ip) {
		for (i = 0; i < a->count; i++) 
			for (j = 0; j < b->count; j++) 
				if (a->data.ip[i] == b->data.ip[j])
					return 1;
	}
	return 0;
}

void
#line 235
bi_primitive_ismx(eval_environ_t env)
#line 235

#line 235

#line 235 "dns.bi"
{
#line 235
	
#line 235

#line 235

#line 235
char *  domain;
#line 235
        char *  ipstr;
#line 235
        
#line 235
get_string_arg(env, 0, &domain);
#line 235
        get_string_arg(env, 1, &ipstr);
#line 235
        
#line 235

#line 235
        adjust_stack(env, 2);
#line 235

#line 235

#line 235
	if (builtin_module_trace(BUILTIN_IDX_dns))
#line 235
		prog_trace(env, "primitive_ismx %s %s",domain, ipstr);;
#line 235

{
	struct dns_reply areply, mxreply;
	dns_status status;
	int rc = 0;

	status = resolve_host(ipstr, &areply);
		if (!(status == dns_success))
#line 242
		(
#line 242
	env_throw_bi(env, mf_status_to_exception(dns_to_mf_status(status)), "primitive_ismx", _("cannot resolve host name %s"),ipstr)
#line 242
)
#line 244
;
	status = mx_lookup(domain, 1, &mxreply);
	if (status != dns_success) {
		dns_reply_free(&areply);
		(
#line 248
	env_throw_bi(env, mf_status_to_exception(dns_to_mf_status(status)), "primitive_ismx", _("cannot get MXs for %s"),domain)
#line 248
);
#line 250
	}
	rc = dns_replies_intersect(&areply, &mxreply);
	dns_reply_free(&areply);
	dns_reply_free(&mxreply);
	
#line 254
do {
#line 254
  push(env, (STKVAL)(mft_number)(rc));
#line 254
  goto endlab;
#line 254
} while (0);
}
endlab:
#line 256
        env_function_cleanup_flush(env, NULL);
#line 256
	return;
#line 256
}

void
#line 258
bi_relayed(eval_environ_t env)
#line 258

#line 258

#line 258 "dns.bi"
{
#line 258
	
#line 258

#line 258

#line 258
char *  s;
#line 258
        
#line 258
get_string_arg(env, 0, &s);
#line 258
        
#line 258

#line 258
        adjust_stack(env, 1);
#line 258

#line 258

#line 258
	if (builtin_module_trace(BUILTIN_IDX_dns))
#line 258
		prog_trace(env, "relayed %s",s);;
#line 258

{
	
#line 260
do {
#line 260
  push(env, (STKVAL)(mft_number)(relayed_domain_p(s)));
#line 260
  goto endlab;
#line 260
} while (0);
}
endlab:
#line 262
        env_function_cleanup_flush(env, NULL);
#line 262
	return;
#line 262
}

void
#line 264
bi_ptr_validate(eval_environ_t env)
#line 264

#line 264

#line 264 "dns.bi"
{
#line 264
	
#line 264

#line 264

#line 264
char *  s;
#line 264
        
#line 264
get_string_arg(env, 0, &s);
#line 264
        
#line 264

#line 264
        adjust_stack(env, 1);
#line 264

#line 264

#line 264
	if (builtin_module_trace(BUILTIN_IDX_dns))
#line 264
		prog_trace(env, "ptr_validate %s",s);;
#line 264

{
	int rc, res;
	switch (rc = ptr_validate(s, NULL)) {
	case dns_success:
		res = 1;
		break;
	case dns_not_found:
		res = 0;
		break;
	default:
		(
#line 275
	env_throw_bi(env, mf_status_to_exception(dns_to_mf_status(rc)), "ptr_validate", _("failed to get PTR record for %s"),s)
#line 275
);
#line 277
	}
	
#line 278
do {
#line 278
  push(env, (STKVAL)(mft_number)(res));
#line 278
  goto endlab;
#line 278
} while (0);
}
endlab:
#line 280
        env_function_cleanup_flush(env, NULL);
#line 280
	return;
#line 280
}

void
#line 282
bi_primitive_hasns(eval_environ_t env)
#line 282

#line 282

#line 282 "dns.bi"
{
#line 282
	
#line 282

#line 282

#line 282
char *  dom;
#line 282
        
#line 282
get_string_arg(env, 0, &dom);
#line 282
        
#line 282

#line 282
        adjust_stack(env, 1);
#line 282

#line 282

#line 282
	if (builtin_module_trace(BUILTIN_IDX_dns))
#line 282
		prog_trace(env, "primitive_hasns %s",dom);;
#line 282

{
	struct dns_reply repl;
	mf_status stat = dns_to_mf_status(ns_lookup(dom, 0, &repl));
		if (!(stat == mf_success || stat == mf_not_found))
#line 286
		(
#line 286
	env_throw_bi(env, mf_status_to_exception(stat), "primitive_hasns", _("cannot get NS records for %s"),dom)
#line 286
)
#line 289
;
	dns_reply_free(&repl);
	if (stat == mf_success) {
		
#line 292
do {
#line 292
  push(env, (STKVAL)(mft_number)(1));
#line 292
  goto endlab;
#line 292
} while (0);
	}
	
#line 294
do {
#line 294
  push(env, (STKVAL)(mft_number)(0));
#line 294
  goto endlab;
#line 294
} while (0);
}
endlab:
#line 296
        env_function_cleanup_flush(env, NULL);
#line 296
	return;
#line 296
}

static int
cmp_ip(void const *a, void const *b)
{
	GACOPYZ_UINT32_T ipa = *(GACOPYZ_UINT32_T const *)a;
	GACOPYZ_UINT32_T ipb = *(GACOPYZ_UINT32_T const *)b;
	if (ipa < ipb)
		return -1;
	if (ipa > ipb)
		return 1;
	return 0;
}

static int
cmp_str(void const *a, void const *b)
{
	char * const *stra = a;
	char * const *strb = b;
	return strcmp(*stra, *strb);
}

void
#line 318
bi_getns(eval_environ_t env)
#line 318

#line 318

#line 318 "dns.bi"
{
#line 318
	
#line 318

#line 318
long __bi_argcnt;
#line 318
char * MFL_DATASEG domain;
#line 318
        long  resolve;
#line 318
        long  sort;
#line 318
        
#line 318
get_string_arg(env, 1, &domain);
#line 318
        get_numeric_arg(env, 2, &resolve);
#line 318
        get_numeric_arg(env, 3, &sort);
#line 318
        
#line 318
get_numeric_arg(env, 0, &__bi_argcnt);
#line 318
        adjust_stack(env, __bi_argcnt + 1);
#line 318

#line 318

#line 318
	if (builtin_module_trace(BUILTIN_IDX_dns))
#line 318
		prog_trace(env, "getns %s %lu %lu",domain, ((__bi_argcnt > 1) ? resolve : 0), ((__bi_argcnt > 2) ? sort : 0));;
#line 318

{
	mf_status stat;
	struct dns_reply reply;
	int i;
	
	stat = dns_to_mf_status(ns_lookup(domain, ((__bi_argcnt > 1) ? resolve : 0),
					  &reply));
	if (!mf_resolved(stat)) {
		(
#line 327
	env_throw_bi(env, mf_status_to_exception(stat), "getns", _("cannot get MX records for %s"),domain)
#line 327
);
#line 329
	}
	if (stat == mf_not_found) {
		
#line 331
do {
#line 331
  pushs(env, "");
#line 331
  goto endlab;
#line 331
} while (0);
	}

	heap_obstack_begin(env);
	if (reply.type == dns_reply_ip) {
		if (sort)
			qsort(reply.data.ip,
			      reply.count,
			      sizeof(reply.data.ip[0]),
			      cmp_ip);
		for (i = 0; i < reply.count; i++) {
			struct in_addr s;
			s.s_addr = reply.data.ip[i];
			if (i > 0)
				do { char __c = ' '; heap_obstack_grow(env, &__c, 1); } while(0);
			
#line 346
do {
#line 346
  char *__s = inet_ntoa(s);
#line 346
  heap_obstack_grow(env, __s, strlen(__s));
#line 346
} while (0);
		}
	} else {
		if (sort)
			qsort(reply.data.str,
			      reply.count,
			      sizeof(reply.data.str[0]),
			      cmp_str);
		for (i = 0; i < reply.count; i++) {
			if (i > 0)
				do { char __c = ' '; heap_obstack_grow(env, &__c, 1); } while(0);
			
#line 357
do {
#line 357
  char *__s = reply.data.str[i];
#line 357
  heap_obstack_grow(env, __s, strlen(__s));
#line 357
} while (0);
		}
	}
	do { char __c = 0; heap_obstack_grow(env, &__c, 1); } while(0);
	dns_reply_free(&reply);
	
#line 362
do {
#line 362
  push(env, (STKVAL) (heap_obstack_finish(env)));
#line 362
  goto endlab;
#line 362
} while (0);
}
endlab:
#line 364
        env_function_cleanup_flush(env, NULL);
#line 364
	return;
#line 364
}

#line 945 "../../src/builtin/snarf.m4"

#line 945

#line 945

#line 945
void
#line 945
dns_init_builtin(void)
#line 945
{
#line 945
	
#line 945
	#line 26 "dns.bi"
va_builtin_install_ex("primitive_hostname", bi_primitive_hostname, 0, dtype_string, 1, 0, 0|0, dtype_string);
#line 42 "dns.bi"
va_builtin_install_ex("primitive_resolve", bi_primitive_resolve, 0, dtype_string, 2, 1, 0|0, dtype_string, dtype_string);
#line 75 "dns.bi"
va_builtin_install_ex("dns_getaddr", bi_dns_getaddr, 0, dtype_string, 1, 0, 0|0, dtype_string);
#line 115 "dns.bi"
va_builtin_install_ex("dns_getname", bi_dns_getname, 0, dtype_string, 1, 0, 0|0, dtype_string);
#line 152 "dns.bi"
va_builtin_install_ex("primitive_hasmx", bi_primitive_hasmx, 0, dtype_number, 1, 0, 0|0, dtype_string);
#line 171 "dns.bi"
va_builtin_install_ex("getmx", bi_getmx, 0, dtype_string, 2, 1, 0|0, dtype_string, dtype_number);
#line 235 "dns.bi"
va_builtin_install_ex("primitive_ismx", bi_primitive_ismx, 0, dtype_number, 2, 0, 0|0, dtype_string, dtype_string);
#line 258 "dns.bi"
va_builtin_install_ex("relayed", bi_relayed, 0, dtype_number, 1, 0, 0|0, dtype_string);
#line 264 "dns.bi"
va_builtin_install_ex("ptr_validate", bi_ptr_validate, 0, dtype_number, 1, 0, 0|0, dtype_string);
#line 282 "dns.bi"
va_builtin_install_ex("primitive_hasns", bi_primitive_hasns, 0, dtype_number, 1, 0, 0|0, dtype_string);
#line 318 "dns.bi"
va_builtin_install_ex("getns", bi_getns, 0, dtype_string, 3, 2, 0|0, dtype_string, dtype_number, dtype_number);

#line 945 "../../src/builtin/snarf.m4"
	
#line 945
}
#line 945 "../../src/builtin/snarf.m4"