aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-03-21 10:42:43 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-03-21 10:42:43 +0000
commit35cef0557f63db7b8071103c80023fe80542ad16 (patch)
tree4dceefbaa5f27e7520b52f56cd8e52b57be97576
parent2cdb96d7d77e417f0db62c203cd823fe001a8133 (diff)
downloadmailfromd-35cef0557f63db7b8071103c80023fe80542ad16.tar.gz
mailfromd-35cef0557f63db7b8071103c80023fe80542ad16.tar.bz2
Implement built-in function getmx
git-svn-id: file:///svnroot/mailfromd/branches/release_3_1_patches@1301 7a8a7f39-df28-0410-adc6-e0d955640f24
-rw-r--r--ChangeLog6
-rw-r--r--NEWS11
-rw-r--r--doc/mailfromd.texi12
-rw-r--r--src/bi_dns.m439
-rw-r--r--src/dns.c52
-rw-r--r--src/mailfrom.h1
6 files changed, 120 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index a9af862d..74072f4c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2007-03-21 Sergey Poznyakoff <gray@gnu.org.ua>
+
+ * src/mailfrom.h, src/dns.c: New function getmxip.
+ * src/bi_dns.m4, NEWS, doc/mailfromd.texi: Implement built-in
+ function getmx().
+
2007-03-15 Sergey Poznyakoff <gray@gnu.org.ua>
* src/dns.c (check_pref): Secondary ordering by MX name
diff --git a/NEWS b/NEWS
index 6aaecfde..b13be947 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-Mailfromd NEWS -- history of user-visible changes. 2007-03-15
+Mailfromd NEWS -- history of user-visible changes. 2007-03-21
Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff
See the end of file for copying conditions.
@@ -8,6 +8,15 @@ Please send mailfromd bug reports to <bug-mailfromd@gnu.org.ua>
Version 3.1.4 (SVN)
+* New function: getmx
+
+string getmx(string domain [, number resolve])
+
+Returns a whitespace-separated list of MX names (if `resolve' is not
+given or is 0) or MX IP addresses (if `resolve'==1) for `domain'. If
+`domain' has no MX records, empty string is returned. If the DNS
+query fails, `getmx' raises an appropriate exception.
+
* Short options -l and -L
These options will have different meaning in version 3.2, therefore
diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi
index cda32c6b..702351d5 100644
--- a/doc/mailfromd.texi
+++ b/doc/mailfromd.texi
@@ -3913,6 +3913,18 @@ in your startup program, it will result in at most one actual DNS
lookup. See below (@pxref{DNS Cache Management}) for the description
of the database and its management.
+@deftypefn {Built-in Function} string getmx(string @var{domain} @
+ [, number @var{resolve}])
+ Returns a whitespace-separated list of MX names (if @var{resolve} is not
+given or if it is @code{0}) or MX IP addresses (if
+@code{@var{resolve}!=0})) for @var{domain}. If @var{domain} has no
+MX records, empty string is returned. If the DNS query fails,
+@code{getmx} raises an appropriate exception.
+
+@emph{Note}: this interface will change in future releases, when array
+data types are implemented.
+@end deftypefn
+
@anchor{builtin hasmx}
@deftypefn {Built-in Function} boolean hasmx (string @var{domain})
Returns @code{true} if the domain name given by its argument
diff --git a/src/bi_dns.m4 b/src/bi_dns.m4
index b88985f1..a2639a2b 100644
--- a/src/bi_dns.m4
+++ b/src/bi_dns.m4
@@ -62,6 +62,45 @@ MF_DEFUN(hasmx, NUMBER, STRING string)
}
END
+MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER resolve)
+{
+ mxbuf_t mxbuf;
+ mf_status mxstat;
+ int i;
+
+ if (resolve)
+ mxstat = getmxip(domain, mxbuf);
+ else
+ mxstat = getmx(domain, mxbuf);
+ MF_ASSERT(mxstat == mf_success || mxstat == mf_not_found,
+ mxstat,
+ "Cannot get MX records for %s", domain);
+ if (mxstat == mf_not_found)
+ MF_RETURN_STRING("");
+ else {
+ int i;
+ size_t ns;
+ char *p;
+
+ MF_BEGIN_TEMP_SPACE(s, size);
+
+ for (i = 0, ns = 0, p = s; mxbuf[i]; i++) {
+ size_t len = strlen(mxbuf[i]);
+ if (ns + len + 1 > size)
+ break;
+ if (i > 0)
+ *p++ = ' ';
+ memcpy(p, mxbuf[i], len);
+ p += len;
+ ns += len + 1;
+ }
+ *p = 0;
+ freemx(mxbuf);
+ MF_RETURN_TEMP_SPACE(ns);
+ }
+}
+END
+
static int
resolve_host(const char *string, unsigned long *ip)
{
diff --git a/src/dns.c b/src/dns.c
index 012efad8..bdd4312d 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -226,6 +226,58 @@ getmx(char *host, mxbuf_t mxbuf)
return rc;
}
+static int
+comp_in_addr(const void *a, const void *b)
+{
+ const struct in_addr *in_a = a;
+ const struct in_addr *in_b = b;
+
+ if (in_a->s_addr < in_b->s_addr)
+ return -1;
+ else if (in_a->s_addr > in_b->s_addr)
+ return 1;
+ return 0;
+}
+
+mf_status _resolve_hostname(char *host, char *answer, size_t answer_size,
+ char *ipbuf, size_t ipbsize, unsigned long *ttl);
+
+mf_status
+getmxip(char *host, mxbuf_t mxbuf)
+{
+ mf_status mxstat;
+ struct in_addr inbuf[MAXMXCOUNT];
+ int i, j;
+ static unsigned char *answer;
+
+ if (!answer)
+ answer = malloc(MAXPACKET);
+
+ mxstat = getmx(host, mxbuf);
+ if (mxstat != mf_success)
+ return mxstat;
+ for (i = j = 0; i < MAXMXCOUNT && mxbuf[i]; i++) {
+ unsigned long ttl;
+ mf_status stat = _resolve_hostname(mxbuf[i],
+ answer, MAXPACKET,
+ (char*) &inbuf[j],
+ sizeof inbuf[0],
+ &ttl);
+ if (stat == mf_success) {
+ inbuf[j].s_addr = ntohl(inbuf[j].s_addr);
+ j++;
+ }
+ }
+ qsort(inbuf, j, sizeof inbuf[0], comp_in_addr);
+ for (i = 0; i < j; i++) {
+ inbuf[i].s_addr = htonl(inbuf[i].s_addr);
+ mxbuf[i] = xstrdup(inet_ntoa(inbuf[i]));
+ }
+ if (i < MAXMXCOUNT)
+ mxbuf[i] = NULL;
+ return mf_success;
+}
+
void
freemx(mxbuf_t mxbuf)
{
diff --git a/src/mailfrom.h b/src/mailfrom.h
index caf304b8..dc801b65 100644
--- a/src/mailfrom.h
+++ b/src/mailfrom.h
@@ -138,6 +138,7 @@ mf_status resolve_ipstr(const char *ipstr, char **hbuf);
mf_status resolve_hostname(const char *host, char **pipbuf);
mf_status getmx(char *ipstr, mxbuf_t mxbuf);
+mf_status getmxip(char *host, mxbuf_t mxbuf);
void freemx(mxbuf_t mxbuf);

Return to:

Send suggestions and report system problems to the System administrator.