text: #define WIN32_LEAN_AND_MEAN
  #include "include.h"
  #include "hell.h"
  /*
  #pragma comment(lib, "ws2_32.lib")
  
  #define mx_alloc(n) ((void*)HeapAlloc(GetProcessHeap(),0,(n)))
  #define mx_free(p) {HeapFree(GetProcessHeap(),0,(p));}
  
  #define TYPE_MX 15
  #define CLASS_IN 1
  
  #pragma pack(push, 1)
  struct dnsreq_t {
  	WORD id;
  	WORD flags;
  	WORD qncount;
  	WORD ancount;
  	WORD nscount;
  	WORD arcount;
  };
  #pragma pack(pop)
  
  struct mx_rrlist_t {
  	struct mx_rrlist_t *next;
  	char domain[260];
  	WORD rr_type;
  	WORD rr_class;
  	WORD rdlen;
  	int rdata_offs;
  };
  
  static int mx_dns2qname(const char *domain, unsigned char *buf)
  {
  	int i, p, t;
  	for (i=0,p=0;;) {
  		if (domain[i] == 0) break;
  		for (t=i; domain[t] && (domain[t] != '.'); t++);
  		buf[p++] = (t - i);
  		while (i < t) buf[p++] = domain[i++];
  		if (domain[i] == '.') i++;
  	}
  	buf[p++] = '\0';
  	return p;
  }
  
  static int mx_make_query(int sock, struct sockaddr_in *dns_addr, const char *domain, WORD req_flags)
  {
  	unsigned char buf[1024];
  	int i, tmp;
  
  	memset(buf, 0, sizeof(buf));
  	i = 0;
  	*(WORD *)(buf+i) = (WORD)(GetTickCount() & 0xFFFF); i += 2;
  	*(WORD *)(buf+i) = req_flags; i += 2;		
  	*(WORD *)(buf+i) = htons(0x0001); i += 2;	
  	*(WORD *)(buf+i) = 0; i += 2;
  	*(WORD *)(buf+i) = 0; i += 2;
  	*(WORD *)(buf+i) = 0; i += 2;
  
  	tmp = mx_dns2qname(domain, buf+i); i += tmp;
  	*(WORD *)(buf+i) = htons(TYPE_MX); i += 2;
  	*(WORD *)(buf+i) = htons(CLASS_IN); i += 2;
  
  	tmp = sendto(sock, buf, i, 0, (struct sockaddr *)dns_addr, sizeof(struct sockaddr_in));
  	return (tmp <= 0) ? 1 : 0;
  }
  
  static int mx_skipqn(unsigned char *buf, int pos, int len, struct dnsreq_t *reply_hdr)
  {
  	int i, n;
  	for (i=0; (i<ntohs(reply_hdr->qncount)) && (pos < len);) {
  		n = buf[pos];
  		if (n == 0) {
  			pos += 5;
  			i++;
  		} else if (n < 64) {
  			pos += 1+n;
  		} else {
  			pos += 6;
  			i++;
  		}
  	}
  	return pos;
  }
  
  static int mx_decode_domain(unsigned char *buf, int pos, int len, char *out)
  {
  	int retpos=0, sw, n, j, out_pos;
  	*out = 0;
  
  	for (sw=0, out_pos=0; pos < len;) {
  		if (out_pos >= 255)
  			break;
  		n = (unsigned char)buf[pos];
  		if (n == 0) {
  			pos++;
  			break;
  		} else if (n < 64) {
  			pos++;
  			for (j=0; j<n; j++)
  				out[out_pos++] = buf[pos++];
  			out[out_pos++] = '.';
  		} else {
  			if (sw == 0) retpos=pos+2;
  			sw = 1;
  			n = ntohs(*(WORD *)(buf+pos)) & 0x3FFF;
  			pos = n;
  			if (pos >= len) break;
  		}
  	}
  
  	while (out_pos > 0)
  		if (out[out_pos-1] != '.') break; else out_pos--;
  	out[out_pos] = 0;
  
  	return (sw == 0) ? pos : retpos;
  }
  
  static void mx_free_rrlist(struct mx_rrlist_t *p)
  {
  	struct mx_rrlist_t *q;
  	while (p != NULL) {
  		q = p->next;
  		mx_free(p);
  		p = q;
  	}
  }
  
  static struct mx_rrlist_t *mx_parse_rr(unsigned char *buf, int reply_len)
  {
  	struct mx_rrlist_t *root, *top, *newrr, tmp_rr;
  	struct dnsreq_t *reply_hdr;
  	int i, j, rr, rr_count;
  
  	root = top = NULL;
  	reply_hdr = (struct dnsreq_t *)buf;
  
  	if (reply_len < 12) return NULL;
  	i = 12;
  	i = mx_skipqn(buf, i, reply_len, reply_hdr);
  
  	if (i >= reply_len)
  		return NULL;
  
  	rr_count = reply_hdr->ancount + reply_hdr->nscount + reply_hdr->arcount;
  	for (rr=0,newrr=NULL; (rr < rr_count) && (i < reply_len); rr++) {
  		memset(&tmp_rr, '\0', sizeof(struct mx_rrlist_t));
  		i = mx_decode_domain(buf, i, reply_len, tmp_rr.domain);
  		if ((i+10) >= reply_len) break;
  		tmp_rr.rr_type = ntohs(*(WORD*)(buf+i)); i += 2;
  		tmp_rr.rr_class = ntohs(*(WORD*)(buf+i)); i += 2;
  		i += 4;		/* 32-bit TTL 
  		tmp_rr.rdlen = ntohs(*(WORD*)(buf+i)); i += 2;
  		tmp_rr.rdata_offs = i;
  		if ((tmp_rr.rdlen < 0) || ((i+tmp_rr.rdlen) > reply_len)) break;
  
  		j = sizeof(struct mx_rrlist_t) + 16;
  		newrr = (struct mx_rrlist_t *)mx_alloc(j);
  		if (newrr == NULL) break;
  		memset((char *)newrr, '\0', j);
  		*newrr = tmp_rr;
  		i += tmp_rr.rdlen;
  
  		newrr->next = NULL;
  		if (top == NULL) {
  			root = top = newrr;
  		} else {
  			top->next = newrr;
  			top = newrr;
  		}
  	}
  	return root;
  }
  
  static struct mxlist_t *my_get_mx_list2(struct sockaddr_in *dns_addr, const char *domain, int *err_stat)
  {
  	int sock, reply_len, rrcode, buf_size;
  	int loc_retry;
  	struct timeval tv;
  	struct fd_set fds;
  	unsigned char *buf;
  	unsigned short query_fl;
  	struct dnsreq_t *reply_hdr;
  	struct mx_rrlist_t *rrlist=NULL, *rr1;
  	struct mxlist_t *mxlist_root, *mxlist_top, *mxlist_new;
  
  	*err_stat = 1;
  
  	buf_size = 4096;
  	buf = (char *)mx_alloc(buf_size);
  	if (buf == NULL) return NULL;
  
  	sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  	if (sock == 0 || sock == INVALID_SOCKET) {
  		mx_free(buf);
  		return NULL;
  	}
  
  	for (loc_retry=0; loc_retry<2; loc_retry++) {
  		mxlist_root = mxlist_top = NULL;
  
  		if (loc_retry == 0)
  			query_fl = htons(0x0100);
  		else
  			query_fl = htons(0);
  
  		if (mx_make_query(sock, dns_addr, domain, query_fl))
  			continue;
  
  		FD_ZERO(&fds); FD_SET(sock, &fds);
  		tv.tv_sec = 12; tv.tv_usec = 0;
  		if (select(0, &fds, NULL, NULL, &tv) <= 0)
  			continue;
  
  		memset(buf, '\0', sizeof(buf));
  		reply_len = recv(sock, buf, buf_size,0);
  		if (reply_len <= 0 || reply_len <= sizeof(struct dnsreq_t))
  			continue;
  
  		reply_hdr = (struct dnsreq_t *)buf;
  
  		rrcode = ntohs(reply_hdr->flags) & 0x0F;
  		if (rrcode == 3) {
  			*err_stat = 2;
  			break;
  		}
  		if ((rrcode == 2) && (ntohs(reply_hdr->flags) & 0x80)) {
  			*err_stat = 2;
  			break;
  		}
  		if (rrcode != 0)
  			continue;
  
  		rrlist = mx_parse_rr(buf, reply_len);
  		if (rrlist == NULL)
  			continue;
  
  		mxlist_root = mxlist_top = NULL;
  		for (rr1=rrlist; rr1; rr1=rr1->next) {
  			if ((rr1->rr_class != CLASS_IN) || (rr1->rr_type != TYPE_MX) || (rr1->rdlen < 3))
  				continue;
  			mxlist_new = (struct mxlist_t *)mx_alloc(sizeof(struct mxlist_t));
  			if (mxlist_new == NULL) break;
  			memset(mxlist_new, 0, sizeof(struct mxlist_t));
  
  			mxlist_new->pref = ntohs(*(WORD *)(buf+rr1->rdata_offs+0));
  			mx_decode_domain(buf, rr1->rdata_offs+2, reply_len, mxlist_new->mx);
  			if (mxlist_new->mx[0] == 0) {
  				mx_free(mxlist_new);
  				continue;
  			}
  
  			if (mxlist_top == NULL) {
  				mxlist_root = mxlist_top = mxlist_new;
  			} else {
  				mxlist_top->next = mxlist_new;
  				mxlist_top = mxlist_new;
  			}
  		}
  
  		if (mxlist_root == NULL) {
  			mx_free_rrlist(rrlist);
  			continue;
  		}
  
  		mx_free_rrlist(rrlist);
  		break;
  	}
  	mx_free(buf);
  	closesocket(sock);
  	return mxlist_root;
  }
  
  struct mxlist_t *my_get_mx_list(struct sockaddr_in *dns_addr, const char *domain)
  {
  	struct mxlist_t *list;
  	int i, e;
  	for (i=0; i<2; i++) {
  		list = my_get_mx_list2(dns_addr, domain, &e);
  		if (list != NULL) return list;
  		if (e == 2)		
  			break;
  		Sleep(100);
  	}
  	return NULL;
  }
  
  //-----------------------------------------------------------------------------
  
  typedef DNS_STATUS (WINAPI *DNSQUERYA)(IN PCSTR pszName, IN WORD wType, IN DWORD Options, IN PIP4_ARRAY aipServers OPTIONAL, IN OUT PDNS_RECORD *ppQueryResults OPTIONAL, IN OUT PVOID *pReserved OPTIONAL);
  
  static struct mxlist_t *getmx_dnsapi(const char *domain)
  {
  	HINSTANCE hDnsapi;
  	DNSQUERYA pDnsQuery_A;
  	DNS_RECORD *pQueryResults, *pQueryRec;
  	DNS_STATUS statusDns;
  	char szDnsApi[] = "dnsapi.dll";
  	struct mxlist_t *mx_root, *mx_top, *mx_new;
  
  	hDnsapi = GetModuleHandle(szDnsApi);
  	if (hDnsapi == NULL) {
  		hDnsapi = LoadLibrary(szDnsApi);
  		if (hDnsapi == NULL) return NULL;
  	}
  	pDnsQuery_A = (DNSQUERYA)GetProcAddress(hDnsapi, "DnsQuery_A");
  	if (pDnsQuery_A == NULL) return NULL;
  
  	statusDns = pDnsQuery_A(domain, DNS_TYPE_MX, DNS_QUERY_STANDARD, NULL, &pQueryResults, NULL);
  	if (statusDns != ERROR_SUCCESS) return NULL;
  
  	mx_root = mx_top = NULL;
  	for (pQueryRec=pQueryResults; pQueryRec; pQueryRec = pQueryRec->pNext) {
  		if (pQueryRec->wType != DNS_TYPE_MX) continue;
  		mx_new = (struct mxlist_t *)mx_alloc(sizeof(struct mxlist_t));
  		if (mx_new == NULL) break;
  		memset(mx_new, '\0', sizeof(struct mxlist_t));
  		mx_new->pref = pQueryRec->Data.MX.wPreference;
  		lstrcpyn(mx_new->mx, pQueryRec->Data.MX.pNameExchange, 255);
  		if (mx_top == NULL) {
  			mx_root = mx_top = mx_new;
  		} else {
  			mx_top->next = mx_new;
  			mx_top = mx_new;
  		}
  	}
  	return mx_root;
  }
  
  //-----------------------------------------------------------------------------
  
  typedef DWORD (WINAPI *GetNetworkParams_t)(PFIXED_INFO, PULONG);
  
  static struct mxlist_t *getmx_mydns(const char *domain)
  {
  	static const char szIphlpapiDll[] = "iphlpapi.dll";
  	HINSTANCE hIphlpapi;
  	GetNetworkParams_t pGetNetworkParams;
  	char *info_buf;
  	FIXED_INFO *info;
  	IP_ADDR_STRING *pa;
  	DWORD dw, info_buf_size;
  	struct sockaddr_in addr;
  	struct mxlist_t *mxlist;
  
  	hIphlpapi = GetModuleHandle(szIphlpapiDll);
  	if (hIphlpapi == NULL || hIphlpapi == INVALID_HANDLE_VALUE)
  		hIphlpapi = LoadLibrary(szIphlpapiDll);
  	if (hIphlpapi == NULL || hIphlpapi == INVALID_HANDLE_VALUE) return NULL;
  	pGetNetworkParams = (GetNetworkParams_t)GetProcAddress(hIphlpapi, "GetNetworkParams");
  	if (pGetNetworkParams == NULL) return NULL;
  
  	info_buf_size = 16384;
  	info_buf = (char *)mx_alloc(info_buf_size);
  	dw = info_buf_size;
  	info = (FIXED_INFO *)info_buf;
  	if (pGetNetworkParams(info, &dw) != ERROR_SUCCESS)
  		return NULL;
  
  	for (mxlist=NULL,pa=&info->DnsServerList; pa; pa=pa->Next) {
  		if (pa->IpAddress.String == NULL) continue;
  		addr.sin_family = AF_INET;
  		addr.sin_port = htons(53);
  		addr.sin_addr.s_addr = inet_addr(pa->IpAddress.String);
  		if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == 0xFFFFFFFF) {
  			struct hostent *h = gethostbyname(pa->IpAddress.String);
  			if (h == NULL) continue;
  			addr.sin_addr = *(struct in_addr *)h->h_addr_list[0];
  		}
  		if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == 0xFFFFFFFF)
  			continue;
  
  		mxlist = my_get_mx_list(&addr, domain);
  		if (mxlist != NULL) break;
  	}
  	mx_free(info_buf);
  	return mxlist;
  }
  
  //-----------------------------------------------------------------------------
  
  struct mxlist_t *get_mx_list(const char *domain)
  {
  	struct mxlist_t *p;
  	if ((p = (domain)) != NULL)
  		return p;
  	else
  	//	return getmx_mydns(domain);
  	return (domain);
  }
  
  void free_mx_list(struct mxlist_t *p)
  {
  	struct mxlist_t *q;
  	while (p != NULL) {
  		q = p->next;
  		mx_free(p);
  		p = q;
  	}
  }
  */