* Vanquished the evil dn_expand() beast. getmx() now seems to be working.
[citadel.git] / citadel / domain.c
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <netinet/in.h>
4 #include <arpa/nameser.h>
5 #include <resolv.h>
6 #include "sysdep_decls.h"
7 #include "domain.h"
8
9 #define SMART_HOST      "gatekeeper.wdcs.com"
10
11 /*
12  * sort_mxrecs()
13  *
14  * Sort a pile of MX records (struct mx, definted in domain.h) by preference
15  *
16  */
17 void sort_mxrecs(struct mx *mxrecs, int num_mxrecs) {
18         int a, b;
19         struct mx hold1, hold2;
20
21         if (num_mxrecs < 2) return;
22
23         /* do the sort */
24         for (a = num_mxrecs - 2; a >= 0; --a) {
25                 for (b = 0; b <= a; ++b) {
26                         if (mxrecs[b].pref > mxrecs[b+1].pref) {
27
28                                 memcpy(hold1, mxrefs[b], sizeof(struct mx));
29                                 memcpy(hold2, mxrefs[b+1], sizeof(struct mx));
30                                 memcpy(mxrefs[b], hold2, sizeof(struct mx));
31                                 memcpy(mxrefs[b+1], hold1, sizeof(struct mx));
32                         }
33                 }
34         }
35 }
36
37
38
39 /* 
40  * getmx()
41  *
42  * Return one or more MX's for a mail destination.
43  *
44  * Upon success, it fills 'mxbuf' with one or more MX hosts, separated by
45  * vertical bar characters, and returns the number of hosts as its return
46  * value.  If no MX's are found, it returns 0.
47  *
48  */
49 int getmx(char *mxbuf, char *dest) {
50         char answer[1024];
51         int ret;
52         unsigned char *startptr, *endptr, *ptr;
53         int expanded_size;
54         char expanded_buf[1024];
55         unsigned short pref, type;
56         int n;
57         HEADER *hp;
58         int qdcount;
59
60         struct mx *mxrecs = NULL;
61         int num_mxrecs = 0;
62
63         /* If we're configured to send all mail to a smart-host, then our
64          * job here is really easy.
65          */
66         if (0) {        /* FIX */
67                 strcpy(mxbuf, SMART_HOST);
68                 return(1);
69         }
70
71         /* No smart-host?  Look up the best MX for a site.
72          */
73         ret = res_query(
74                 dest,
75                 C_IN, T_MX, (unsigned char *)answer, sizeof(answer)  );
76
77         if (ret < 0) {
78                 lprintf(5, "No MX found\n");
79                 return(0);
80         }
81
82         /* If we had to truncate, shrink the number to avoid fireworks */
83         if (ret > sizeof(answer))
84                 ret = sizeof(answer);
85
86         hp = (HEADER *)&answer[0];
87         startptr = &answer[0];          /* start and end of buffer */
88         endptr = &answer[ret];
89         ptr = startptr + HFIXEDSZ;      /* advance past header */
90
91         for (qdcount = ntohs(hp->qdcount); qdcount--; ptr += ret + QFIXEDSZ) {
92                 if ((ret = dn_skipname(ptr, endptr)) < 0) {
93                         lprintf(9, "dn_skipname error\n");
94                         return(0);
95                 }
96         }
97
98         while(1) {
99                 memset(expanded_buf, 0, sizeof(expanded_buf));
100                 ret = dn_expand(startptr,
101                                 endptr,
102                                 ptr,
103                                 expanded_buf,
104                                 sizeof(expanded_buf)
105                                 );
106                 if (ret < 0) break;
107                 ptr += ret;
108
109                 GETSHORT(type, ptr);
110                 ptr += INT16SZ + INT32SZ;
111                 GETSHORT(n, ptr);
112
113                 if (type != T_MX) {
114                         ptr += n;
115                 }
116
117                 else {
118                         GETSHORT(pref, ptr);
119                         ret = dn_expand(startptr,
120                                         endptr,
121                                         ptr,
122                                         expanded_buf,
123                                         sizeof(expanded_buf)
124                                         );
125                         ptr += ret;
126
127                         ++num_mxrecs;
128                         if (mxrecs == NULL) {
129                                 mxrecs = mallok(sizeof(struct mx));
130                         }
131                         else {
132                                 mxrecs = reallok(mxrecs,
133                                         (sizeof(struct mx) * num_mxrecs) );
134                         }
135
136                         mxrecs[num_mxrecs - 1].pref = pref;
137                         strcpy(mxrecs[num_mxrecs - 1].host, expanded_buf);
138                 }
139         }
140
141         lprintf(9, "unsorted...\n");
142         for (n=0; n<num_mxrecs; ++n)
143                 lprintf(9, "%10d %s\n", mxrecs[n].pref, mxrecs[n].host);
144         sort_mxrecs(mxrecs, num_mxrecs);
145         lprintf(9, "sorted...\n");
146         for (n=0; n<num_mxrecs; ++n)
147                 lprintf(9, "%10d %s\n", mxrecs[n].pref, mxrecs[n].host);
148
149         strcpy(mxbuf, "");
150         for (n=0; n<num_mxrecs; ++n) {
151                 strcat(mxbuf, mxrecs[n].host);
152                 strcat(mxbuf, "|");
153         }
154         phree(mxrecs);
155         return(num_msrecs);
156 }