diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2019-01-03 12:40:52 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2019-01-03 12:40:52 +0200 |
commit | c70f5d055d37bba1b26beafec8bfee902dc1b758 (patch) | |
tree | 7f7c140369fbab7c9d37765eec814e2fb81cf7fc | |
parent | 33f88906896d016ebd4e387ddc7a29c9f6c0dbc7 (diff) | |
download | mailfromd-c70f5d055d37bba1b26beafec8bfee902dc1b758.tar.gz mailfromd-c70f5d055d37bba1b26beafec8bfee902dc1b758.tar.bz2 |
Version 8.7release_8_7
* NEWS: Update.
* configure.ac: Raise minor version.
* doc/functions.texi: Document new functions
Include the implementation of the NS resolving MFL functions, as
proposed by Jan Rafaj
* lib/dns.c (ns_lookup): New function.
* lib/dns.h (ns_lookup): New proto.
* mflib/dns.mf4 (hasns): New function.
* src/builtin/dns.bi (primitive_hasns, getns): New functions.
-rw-r--r-- | NEWS | 23 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | doc/functions.texi | 100 | ||||
-rw-r--r-- | lib/dns.c | 30 | ||||
-rw-r--r-- | lib/dns.h | 2 | ||||
-rw-r--r-- | mflib/dns.mf4 | 13 | ||||
-rw-r--r-- | src/builtin/dns.bi | 84 |
7 files changed, 216 insertions, 40 deletions
@@ -1,2 +1,2 @@ -Mailfromd NEWS -- history of user-visible changes. 2018-11-12 +Mailfromd NEWS -- history of user-visible changes. 2019-01-03 See the end of file for copying conditions. @@ -5,3 +5,3 @@ Please send Mailfromd bug reports to <bug-mailfromd@gnu.org.ua> -Version 8.6.90 (Git) +Version 8.7, 2019-01-03 @@ -17,2 +17,21 @@ sockets when starting new mailfromd instance. +* NS lookup NFL functions + +This release implements the following new MFL functions: + +number primitive_hasns (string DOM) + Returns 1 if the domain DOM has at least one NS record and 0 + otherwise. Throws an error if DNS lookup fails. + +require 'dns' +number hasns (string DOM) + Same as above, but returns 0 on DNS lookup failures. + +string getns (string DOM ; number RESOLVE, number SORT) + + Returns a whitespace-separated list of all the NS records for + the domain DOM. If optional parameter RESOLVE is 1, the returned list + contains IP addresses. Optional SORT controls whether the entries are + sorted. + * Bugfixes diff --git a/configure.ac b/configure.ac index 3585d967..54c9ebd8 100644 --- a/configure.ac +++ b/configure.ac @@ -18,4 +18,4 @@ AC_PREREQ(2.63) m4_define([MF_VERSION_MAJOR], 8) -m4_define([MF_VERSION_MINOR], 6) -m4_define([MF_VERSION_PATCH], 90) +m4_define([MF_VERSION_MINOR], 7) +dnl m4_define([MF_VERSION_PATCH], 0) AC_INIT([mailfromd], diff --git a/doc/functions.texi b/doc/functions.texi index 75eed904..d25911aa 100644 --- a/doc/functions.texi +++ b/doc/functions.texi @@ -7,3 +7,6 @@ This chapter describes library functions available in Mailfromd -version @value{VERSION}. +version @value{VERSION}. For the simplicity of explanation, we use +the word @samp{boolean} to indicate variables of numeric type that are +used as boolean values. For such variables, the term @samp{False} +stands for the numeric 0, and @samp{True} for any non-zero value. @@ -67,3 +70,3 @@ macro names programmatically, e.g.: -@deftypefn {Built-in Function} number macro_defined (string @var{name}) +@deftypefn {Built-in Function} boolean macro_defined (string @var{name}) Return true if Sendmail macro @var{name} is defined. @@ -604,3 +607,3 @@ is outside of the character class (characters are indexed from 0). -@deftypefn {Built-in Function} number isalnum (string @var{str}) +@deftypefn {Built-in Function} boolean isalnum (string @var{str}) Checks for alphanumeric characters: @@ -613,3 +616,3 @@ Checks for alphanumeric characters: -@deftypefn {Built-in Function} number isalpha (string @var{str}) +@deftypefn {Built-in Function} boolean isalpha (string @var{str}) Checks for an alphabetic character: @@ -622,3 +625,3 @@ Checks for an alphabetic character: -@deftypefn {Built-in Function} number isascii (string @var{str}) +@deftypefn {Built-in Function} boolean isascii (string @var{str}) Checks whether all characters in @var{str} are 7-bit ones, that fit into @@ -632,3 +635,3 @@ the @acronym{ASCII} character set. -@deftypefn {Built-in Function} number isblank (string @var{str}) +@deftypefn {Built-in Function} boolean isblank (string @var{str}) Checks if @var{str} contains only blank characters; that is, spaces or @@ -637,3 +640,3 @@ tabs. -@deftypefn {Built-in Function} number iscntrl (string @var{str}) +@deftypefn {Built-in Function} boolean iscntrl (string @var{str}) Checks for control characters. @@ -641,3 +644,3 @@ Checks for control characters. -@deftypefn {Built-in Function} number isdigit (string @var{str}) +@deftypefn {Built-in Function} boolean isdigit (string @var{str}) Checks for digits (0 through 9). @@ -645,3 +648,3 @@ Checks for digits (0 through 9). -@deftypefn {Built-in Function} number isgraph (string @var{str}) +@deftypefn {Built-in Function} boolean isgraph (string @var{str}) Checks for any printable characters except spaces. @@ -649,3 +652,3 @@ Checks for any printable characters except spaces. -@deftypefn {Built-in Function} number islower (string @var{str}) +@deftypefn {Built-in Function} boolean islower (string @var{str}) Checks for lower-case characters. @@ -653,3 +656,3 @@ Checks for lower-case characters. -@deftypefn {Built-in Function} number isprint (string @var{str}) +@deftypefn {Built-in Function} boolean isprint (string @var{str}) Checks for printable characters including space. @@ -657,3 +660,3 @@ Checks for printable characters including space. -@deftypefn {Built-in Function} number ispunct (string @var{str}) +@deftypefn {Built-in Function} boolean ispunct (string @var{str}) Checks for any printable characters which are not a spaces or @@ -662,3 +665,3 @@ alphanumeric characters. -@deftypefn {Built-in Function} number isspace (string @var{str}) +@deftypefn {Built-in Function} boolean isspace (string @var{str}) Checks for white-space characters, i.e.: space, form-feed (@samp{\f}), @@ -668,3 +671,3 @@ newline (@samp{\n}), carriage return (@samp{\r}), horizontal tab -@deftypefn {Built-in Function} number isupper (string @var{str}) +@deftypefn {Built-in Function} boolean isupper (string @var{str}) Checks for uppercase letters. @@ -672,3 +675,3 @@ Checks for uppercase letters. -@deftypefn {Built-in Function} number isxdigit (string @var{str}) +@deftypefn {Built-in Function} boolean isxdigit (string @var{str}) Checks for hexadecimal digits, i.e. one of @samp{0}, @samp{1}, @@ -719,3 +722,3 @@ email address. @deftypefn {Library Function} boolean email_valid (string @var{email}) - Returns @var{True} if @var{email} is a valid email address, + Returns @samp{True} (1) if @var{email} is a valid email address, consisting of local and domain parts only. E.g.: @@ -1706,3 +1709,3 @@ must require prior to using any of them. -@deftypefn {Library Function} number _pollhost @ +@deftypefn {Library Function} boolean _pollhost @ (string @var{ip}, string @var{email}, string @var{domain}, @ @@ -1718,3 +1721,3 @@ exceptions: @code{e_failure}, @code{e_temp_failure}. -@deftypefn {Library Function} number _pollmx @ +@deftypefn {Library Function} boolean _pollmx @ (string @var{ip}, string @var{email}, string @var{domain}, @ @@ -1730,3 +1733,3 @@ exceptions: @code{e_failure}, @code{e_temp_failure}. -@deftypefn {Library Function} number stdpoll @ +@deftypefn {Library Function} boolean stdpoll @ (string @var{email}, string @var{domain}, string @var{mailfrom}) @@ -1742,3 +1745,3 @@ without explicit @var{host}. @FIXME{more details and references.} -@deftypefn {Library Function} number strictpoll @ +@deftypefn {Library Function} boolean strictpoll @ (string @var{host}, string @var{email}, @ @@ -1927,3 +1930,3 @@ records) for the @acronym{IP}v4 address @var{ipstr}. @deftypefn {Built-in Function} string getmx (string @var{domain} @ - [, number @var{ip}]) + [, boolean @var{ip}]) Returns a whitespace-separated list of @samp{MX} names (if @var{ip} is not @@ -2116,2 +2119,26 @@ matching A record is found. +@deftypefn {Built-in Function} boolean primitive_hasns (string @var{domain}) +Returns @samp{True} if the domain @var{domain} has at least one +@samp{NS} record. Throws exception if DNS lookup fails. +@end deftypefn + +@deftypefn {Library Function} boolean hasns (string @var{domain}) +Returns @samp{True} if the domain @var{domain} has at least one +@samp{NS} record. Returns @samp{False} if there are no @samp{NS} +records or if the DNS lookup fails. +@end deftypefn + +@deftypefn {Built-in Function} string getns (string @var{domain} ; @ + boolean @var{resolve}, boolean @var{sort}) + Returns a whitespace-separated list of all the @samp{NS} records for +the domain @var{domain}. Optional parameters @var{resolve} and +@var{sort} control the formatting. If @var{resolve} is 0 (the default), the +resulting string will contain IP addresses of the NS servers. If +@var{resolve} is not 0, hostnames will be returned instead. If +@var{sort} is 1, the returned items will be sorted. + +If the @acronym{DNS} query fails, @code{getns} raises an appropriate +exception. +@end deftypefn + @node Geolocation functions @@ -2251,3 +2278,3 @@ argument to the database functions (in description below, marked as @deftypefn {Built-in Function} boolean dbmap (string @var{db}, @ - string @var{key}, [number @var{null}]) + string @var{key}, [boolean @var{null}]) Looks up @var{key} in the @acronym{DBM} file @var{db} and returns @@ -2261,3 +2288,3 @@ argument to the database functions (in description below, marked as @deftypefn {Built-in Function} string dbget (string @var{db}, @ - string @var{key} [, string @var{default}, number @var{null}]) + string @var{key} [, string @var{default}, boolean @var{null}]) Looks up @var{key} in the database @var{db} and returns the value @@ -2271,3 +2298,3 @@ specified, or empty string otherwise. string @var{key}, string @var{value} [, @ - number @var{null}, number @var{mode} ]) + boolean @var{null}, number @var{mode} ]) Inserts in the database a record with the given @var{key} and @@ -2283,3 +2310,3 @@ to explicitly specify the file mode for this database. See also string @var{key}, string @var{value} [, @ - number @var{replace}, number @var{null}, number @var{mode} ]) + boolean @var{replace}, boolean @var{null}, number @var{mode} ]) This is an improved variant of @code{dbput}, which provides a @@ -2292,3 +2319,3 @@ is thrown. @deftypefn {Built-in Function} void dbdel (string @var{db}, @ - string @var{key} [, number @var{null}, number @var{mode}]) + string @var{key} [, boolean @var{null}, number @var{mode}]) Delete from the database the record with the given @var{key}. If @@ -2315,3 +2342,3 @@ The exception-safe interfaces are: @deftypefn {Library Function} string safedbmap (string @var{db}, @ - string @var{key} [, string @var{default}, number @var{null}]) + string @var{key} [, string @var{default}, boolean @var{null}]) @@ -2324,3 +2351,3 @@ not defined. @deftypefn {Library Function} string safedbget (string @var{db}, @ - string @var{key} [, string @var{default}, number @var{null}]) + string @var{key} [, string @var{default}, boolean @var{null}]) @@ -2333,3 +2360,3 @@ not defined. @deftypefn {Library Function} void safedbput (string @var{db}, @ - string @var{key}, string @var{value} [, number @var{null}]) + string @var{key}, string @var{value} [, boolean @var{null}]) @@ -2341,3 +2368,3 @@ the function returns without raising exception. @deftypefn {Library Function} void safedbdel (string @var{db}, @ - string @var{key} [, number @var{null}]) + string @var{key} [, boolean @var{null}]) @@ -2424,4 +2451,5 @@ is currently enabled. If @var{fmtid} does not match any known format, @cindex cache, disabling -@deftypefn {Built-in Function} void db_set_active (string @var{fmtid}, number @var{enable}) - Enables the cache database @var{fmtid} if @var{enable} is not null, +@deftypefn {Built-in Function} void db_set_active (string @var{fmtid}, @ + boolean @var{enable}) + Enables the cache database @var{fmtid} if @var{enable} is @samp{True}, or disables it otherwise. For example, to disable @acronym{DNS} @@ -2786,3 +2814,3 @@ The function @code{revip} is defined in @ref{revip}. -@deftypefn {Built-in Function} number access (string @var{pathname}, @ +@deftypefn {Built-in Function} boolean access (string @var{pathname}, @ number @var{mode}) @@ -2790,4 +2818,4 @@ Checks whether the calling process can access the file @var{pathname}. If @var{pathname} is a symbolic link, it is dereferenced. The -function returns 1 (@samp{true}) if the file can be accessed and 0 -(@samp{false}) otherwise@footnote{@emph{Note}, that the return code is +function returns @samp{True} if the file can be accessed and +@samp{False} otherwise@footnote{@emph{Note}, that the return code is inverted in respect to the system function @samp{access(2)}.}. @@ -4835,3 +4863,3 @@ debug_level("db") @result{} 0 -@deftypefn {Built-in Function} number callout_transcript ([number @var{value}]) +@deftypefn {Built-in Function} boolean callout_transcript ([boolean @var{value}]) Returns the current state of the callout SMTP transcript. The result @@ -29,2 +29,3 @@ #include <mailutils/stream.h> +#include <mailutils/cstr.h> @@ -720 +721,30 @@ resolve_hostname(const char *host, char **pipbuf) } + +/* Return NS records for the given DOMAIN. */ +dns_status +ns_lookup(const char *domain, int resolve, struct dns_reply *reply) +{ + dns_status status = dns_failure; + int rc; + adns_answer *ans; + int i; + + rc = adns_synchronous(get_state(), domain, adns_r_ns_raw, + DEFAULT_QFLAGS, + &ans); + if (rc) + return errno_to_dns_status(rc); + status = adns_to_dns_status(ans->status); + if (status != dns_success) + return status; + + dns_reply_init(reply, dns_reply_str, ans->nrrs); + for (i = 0; i < ans->nrrs; i++) + reply->data.str[i] = mu_strdup(ans->rrs.str[i]); + free(ans); + + if (resolve) + status = dns_reply_resolve(reply); + + return status; +} @@ -72,2 +72,4 @@ dns_status mx_lookup(const char *host, int resolve, struct dns_reply *repl); +dns_status ns_lookup(const char *host, int resolve, struct dns_reply *reply); + #endif diff --git a/mflib/dns.mf4 b/mflib/dns.mf4 index e13130b1..e51656d8 100644 --- a/mflib/dns.mf4 +++ b/mflib/dns.mf4 @@ -61 +61,14 @@ do done + +func hasns (string str) + returns number +do + try + do + return primitive_hasns (str) + done + catch * + do + return 0 + done +done diff --git a/src/builtin/dns.bi b/src/builtin/dns.bi index 3f68f459..0e1e3279 100644 --- a/src/builtin/dns.bi +++ b/src/builtin/dns.bi @@ -281 +281,85 @@ END +MF_DEFUN(primitive_hasns, NUMBER, STRING dom) +{ + struct dns_reply repl; + mf_status stat = dns_to_mf_status(ns_lookup(dom, 0, &repl)); + MF_ASSERT(stat == mf_success || stat == mf_not_found, + mf_status_to_exception(stat), + _("cannot get NS records for %s"), + dom); + dns_reply_free(&repl); + if (stat == mf_success) { + MF_RETURN(1); + } + MF_RETURN(0); +} +END + +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); +} + +MF_DEFUN(getns, STRING, STRING domain, OPTIONAL, NUMBER resolve, NUMBER sort) +{ + mf_status stat; + struct dns_reply reply; + int i; + + stat = dns_to_mf_status(ns_lookup(domain, MF_OPTVAL(resolve), + &reply)); + if (!mf_resolved(stat)) { + MF_THROW(mf_status_to_exception(stat), + _("cannot get MX records for %s"), domain); + } + if (stat == mf_not_found) { + MF_RETURN(""); + } + + MF_OBSTACK_BEGIN(); + 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) + MF_OBSTACK_1GROW(' '); + MF_OBSTACK_GROW(inet_ntoa(s)); + } + } 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) + MF_OBSTACK_1GROW(' '); + MF_OBSTACK_GROW(reply.data.str[i]); + } + } + MF_OBSTACK_1GROW(0); + dns_reply_free(&reply); + MF_RETURN_OBSTACK(); +} +END + |