SMTProbe & SMTPRedirectToRelay |
Try another host for delivery instead of bouncing if blocked by a DNSBL |
|
|
Spammers become more and more aggressive and the operators of DNSBLs follow-up, and there seems to be an increasing tendency for black listing complete IP blocks instead of single addresses. For this reason also regular mail services are collaterally damaged by all sorts of DNSBL's which list whole address blocks instead of single IP's. Unfortunately, the operators of DNSBL's become increasingly incooperative in reducing this kind of collateral damage. As an operator of a small to medium sized mail service you have no chance to become delisted from SPEWS, Spamhaus, SORBS and MAPS - they don't even want to know about you having a problem because of their listing, and if you have the luck to receive a response, then they ask you to either get your ISP to resolve the problem or otherwise to change the ISP. This situation might catch every small to medium mail service, and it is even more likely if it resides outside of western europe or the U.S. See discussion at list.postfix.users: |
|
|
SMTProbe.c
// SMTProbe.c
//
// Part of the SMTProbe Package
//
// Created by Rolf on 2006-10-18.
// Copyright 2006 InstantWare - Dr. Rolf Jansen. All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THIS SOFTWARE IS PROVIDED BY InstantWare - Dr. Rolf Jansen "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL InstantWare - Dr. Rolf Jansen
// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
// Standard C includes
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <unistd.h>
// header files which must be included for
// high level DNS services and threaded
// (a)synchronous socket connections
#include <sys/time.h>
#include <pthread.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// header files for the low level nameserver interface
#include <sys/types.h>
#include <resolv.h>
#include <arpa/nameser.h>
// constants
#define defaultBufferSize 4096
#define maxThreads 25
// types
typedef struct MXRecord *MXPtr, **MXRef;
typedef struct MXRecord
{
short pref;
char name[NS_MAXDNAME];
} MXRecord;
typedef struct MXRecordList *MXListPtr;
typedef struct MXRecordList
{
short count;
MXPtr entry[];
} MXRecordList;
typedef struct DomainRecord *DomainPtr, **DomainRef;
typedef struct DomainRecord
{
short count; // number of recipients
char* *recipients; // string ptr array of recipients @ this domain
char* domainName; // the domain name
short B; // balance indicator
DomainPtr L, R; // left and right branch of this node
} DomainRecord;
typedef struct sockaddr_in *SocketAddressPtr;
//global variables
int gRemoteRelayArgCount = 3; // at least the executable + PID + sender name
int gLocalRecipientCount = 0;
char **gRemoteRelayArgV;
char *gLocalRelayArgL;
DomainPtr gSender, gRecipients;
short gThreadCount = 0;
pthread_mutex_t gThreadMutex = PTHREAD_MUTEX_INITIALIZER;
void *mallocclear(size_t size)
{
return calloc(size/4 + 1, 4);
}
// code for looking up the MX hosts for a given domain
// returns an array of MXRecords sorted by preferences
int MXCompare(const void *A, const void *B)
{
short a = (*(MXRef)A)->pref;
short b = (*(MXRef)B)->pref;
if (a < b)
return -1;
else if (a > b)
return 1;
else
return 0;
}
MXListPtr MXLookup(char *domainName)
{
int i, responseLen, resourceRecordCount;
unsigned char response[defaultBufferSize];
ns_msg msgHandle;
ns_rr resourceRecord;
MXPtr MX;
MXListPtr MXList = mallocclear(sizeof(short));
if ((responseLen = res_query(domainName, ns_c_in, ns_t_mx, response, defaultBufferSize)) > 0)
if (ns_initparse(response, responseLen, &msgHandle) == 0)
{
resourceRecordCount = ns_msg_count(msgHandle, ns_s_an);
for(i = 0; i < resourceRecordCount; i++)
{
if (ns_parserr(&msgHandle, ns_s_an, i, &resourceRecord) == 0 && ns_rr_type(resourceRecord) == ns_t_mx)
{
MXList = realloc(MXList, sizeof(short) + (MXList->count + 1)*sizeof(MXPtr));
MXList->entry[MXList->count++] = MX = mallocclear(sizeof(MXRecord));
MX->pref = ns_get16(ns_rr_rdata(resourceRecord));
ns_name_uncompress(ns_msg_base(msgHandle), ns_msg_end(msgHandle), ns_rr_rdata(resourceRecord) + NS_INT16SZ, MX->name, NS_MAXDNAME);
}
}
}
if (MXList->count > 1)
qsort(&MXList->entry[0], MXList->count, sizeof(MXPtr), MXCompare);
return MXList;
}
void MXListFree(MXListPtr MXList)
{
short i;
for (i = 0; i < MXList->count; i++)
free(MXList->entry[i]);
free(MXList);
}
// Collect domain wise all recipients in a balanced binary tree
bool AddDomainNode(char* recipient, char* domainName, DomainRef node)
{
// variables
bool balanced;
DomainPtr p0, p1, p2;
// begin
p0 = *node;
if (!p0)
{ // Schlüssel nicht im Baum; füge ihn ein
balanced = false;
p0 = mallocclear(sizeof(DomainRecord));
if (recipient)
{
p0->count = 1;
p0->recipients = malloc(sizeof(char *));
p0->recipients[0] = recipient;
}
p0->domainName = domainName;
}
else if (strcmp(domainName, p0->domainName) < 0)
{
balanced = AddDomainNode(recipient, domainName, &p0->L);
if (!balanced) // linker Ast wurde größer
switch (p0->B)
{
case +1: // +1 => linker Ast war kürzer als der rechter Ast,
p0->B = 0; // und die Unausgeglichenheit wurde jetzt ausgeglichen
balanced = true;
break;
case 0: // 0 => beide Äste waren gleich lang,
p0->B = -1; // und durch Einfügen wurde der linke Ast jetzt länger
break;
case -1: // -1 => linker Ast war schon länger als der rechte Ast,
p1 = p0->L; // und erneutes Ausgleichen wird notwendig
if (p1->B == -1)
{ // einfache LL Rotation
p0->L = p1->R;
p1->R = p0;
p0->B = 0;
p0 = p1;
}
else
{ // doppelte LR Rotation
p2 = p1->R;
p1->R = p2->L;
p2->L = p1;
p0->L = p2->R;
p2->R = p0;
p0->B = (p2->B == -1) ? +1 : 0;
p1->B = (p2->B == +1) ? -1 : 0;
p0 = p2;
}
p0->B = 0;
balanced = true;
break;
}
}
else if (strcmp(domainName, p0->domainName) > 0)
{
balanced = AddDomainNode(recipient, domainName, &p0->R);
if (!balanced) // rechter Ast wurde größer
switch (p0->B)
{
case -1: // -1 => rechter Ast war kürzer als der linke Ast,
p0->B = 0; // und die Unausgeglichenheit wurde jetzt ausgeglichen
balanced = true;
break;
case 0: // 0 => beide Äste waren gleich lang,
p0->B = +1; // und durch Einfügen wurde der rechte Ast jetzt länger
break;
case +1: // +1 => rechter Ast war schon länger als der linke Ast,
p1 = p0->R; // und erneutes Ausgleichen wird notwendig
if (p1->B == +1)
{ // einfache RR Rotation
p0->R = p1->L;
p1->L = p0;
p0->B = 0;
p0 = p1;
}
else
{ // doppelte RL Rotation
p2 = p1->L;
p1->L = p2->R;
p2->R = p1;
p0->R = p2->L;
p2->L = p0;
p0->B = (p2->B == +1) ? -1 : 0;
p1->B = (p2->B == -1) ? +1 : 0;
p0 = p2;
}
p0->B = 0;
balanced = true;
break;
}
}
else
{ // gefunden
balanced = true;
if (recipient)
{
p0->recipients = realloc(p0->recipients, (p0->count + 1) * sizeof(char *));
p0->recipients[p0->count++] = recipient;
}
}
*node = p0;
return balanced;
}
short doSMTPTransaction(int smtpSocket, char *sendBuffer, long sendBufferSize, char *receiveBuffer)
{
long receiveSize;
if (sendBuffer && send(smtpSocket, sendBuffer, sendBufferSize, 0) == -1)
return 1000;
else if ((receiveSize = recv(smtpSocket, receiveBuffer, defaultBufferSize - 1, 0)) < 0)
return 2000;
else
{
receiveBuffer[receiveSize] = '\0';
return strtol(receiveBuffer, NULL, 10);
}
}
int connectWithTimeout(int sock, const struct sockaddr *address, socklen_t addressLen, unsigned long timeoutSecs)
{
if (timeoutSecs == 0)
return connect(sock, address, addressLen);
else
{
int connectErr, connectResult = -1;
socklen_t connectErrLen = sizeof(connectErr);
struct timeval timeout = {timeoutSecs, 0};
fd_set socketIOSet;
// set socket to asynchronous mode
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, NULL) | O_NONBLOCK);
if ((connectResult = connect(sock, address, addressLen)) < 0)
{
if (errno == EINPROGRESS)
{
FD_ZERO(&socketIOSet);
FD_SET(sock, &socketIOSet);
if ((connectResult = select(sock + 1, NULL, &socketIOSet, NULL, &timeout)) > 0)
{
getsockopt(sock, SOL_SOCKET, SO_ERROR, &connectErr, &connectErrLen);
if (connectErr != 0)
return -1;
}
else
return -1;
}
else
return -1;
}
// reset socket to synchronous mode
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, NULL) & (~O_NONBLOCK));
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval));
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));
return connectResult;
}
}
typedef struct ProbeThreadArgs *ProbeThreadArgPtr;
typedef struct ProbeThreadArgs
{
struct sockaddr_in address;
DomainPtr domainNode;
} ProbeThreadArgs;
void *SMTProbeThread(void *probeThreadArgs)
{
SocketAddressPtr address = &((ProbeThreadArgPtr)probeThreadArgs)->address;
DomainPtr node = ((ProbeThreadArgPtr)probeThreadArgs)->domainNode;
short i, smtpCode = 0;
int mutexResultCode;
long smtpSocket, sendBufferSize, domainStrLen, recipientListLen;
char *p, transferBuffer[defaultBufferSize];
if (address->sin_port != 0 && (smtpSocket = socket(AF_INET, SOCK_STREAM, 0)) != -1)
{
if (connectWithTimeout(smtpSocket, (struct sockaddr *)address, sizeof(struct sockaddr_in), 15) != -1)
{
if ((smtpCode = doSMTPTransaction(smtpSocket, NULL, 0, transferBuffer)) > 299)
goto closeSession;
sendBufferSize = snprintf(transferBuffer, defaultBufferSize, "EHLO %s\r\n", gSender->domainName);
if ((smtpCode = doSMTPTransaction(smtpSocket, transferBuffer, sendBufferSize, transferBuffer)) > 299)
goto closeSession;
sendBufferSize = snprintf(transferBuffer, defaultBufferSize, "MAIL FROM:<%s@%s>\r\n", gSender->recipients[0], gSender->domainName);
if ((smtpCode = doSMTPTransaction(smtpSocket, transferBuffer, sendBufferSize, transferBuffer)) > 299)
goto closeSession;
for (i = 0; i < node->count; i++)
{
sendBufferSize = snprintf(transferBuffer, defaultBufferSize, "RCPT TO:<%s@%s>\r\n", node->recipients[i], node->domainName);
if ((smtpCode = doSMTPTransaction(smtpSocket, transferBuffer, sendBufferSize, transferBuffer)) == 421 || smtpCode == 554 || smtpCode >= 1000)
goto closeSession;
}
sendBufferSize = sprintf(transferBuffer, "QUIT\r\n");
smtpCode = doSMTPTransaction(smtpSocket, transferBuffer, sendBufferSize, transferBuffer);
closeSession:
close(smtpSocket);
}
}
// process the recipients list according to the received error codes
mutexResultCode = pthread_mutex_lock(&gThreadMutex);
domainStrLen = strlen(node->domainName) + 2; // reserve space for the leading @ and the trailing '\0'
if (smtpCode == 421 || smtpCode == 554)
{ // got a policy rejection
gRemoteRelayArgV = realloc(gRemoteRelayArgV, sizeof(char*) * (gRemoteRelayArgCount + node->count + 1));
for (i = 0; i < node->count; i++)
{
gRemoteRelayArgV[gRemoteRelayArgCount + i] = p = malloc(strlen(node->recipients[i]) + domainStrLen);
sprintf(p, "%s@%s", node->recipients[i], node->domainName);
}
gRemoteRelayArgCount += node->count;
}
else // handle all other cases (OK and error replies) by the local MTA
{
recipientListLen = 1; // reserve space for the leading blank
for (i = 0; i < node->count; i++)
recipientListLen += strlen(node->recipients[i]) + domainStrLen;
gLocalRelayArgL = realloc(gLocalRelayArgL, strlen(gLocalRelayArgL) + recipientListLen);
for (i = 0; i < node->count; i++)
sprintf(gLocalRelayArgL, "%s %s@%s", gLocalRelayArgL, node->recipients[i], node->domainName);
gLocalRecipientCount += node->count;
}
gThreadCount--;
mutexResultCode = pthread_mutex_unlock(&gThreadMutex);
free(probeThreadArgs);
pthread_exit(NULL);
}
void SMTProbeRecipientDomains(DomainPtr node)
{
bool ipOK = false;
short i;
int threadID;
struct timespec delay = {0, 10};
pthread_t probeThread;
struct hostent *host;
MXListPtr MXList;
ProbeThreadArgPtr threadArgs = mallocclear(sizeof(ProbeThreadArgs));
if (node)
{
SMTProbeRecipientDomains(node->L);
MXList = MXLookup(node->domainName);
for (i = 0; i < MXList->count && !ipOK; i++)
if (!(ipOK = inet_aton(MXList->entry[i]->name, &threadArgs->address.sin_addr)))
if (ipOK = ((host = gethostbyname(MXList->entry[i]->name)) != NULL))
threadArgs->address.sin_addr = *(struct in_addr*)host->h_addr;
MXListFree(MXList);
if (!ipOK) // did not found a valid MX IP, so try to connect to the @domain itself
if (!(ipOK = inet_aton(node->domainName, &threadArgs->address.sin_addr)))
if (ipOK = ((host = gethostbyname(node->domainName)) != NULL))
threadArgs->address.sin_addr = *(struct in_addr*)host->h_addr;
if (ipOK)
{
threadArgs->address.sin_port = htons(25);
threadArgs->address.sin_family = AF_INET;
}
else
threadArgs->address.sin_addr.s_addr = 0;
threadArgs->domainNode = node;
// wait until the next free slot for a new thread
while (gThreadCount >= maxThreads)
nanosleep(&delay, NULL);
gThreadCount++;
threadID = pthread_create(&probeThread, NULL, SMTProbeThread, (void *)threadArgs);
SMTProbeRecipientDomains(node->R);
}
}
void SMTProbeDomainsFree(DomainPtr node)
{
if (node)
{
SMTProbeDomainsFree(node->L);
SMTProbeDomainsFree(node->R);
if (node->recipients)
free(node->recipients);
free(node);
}
}
int main(int argc, char *argv[])
{
char c, inName[256], outName[256];
FILE *in, *out;
int i;
char *p;
long relayStrLen;
char *relayStrFormat = "-f %s --";
struct timespec delay = {0, 10};
res_init();
// the command line arguments should come in the form
// PID -f <sender> -- <recipient 1> <recipient 1> ... <recipient n>
// since SMTProbe is meant to be called by a shell script
// no error checking is done.
int senderArgIndex = 0;
int recipientsArgIndex = 0;
for (i = 2; i < argc; i++)
{
if (senderArgIndex == 0 && strcmp(argv[i], "-f") == 0)
senderArgIndex = ++i;
else if (recipientsArgIndex == 0 && strcmp(argv[i], "--") == 0)
{
recipientsArgIndex = ++i;
break;
}
}
gRemoteRelayArgV = malloc(sizeof(char*) * (gRemoteRelayArgCount + 2));
gRemoteRelayArgV[0] = "SMTPRedirectToRelay"; // the file name of the redirection tool
gRemoteRelayArgV[1] = argv[1]; // copy the PID parameter for identification of the temp file
relayStrLen = strlen(argv[senderArgIndex]) + 1; // reserve space for the terminating '\0'
gRemoteRelayArgV[2] = malloc(relayStrLen);
strcpy(gRemoteRelayArgV[2], argv[senderArgIndex]); // make a copy of the fully qualified senders e-mail address
gLocalRelayArgL = malloc(relayStrLen);
relayStrLen += strlen(relayStrFormat) - 2; // subtract 2 for the %s in the format specifier
sprintf(gLocalRelayArgL, relayStrFormat, argv[senderArgIndex]);
gSender = mallocclear(sizeof(DomainRecord)); // set up the sender domain record
gSender->count = 1;
gSender->recipients = malloc(sizeof(char*));
gSender->recipients[0] = p = argv[senderArgIndex];
while(*p != '@' && *p != '%' && *p != '\0')
p++;
*p++ = '\0';
gSender->domainName = p;
gRecipients = mallocclear(sizeof(DomainRecord)); // set up the root node of the binary tree
gRecipients->count = 1; // of the recipients domain records
gRecipients->recipients = malloc(sizeof(char*));
gRecipients->recipients[0] = p = argv[recipientsArgIndex];
while(*p != '@' && *p != '%' && *p != '\0')
p++;
*p++ = '\0';
gRecipients->domainName = p;
for (i = recipientsArgIndex + 1; i < argc; i++) // add the remaining recipient domains records
{ // to the domain records tree
p = argv[i];
while(*p != '@' && *p != '%' && *p != '\0')
p++;
*p++ = '\0';
AddDomainNode(argv[i], p, &gRecipients);
}
SMTProbeRecipientDomains(gRecipients); // probe the recipients
while(gThreadCount > 0) // wait for completion
nanosleep(&delay, NULL);
SMTProbeDomainsFree(gRecipients); // clean up the recipients domain tree
if (gRemoteRelayArgCount > 3)
{
sprintf(inName, "out.%s", argv[1]); // put a copy of the e-mail text file into
sprintf(outName, "RelayQueue/out.%s", argv[1]); // our RelayQueue directory.
if ((in = fopen(inName, "r")) && (out = fopen(outName, "w")))
{
while ((c = fgetc(in)) != EOF)
fputc(c, out);
fclose(in);
fclose(out);
}
else
return -1; // fatal file system error
if (fork() != 0) // fork our process
{ // the original process continues here
if (gLocalRecipientCount > 0)
{
printf("%s", gLocalRelayArgL); // some recipients can be handled by the local MTA
return 1; // others need to be redirect to our relay MTA
}
else
return 2; // redirect message for all recipients to our relay MTA
}
else
{ // the forked out process continues here
gRemoteRelayArgV[gRemoteRelayArgCount] = NULL;
execvp(gRemoteRelayArgV[0], gRemoteRelayArgV); // use it to call the SMTPRedirectToRelay tool
return 0;
}
}
else
return 0; // Normal operation -- no redirection necessary
}
SMTPRedirectToRelay.c
// SMTPRedirectToRelay.c
//
// Part of the SMTProbe Package
//
// Created by Rolf on 2006-10-22.
// Copyright 2006 InstantWare - Dr. Rolf Jansen. All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THIS SOFTWARE IS PROVIDED BY InstantWare - Dr. Rolf Jansen "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL InstantWare - Dr. Rolf Jansen
// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
// Standard C includes
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <unistd.h>
// header files which must be included for
// high level DNS services and socket connections
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// constants
#define defaultBufferSize 4096
short doSMTPTransaction(int smtpSocket, char *sendBuffer, long sendBufferSize, char *receiveBuffer)
{
long receiveSize = 0;
if (sendBuffer != NULL && send(smtpSocket, sendBuffer, sendBufferSize, 0) == -1)
return 1000;
else if (receiveBuffer != NULL && (receiveSize = recv(smtpSocket, receiveBuffer, defaultBufferSize - 1, 0)) < 0)
return 2000;
if (receiveSize != 0)
{
receiveBuffer[receiveSize] = '\0';
return strtol(receiveBuffer, NULL, 10);
}
else
return 0;
}
// argv[0]: size of head in bytes
// argv[1]: pid of calling process => temp file extension => ReleayQueue/out.PID
// argv[2]: fully qualified senders accress
// argv[3..n]: fully qualified recipient addresses
int main(int argc, char *argv[])
{
short i, smtpCode = 0, resultCode = 1;
long smtpSocket, sendBufferSize;
char c = 0;
char inName[256], transferBuffer[defaultBufferSize];
FILE *in;
struct hostent *host = NULL;
struct sockaddr_in address;
char *smtpMyHostHELOName = "myHELOdomain.com"; // replace with your valid HELO identifier
char *smtpRelayHostName = "smtp.relayserver.com"; // replace with address of the relay server
char *smtpAuthLoginID = "U01UUF9Mb2dpbl9JRAo=\r\n"; // replace with your base 64 encoded SMTP login ID
char *smtpAuthPassword = "ZG9uJ3QgdXNlIDEyMzQ1Njc4OSBhcyBwYXNzd29yZAo=\r\n"; // replace with your base 64 encoded SMTP auth password
sprintf(inName, "RelayQueue/out.%s", argv[1]);
if ((in = fopen(inName, "r")) != NULL)
{
if (!inet_aton(smtpRelayHostName, &address.sin_addr))
if ((host = gethostbyname(smtpRelayHostName)))
address.sin_addr = *(struct in_addr*)host->h_addr;
else
return 1;
address.sin_port = htons(25);
address.sin_family = AF_INET;
if ((smtpSocket = socket(AF_INET, SOCK_STREAM, 0)) != -1)
{
if (connect(smtpSocket, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) != -1)
{
if ((smtpCode = doSMTPTransaction(smtpSocket, NULL, 0, transferBuffer)) > 299)
goto closeSession;
sendBufferSize = snprintf(transferBuffer, defaultBufferSize, "EHLO %s\r\n", smtpMyHostHELOName);
if ((smtpCode = doSMTPTransaction(smtpSocket, transferBuffer, sendBufferSize, transferBuffer)) > 299)
goto closeSession;
sendBufferSize = sprintf(transferBuffer, "AUTH LOGIN\r\n");
if ((smtpCode = doSMTPTransaction(smtpSocket, transferBuffer, sendBufferSize, transferBuffer)) > 334)
goto closeSession;
if ((smtpCode = doSMTPTransaction(smtpSocket, smtpAuthLoginID, strlen(smtpAuthLoginID), transferBuffer)) != 334)
goto closeSession;
if ((smtpCode = doSMTPTransaction(smtpSocket, smtpAuthPassword, strlen(smtpAuthPassword), transferBuffer)) != 235)
goto closeSession;
sendBufferSize = snprintf(transferBuffer, defaultBufferSize, "MAIL FROM:<%s>\r\n", argv[2]);
if ((smtpCode = doSMTPTransaction(smtpSocket, transferBuffer, sendBufferSize, transferBuffer)) > 299)
goto closeSession;
for (i = 3; i < argc; i++)
{
sendBufferSize = snprintf(transferBuffer, defaultBufferSize, "RCPT TO:<%s>\r\n", argv[i]);
if ((smtpCode = doSMTPTransaction(smtpSocket, transferBuffer, sendBufferSize, transferBuffer)) > 299)
goto closeSession;
}
sendBufferSize = sprintf(transferBuffer, "DATA\r\n");
if ((smtpCode = doSMTPTransaction(smtpSocket, transferBuffer, sendBufferSize, transferBuffer)) != 354)
goto closeSession;
while (c != EOF)
{
for (i = 0; i < defaultBufferSize && (c = fgetc(in)) != EOF; i++)
transferBuffer[i] = c;
smtpCode = doSMTPTransaction(smtpSocket, transferBuffer, i, NULL);
}
sendBufferSize = sprintf(transferBuffer, "\r\n.\r\nQUIT\r\n");
if ((smtpCode = doSMTPTransaction(smtpSocket, transferBuffer, sendBufferSize, transferBuffer)) == 250)
resultCode = 0;
closeSession:
close(smtpSocket);
fclose(in);
}
}
remove(inName);
}
return resultCode;
}
Imprint / Impressum
Dr. Rolf Jansen
Rua Reginaldo de Lima, 98 - Parque São Diogo
09732-550 São Bernardo do Campo
São Paulo - Brazil
rj(at)cyclaero.com
Cyclaero Blog (German)