eMaxSMTPC
} eSMTP_C_States;
-const long SMTP_C_ConnTimeout = 300; /* wail 5 minutes for connections... */
-const long SMTP_C_ReadTimeouts[eMaxSMTPC] = {
- 90, /* Greeting... */
- 30, /* EHLO */
- 30, /* HELO */
- 30, /* Auth */
- 30, /* From */
- 30, /* RCPT */
- 30, /* DATA */
- 90, /* DATABody */
- 900, /* end of body... */
- 30 /* QUIT */
+const double SMTP_C_ConnTimeout = 60.; /* wail 1 minute for connections... */
+const double SMTP_C_ReadTimeouts[eMaxSMTPC] = {
+ 300., /* Greeting... */
+ 30., /* EHLO */
+ 30., /* HELO */
+ 30., /* Auth */
+ 30., /* From */
+ 90., /* RCPT */
+ 30., /* DATA */
+ 90., /* DATABody */
+ 90., /* end of body... */
+ 30. /* QUIT */
};
-/*
-const long SMTP_C_SendTimeouts[eMaxSMTPC] = {
-
-}; */
-const char *ReadErrors[eMaxSMTPC] = {
- "Connection broken during SMTP conversation",
- "Connection broken during SMTP EHLO",
- "Connection broken during SMTP HELO",
- "Connection broken during SMTP AUTH",
- "Connection broken during SMTP MAIL FROM",
- "Connection broken during SMTP RCPT",
- "Connection broken during SMTP DATA",
- "Connection broken during SMTP message transmit",
- ""/* quit reply, don't care. */
+const double SMTP_C_SendTimeouts[eMaxSMTPC] = {
+ 90., /* Greeting... */
+ 30., /* EHLO */
+ 30., /* HELO */
+ 30., /* Auth */
+ 30., /* From */
+ 30., /* RCPT */
+ 30., /* DATA */
+ 90., /* DATABody */
+ 900., /* end of body... */
+ 30. /* QUIT */
+};
+
+static const ConstStr ReadErrors[eMaxSMTPC] = {
+ {HKEY("Connection broken during SMTP conversation")},
+ {HKEY("Connection broken during SMTP EHLO")},
+ {HKEY("Connection broken during SMTP HELO")},
+ {HKEY("Connection broken during SMTP AUTH")},
+ {HKEY("Connection broken during SMTP MAIL FROM")},
+ {HKEY("Connection broken during SMTP RCPT")},
+ {HKEY("Connection broken during SMTP DATA")},
+ {HKEY("Connection broken during SMTP message transmit")},
+ {HKEY("")}/* quit reply, don't care. */
};
struct hostent *OneMX;
- char mx_user[1024];
- char mx_pass[1024];
+ ParsedURL *Relay;
+ ParsedURL *pCurrRelay;
StrBuf *msgtext;
char *envelope_from;
char user[1024];
free(Msg);
}
-eNextState SMTP_C_Timeout(void *Data);
-eNextState SMTP_C_ConnFail(void *Data);
-eNextState SMTP_C_DispatchReadDone(void *Data);
-eNextState SMTP_C_DispatchWriteDone(void *Data);
-eNextState SMTP_C_Terminate(void *Data);
+eNextState SMTP_C_Timeout(AsyncIO *IO);
+eNextState SMTP_C_ConnFail(AsyncIO *IO);
+eNextState SMTP_C_DispatchReadDone(AsyncIO *IO);
+eNextState SMTP_C_DispatchWriteDone(AsyncIO *IO);
+eNextState SMTP_C_Terminate(AsyncIO *IO);
eReadState SMTP_C_ReadServerStatus(AsyncIO *IO);
typedef eNextState (*SMTPReadHandler)(SmtpOutMsg *Msg);
void FinalizeMessageSend(SmtpOutMsg *Msg)
{
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
+
if (DecreaseQReference(Msg->MyQItem))
{
int nRemain;
msg->cm_anon_type = MES_NORMAL;
msg->cm_format_type = FMT_RFC822;
msg->cm_fields['M'] = SmashStrBuf(&MsgData);
- /* Generate 'bounce' messages */
- smtp_do_bounce(msg->cm_fields['M'],
- Msg->msgtext);
-
CtdlSubmitMsg(msg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR);
CtdlFreeMessage(msg);
}
+ else {
+ CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, &Msg->MyQItem->MessageID, 1, "");
+ FreeStrBuf(&MsgData);
+ }
RemoveQItem(Msg->MyQItem);
}
-
- close(Msg->IO.sock);
DeleteSmtpOutMsg(Msg);
}
-
-void get_one_mx_host_ip_done(void *Ctx,
- int status,
- int timeouts,
- struct hostent *hostent)
+eNextState mx_connect_relay_ip(AsyncIO *IO)
{
- AsyncIO *IO = Ctx;
+
SmtpOutMsg *SendMsg = IO->Data;
- if ((status == ARES_SUCCESS) && (hostent != NULL) ) {
+
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
+
+ IO->IP6 = SendMsg->pCurrRelay->af == AF_INET6;
+
+ if (SendMsg->pCurrRelay->Port != 0)
+ IO->dport = SendMsg->pCurrRelay->Port;
+
+ memset(&IO->Addr, 0, sizeof(struct in6_addr));
+ if (IO->IP6) {
+ memcpy(&IO->Addr.sin6_addr.s6_addr,
+ &SendMsg->pCurrRelay->Addr,
+ sizeof(struct in6_addr));
+
+ IO->Addr.sin6_family = AF_INET6;
+ IO->Addr.sin6_port = htons(IO->dport);
+ }
+ else {
+ struct sockaddr_in *addr = (struct sockaddr_in*) &IO->Addr;
+ /* Bypass the ns lookup result like this: IO->Addr.sin_addr.s_addr = inet_addr("127.0.0.1"); */
+ memcpy(&addr->sin_addr,
+ &SendMsg->pCurrRelay->Addr,
+ sizeof(struct in_addr));
+
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(IO->dport);
+ }
+
+
+
+/*
+
+ SendMsg->pCurrRelay->
+ if ((SendMsg->pCurrRelay != NULL) && (SendMsg->pCurrRelay->IsIP)) {
+ connect = 1;
+
+ }
+ unsigned long psaddr;
+
+
+ memcpy(&psaddr, hostent->h_addr_list[0], sizeof(psaddr));
+ psaddr = ntohl(psaddr);
+
CtdlLogPrintf(CTDL_DEBUG,
- "SMTP client[%ld]: connecting to %s [ip]: %d ...\n",
+ "SMTP client[%ld]: connecting to %s [%ld.%ld.%ld.%ld:%d] ...\n",
SendMsg->n,
SendMsg->mx_host,
+ (psaddr >> 24) & 0xFF,
+ (psaddr >> 16) & 0xFF,
+ (psaddr >> 8) & 0xFF,
+ (psaddr >> 0) & 0xFF,
SendMsg->IO.dport);
SendMsg->MyQEntry->Status = 5;
StrBufPrintf(SendMsg->MyQEntry->StatusMessage,
- "Timeout while connecting %s",
- SendMsg->mx_host);
+ "Timeout while connecting %s [%ld.%ld.%ld.%ld:%d] ",
+ SendMsg->mx_host,
+ (psaddr >> 24) & 0xFF,
+ (psaddr >> 16) & 0xFF,
+ (psaddr >> 8) & 0xFF,
+ (psaddr >> 0) & 0xFF,
+ SendMsg->IO.dport);
+
+
+ }
+*/
+ /// TODO: else fail!
+ InitEventIO(IO, SendMsg,
+ SMTP_C_ConnTimeout,
+ SMTP_C_ReadTimeouts[0],
+ 1);
+}
+
+void get_one_mx_host_ip_done(void *Ctx,
+ int status,
+ int timeouts,
+ struct hostent *hostent)
+{
+ AsyncIO *IO = (AsyncIO *) Ctx;
+ SmtpOutMsg *SendMsg = IO->Data;
+ if ((status == ARES_SUCCESS) && (hostent != NULL) ) {
+
+ IO->IP6 = hostent->h_addrtype == AF_INET6;
+
+ memset(&IO->Addr, 0, sizeof(struct in6_addr));
+ if (IO->IP6) {
+ memcpy(&IO->Addr.sin6_addr.s6_addr,
+ IO->HEnt->h_addr_list[0],
+ sizeof(struct in6_addr));
+
+ IO->Addr.sin6_family = hostent->h_addrtype;
+ IO->Addr.sin6_port = htons(IO->dport);
+ }
+ else {
+ struct sockaddr_in *addr = (struct sockaddr_in*) &IO->Addr;
+ /* Bypass the ns lookup result like this: IO->Addr.sin_addr.s_addr = inet_addr("127.0.0.1"); */
+ memcpy(&addr->sin_addr,
+ IO->HEnt->h_addr_list[0],
+ sizeof(struct in_addr));
+
+ addr->sin_family = hostent->h_addrtype;
+ addr->sin_port = htons(IO->dport);
+
+ }
SendMsg->IO.HEnt = hostent;
InitEventIO(IO, SendMsg,
- SMTP_C_DispatchReadDone,
- SMTP_C_DispatchWriteDone,
- SMTP_C_Terminate,
- SMTP_C_Timeout,
- SMTP_C_ConnFail,
- SMTP_C_ReadServerStatus,
SMTP_C_ConnTimeout,
SMTP_C_ReadTimeouts[0],
1);
-
}
}
const unsigned short DefaultMXPort = 25;
-void get_one_mx_host_ip(SmtpOutMsg *SendMsg)
+eNextState get_one_mx_host_ip(AsyncIO *IO)
{
+ SmtpOutMsg * SendMsg = IO->Data;
+
//char *endpart;
//char buf[SIZ];
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
SendMsg->IO.dport = DefaultMXPort;
-
-/* TODO: Relay!
- *SendMsg->mx_user = '\0';
- *SendMsg->mx_pass = '\0';
- if (num_tokens(buf, '@') > 1) {
- strcpy (SendMsg->mx_user, buf);
- endpart = strrchr(SendMsg->mx_user, '@');
- *endpart = '\0';
- strcpy (SendMsg->mx_host, endpart + 1);
- endpart = strrchr(SendMsg->mx_user, ':');
- if (endpart != NULL) {
- strcpy(SendMsg->mx_pass, endpart+1);
- *endpart = '\0';
- }
-
- endpart = strrchr(SendMsg->mx_host, ':');
- if (endpart != 0){
- *endpart = '\0';
- strcpy(SendMsg->mx_port, endpart + 1);
- }
- }
- else
-*/
SendMsg->mx_host = SendMsg->CurrMX->host;
SendMsg->CurrMX = SendMsg->CurrMX->next;
CtdlLogPrintf(CTDL_DEBUG,
"SMTP client[%ld]: looking up %s : %d ...\n",
SendMsg->n,
- SendMsg->mx_host);
+ SendMsg->mx_host,
+ SendMsg->IO.dport);
ares_gethostbyname(SendMsg->IO.DNSChannel,
SendMsg->mx_host,
}
-eNextState smtp_resolve_mx_done(void *data)
+eNextState smtp_resolve_mx_done(AsyncIO *IO)
{
- AsyncIO *IO = data;
SmtpOutMsg * SendMsg = IO->Data;
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
+
SendMsg->IO.SendBuf.Buf = NewStrBufPlain(NULL, 1024);
SendMsg->IO.RecvBuf.Buf = NewStrBufPlain(NULL, 1024);
SendMsg->IO.IOBuf = NewStrBuf();
SendMsg->CurrMX = SendMsg->AllMX = IO->VParsedDNSReply;
//// TODO: should we remove the current ares context???
- get_one_mx_host_ip(SendMsg);
+ get_one_mx_host_ip(IO);
return 0;
}
-int resolve_mx_records(void *Ctx)
+eNextState resolve_mx_records(AsyncIO *IO)
{
- SmtpOutMsg * SendMsg = Ctx;
+ SmtpOutMsg * SendMsg = IO->Data;
+
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
if (!QueueQuery(ns_t_mx,
SendMsg->node,
int lp, rp;
int i;
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
+
+ if ((SendMsg==NULL) ||
+ (SendMsg->MyQEntry == NULL) ||
+ (StrLength(SendMsg->MyQEntry->Recipient) == 0)) {
+ return 0;
+ }
+
/* Parse out the host portion of the recipient address */
process_rfc822_addr(ChrPtr(SendMsg->MyQEntry->Recipient),
SendMsg->user,
SendMsg->envelope_from = SendMsg->mailfrom;
}
- return 0;
+ return 1;
}
{
SmtpOutMsg * SendMsg;
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
+
SendMsg = (SmtpOutMsg *) malloc(sizeof(SmtpOutMsg));
memset(SendMsg, 0, sizeof(SmtpOutMsg));
- SendMsg->IO.sock = (-1);
- SendMsg->n = MsgCount++;
- SendMsg->MyQEntry = MyQEntry;
- SendMsg->MyQItem = MyQItem;
- SendMsg->IO.Data = SendMsg;
- if (KeepMsgText)
- SendMsg->msgtext = MsgText;
- else
+ SendMsg->IO.sock = (-1);
+ SendMsg->n = MsgCount++;
+ SendMsg->MyQEntry = MyQEntry;
+ SendMsg->MyQItem = MyQItem;
+ SendMsg->pCurrRelay = MyQItem->URL;
+
+ SendMsg->IO.Data = SendMsg;
+ SendMsg->IO.SendDone = SMTP_C_DispatchWriteDone;
+ SendMsg->IO.ReadDone = SMTP_C_DispatchReadDone;
+ SendMsg->IO.Terminate = SMTP_C_Terminate;
+ SendMsg->IO.LineReader = SMTP_C_ReadServerStatus;
+ SendMsg->IO.ConnFail = SMTP_C_ConnFail;
+ SendMsg->IO.Timeout = SMTP_C_Timeout;
+
+ if (KeepMsgText) {
+ SendMsg->msgtext = MsgText;
+ }
+ else {
SendMsg->msgtext = NewStrBufDup(MsgText);
+ }
- smtp_resolve_recipients(SendMsg);
-
- QueueEventContext(SendMsg,
- &SendMsg->IO,
- resolve_mx_records);
+ if (smtp_resolve_recipients(SendMsg)) {
+ if (SendMsg->pCurrRelay == NULL)
+ QueueEventContext(&SendMsg->IO,
+ resolve_mx_records);
+ else {
+ if (SendMsg->pCurrRelay->IsIP) {
+ QueueEventContext(&SendMsg->IO,
+ mx_connect_relay_ip);
+ }
+ else {
+ QueueEventContext(&SendMsg->IO,
+ get_one_mx_host_ip);
+ }
+ }
+ }
+ else {
+ if ((SendMsg==NULL) ||
+ (SendMsg->MyQEntry == NULL)) {
+ SendMsg->MyQEntry->Status = 5;
+ StrBufPlain(SendMsg->MyQEntry->StatusMessage,
+ HKEY("Invalid Recipient!"));
+ }
+ FinalizeMessageSend(SendMsg);
+ }
}
if (SMTP_IS_STATE('2')) {
SendMsg->State ++;
- if (IsEmptyStr(SendMsg->mx_user))
+
+ if (SendMsg->pCurrRelay->User == NULL)
SendMsg->State ++; /* Skip auth... */
}
/* else we fall back to 'helo' */
else
SMTP_VERROR(5);
}
- if (!IsEmptyStr(SendMsg->mx_user))
+ if (SendMsg->pCurrRelay->User == NULL)
SendMsg->State ++; /* Skip auth... */
return eSendReply;
}
/* Do an AUTH command if necessary */
sprintf(buf, "%s%c%s%c%s",
- SendMsg->mx_user, '\0',
- SendMsg->mx_user, '\0',
- SendMsg->mx_pass);
+ SendMsg->pCurrRelay->User, '\0',
+ SendMsg->pCurrRelay->User, '\0',
+ SendMsg->pCurrRelay->Pass);
CtdlEncodeBase64(encoded, buf,
- strlen(SendMsg->mx_user) +
- strlen(SendMsg->mx_user) +
- strlen(SendMsg->mx_pass) + 2, 0);
+ strlen(SendMsg->pCurrRelay->User) * 2 +
+ strlen(SendMsg->pCurrRelay->Pass) + 2, 0);
StrBufPrintf(SendMsg->IO.SendBuf.Buf,
"AUTH PLAIN %s\r\n", encoded);
-
+
SMTP_DBG_SEND();
return eReadMessage;
}
Buf = SendMsg->IO.SendBuf.Buf;
SendMsg->IO.SendBuf.Buf = SendMsg->msgtext;
SendMsg->msgtext = Buf;
- //// TODO timeout like that: (SendMsg->msg_size / 128) + 50);
SendMsg->State ++;
return eSendMore;
SMTPC_send_terminate_data_body,
SMTPC_send_QUIT
};
-eNextState SMTP_C_DispatchReadDone(void *Data)
+
+void SMTPSetTimeout(eNextState NextTCPState, SmtpOutMsg *pMsg)
+{
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
+ double Timeout;
+ switch (NextTCPState) {
+ case eSendReply:
+ case eSendMore:
+ Timeout = SMTP_C_SendTimeouts[pMsg->State];
+ if (pMsg->State == eDATABody) {
+ /* if we're sending a huge message, we need more time. */
+ Timeout += StrLength(pMsg->msgtext) / 1024;
+ }
+ break;
+ case eReadMessage:
+ Timeout = SMTP_C_ReadTimeouts[pMsg->State];
+ if (pMsg->State == eDATATerminateBody) {
+ /*
+ * some mailservers take a nap before accepting the message
+ * content inspection and such.
+ */
+ Timeout += StrLength(pMsg->msgtext) / 1024;
+ }
+ break;
+ case eTerminateConnection:
+ case eAbort:
+ return;
+ }
+ SetNextTimeout(&pMsg->IO, Timeout);
+}
+eNextState SMTP_C_DispatchReadDone(AsyncIO *IO)
{
- SmtpOutMsg *pMsg = Data;
- eNextState rc = ReadHandlers[pMsg->State](pMsg);
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
+ SmtpOutMsg *pMsg = IO->Data;
+ eNextState rc;
+
+ rc = ReadHandlers[pMsg->State](pMsg);
pMsg->State++;
+ SMTPSetTimeout(rc, pMsg);
return rc;
}
-eNextState SMTP_C_DispatchWriteDone(void *Data)
+eNextState SMTP_C_DispatchWriteDone(AsyncIO *IO)
{
- SmtpOutMsg *pMsg = Data;
- return SendHandlers[pMsg->State](pMsg);
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
+ SmtpOutMsg *pMsg = IO->Data;
+ eNextState rc;
+
+ rc = SendHandlers[pMsg->State](pMsg);
+ SMTPSetTimeout(rc, pMsg);
+ return rc;
}
/*****************************************************************************/
/* SMTP CLIENT ERROR CATCHERS */
/*****************************************************************************/
-eNextState SMTP_C_Terminate(void *Data)
+eNextState SMTP_C_Terminate(AsyncIO *IO)
{
- SmtpOutMsg *pMsg = Data;
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
+ SmtpOutMsg *pMsg = IO->Data;
FinalizeMessageSend(pMsg);
return 0;
}
-eNextState SMTP_C_Timeout(void *Data)
+eNextState SMTP_C_Timeout(AsyncIO *IO)
{
- SmtpOutMsg *pMsg = Data;
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
+ SmtpOutMsg *pMsg = IO->Data;
+ StrBufPlain(IO->ErrMsg, CKEY(ReadErrors[pMsg->State]));
FinalizeMessageSend(pMsg);
return 0;
}
-eNextState SMTP_C_ConnFail(void *Data)
+eNextState SMTP_C_ConnFail(AsyncIO *IO)
{
- SmtpOutMsg *pMsg = Data;
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP: %s\n", __FUNCTION__);
+ SmtpOutMsg *pMsg = IO->Data;
FinalizeMessageSend(pMsg);
return 0;
}
return Finished;
}
-
#endif
CTDL_MODULE_INIT(smtp_eventclient)
{