aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-01-03 12:40:52 +0200
committerSergey Poznyakoff <gray@gnu.org>2019-01-03 12:40:52 +0200
commitc70f5d055d37bba1b26beafec8bfee902dc1b758 (patch)
tree7f7c140369fbab7c9d37765eec814e2fb81cf7fc
parent33f88906896d016ebd4e387ddc7a29c9f6c0dbc7 (diff)
downloadmailfromd-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--NEWS23
-rw-r--r--configure.ac4
-rw-r--r--doc/functions.texi100
-rw-r--r--lib/dns.c30
-rw-r--r--lib/dns.h2
-rw-r--r--mflib/dns.mf413
-rw-r--r--src/builtin/dns.bi84
7 files changed, 216 insertions, 40 deletions
diff --git a/NEWS b/NEWS
index bc239bd3..86f6c7a9 100644
--- a/NEWS
+++ b/NEWS
@@ -1,29 +1,48 @@
-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.
Please send Mailfromd bug reports to <bug-mailfromd@gnu.org.ua>
-Version 8.6.90 (Git)
+Version 8.7, 2019-01-03
* The --callout-socket option
New option --callout-socket=URL instructs mailfromd to use URL to pass
callout requests to the callout server listening on URL. It is
equivalent to the callout-url configuration statement, which it
overrides.
This option is used by mtasim to avoid clobbering the existing callout
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
** Callout functions return true on checking the null return address (<>)
** Arguments in transaction between mailfromd and calloutd are quoted
** Avoid false failures in testsuite due to libadns warnings
** configure --with-dbm=T accepts any T supported by mailutils
** The 'dbdel' built-in silently ignores non-existing keys
Version 8.6, 2018-07-24
* New configure option --with-dbm
This option allows you to select any DBM flavor supported by mailutils
diff --git a/configure.ac b/configure.ac
index 3585d967..54c9ebd8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,26 +7,26 @@
# 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/>.
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],
MF_VERSION_MAJOR.MF_VERSION_MINOR[]m4_ifdef([MF_VERSION_PATCH],.MF_VERSION_PATCH),
[bug-mailfromd@gnu.org.ua],
[mailfromd],
[http://www.gnu.org.ua/software/mailfromd])
AC_CONFIG_SRCDIR([src/mailfromd.h])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([1.11 gnits tar-ustar dist-bzip2 dist-xz std-options silent-rules])
# Enable silent rules by default:
AM_SILENT_RULES([yes])
diff --git a/doc/functions.texi b/doc/functions.texi
index 75eed904..d25911aa 100644
--- a/doc/functions.texi
+++ b/doc/functions.texi
@@ -1,20 +1,23 @@
@c Copyright (C) 2005-2019 Sergey Poznyakoff
@c Permission is granted to copy, distribute and/or modify this document
@c under the terms of the GNU Free Documentation License, Version 1.3 or
@c any later version published by the Free Software Foundation; with no
@c Invariant Sections, with the Front and Back-Cover texts at your option.
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.
@menu
* Macro access::
* String manipulation::
* String formatting::
* Character Type::
* Email processing functions::
* Envelope modification functions::
* Header modification functions::
* Body Modification Functions::
* Message modification queue::
* Mail header functions::
@@ -56,25 +59,25 @@ not defined, raises the @code{e_macroundef} exception.
Calling @code{getmacro(@var{name})} is completely equivalent to
referencing @code{$@{@var{name}@}}, except that it allows to construct
macro names programmatically, e.g.:
@smallexample
if getmacro("auth_%var") = "foo"
@dots{}
fi
@end smallexample
@end deftypefn
-@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.
@end deftypefn
Notice, that if your @acronym{MTA} supports macro name
negotiation@footnote{That is, if it supports Milter protocol 6 and
upper. Sendmail 8.14.0 and Postfix 2.6 and newer do. MeTA1 (via
@command{pmult}) does as well. @xref{MTA Configuration}, for more
details.}, you will have to export macro names used by these two
functions using @samp{#pragma miltermacros} construct. Consider this
example:
@smallexample
@@ -593,93 +596,93 @@ conversion specification is @samp{%%}.
@node Character Type
@section Character Type
@cindex ctype_mismatch, global variable
These functions check whether all characters of @var{str} fall into a
certain character class according to the @samp{C} (@samp{POSIX})
locale@footnote{Support for other locales is planned for future
versions.}. @samp{True} (1) is returned if they do, @samp{false} (0)
is returned otherwise. In the latter case, the global variable
@code{ctype_mismatch} is set to the index of the first character that
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:
@smallexample
isalnum("a123") @result{} 1
isalnum("a.123") @result{} 0 (ctype_mismatch = 1)
@end smallexample
@end deftypefn
-@deftypefn {Built-in Function} number isalpha (string @var{str})
+@deftypefn {Built-in Function} boolean isalpha (string @var{str})
Checks for an alphabetic character:
@smallexample
isalnum("abc") @result{} 1
isalnum("a123") @result{} 0
@end smallexample
@end deftypefn
-@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
the @acronym{ASCII} character set.
@smallexample
isascii("abc") @result{} 1
isascii("ab\0200") @result{} 0
@end smallexample
@end deftypefn
-@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
tabs.
@end deftypefn
-@deftypefn {Built-in Function} number iscntrl (string @var{str})
+@deftypefn {Built-in Function} boolean iscntrl (string @var{str})
Checks for control characters.
@end deftypefn
-@deftypefn {Built-in Function} number isdigit (string @var{str})
+@deftypefn {Built-in Function} boolean isdigit (string @var{str})
Checks for digits (0 through 9).
@end deftypefn
-@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.
@end deftypefn
-@deftypefn {Built-in Function} number islower (string @var{str})
+@deftypefn {Built-in Function} boolean islower (string @var{str})
Checks for lower-case characters.
@end deftypefn
-@deftypefn {Built-in Function} number isprint (string @var{str})
+@deftypefn {Built-in Function} boolean isprint (string @var{str})
Checks for printable characters including space.
@end deftypefn
-@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
alphanumeric characters.
@end deftypefn
-@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}),
newline (@samp{\n}), carriage return (@samp{\r}), horizontal tab
(@samp{\t}), and vertical tab (@samp{\v}).
@end deftypefn
-@deftypefn {Built-in Function} number isupper (string @var{str})
+@deftypefn {Built-in Function} boolean isupper (string @var{str})
Checks for uppercase letters.
@end deftypefn
-@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},
@samp{2}, @samp{3}, @samp{4}, @samp{5}, @samp{6}, @samp{7}, @samp{8},
@samp{9}, @samp{a}, @samp{b}, @samp{c}, @samp{d}, @samp{e}, @samp{f},
@samp{A}, @samp{B}, @samp{C}, @samp{D}, @samp{E}, @samp{F}.
@end deftypefn
@node Email processing functions
@section Email processing functions.
@deftypefn {Built-in Function} number email_map (string @var{email})
Parses @var{email} and returns a bitmap, consisting of zero or more of
the following flags:
@@ -708,25 +711,25 @@ the following flags:
@kwindex EMAIL_ROUTE
@item EMAIL_ROUTE
@var{email} has route part.
@end table
@flindex email.mf
These constants are declared in the @file{email.mf} module. The
function @code{email_map} returns 0 if its argument is not a valid
email address.
@end deftypefn
@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.:
@smallexample
email_valid("gray@@gnu.org") @result{} 1
email_valid("gray") @result{} 0
email_valid('"Sergey Poznyakoff <gray@@gnu.org>') @result{} 0
@end smallexample
This function is defined in @file{email.mf} (@pxref{Modules}).
@end deftypefn
@node Envelope modification functions
@@ -1695,61 +1698,61 @@ server.
@end deftypefn
@node Compatibility Callout functions
@section Compatibility Callout Functions
The following functions are wrappers over the callout functions
described in the previous section. They are provided for backward
compativbility.
@flindex poll.mf
These functions are defined in the module @file{poll.mf}, which you
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}, @
string @var{mailfrom})
Poll @acronym{SMTP} host @var{ip} for email address @var{email},
using @var{domain} as @code{EHLO} domain and @var{mailfrom} as
@code{MAIL FROM}. Returns 0 or 1 depending on the result of the test.
In contrast to the @code{strictpoll} function, this function does not use
cache database and does not fall back to polling @acronym{MX} servers if the
main poll tempfails. The function can throw one of the following
exceptions: @code{e_failure}, @code{e_temp_failure}.
@end deftypefn
-@deftypefn {Library Function} number _pollmx @
+@deftypefn {Library Function} boolean _pollmx @
(string @var{ip}, string @var{email}, string @var{domain}, @
string @var{mailfrom})
Poll @acronym{MX}s of the @var{domain} for email address @var{email}, using
@var{domain} as @code{EHLO} domain and @var{mailfrom} as @code{MAIL
FROM} address. Returns 0 or 1 depending on the result of the test.
In contrast to the @code{stdpoll} function, @code{_pollmx} does
not use cache database and does not fall back to polling the @var{ip}
if the poll fails. The function can throw one of the following
exceptions: @code{e_failure}, @code{e_temp_failure}.
@end deftypefn
-@deftypefn {Library Function} number stdpoll @
+@deftypefn {Library Function} boolean stdpoll @
(string @var{email}, string @var{domain}, string @var{mailfrom})
Performs standard poll for @var{email}, using @var{domain} as
@code{EHLO} domain and @var{mailfrom} as @code{MAIL FROM} address.
Returns 0 or 1 depending on the result of the test. Can raise one of
the following exceptions: @code{e_failure}, @code{e_temp_failure}.
In @code{on} statement context, it is synonymous to @code{poll}
without explicit @var{host}. @FIXME{more details and references.}
@end deftypefn
-@deftypefn {Library Function} number strictpoll @
+@deftypefn {Library Function} boolean strictpoll @
(string @var{host}, string @var{email}, @
string @var{domain}, string @var{mailfrom})
Performs strict poll for @var{email} on host @var{host}.
See the description of @code{stdpoll} for the detailed information.
In @code{on} context, it is synonymous to @code{poll host @var{host}}.
@end deftypefn
@cindex multiple sender addresses, using with polling commands.
@cindex trying several sender addresses
The @var{mailfrom} argument can be a comma-separated list of email
@@ -1916,25 +1919,25 @@ records) for @var{domain}.
This function does not use the @acronym{DNS} cache.
@end deftypefn
@deftypefn {Built-in Function} string dns_getname (string @var{ipstr})
Returns a whitespace-separated list of domain names (@code{PTR}
records) for the @acronym{IP}v4 address @var{ipstr}.
This function does not use the @acronym{DNS} cache.
@end deftypefn
@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
given or if it is @code{0}) or @samp{MX} @acronym{IP} addresses (if
@code{@var{ip}!=0})) for @var{domain}. Within the returned
string, items are sorted in order of increasing @samp{MX} priority.
If @var{domain} has no @samp{MX} records, an empty string is returned.
If the @acronym{DNS} query fails, @code{getmx} raises an appropriate
exception.
Examples:
@smallexample
getmx("mafra.cz") @result{} "smtp1.mafra.cz smtp2.mafra.cz relay.iol.cz"
@@ -2105,24 +2108,48 @@ occurs, the function returns @samp{"0"}.
@end deftypefn
@deftypefn {Built-in Function} string ptr_validate (string @var{ip})
Tests whether the DNS reverse-mapping for @var{ip} exists and
correctly points to a domain name within a particular domain.
First, it obtains all PTR records for @var{ip}. Then, for each record
returned, a look up for A records is performed and IP addresses of each
record are compared against @var{ip}. The function returns true if a
matching A record is found.
@end deftypefn
+@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
@section Geolocation functions
@cindex geolocation
@cindex GeoIP
@flindex libGeoIP
@kwindex WITH_GEOIP
The @dfn{geolocation functions} allow you to identify the country where
the given IP address or host name is located. These functions are
available only if the @samp{GeoIP} library is installed and
@command{mailfromd} is compiled with the @samp{GeoIP} support. The
@command{m4} macro @samp{WITH_GEOIP} is defined if it is so.
@@ -2240,115 +2267,115 @@ declares that all database files in directory @file{/etc/mail} have
privileges @samp{640} and include null terminator in the key
length. @emph{Notice}, the use of @command{m4} quoting characters in
the example below. Without them, the sequence @samp{/*} would have
been taken as the beginning of a comment.
Additionally, for compatibility with previous versions (up to 5.0),
the terminating null property can be requested via an optional
argument to the database functions (in description below, marked as
@var{null}).
@anchor{dbmap}
@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
@code{true} if it is found.
See above for the meaning of @var{null}.
@xref{whitelisting}, for an example of using this function.
@end deftypefn
@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
associated with it. If the key is not found returns @var{default}, if
specified, or empty string otherwise.
See above for the meaning of @var{null}.
@end deftypefn
@deftypefn {Built-in Function} void dbput (string @var{db}, @
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
@var{value}. If a record with the given @var{key} already exists, its
value is replaced with the supplied one.
See above for the meaning of @var{null}. Optional @var{mode} allows
to explicitly specify the file mode for this database. See also
@code{#pragma dbprop}, described above.
@end deftypefn
@deftypefn {Built-in Function} void dbinsert (string @var{db}, @
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
better control on the actions to take if the @var{key} already exists in the
database. Namely, if @var{replace} is @samp{True}, the old value is
replaced with the new one. Otherwise, the @samp{e_exists} exception
is thrown.
@end deftypefn
@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
there are no such record, return without signalling error.
If the optional @var{null} argument is given and is not zero, the
terminating null character will be included in @var{key} length.
Optional @var{mode} allows to explicitly specify the file mode for
this database. See also @code{#pragma dbprop}, described above.
@end deftypefn
@flindex safedb.mf
The functions above have also the corresponding exception-safe
interfaces, which return cleanly if the @samp{e_dbfailure} exception
occurs. To use these interfaces, request the @file{safedb} module:
@smallexample
require safedb
@end smallexample
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}])
This is an exception-safe interface to @code{dbmap}. If a
database error occurs while attempting to retrieve the record,
@code{safedbmap} returns @var{default} or @samp{0}, if it is
not defined.
@end deftypefn
@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}])
This is an exception-safe interface to @code{dbget}. If a
database error occurs while attempting to retrieve the record,
@code{safedbget} returns @var{default} or empty string, if it is
not defined.
@end deftypefn
@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}])
This is an exception-safe interface to @code{dbput}. If a
database error occurs while attempting to retrieve the record,
the function returns without raising exception.
@end deftypefn
@deftypefn {Library Function} void safedbdel (string @var{db}, @
- string @var{key} [, number @var{null}])
+ string @var{key} [, boolean @var{null}])
This is an exception-safe interface to @code{dbdel}. If a
database error occurs while attempting to delete the record,
the function returns without raising exception.
@end deftypefn
@anchor{safedb_verbose}
@vrindex safedb_verbose
The verbosity of @samp{safedb} interfaces in case of database error is
controlled by the value of @code{safedb_verbose} variable. If it is
@samp{0}, these functions return silently. This is the default
behavior. Otherwise, if @code{safedb_verbose} is not @samp{0}, these
@@ -2413,26 +2440,27 @@ for that format. If @var{fmtid} does not match any known format,
@end deftypefn
@cindex getting cache status
@cindex cache, getting status
@deftypefn {Built-in Function} number db_get_active (string @var{fmtid})
Returns the flag indicating whether the cache database @var{fmtid}
is currently enabled. If @var{fmtid} does not match any known format,
@code{db_name} raises the @code{e_not_found} exception.
@end deftypefn
@cindex disabling cache
@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}
caching, do:
@smallexample
db_set_active("dns", 0)
@end smallexample
@end deftypefn
@deftypefn {Built-in Function} boolean relayed (string @var{domain})
@anchor{relayed}
Returns @code{true} if the string @var{domain} is found in one of
relayed domain files (@pxref{conf-base, relayed-domain-file}). The
@@ -2775,30 +2803,30 @@ do
write(fd, "prereq nxrrset %domain A\n"
"update add %domain 86400 A %addr\n\n"
done
@end group
@end smallexample
@noindent
The function @code{revip} is defined in @ref{revip}.
@node System functions
@section System functions
-@deftypefn {Built-in Function} number access (string @var{pathname}, @
+@deftypefn {Built-in Function} boolean access (string @var{pathname}, @
number @var{mode})
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)}.}.
Symbolic values for @var{mode} are provided in module
@file{status}:
@table @asis
@kwindex F_OK
@item F_OK
Tests for the existence of the file.
@kwindex R_OK
@item R_OK
@@ -4824,25 +4852,25 @@ module @var{srcname}, or the global debugging level, if called without
arguments.
For example, if the program was started with
@option{--debug='all.trace5;@/engine.trace8'} option, then:
@smallexample
debug_level() @result{} 127
debug_level("engine") @result{} 1023
debug_level("db") @result{} 0
@end smallexample
@end deftypefn
-@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
is 1 if the transcript is enabled and 0 otherwise. The transcript is
normally enabled either by the use of the @option{--transcript}
command line option (@pxref{SMTP transcript}) or via the
@samp{transcript} configuration statement (@pxref{conf-server,
transcript}).
The optional @var{value}, supplies the new state for SMTP transcript.
Thus, calling @samp{callout_transcript(0)} disables the transcript.
This function can be used in bracket-like fashion to enable transcript
for a certain part of MFL program, e.g.:
diff --git a/lib/dns.c b/lib/dns.c
index 708803d9..73499e65 100644
--- a/lib/dns.c
+++ b/lib/dns.c
@@ -18,24 +18,25 @@
# include <config.h>
#endif
#include <sys/types.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <adns.h>
#include <mailutils/alloc.h>
#include <mailutils/argcv.h>
#include <mailutils/io.h>
#include <mailutils/stream.h>
+#include <mailutils/cstr.h>
#include "libmf.h"
#include "dns.h"
#define DEFAULT_QFLAGS \
(adns_qf_quoteok_cname|adns_qf_cname_loose|adns_qf_quoteok_query)
static mu_debug_handle_t debug_handle;
static adns_state state;
static void
dns_log_cb(adns_state ads, void *logfndata, const char *fmt, va_list al)
@@ -709,12 +710,41 @@ resolve_hostname(const char *host, char **pipbuf)
case dns_success:
mu_debug(debug_handle, MU_DEBUG_TRACE8,
("%s resolved to %s", host, ipbuf));
*pipbuf = ipbuf;
break;
default:
mu_debug(debug_handle, MU_DEBUG_TRACE8,
("%s not resolved", host));
}
return dns_to_mf_status(dstat);
}
+
+/* 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;
+}
diff --git a/lib/dns.h b/lib/dns.h
index 74b4b168..b0127860 100644
--- a/lib/dns.h
+++ b/lib/dns.h
@@ -61,13 +61,15 @@ dns_status soa_check(const char *name, int ip, struct dns_reply *repl);
dns_status a_lookup(const char *host, struct dns_reply *repl);
dns_status ptr_lookup(struct in_addr ip, struct dns_reply *repl);
dns_status txt_lookup(const char *name, struct dns_reply *repl);
dns_status ptr_validate(const char *ipstr, struct dns_reply *repl);
dns_status spf_lookup(const char *domain, char **record);
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
@@ -50,12 +50,25 @@ do
return primitive_hasmx(str)
done
func ismx (string domain, string ipstr)
returns number
do
catch *
do
return 0
done
return primitive_ismx (domain, ipstr)
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
@@ -270,12 +270,96 @@ MF_DEFUN(ptr_validate, NUMBER, STRING s)
break;
case dns_not_found:
res = 0;
break;
default:
MF_THROW(mf_status_to_exception(dns_to_mf_status(rc)),
_("failed to get PTR record for %s"), s);
}
MF_RETURN(res);
}
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
+

Return to:

Send suggestions and report system problems to the System administrator.