diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-03-21 10:42:43 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-03-21 10:42:43 +0000 |
commit | 35cef0557f63db7b8071103c80023fe80542ad16 (patch) | |
tree | 4dceefbaa5f27e7520b52f56cd8e52b57be97576 | |
parent | 2cdb96d7d77e417f0db62c203cd823fe001a8133 (diff) | |
download | mailfromd-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-- | ChangeLog | 6 | ||||
-rw-r--r-- | NEWS | 11 | ||||
-rw-r--r-- | doc/mailfromd.texi | 12 | ||||
-rw-r--r-- | src/bi_dns.m4 | 39 | ||||
-rw-r--r-- | src/dns.c | 52 | ||||
-rw-r--r-- | src/mailfrom.h | 1 |
6 files changed, 120 insertions, 1 deletions
@@ -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 @@ -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) { @@ -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); |