eSMTP_C_States State;
- int SMTPstatus;
+ 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);
void *vHandler;
StrBufExtract_NextToken(Line, RawQItem, &pLine, '\n');
+ if (StrLength(Line) == 0) continue;
StrBufExtract_NextToken(Token, Line, &pItemPart, '|');
if (GetHash(QItemHandlers, SKEY(Token), &vHandler))
{
}
/// TODO : else free message...
+ close(Msg->IO.sock);
DeleteSmtpOutMsg(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->SMTPstatus = 5;
- StrBufPrintf(SendMsg->MyQEntry->StatusMessage,
- "No MX hosts found for <%s>", SendMsg->node);
- return; ///////TODO: abort!
- }
-}
-/* TODO: abort... */
-#define SMTP_ERROR(WHICH_ERR, ERRSTR) {SendMsg->SMTPstatus = WHICH_ERR; StrBufAppendBufPlain(SendMsg->MyQEntry->StatusMessage, HKEY(ERRSTR), 0); return eAbort; }
-#define SMTP_VERROR(WHICH_ERR) { SendMsg->SMTPstatus = WHICH_ERR; StrBufAppendBufPlain(SendMsg->MyQEntry->StatusMessage, &ChrPtr(SendMsg->IO.IOBuf)[4], -1, 0); return eAbort; }
+#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_IS_STATE(WHICH_STATE) (ChrPtr(SendMsg->IO.IOBuf)[0] == WHICH_STATE)
#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;
- 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]: connected!\n", SendMsg->n);
- 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);
- }
- }
- /// hier: naechsten mx ausprobieren.
- if (SendMsg->IO.sock < 0) {
- SendMsg->SMTPstatus = 4; /* dsn is already filled in */
- //// hier: abbrechen & bounce.
- return -1;
+ /// TODO: abort
}
-
-
- SendMsg->IO.SendBuf.Buf = NewStrBuf();
- SendMsg->IO.RecvBuf.Buf = NewStrBuf();
- 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 */
StrBufPlain(SendMsg->MyQEntry->StatusMessage,
&ChrPtr(SendMsg->IO.RecvBuf.Buf)[4],
StrLength(SendMsg->IO.RecvBuf.Buf) - 4);
- SendMsg->SMTPstatus = 2;
+ SendMsg->MyQEntry->Status = 2;
return eSendReply;
}
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->msgtext = MsgText;
+ 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);
}
StrBufExtract_NextToken(Item->Current->Recipient, Line, Pos, '|');
Item->Current->Status = StrBufExtractNext_int(Line, Pos, '|');
StrBufExtract_NextToken(Item->Current->StatusMessage, Line, Pos, '|');
+ Item->Current = NULL; // TODO: is this always right?
}
long len;
const char *Key;
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client: smtp_do_procmsg(%ld)\n", msgnum);
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP Queue: smtp_do_procmsg(%ld)\n", msgnum);
///strcpy(envelope_from, "");
msg = CtdlFetchMessage(msgnum, 1);
if (msg == NULL) {
- CtdlLogPrintf(CTDL_ERR, "SMTP client: tried %ld but no such message!\n", msgnum);
+ CtdlLogPrintf(CTDL_ERR, "SMTP Queue: tried %ld but no such message!\n", msgnum);
return;
}
MyQItem = DeserializeQueueItem(PlainQItem, msgnum);
FreeStrBuf(&PlainQItem);
- if (MyQItem == NULL)
+ if (MyQItem == NULL) {
+ CtdlLogPrintf(CTDL_ERR, "SMTP Queue: Msg No %ld: already in progress!\n", msgnum);
return; /* s.b. else is already processing... */
-
+ }
/*
* Postpone delivery if we've already tried recently.
* Bail out if there's no actual message associated with this
*/
if (MyQItem->MessageID < 0L) {
- CtdlLogPrintf(CTDL_ERR, "SMTP client: no 'msgid' directive found!\n");
+ CtdlLogPrintf(CTDL_ERR, "SMTP Queue: no 'msgid' directive found!\n");
It = GetNewHashPos(MyQItem->MailQEntries, 0);
citthread_mutex_lock(&ActiveQItemsLock);
{
return;
}
+ It = GetNewHashPos(MyQItem->MailQEntries, 0);
+ while (GetNextHashPos(MyQItem->MailQEntries, It, &len, &Key, &vQE))
+ {
+ MailQEntry *ThisItem = vQE;
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP Queue: Task: <%s> %d\n", ChrPtr(ThisItem->Recipient), ThisItem->Active);
+ }
+ DeleteHashPos(&It);
+
CountActiveQueueEntries(MyQItem);
if (MyQItem->ActiveDeliveries > 0)
{
{
MailQEntry *ThisItem = vQE;
if (ThisItem->Active == 1) {
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client: Trying <%s>\n", ChrPtr(ThisItem->Recipient));
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP Queue: Trying <%s>\n", ChrPtr(ThisItem->Recipient));
smtp_try(MyQItem, ThisItem, Msg, (i == MyQItem->ActiveDeliveries));
i++;
}
int num_processed = 0;
struct CitContext smtp_queue_CC;
+ CtdlThreadSleep(10);
+
CtdlFillSystemContext(&smtp_queue_CC, "SMTP Send");
citthread_setspecific(MyConKey, (void *)&smtp_queue_CC);
CtdlLogPrintf(CTDL_DEBUG, "smtp_queue_thread() initializing\n");
{
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");