eSMTP_C_States State;
-/// int SMTPstatus; ->MyQEntry->Status
+ struct ares_mx_reply *AllMX;
+ struct ares_mx_reply *CurrMX;
+ const char *mx_port;
+ const char *mx_host;
+
+ struct hostent *OneMX;
- int i_mx;
- int n_mx;
- int num_mxhosts;
char mx_user[1024];
char mx_pass[1024];
- char mx_host[1024];
- char mx_port[1024];
- char mxhosts[SIZ];
-
StrBuf *msgtext;
char *envelope_from;
char user[1024];
char node[1024];
char name[1024];
-/// char addr[SIZ]; -> MyQEntry->Recipient
-/// char dsn[1024]; -> MyQEntry->StatusMessage
-/// char envelope_from_buf[1024]; MyQItem->EnvelopeFrom
char mailfrom[1024];
} SmtpOutMsg;
void DeleteSmtpOutMsg(void *v)
{
SmtpOutMsg *Msg = v;
+
+ ares_free_data(Msg->AllMX);
FreeStrBuf(&Msg->msgtext);
FreeAsyncIOContents(&Msg->IO);
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_MXLookup(void *Data);
typedef eNextState (*SMTPReadHandler)(SmtpOutMsg *Msg);
typedef eNextState (*SMTPSendHandler)(SmtpOutMsg *Msg);
return 0;
}
-void resolve_mx_hosts(SmtpOutMsg *SendMsg)
-{
- /// well this is blocking and sux, but libevent jsut supports async dns since v2
- /* Figure out what mail exchanger host we have to connect to */
- SendMsg->num_mxhosts = getmx(SendMsg->mxhosts, SendMsg->node);
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client[%ld]: Number of MX hosts for <%s> is %d [%s]\n",
- SendMsg->n, SendMsg->node, SendMsg->num_mxhosts, SendMsg->mxhosts);
- if (SendMsg->num_mxhosts < 1) {
- SendMsg->MyQEntry->Status = 5;
- StrBufPrintf(SendMsg->MyQEntry->StatusMessage,
- "No MX hosts found for <%s>", SendMsg->node);
- return; ///////TODO: abort!
- }
-
-}
#define SMTP_ERROR(WHICH_ERR, ERRSTR) {SendMsg->MyQEntry->Status = WHICH_ERR; StrBufAppendBufPlain(SendMsg->MyQEntry->StatusMessage, HKEY(ERRSTR), 0); return eAbort; }
#define SMTP_VERROR(WHICH_ERR) { SendMsg->MyQEntry->Status = WHICH_ERR; StrBufAppendBufPlain(SendMsg->MyQEntry->StatusMessage, &ChrPtr(SendMsg->IO.IOBuf)[4], -1, 0); return eAbort; }
#define SMTP_DBG_SEND() CtdlLogPrintf(CTDL_DEBUG, "SMTP client[%ld]: > %s\n", SendMsg->n, ChrPtr(SendMsg->IO.IOBuf))
#define SMTP_DBG_READ() CtdlLogPrintf(CTDL_DEBUG, "SMTP client[%ld]: < %s\n", SendMsg->n, ChrPtr(SendMsg->IO.IOBuf))
+void get_one_mx_host_name_done(void *Ctx,
+ int status,
+ int timeouts,
+ struct hostent *hostent)
+{
+ AsyncIO *IO = Ctx;
+ SmtpOutMsg *SendMsg = IO->Data;
+ if ((status == ARES_SUCCESS) && (hostent != NULL) ) {
+
+ 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,
+ 1);
+
+ }
+}
+
+const unsigned short DefaultMXPort = 25;
void connect_one_smtpsrv(SmtpOutMsg *SendMsg)
{
- char *endpart;
- char buf[SIZ];
+ //char *endpart;
+ //char buf[SIZ];
+
+ SendMsg->IO.dport = DefaultMXPort;
+
- extract_token(buf, SendMsg->mxhosts, SendMsg->n_mx, '|', sizeof(buf));
- strcpy(SendMsg->mx_user, "");
- strcpy(SendMsg->mx_pass, "");
+/* 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, '@');
strcpy(SendMsg->mx_pass, endpart+1);
*endpart = '\0';
}
- }
- else
- strcpy (SendMsg->mx_host, buf);
+
endpart = strrchr(SendMsg->mx_host, ':');
if (endpart != 0){
*endpart = '\0';
strcpy(SendMsg->mx_port, endpart + 1);
}
- else {
- strcpy(SendMsg->mx_port, "25");
}
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client[%ld]: connecting to %s : %s ...\n",
- SendMsg->n, SendMsg->mx_host, SendMsg->mx_port);
-
-}
-
-
-int connect_one_smtpsrv_xamine_result(void *Ctx)
-{
- SmtpOutMsg *SendMsg = Ctx;
-
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client[%ld]: connecting [%s:%s]!\n",
- SendMsg->n, SendMsg->mx_host, SendMsg->mx_port);
-
- SendMsg->IO.SendBuf.fd =
- SendMsg->IO.RecvBuf.fd =
- SendMsg->IO.sock = sock_connect(SendMsg->mx_host, SendMsg->mx_port);
-
- StrBufPrintf(SendMsg->MyQEntry->StatusMessage,
- "Could not connect: %s", strerror(errno));
- if (SendMsg->IO.sock >= 0)
+ else
+*/
+ SendMsg->mx_host = SendMsg->CurrMX->host;
+ SendMsg->CurrMX = SendMsg->CurrMX->next;
+
+ CtdlLogPrintf(CTDL_DEBUG,
+ "SMTP client[%ld]: connecting to %s : %d ...\n",
+ SendMsg->n,
+ SendMsg->mx_host,
+ SendMsg->IO.dport);
+
+ ares_gethostbyname(SendMsg->IO.DNSChannel,
+ SendMsg->mx_host,
+ AF_INET6, /* it falls back to ipv4 in doubt... */
+ get_one_mx_host_name_done,
+ &SendMsg->IO);
+/*
+ if (!QueueQuery(ns_t_a,
+ SendMsg->mx_host,
+ &SendMsg->IO,
+ connect_one_smtpsrv_xamine_result))
{
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client[%ld:%ld]: connected!\n", SendMsg->n, SendMsg->IO.sock);
- int fdflags;
- fdflags = fcntl(SendMsg->IO.sock, F_GETFL);
- if (fdflags < 0)
- CtdlLogPrintf(CTDL_DEBUG,
- "SMTP client[%ld]: unable to get socket flags! %s \n",
- SendMsg->n, strerror(errno));
- fdflags = fdflags | O_NONBLOCK;
- if (fcntl(SendMsg->IO.sock, F_SETFL, fdflags) < 0)
- CtdlLogPrintf(CTDL_DEBUG,
- "SMTP client[%ld]: unable to set socket nonblocking flags! %s \n",
- SendMsg->n, strerror(errno));
- }
- if (SendMsg->IO.sock < 0) {
- if (errno > 0) {
- StrBufPlain(SendMsg->MyQEntry->StatusMessage,
- strerror(errno), -1);
- }
- else {
- StrBufPrintf(SendMsg->MyQEntry->StatusMessage,
- "Unable to connect to %s : %s\n",
- SendMsg->mx_host, SendMsg->mx_port);
- }
+ /// TODO: abort
}
- /// hier: naechsten mx ausprobieren.
- if (SendMsg->IO.sock < 0) {
- SendMsg->MyQEntry->Status = 4; /* dsn is already filled in */
- //// hier: abbrechen & bounce.
- return -1;
- }
-
-
- SendMsg->IO.SendBuf.Buf = NewStrBufPlain(NULL, 1024);
- SendMsg->IO.RecvBuf.Buf = NewStrBufPlain(NULL, 1024);
- SendMsg->IO.IOBuf = NewStrBuf();
- InitEventIO(&SendMsg->IO, SendMsg,
- SMTP_C_DispatchReadDone,
- SMTP_C_DispatchWriteDone,
- SMTP_C_Terminate,
- SMTP_C_ReadServerStatus,
- 1);
- return 0;
+*/
}
+
eNextState SMTPC_read_greeting(SmtpOutMsg *SendMsg)
{
/* Process the SMTP greeting from the server */
return eReadMessage;
}
+eNextState smtp_resolve_mx_done(void *data)
+{/// VParsedDNSReply
+ AsyncIO *IO = data;
+ SmtpOutMsg * SendMsg = IO->Data;
+
+ SendMsg->IO.SendBuf.Buf = NewStrBufPlain(NULL, 1024);
+ SendMsg->IO.RecvBuf.Buf = NewStrBufPlain(NULL, 1024);
+ SendMsg->IO.IOBuf = NewStrBuf();
+ SendMsg->IO.ErrMsg = SendMsg->MyQEntry->StatusMessage;
+
+ //// connect_one_smtpsrv_xamine_result
+ SendMsg->CurrMX = SendMsg->AllMX = IO->VParsedDNSReply;
+ //// TODO: should we remove the current ares context???
+ connect_one_smtpsrv(SendMsg);
+ return 0;
+}
+
+
+
+int resolve_mx_records(void *Ctx)
+{
+ SmtpOutMsg * SendMsg = Ctx;
+
+ if (!QueueQuery(ns_t_mx,
+ SendMsg->node,
+ &SendMsg->IO,
+ smtp_resolve_mx_done))
+ {
+ SendMsg->MyQEntry->Status = 5;
+ StrBufPrintf(SendMsg->MyQEntry->StatusMessage,
+ "No MX hosts found for <%s>", SendMsg->node);
+ return 0; ///////TODO: abort!
+ }
+ return 0;
+}
+
void smtp_try(OneQueItem *MyQItem,
MailQEntry *MyQEntry,
StrBuf *MsgText,
SendMsg->n = MsgCount++;
SendMsg->MyQEntry = MyQEntry;
SendMsg->MyQItem = MyQItem;
+ SendMsg->IO.Data = SendMsg;
if (KeepMsgText)
SendMsg->msgtext = MsgText;
else
SendMsg->msgtext = NewStrBufDup(MsgText);
smtp_resolve_recipients(SendMsg);
- resolve_mx_hosts(SendMsg);
- connect_one_smtpsrv(SendMsg);
+
QueueEventContext(SendMsg,
&SendMsg->IO,
- connect_one_smtpsrv_xamine_result);
+ resolve_mx_records);
}
{
SmtpOutMsg *pMsg = Data;
FinalizeMessageSend(pMsg);
+ return 0;
+}
+eNextState SMTP_C_Timeout(void *Data)
+{
+ SmtpOutMsg *pMsg = Data;
+ FinalizeMessageSend(pMsg);
+ return 0;
}
+
+eNextState SMTP_C_ConnFail(void *Data)
+{
+ SmtpOutMsg *pMsg = Data;
+ FinalizeMessageSend(pMsg);
+ return 0;
+}
+
eNextState SMTP_C_DispatchReadDone(void *Data)
{
SmtpOutMsg *pMsg = Data;
}
+void smtp_evc_cleanup(void)
+{
+ DeleteHash(&QItemHandlers);
+ DeleteHash(&ActiveQItems);
+}
#endif
CTDL_MODULE_INIT(smtp_eventclient)
smtp_init_spoolout();
+
+ CtdlRegisterCleanupHook(smtp_evc_cleanup);
CtdlThreadCreate("SMTPEvent Send", CTDLTHREAD_BIGSTACK, smtp_queue_thread, NULL);
CtdlRegisterProtoHook(cmd_smtp, "SMTP", "SMTP utility commands");