From: Art Cancro Date: Wed, 22 Dec 2010 04:38:26 +0000 (-0500) Subject: Revert "Libevent integration" X-Git-Tag: v8.01~252^2~243 X-Git-Url: https://code.citadel.org/?a=commitdiff_plain;h=994b5f5a1af0c3538e85e5b2b38ec6dad8aaa96a;p=citadel.git Revert "Libevent integration" This reverts commit fdb030b497950239b2b7db63b3953f6a6f425f1e. --- diff --git a/citadel/Makefile.in b/citadel/Makefile.in index d74de398e..d51191ae3 100644 --- a/citadel/Makefile.in +++ b/citadel/Makefile.in @@ -86,7 +86,7 @@ SOURCES=utils/aidepost.c utils/stress.c utils/whobbs.c utils/citmail.c \ locate_host.c md5.c auth.c msgbase.c parsedate.c \ room_ops.c euidindex.c server_main.c snprintf.c ldap.c \ support.c sysdep.c user_ops.c journaling.c threads.c \ - context.c event_client.c + context.c include Make_sources @@ -147,7 +147,7 @@ Make_modules: modules_init.c modules_upgrade.c: modules_init.c -SERV_OBJS = server_main.o utillib/citadel_dirs.o event_client.o \ +SERV_OBJS = server_main.o utillib/citadel_dirs.o\ user_ops.o citserver.o sysdep.o serv_extensions.o \ $(DATABASE:.c=.o) domain.o \ control.o config.o support.o room_ops.o \ diff --git a/citadel/configure.ac b/citadel/configure.ac index baa179e45..f205fa445 100644 --- a/citadel/configure.ac +++ b/citadel/configure.ac @@ -578,40 +578,6 @@ AC_CHECK_HEADER(libcitadel.h, CFLAGS="$saved_CFLAGS" -dnl experimental libevent smtp client remove this to... -AC_ARG_WITH(experimental_eventsmtp, - [ --with-experimental_eventsmtp enable experimental event smtp clients], - [ if test "x$withval" != "xno" ; then - CFLAGS="$CFLAGS -rdynamic " - LDFLAGS="$LDFLAGS -rdynamic " - SERVER_LDFLAGS="$SERVER_LDFLAGS -rdynamic " - -AC_DEFINE(EXPERIMENTAL_SMTP_EVENT_CLIENT, [], [should we use the experimental libevent smtp client?]) -dnl here... -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS $SERVER_LIBS" -dnl Check for libevent -AC_CHECK_HEADER(event.h, - [AC_CHECK_LIB(event, libcitadel_version_string, - [ - LIBS="-levent $LIBS $SERVER_LIBS" - ], - [ - AC_MSG_ERROR(libevent was not found or is not usable. Please install libevent.) - ] - , - )], - [ - AC_MSG_ERROR(event.h was not found or is not usable. Please install libevent.) - ] -) - -CFLAGS="$saved_CFLAGS" -dnl and from here to... - fi - ] -) -dnl here to make it final. # The big search for OpenSSL if test "$with_ssl" != "no"; then diff --git a/citadel/debian/control b/citadel/debian/control index 6c49c4c93..265e37b0c 100644 --- a/citadel/debian/control +++ b/citadel/debian/control @@ -5,7 +5,7 @@ Maintainer: Wilfried Goesgens Build-Depends: debhelper (>= 4), po-debconf, bison, autotools-dev, libdb-dev, libical-dev (>=0.43), libldap2-dev, gettext, locales, libpam0g-dev, libsieve2-dev, libssl-dev, libexpat1-dev, libcitadel-dev (>= 7.42), - libcurl4-openssl-dev | libcurl3-openssl-dev, zlib1g-dev, libevent-dev + libcurl4-openssl-dev | libcurl3-openssl-dev, zlib1g-dev Standards-Version: 3.8.0 Package: citadel-server diff --git a/citadel/debian/rules b/citadel/debian/rules index 5c51eb473..b9e067b2f 100755 --- a/citadel/debian/rules +++ b/citadel/debian/rules @@ -24,9 +24,6 @@ ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 -ggdb -rdynamic -D_GNU_SOURCE -MD -MP -D TECH_PREVIEW LDFLAGS+=-Wl,--no-undefined -Wl,--as-needed EXTRA_ARGS = --with-backtrace - ifneq (,$(findstring event,$(DEB_BUILD_OPTIONS))) - EXTRA_ARGS = --with-backtrace --with-experimental_eventsmtp - endif else LDFLAGS+=-Wl,--no-undefined -Wl,--as-needed CFLAGS += -O2 diff --git a/citadel/event_client.c b/citadel/event_client.c deleted file mode 100644 index 6ffc4c96a..000000000 --- a/citadel/event_client.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * - * Copyright (c) 1998-2009 by the citadel.org team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "sysdep.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "server.h" -#include "citserver.h" -#include "support.h" -#include "config.h" -#include "control.h" -#include "user_ops.h" -#include "database.h" -#include "msgbase.h" -#include "internet_addressing.h" -#include "genstamp.h" -#include "domain.h" -#include "clientsocket.h" -#include "locate_host.h" -#include "citadel_dirs.h" - -#ifdef EXPERIMENTAL_SMTP_EVENT_CLIENT - -#include -#include "event_client.h" - -extern int event_add_pipe[2]; -extern citthread_mutex_t EventQueueMutex; -extern void *QueueEventAddPtr; -extern AsyncIO *QueueThisIO; -extern EventContextAttach EventContextAttachPtr; - -int QueueEventContext(void *Ctx, AsyncIO *IO, EventContextAttach CB) -{ - citthread_mutex_lock(&EventQueueMutex); - - QueueEventAddPtr = Ctx; - EventContextAttachPtr = CB; - QueueThisIO = IO; - - write(event_add_pipe[1], "+_", 1); - citthread_mutex_unlock(&EventQueueMutex); - return 0; -} - - -int ShutDownEventQueue(void) -{ - write(event_add_pipe[1], "x_", 1); - close(event_add_pipe[1]); - return 0; -} - - - -/* -static void -setup_signal_handlers(struct instance *instance) -{ - signal(SIGPIPE, SIG_IGN); - - event_set(&instance->sigterm_event, SIGTERM, EV_SIGNAL|EV_PERSIST, - exit_event_callback, instance); - event_add(&instance->sigterm_event, NULL); - - event_set(&instance->sigint_event, SIGINT, EV_SIGNAL|EV_PERSIST, - exit_event_callback, instance); - event_add(&instance->sigint_event, NULL); - - event_set(&instance->sigquit_event, SIGQUIT, EV_SIGNAL|EV_PERSIST, - exit_event_callback, instance); - event_add(&instance->sigquit_event, NULL); -} -*/ - -eReadState HandleInbound(AsyncIO *IO) -{ - eReadState Finished = eBufferNotEmpty; - - while ((Finished == eBufferNotEmpty) && (IO->NextState == eReadMessage)){ - if (IO->RecvBuf.nBlobBytesWanted != 0) { - - } - else { /* Reading lines... */ -//// lex line reply in callback, or do it ourselves. as nnn-blabla means continue reading in SMTP - if (IO->LineReader) - Finished = IO->LineReader(IO); - else - Finished = StrBufChunkSipLine(IO->IOBuf, &IO->RecvBuf); - - switch (Finished) { - case eMustReadMore: /// read new from socket... - return Finished; - break; - case eBufferNotEmpty: /* shouldn't happen... */ - case eReadSuccess: /// done for now... - break; - case eReadFail: /// WHUT? - ///todo: shut down! - break; - } - - } - - if (Finished != eMustReadMore) { - event_del(&IO->recv_event); - IO->NextState = IO->ReadDone(IO->Data); - Finished = StrBufCheckBuffer(&IO->RecvBuf); - } - } - - - if ((IO->NextState == eSendReply) || - (IO->NextState == eSendMore)) - { - IO->NextState = IO->SendDone(IO->Data); - event_add(&IO->send_event, NULL); - - } - return Finished; -} - - -static void -IO_send_callback(int fd, short event, void *ctx) -{ - int rc; - AsyncIO *IO = ctx; - - (void)fd; - (void)event; - -/// assert(fd == IO->sock); - - rc = StrBuf_write_one_chunk_callback(fd, event, &IO->SendBuf); - - if (rc == 0) - { - event_del(&IO->send_event); - switch (IO->NextState) { - case eSendReply: - break; - case eSendMore: - IO->NextState = IO->SendDone(IO->Data); - event_add(&IO->send_event, NULL); - break; - case eReadMessage: - if (StrBufCheckBuffer(&IO->RecvBuf) == eBufferNotEmpty) { - HandleInbound(IO); - } - else { - event_add(&IO->recv_event, NULL); - } - - break; - case eAbort: - break; - } - } - else if (rc > 0) - return; -// else - ///abort! -} - - -static void -IO_recv_callback(int fd, short event, void *ctx) -{ - ssize_t nbytes; - AsyncIO *IO = ctx; - -// assert(fd == IO->sock); - -// assert(fd == sb->fd); - - nbytes = StrBuf_read_one_chunk_callback(fd, event, &IO->RecvBuf); - if (nbytes > 0) { - HandleInbound(IO); - } else if (nbytes == 0) { - /// TODO: this is a timeout??? sock_buff_invoke_free(sb, 0); - return; - } else if (nbytes == -1) { -/// TODO: FD is gone. kick it. sock_buff_invoke_free(sb, errno); - return; - } -} - -void IOReadNextLine(AsyncIO *IO, int timeout) -{ - -} - -void IOReadNextBLOB(AsyncIO *IO, int timeout, long size) -{ -} - -void InitEventIO(AsyncIO *IO, - void *pData, - IO_CallBack ReadDone, - IO_CallBack SendDone, - IO_LineReaderCallback LineReader, - int ReadFirst) -{ - IO->Data = pData; - IO->SendDone = SendDone; - IO->ReadDone = ReadDone; - IO->LineReader = LineReader; - - event_set(&IO->recv_event, - IO->sock, - EV_READ|EV_PERSIST, - IO_recv_callback, - IO); - - event_set(&IO->send_event, - IO->sock, - EV_WRITE|EV_PERSIST, - IO_send_callback, - IO); - - if (ReadFirst) { - IO->NextState = eReadMessage; - event_add(&IO->recv_event, NULL); - } - else { - IO->NextState = eSendReply; - } -} - - -#endif diff --git a/citadel/event_client.h b/citadel/event_client.h deleted file mode 100644 index 0fc06b81c..000000000 --- a/citadel/event_client.h +++ /dev/null @@ -1,35 +0,0 @@ -#include - -typedef struct AsyncIO AsyncIO; - -typedef enum _eNextState { - eSendReply, - eSendMore, - eReadMessage, - eAbort -}eNextState; - -typedef int (*EventContextAttach)(void *Data); -typedef eNextState (*IO_CallBack)(void *Data); -typedef eReadState (*IO_LineReaderCallback)(AsyncIO *IO); - -struct AsyncIO { - int sock; - struct event recv_event, send_event; - IOBuffer SendBuf, RecvBuf; - IO_LineReaderCallback LineReader; - IO_CallBack ReadDone, SendDone; - StrBuf *IOBuf; - void *Data; - eNextState NextState; -}; - - -int QueueEventContext(void *Ctx, EventContextAttach CB); - -void InitEventIO(AsyncIO *IO, - void *pData, - IO_CallBack ReadDone, - IO_CallBack SendDone, - IO_LineReaderCallback LineReader, - int ReadFirst); diff --git a/citadel/modules/eventclient/serv_evventclient.c b/citadel/modules/eventclient/serv_evventclient.c deleted file mode 100644 index c225130d7..000000000 --- a/citadel/modules/eventclient/serv_evventclient.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * This module is an SMTP and ESMTP implementation for the Citadel system. - * It is compliant with all of the following: - * - * RFC 821 - Simple Mail Transfer Protocol - * RFC 876 - Survey of SMTP Implementations - * RFC 1047 - Duplicate messages and SMTP - * RFC 1652 - 8 bit MIME - * RFC 1869 - Extended Simple Mail Transfer Protocol - * RFC 1870 - SMTP Service Extension for Message Size Declaration - * RFC 2033 - Local Mail Transfer Protocol - * RFC 2197 - SMTP Service Extension for Command Pipelining - * RFC 2476 - Message Submission - * RFC 2487 - SMTP Service Extension for Secure SMTP over TLS - * RFC 2554 - SMTP Service Extension for Authentication - * RFC 2821 - Simple Mail Transfer Protocol - * RFC 2822 - Internet Message Format - * RFC 2920 - SMTP Service Extension for Command Pipelining - * - * The VRFY and EXPN commands have been removed from this implementation - * because nobody uses these commands anymore, except for spammers. - * - * Copyright (c) 1998-2009 by the citadel.org team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "sysdep.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "server.h" -#include "citserver.h" -#include "support.h" - -#include "ctdl_module.h" - -#ifdef EXPERIMENTAL_SMTP_EVENT_CLIENT - -#include "event_client.h" - -int event_add_pipe[2]; - -citthread_mutex_t EventQueueMutex; /* locks the access to the following vars: */ -void *QueueEventAddPtr = NULL; -EventContextAttach EventContextAttachPtr; -AsyncIO *QueueThisIO; -HashList *QueueEvents = NULL; - -static struct event_base *event_base; -struct event queue_add_event; - -static void QueueEventAddCallback(int fd, short event, void *ctx) -{ - char buf[10]; - - /* get the control command... */ - read(fd, buf, 1); - switch (buf[0]) { - case '+': - EventContextAttachPtr(QueueEventAddPtr); -/// TODO: add it to QueueEvents - break; - case 'x': - event_del(&queue_add_event); - close(event_add_pipe[0]); -/// TODO; flush QueueEvents fd's and delete it. - } - /* Unblock the other side */ - read(fd, buf, 1); -} - -/* - * this thread operates the select() etc. via libevent. - * - * - */ -void *client_event_thread(void *arg) { - struct CitContext libevent_client_CC; - event_base = event_init(); -/* - base = event_base_new(); - if (!base) - return NULL; /*XXXerr*/ - - citthread_mutex_init(&EventQueueMutex, NULL); - CtdlFillSystemContext(&libevent_client_CC, "LibEvent Thread"); -// citthread_setspecific(MyConKey, (void *)&smtp_queue_CC); - CtdlLogPrintf(CTDL_DEBUG, "client_event_thread() initializing\n"); - - if (pipe(event_add_pipe) != 0) { - CtdlLogPrintf(CTDL_EMERG, "Unable to create pipe for libevent queueing: %s\n", strerror(errno)); - abort(); - } - - event_set(&queue_add_event, - event_add_pipe[0], - EV_READ|EV_PERSIST, - QueueEventAddCallback, - NULL); - - event_add(&queue_add_event, NULL); - - - event_dispatch(); - CtdlClearSystemContext(); - event_base_free(event_base); - citthread_mutex_destroy(&EventQueueMutex); - return(NULL); -} - -#endif - -CTDL_MODULE_INIT(event_client) -{ -#ifdef EXPERIMENTAL_SMTP_EVENT_CLIENT - if (!threading) - { - CtdlThreadCreate("Client event", CTDLTHREAD_BIGSTACK, client_event_thread, NULL); - QueueEvents = NewHashList(1, Flathash); -/// todo register shutdown callback. - } -#endif - return "event"; -} diff --git a/citadel/modules/smtp/serv_smtpclient.c b/citadel/modules/smtp/serv_smtpclient.c index c3f33fecd..cafe1ed03 100644 --- a/citadel/modules/smtp/serv_smtpclient.c +++ b/citadel/modules/smtp/serv_smtpclient.c @@ -87,7 +87,6 @@ #include "ctdl_module.h" #include "smtp_util.h" -#ifndef EXPERIMENTAL_SMTP_EVENT_CLIENT int run_queue_now = 0; /* Set to 1 to ignore SMTP send retry times */ @@ -989,11 +988,10 @@ void smtp_init_spoolout(void) { } -#endif + CTDL_MODULE_INIT(smtp_client) { -#ifndef EXPERIMENTAL_SMTP_EVENT_CLIENT if (!threading) { smtp_init_spoolout(); @@ -1001,8 +999,6 @@ CTDL_MODULE_INIT(smtp_client) CtdlRegisterProtoHook(cmd_smtp, "SMTP", "SMTP utility commands"); } -#endif /* return our Subversion id for the Log */ - return "smtpclient"; + return "smtp"; } - diff --git a/citadel/modules/smtp/serv_smtpeventclient.c b/citadel/modules/smtp/serv_smtpeventclient.c deleted file mode 100644 index bb539fa62..000000000 --- a/citadel/modules/smtp/serv_smtpeventclient.c +++ /dev/null @@ -1,1242 +0,0 @@ -/* - * This module is an SMTP and ESMTP implementation for the Citadel system. - * It is compliant with all of the following: - * - * RFC 821 - Simple Mail Transfer Protocol - * RFC 876 - Survey of SMTP Implementations - * RFC 1047 - Duplicate messages and SMTP - * RFC 1652 - 8 bit MIME - * RFC 1869 - Extended Simple Mail Transfer Protocol - * RFC 1870 - SMTP Service Extension for Message Size Declaration - * RFC 2033 - Local Mail Transfer Protocol - * RFC 2197 - SMTP Service Extension for Command Pipelining - * RFC 2476 - Message Submission - * RFC 2487 - SMTP Service Extension for Secure SMTP over TLS - * RFC 2554 - SMTP Service Extension for Authentication - * RFC 2821 - Simple Mail Transfer Protocol - * RFC 2822 - Internet Message Format - * RFC 2920 - SMTP Service Extension for Command Pipelining - * - * The VRFY and EXPN commands have been removed from this implementation - * because nobody uses these commands anymore, except for spammers. - * - * Copyright (c) 1998-2009 by the citadel.org team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "sysdep.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "server.h" -#include "citserver.h" -#include "support.h" -#include "config.h" -#include "control.h" -#include "user_ops.h" -#include "database.h" -#include "msgbase.h" -#include "internet_addressing.h" -#include "genstamp.h" -#include "domain.h" -#include "clientsocket.h" -#include "locate_host.h" -#include "citadel_dirs.h" - -#include "ctdl_module.h" - -#include "smtp_util.h" -#include "event_client.h" - -#ifdef EXPERIMENTAL_SMTP_EVENT_CLIENT - -int run_queue_now = 0; /* Set to 1 to ignore SMTP send retry times */ -int MsgCount = 0; -/*****************************************************************************/ -/* SMTP CLIENT (OUTBOUND PROCESSING) STUFF */ -/*****************************************************************************/ - - -typedef enum _eSMTP_C_States { - eConnect, - eEHLO, - eHELO, - eSMTPAuth, - eFROM, - eRCPT, - eDATA, - eDATABody, - eDATATerminateBody, - eQUIT, - eMaxSMTPC -} eSMTP_C_States; - -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 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. */ -}; - - -typedef struct _stmp_out_msg { - long n; - AsyncIO IO; - - eSMTP_C_States State; - - int SMTPstatus; - - 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]; - char dsn[1024]; - char envelope_from_buf[1024]; - char mailfrom[1024]; -} SmtpOutMsg; - -eNextState SMTP_C_DispatchReadDone(void *Data); -eNextState SMTP_C_DispatchWriteDone(void *Data); - - -typedef eNextState (*SMTPReadHandler)(SmtpOutMsg *Msg); -typedef eNextState (*SMTPSendHandler)(SmtpOutMsg *Msg); - - -eReadState SMTP_C_ReadServerStatus(AsyncIO *IO) -{ - eReadState Finished = eBufferNotEmpty; - - while (Finished == eBufferNotEmpty) { - Finished = StrBufChunkSipLine(IO->IOBuf, &IO->RecvBuf); - - switch (Finished) { - case eMustReadMore: /// read new from socket... - return Finished; - break; - case eBufferNotEmpty: /* shouldn't happen... */ - case eReadSuccess: /// done for now... - if (StrLength(IO->IOBuf) < 4) - continue; - if (ChrPtr(IO->IOBuf)[3] == '-') - Finished = eBufferNotEmpty; - else - return Finished; - break; - case eReadFail: /// WHUT? - ///todo: shut down! - break; - } - } - return Finished; -} - - - - -/** - * this one has to have the context for loading the message via the redirect buffer... - */ -SmtpOutMsg *smtp_load_msg(long msgnum, const char *addr, char *envelope_from) -{ - CitContext *CCC=CC; - SmtpOutMsg *SendMsg; - - SendMsg = (SmtpOutMsg *) malloc(sizeof(SmtpOutMsg)); - - memset(SendMsg, 0, sizeof(SmtpOutMsg)); - SendMsg->IO.sock = (-1); - - SendMsg->n = MsgCount++; - /* Load the message out of the database */ - CCC->redirect_buffer = NewStrBufPlain(NULL, SIZ); - CtdlOutputMsg(msgnum, MT_RFC822, HEADERS_ALL, 0, 1, NULL, (ESC_DOT|SUPPRESS_ENV_TO) ); - SendMsg->msgtext = CCC->redirect_buffer; - CCC->redirect_buffer = NULL; - if ((StrLength(SendMsg->msgtext) > 0) && - ChrPtr(SendMsg->msgtext)[StrLength(SendMsg->msgtext) - 1] != '\n') { - CtdlLogPrintf(CTDL_WARNING, - "SMTP client[%ld]: Possible problem: message did not " - "correctly terminate. (expecting 0x10, got 0x%02x)\n", - SendMsg->n, - ChrPtr(SendMsg->msgtext)[StrLength(SendMsg->msgtext) - 1] ); - StrBufAppendBufPlain(SendMsg->msgtext, HKEY("\r\n"), 0); - } - - safestrncpy(SendMsg->addr, addr, SIZ); - safestrncpy(SendMsg->envelope_from_buf, envelope_from, 1024); - - return SendMsg; -} - - -int smtp_resolve_recipients(SmtpOutMsg *SendMsg) -{ - const char *ptr; - char buf[1024]; - int scan_done; - int lp, rp; - int i; - - /* Parse out the host portion of the recipient address */ - process_rfc822_addr(SendMsg->addr, SendMsg->user, SendMsg->node, SendMsg->name); - - CtdlLogPrintf(CTDL_DEBUG, "SMTP client[%ld]: Attempting delivery to <%s> @ <%s> (%s)\n", - SendMsg->n, SendMsg->user, SendMsg->node, SendMsg->name); - /* If no envelope_from is supplied, extract one from the message */ - if ( (SendMsg->envelope_from == NULL) || - (IsEmptyStr(SendMsg->envelope_from)) ) { - SendMsg->mailfrom[0] = '\0'; - scan_done = 0; - ptr = ChrPtr(SendMsg->msgtext); - do { - if (ptr = cmemreadline(ptr, buf, sizeof buf), *ptr == 0) { - scan_done = 1; - } - if (!strncasecmp(buf, "From:", 5)) { - safestrncpy(SendMsg->mailfrom, &buf[5], sizeof SendMsg->mailfrom); - striplt(SendMsg->mailfrom); - for (i=0; SendMsg->mailfrom[i]; ++i) { - if (!isprint(SendMsg->mailfrom[i])) { - strcpy(&SendMsg->mailfrom[i], &SendMsg->mailfrom[i+1]); - i=0; - } - } - - /* Strip out parenthesized names */ - lp = (-1); - rp = (-1); - for (i=0; !IsEmptyStr(SendMsg->mailfrom + i); ++i) { - if (SendMsg->mailfrom[i] == '(') lp = i; - if (SendMsg->mailfrom[i] == ')') rp = i; - } - if ((lp>0)&&(rp>lp)) { - strcpy(&SendMsg->mailfrom[lp-1], &SendMsg->mailfrom[rp+1]); - } - - /* Prefer brokketized names */ - lp = (-1); - rp = (-1); - for (i=0; !IsEmptyStr(SendMsg->mailfrom + i); ++i) { - if (SendMsg->mailfrom[i] == '<') lp = i; - if (SendMsg->mailfrom[i] == '>') rp = i; - } - if ( (lp>=0) && (rp>lp) ) { - SendMsg->mailfrom[rp] = 0; - memmove(SendMsg->mailfrom, - &SendMsg->mailfrom[lp + 1], - rp - lp); - } - - scan_done = 1; - } - } while (scan_done == 0); - if (IsEmptyStr(SendMsg->mailfrom)) strcpy(SendMsg->mailfrom, "someone@somewhere.org"); - stripallbut(SendMsg->mailfrom, '<', '>'); - SendMsg->envelope_from = SendMsg->mailfrom; - } - - 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; - snprintf(SendMsg->dsn, SIZ, "No MX hosts found for <%s>", SendMsg->node); - return; ///////TODO: abort! - } - -} -/* TODO: abort... */ -#define SMTP_ERROR(WHICH_ERR, ERRSTR) {SendMsg->SMTPstatus = WHICH_ERR; memcpy(SendMsg->dsn, HKEY(ERRSTR) + 1); return eAbort; } -#define SMTP_VERROR(WHICH_ERR) { SendMsg->SMTPstatus = WHICH_ERR; safestrncpy(SendMsg->dsn, &ChrPtr(SendMsg->IO.IOBuf)[4], sizeof(SendMsg->dsn)); 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 connect_one_smtpsrv(SmtpOutMsg *SendMsg) -{ - char *endpart; - char buf[SIZ]; - - extract_token(buf, SendMsg->mxhosts, SendMsg->n_mx, '|', sizeof(buf)); - strcpy(SendMsg->mx_user, ""); - strcpy(SendMsg->mx_pass, ""); - 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'; - } - } - 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); - - snprintf(SendMsg->dsn, SIZ, "Could not connect: %s", strerror(errno)); - if (SendMsg->IO.sock >= 0) - { - 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) { - snprintf(SendMsg->dsn, SIZ, "%s", strerror(errno)); - } - else { - snprintf(SendMsg->dsn, SIZ, "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; - } - 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_ReadServerStatus, - 1); - return 0; -} - -eNextState SMTPC_read_greeting(SmtpOutMsg *SendMsg) -{ - /* Process the SMTP greeting from the server */ - SMTP_DBG_READ(); - - if (!SMTP_IS_STATE('2')) { - if (SMTP_IS_STATE('4')) - SMTP_VERROR(4) - else - SMTP_VERROR(5) - } - return eSendReply; -} - -eNextState SMTPC_send_EHLO(SmtpOutMsg *SendMsg) -{ - /* At this point we know we are talking to a real SMTP server */ - - /* Do a EHLO command. If it fails, try the HELO command. */ - StrBufPrintf(SendMsg->IO.SendBuf.Buf, - "EHLO %s\r\n", config.c_fqdn); - - SMTP_DBG_SEND(); - return eReadMessage; -} - -eNextState SMTPC_read_EHLO_reply(SmtpOutMsg *SendMsg) -{ - SMTP_DBG_READ(); - - if (SMTP_IS_STATE('2')) { - SendMsg->State ++; - if (IsEmptyStr(SendMsg->mx_user)) - SendMsg->State ++; /* Skip auth... */ - } - /* else we fall back to 'helo' */ - return eSendReply; -} - -eNextState STMPC_send_HELO(SmtpOutMsg *SendMsg) -{ - StrBufPrintf(SendMsg->IO.SendBuf.Buf, - "HELO %s\r\n", config.c_fqdn); - - SMTP_DBG_SEND(); - return eReadMessage; -} - -eNextState SMTPC_read_HELO_reply(SmtpOutMsg *SendMsg) -{ - SMTP_DBG_READ(); - - if (!SMTP_IS_STATE('2')) { - if (SMTP_IS_STATE('4')) - SMTP_VERROR(4) - else - SMTP_VERROR(5) - } - if (!IsEmptyStr(SendMsg->mx_user)) - SendMsg->State ++; /* Skip auth... */ - return eSendReply; -} - -eNextState SMTPC_send_auth(SmtpOutMsg *SendMsg) -{ - char buf[SIZ]; - char encoded[1024]; - - /* Do an AUTH command if necessary */ - sprintf(buf, "%s%c%s%c%s", - SendMsg->mx_user, '\0', - SendMsg->mx_user, '\0', - SendMsg->mx_pass); - CtdlEncodeBase64(encoded, buf, - strlen(SendMsg->mx_user) + - strlen(SendMsg->mx_user) + - strlen(SendMsg->mx_pass) + 2, 0); - StrBufPrintf(SendMsg->IO.SendBuf.Buf, - "AUTH PLAIN %s\r\n", encoded); - - SMTP_DBG_SEND(); - return eReadMessage; -} - -eNextState SMTPC_read_auth_reply(SmtpOutMsg *SendMsg) -{ - /* Do an AUTH command if necessary */ - - SMTP_DBG_READ(); - - if (!SMTP_IS_STATE('2')) { - if (SMTP_IS_STATE('4')) - SMTP_VERROR(4) - else - SMTP_VERROR(5) - } - return eSendReply; -} - -eNextState SMTPC_send_FROM(SmtpOutMsg *SendMsg) -{ - /* previous command succeeded, now try the MAIL FROM: command */ - StrBufPrintf(SendMsg->IO.SendBuf.Buf, - "MAIL FROM:<%s>\r\n", - SendMsg->envelope_from); - - SMTP_DBG_SEND(); - return eReadMessage; -} - -eNextState SMTPC_read_FROM_reply(SmtpOutMsg *SendMsg) -{ - SMTP_DBG_READ(); - - if (!SMTP_IS_STATE('2')) { - if (SMTP_IS_STATE('4')) - SMTP_VERROR(4) - else - SMTP_VERROR(5) - } - return eSendReply; -} - - -eNextState SMTPC_send_RCPT(SmtpOutMsg *SendMsg) -{ - /* MAIL succeeded, now try the RCPT To: command */ - StrBufPrintf(SendMsg->IO.SendBuf.Buf, - "RCPT TO:<%s@%s>\r\n", - SendMsg->user, - SendMsg->node); - - SMTP_DBG_SEND(); - return eReadMessage; -} - -eNextState SMTPC_read_RCPT_reply(SmtpOutMsg *SendMsg) -{ - SMTP_DBG_READ(); - - if (!SMTP_IS_STATE('2')) { - if (SMTP_IS_STATE('4')) - SMTP_VERROR(4) - else - SMTP_VERROR(5) - } - return eSendReply; -} - -eNextState SMTPC_send_DATAcmd(SmtpOutMsg *SendMsg) -{ - /* RCPT succeeded, now try the DATA command */ - StrBufPlain(SendMsg->IO.SendBuf.Buf, - HKEY("DATA\r\n")); - - SMTP_DBG_SEND(); - return eReadMessage; -} - -eNextState SMTPC_read_DATAcmd_reply(SmtpOutMsg *SendMsg) -{ - SMTP_DBG_READ(); - - if (!SMTP_IS_STATE('3')) { - if (SMTP_IS_STATE('4')) - SMTP_VERROR(3) - else - SMTP_VERROR(5) - } - return eSendReply; -} - -eNextState SMTPC_send_data_body(SmtpOutMsg *SendMsg) -{ - StrBuf *Buf; - /* If we reach this point, the server is expecting data.*/ - - 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; -} - -eNextState SMTPC_send_terminate_data_body(SmtpOutMsg *SendMsg) -{ - StrBuf *Buf; - - Buf = SendMsg->IO.SendBuf.Buf; - SendMsg->IO.SendBuf.Buf = SendMsg->msgtext; - SendMsg->msgtext = Buf; - - StrBufPlain(SendMsg->IO.SendBuf.Buf, - HKEY(".\r\n")); - - return eReadMessage; - -} - -eNextState SMTPC_read_data_body_reply(SmtpOutMsg *SendMsg) -{ - SMTP_DBG_READ(); - - if (!SMTP_IS_STATE('2')) { - if (SMTP_IS_STATE('4')) - SMTP_VERROR(4) - else - SMTP_VERROR(5) - } - - /* We did it! */ - safestrncpy(SendMsg->dsn, &ChrPtr(SendMsg->IO.RecvBuf.Buf)[4], 1023); - SendMsg->SMTPstatus = 2; - return eSendReply; -} - -eNextState SMTPC_send_QUIT(SmtpOutMsg *SendMsg) -{ - StrBufPlain(SendMsg->IO.SendBuf.Buf, - HKEY("QUIT\r\n")); - - SMTP_DBG_SEND(); - return eReadMessage; -} - -eNextState SMTPC_read_QUIT_reply(SmtpOutMsg *SendMsg) -{ - SMTP_DBG_READ(); - - CtdlLogPrintf(CTDL_INFO, "SMTP client[%ld]: delivery to <%s> @ <%s> (%s) succeeded\n", - SendMsg->n, SendMsg->user, SendMsg->node, SendMsg->name); - return eSendReply; -} - -eNextState SMTPC_read_dummy(SmtpOutMsg *SendMsg) -{ - return eSendReply; -} - -eNextState SMTPC_send_dummy(SmtpOutMsg *SendMsg) -{ - return eReadMessage; -} - -/* - * smtp_do_bounce() is caled by smtp_do_procmsg() to scan a set of delivery - * instructions for "5" codes (permanent fatal errors) and produce/deliver - * a "bounce" message (delivery status notification). - */ -void smtp_do_bounce(char *instr) { - int i; - int lines; - int status; - char buf[1024]; - char key[1024]; - char addr[1024]; - char dsn[1024]; - char bounceto[1024]; - StrBuf *boundary; - int num_bounces = 0; - int bounce_this = 0; - long bounce_msgid = (-1); - time_t submitted = 0L; - struct CtdlMessage *bmsg = NULL; - int give_up = 0; - struct recptypes *valid; - int successful_bounce = 0; - static int seq = 0; - StrBuf *BounceMB; - long omsgid = (-1); - - CtdlLogPrintf(CTDL_DEBUG, "smtp_do_bounce() called\n"); - strcpy(bounceto, ""); - boundary = NewStrBufPlain(HKEY("=_Citadel_Multipart_")); - StrBufAppendPrintf(boundary, "%s_%04x%04x", config.c_fqdn, getpid(), ++seq); - lines = num_tokens(instr, '\n'); - - /* See if it's time to give up on delivery of this message */ - for (i=0; i SMTP_GIVE_UP ) { - give_up = 1; - } - - /* Start building our bounce message */ - - bmsg = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage)); - if (bmsg == NULL) return; - memset(bmsg, 0, sizeof(struct CtdlMessage)); - BounceMB = NewStrBufPlain(NULL, 1024); - - bmsg->cm_magic = CTDLMESSAGE_MAGIC; - bmsg->cm_anon_type = MES_NORMAL; - bmsg->cm_format_type = FMT_RFC822; - bmsg->cm_fields['A'] = strdup("Citadel"); - bmsg->cm_fields['O'] = strdup(MAILROOM); - bmsg->cm_fields['N'] = strdup(config.c_nodename); - bmsg->cm_fields['U'] = strdup("Delivery Status Notification (Failure)"); - StrBufAppendBufPlain(BounceMB, HKEY("Content-type: multipart/mixed; boundary=\""), 0); - StrBufAppendBuf(BounceMB, boundary, 0); - StrBufAppendBufPlain(BounceMB, HKEY("\"\r\n"), 0); - StrBufAppendBufPlain(BounceMB, HKEY("MIME-Version: 1.0\r\n"), 0); - StrBufAppendBufPlain(BounceMB, HKEY("X-Mailer: " CITADEL "\r\n"), 0); - StrBufAppendBufPlain(BounceMB, HKEY("\r\nThis is a multipart message in MIME format.\r\n\r\n"), 0); - StrBufAppendBufPlain(BounceMB, HKEY("--"), 0); - StrBufAppendBuf(BounceMB, boundary, 0); - StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0); - StrBufAppendBufPlain(BounceMB, HKEY("Content-type: text/plain\r\n\r\n"), 0); - - if (give_up) StrBufAppendBufPlain(BounceMB, HKEY( -"A message you sent could not be delivered to some or all of its recipients\n" -"due to prolonged unavailability of its destination(s).\n" -"Giving up on the following addresses:\n\n" - ), 0); - - else StrBufAppendBufPlain(BounceMB, HKEY( -"A message you sent could not be delivered to some or all of its recipients.\n" -"The following addresses were undeliverable:\n\n" - ), 0); - - /* - * Now go through the instructions checking for stuff. - */ - for (i=0; i addr=<%s> status=%d dsn=<%s>\n", - key, addr, status, dsn); - - if (!strcasecmp(key, "bounceto")) { - strcpy(bounceto, addr); - } - - if (!strcasecmp(key, "msgid")) { - omsgid = atol(addr); - } - - if (!strcasecmp(key, "remote")) { - if (status == 5) bounce_this = 1; - if (give_up) bounce_this = 1; - } - - if (bounce_this) { - ++num_bounces; - - StrBufAppendBufPlain(BounceMB, addr, addrlen, 0); - StrBufAppendBufPlain(BounceMB, HKEY(": "), 0); - StrBufAppendBufPlain(BounceMB, dsn, dsnlen, 0); - StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0); - - remove_token(instr, i, '\n'); - --i; - --lines; - } - } - - /* Attach the original message */ - if (omsgid >= 0) { - StrBufAppendBufPlain(BounceMB, HKEY("--"), 0); - StrBufAppendBuf(BounceMB, boundary, 0); - StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0); - StrBufAppendBufPlain(BounceMB, HKEY("Content-type: message/rfc822\r\n"), 0); - StrBufAppendBufPlain(BounceMB, HKEY("Content-Transfer-Encoding: 7bit\r\n"), 0); - StrBufAppendBufPlain(BounceMB, HKEY("Content-Disposition: inline\r\n"), 0); - StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0); - - CC->redirect_buffer = NewStrBufPlain(NULL, SIZ); - CtdlOutputMsg(omsgid, MT_RFC822, HEADERS_ALL, 0, 1, NULL, 0); - StrBufAppendBuf(BounceMB, CC->redirect_buffer, 0); - FreeStrBuf(&CC->redirect_buffer); - } - - /* Close the multipart MIME scope */ - StrBufAppendBufPlain(BounceMB, HKEY("--"), 0); - StrBufAppendBuf(BounceMB, boundary, 0); - StrBufAppendBufPlain(BounceMB, HKEY("--\r\n"), 0); - if (bmsg->cm_fields['A'] != NULL) - free(bmsg->cm_fields['A']); - bmsg->cm_fields['A'] = SmashStrBuf(&BounceMB); - /* Deliver the bounce if there's anything worth mentioning */ - CtdlLogPrintf(CTDL_DEBUG, "num_bounces = %d\n", num_bounces); - if (num_bounces > 0) { - - /* First try the user who sent the message */ - CtdlLogPrintf(CTDL_DEBUG, "bounce to user? <%s>\n", bounceto); - if (IsEmptyStr(bounceto)) { - CtdlLogPrintf(CTDL_ERR, "No bounce address specified\n"); - bounce_msgid = (-1L); - } - - /* Can we deliver the bounce to the original sender? */ - valid = validate_recipients(bounceto, smtp_get_Recipients (), 0); - if (valid != NULL) { - if (valid->num_error == 0) { - CtdlSubmitMsg(bmsg, valid, "", QP_EADDR); - successful_bounce = 1; - } - } - - /* If not, post it in the Aide> room */ - if (successful_bounce == 0) { - CtdlSubmitMsg(bmsg, NULL, config.c_aideroom, QP_EADDR); - } - - /* Free up the memory we used */ - if (valid != NULL) { - free_recipients(valid); - } - } - FreeStrBuf(&boundary); - CtdlFreeMessage(bmsg); - CtdlLogPrintf(CTDL_DEBUG, "Done processing bounces\n"); -} - - -/* - * smtp_purge_completed_deliveries() is caled by smtp_do_procmsg() to scan a - * set of delivery instructions for completed deliveries and remove them. - * - * It returns the number of incomplete deliveries remaining. - */ -int smtp_purge_completed_deliveries(char *instr) { - int i; - int lines; - int status; - char buf[1024]; - char key[1024]; - char addr[1024]; - char dsn[1024]; - int completed; - int incomplete = 0; - - lines = num_tokens(instr, '\n'); - for (i=0; icm_fields['M']); - CtdlFreeMessage(msg); - - /* Strip out the headers amd any other non-instruction line */ - lines = num_tokens(instr, '\n'); - for (i=0; i SMTP_RETRY_MAX) { - retry = SMTP_RETRY_MAX; - } - remove_token(instr, i, '\n'); - } - if (!strcasecmp(key, "attempted")) { - attempted = extract_long(buf, 1); - if (attempted > last_attempted) - last_attempted = attempted; - } - } - - /* - * Postpone delivery if we've already tried recently. - * / - if (((time(NULL) - last_attempted) < retry) && (run_queue_now == 0)) { - CtdlLogPrintf(CTDL_DEBUG, "SMTP client: Retry time not yet reached.\n"); - free(instr); - return; - } -TMP TODO */ - - /* - * Bail out if there's no actual message associated with this - */ - if (text_msgid < 0L) { - CtdlLogPrintf(CTDL_ERR, "SMTP client: no 'msgid' directive found!\n"); - free(instr); - return; - } - - /* Plow through the instructions looking for 'remote' directives and - * a status of 0 (no delivery yet attempted) or 3/4 (transient errors - * were experienced and it's time to try again) - */ - lines = num_tokens(instr, '\n'); - for (i=0; i\n", addr); - smtp_try(key, addr, &status, dsn, sizeof dsn, text_msgid, envelope_from); - if (status != 2) { - if (results == NULL) { - results = malloc(1024); - memset(results, 0, 1024); - } - else { - results = realloc(results, strlen(results) + 1024); - } - snprintf(&results[strlen(results)], 1024, - "%s|%s|%d|%s\n", - key, addr, status, dsn); - } - } - } - - if (results != NULL) { - instr = realloc(instr, strlen(instr) + strlen(results) + 2); - strcat(instr, results); - free(results); - } - - - /* Generate 'bounce' messages */ - smtp_do_bounce(instr); - - /* Go through the delivery list, deleting completed deliveries */ - incomplete_deliveries_remaining = - smtp_purge_completed_deliveries(instr); - - - /* - * No delivery instructions remain, so delete both the instructions - * message and the message message. - */ - if (incomplete_deliveries_remaining <= 0) { - long delmsgs[2]; - delmsgs[0] = msgnum; - delmsgs[1] = text_msgid; - CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, delmsgs, 2, ""); - } - - /* - * Uncompleted delivery instructions remain, so delete the old - * instructions and replace with the updated ones. - */ - if (incomplete_deliveries_remaining > 0) { - CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, &msgnum, 1, ""); - msg = malloc(sizeof(struct CtdlMessage)); - memset(msg, 0, sizeof(struct CtdlMessage)); - msg->cm_magic = CTDLMESSAGE_MAGIC; - msg->cm_anon_type = MES_NORMAL; - msg->cm_format_type = FMT_RFC822; - msg->cm_fields['M'] = malloc(strlen(instr)+SIZ); - snprintf(msg->cm_fields['M'], - strlen(instr)+SIZ, - "Content-type: %s\n\n%s\n" - "attempted|%ld\n" - "retry|%ld\n", - SPOOLMIME, instr, (long)time(NULL), (long)retry ); - CtdlSubmitMsg(msg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR); - CtdlFreeMessage(msg); - } - - free(instr); -} - - -/*****************************************************************************/ -/* SMTP UTILITY COMMANDS */ -/*****************************************************************************/ - -void cmd_smtp(char *argbuf) { - char cmd[64]; - char node[256]; - char buf[1024]; - int i; - int num_mxhosts; - - if (CtdlAccessCheck(ac_aide)) return; - - extract_token(cmd, argbuf, 0, '|', sizeof cmd); - - if (!strcasecmp(cmd, "mx")) { - extract_token(node, argbuf, 1, '|', sizeof node); - num_mxhosts = getmx(buf, node); - cprintf("%d %d MX hosts listed for %s\n", - LISTING_FOLLOWS, num_mxhosts, node); - for (i=0; iroom, SMTP_SPOOLOUT_ROOM) != 0) { - CtdlLogPrintf(CTDL_ERR, "Cannot find room <%s>\n", SMTP_SPOOLOUT_ROOM); - } - else { - num_processed = CtdlForEachMessage(MSGS_ALL, 0L, NULL, SPOOLMIME, NULL, smtp_do_procmsg, NULL); - } - CtdlLogPrintf(CTDL_INFO, "SMTP client: queue run completed; %d messages processed\n", num_processed); - CtdlThreadSleep(60); - } - - CtdlClearSystemContext(); - return(NULL); -} - - -/* - * Initialize the SMTP outbound queue - */ -void smtp_init_spoolout(void) { - struct ctdlroom qrbuf; - - /* - * Create the room. This will silently fail if the room already - * exists, and that's perfectly ok, because we want it to exist. - */ - CtdlCreateRoom(SMTP_SPOOLOUT_ROOM, 3, "", 0, 1, 0, VIEW_MAILBOX); - - /* - * Make sure it's set to be a "system room" so it doesn't show up - * in the nown rooms list for Aides. - */ - if (CtdlGetRoomLock(&qrbuf, SMTP_SPOOLOUT_ROOM) == 0) { - qrbuf.QRflags2 |= QR2_SYSTEM; - CtdlPutRoomLock(&qrbuf); - } -} - - -SMTPReadHandler ReadHandlers[eMaxSMTPC] = { - SMTPC_read_greeting, - SMTPC_read_EHLO_reply, - SMTPC_read_HELO_reply, - SMTPC_read_auth_reply, - SMTPC_read_FROM_reply, - SMTPC_read_RCPT_reply, - SMTPC_read_DATAcmd_reply, - SMTPC_read_dummy, - SMTPC_read_data_body_reply, - SMTPC_read_QUIT_reply -}; - -SMTPSendHandler SendHandlers[eMaxSMTPC] = { - SMTPC_send_dummy, /* we don't send a greeting, the server does... */ - SMTPC_send_EHLO, - STMPC_send_HELO, - SMTPC_send_auth, - SMTPC_send_FROM, - SMTPC_send_RCPT, - SMTPC_send_DATAcmd, - SMTPC_send_data_body, - SMTPC_send_terminate_data_body, - SMTPC_send_QUIT -}; - -eNextState SMTP_C_DispatchReadDone(void *Data) -{ - SmtpOutMsg *pMsg = Data; - eNextState rc = ReadHandlers[pMsg->State](pMsg); - pMsg->State++; - return rc; -} - -eNextState SMTP_C_DispatchWriteDone(void *Data) -{ - SmtpOutMsg *pMsg = Data; - return SendHandlers[pMsg->State](pMsg); - -} - - -#endif -CTDL_MODULE_INIT(smtp_eventclient) -{ -#ifdef EXPERIMENTAL_SMTP_EVENT_CLIENT - if (!threading) - { - smtp_init_spoolout(); - CtdlThreadCreate("SMTPEvent Send", CTDLTHREAD_BIGSTACK, smtp_queue_thread, NULL); - - CtdlRegisterProtoHook(cmd_smtp, "SMTP", "SMTP utility commands"); - } -#endif - - /* return our Subversion id for the Log */ - return "smtpeventclient"; -}