* 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
+ * Copyright (c) 1998-2011 by the citadel.org team
*
- * This program is free software; you can redistribute it and/or modify
+ * This program is open source 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.
*
*/
void smtp_try(const char *key, const char *addr, int *status,
- char *dsn, size_t n, long msgnum, char *envelope_from)
-{
+ char *dsn, size_t n, long msgnum, char *envelope_from
+) {
int sock = (-1);
char mxhosts[1024];
int num_mxhosts;
int scan_done;
CitContext *CCC=CC;
-
/* Parse out the host portion of the recipient address */
process_rfc822_addr(addr, user, node, name);
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client: Attempting delivery to <%s> @ <%s> (%s)\n",
- user, node, name);
+ syslog(LOG_DEBUG, "SMTP client: Attempting delivery to <%s> @ <%s> (%s)", user, node, name);
/* 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) );
- msg_size = StrLength(CC->redirect_buffer);
- msgtext = SmashStrBuf(&CC->redirect_buffer);
+ msg_size = StrLength(CCC->redirect_buffer);
+ msgtext = SmashStrBuf(&CCC->redirect_buffer);
+
+ /* This check is being added on 2011apr02 as we are experiencing a problem where the msg_size
+ * is being reported as zero for every delivery after about 12h of server runtime; this seems
+ * to indicate a heap corruption of some sort? Deferring will allow the message to be delivered
+ * after a server restart instead of discarded. After we fix the real problem, this will still
+ * be a good sanity check to still have in place. --ajc
+ */
+ if (msg_size <= 0) {
+ syslog(LOG_ALERT, "msg_size is zero -- possible data corruption");
+ *status = 4;
+ strcpy(dsn, "Internal server error prevented successful delivery -- deferring");
+ goto bail;
+ }
/* If no envelope_from is supplied, extract one from the message */
if ( (envelope_from == NULL) || (IsEmptyStr(envelope_from)) ) {
scan_done = 1;
}
} while (scan_done == 0);
- if (IsEmptyStr(mailfrom)) strcpy(mailfrom, "someone@somewhere.org");
+ if (IsEmptyStr(mailfrom)) {
+ syslog(LOG_DEBUG, "This message has no From: header. Hmm...");
+ }
stripallbut(mailfrom, '<', '>');
envelope_from = mailfrom;
}
/* Figure out what mail exchanger host we have to connect to */
num_mxhosts = getmx(mxhosts, node);
- CtdlLogPrintf(CTDL_DEBUG, "Number of MX hosts for <%s> is %d [%s]\n", node, num_mxhosts, mxhosts);
+ syslog(LOG_DEBUG, "Number of MX hosts for <%s> is %d [%s]", node, num_mxhosts, mxhosts);
if (num_mxhosts < 1) {
*status = 5;
snprintf(dsn, SIZ, "No MX hosts found for <%s>", node);
else {
strcpy(mx_port, "25");
}
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client: connecting to %s : %s ...\n", mx_host, mx_port);
+ syslog(LOG_DEBUG, "SMTP client: connecting to %s : %s ...", mx_host, mx_port);
sock = sock_connect(mx_host, mx_port);
snprintf(dsn, SIZ, "Could not connect: %s", strerror(errno));
if (sock >= 0)
{
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client: connected!\n");
- int fdflags;
- fdflags = fcntl(sock, F_GETFL);
- if (fdflags < 0)
- CtdlLogPrintf(CTDL_DEBUG,
- "unable to get SMTP-Client socket flags! %s \n",
- strerror(errno));
- fdflags = fdflags | O_NONBLOCK;
- if (fcntl(sock, F_SETFL, fdflags) < 0)
- CtdlLogPrintf(CTDL_DEBUG,
- "unable to set SMTP-Client socket nonblocking flags! %s \n",
- strerror(errno));
+ syslog(LOG_DEBUG, "SMTP client: connected!");
+ int fdflags;
+ fdflags = fcntl(sock, F_GETFL);
+ if (fdflags < 0) {
+ syslog(LOG_DEBUG,
+ "unable to get SMTP-Client socket flags! %s",
+ strerror(errno)
+ );
+ }
+ fdflags = fdflags | O_NONBLOCK;
+ if (fcntl(sock, F_SETFL, fdflags) < 0) {
+ syslog(LOG_DEBUG,
+ "unable to set SMTP-Client socket nonblocking flags! %s",
+ strerror(errno)
+ );
+ }
}
if (sock < 0) {
if (errno > 0) {
strcpy(dsn, "Connection broken during SMTP conversation");
goto bail;
}
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
+ syslog(LOG_DEBUG, "<%s", buf);
if (buf[0] != '2') {
if (buf[0] == '4') {
*status = 4;
/* Do a EHLO command. If it fails, try the HELO command. */
snprintf(buf, sizeof buf, "EHLO %s\r\n", config.c_fqdn);
- CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
+ syslog(LOG_DEBUG, ">%s", buf);
sock_write(&sock, buf, strlen(buf));
if (ml_sock_gets(&sock, buf, 30) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP HELO");
goto bail;
}
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
+ syslog(LOG_DEBUG, "<%s", buf);
if (buf[0] != '2') {
snprintf(buf, sizeof buf, "HELO %s\r\n", config.c_fqdn);
- CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
+ syslog(LOG_DEBUG, ">%s", buf);
sock_write(&sock, buf, strlen(buf));
if (ml_sock_gets(&sock, buf, 30) < 0) {
*status = 4;
sprintf(buf, "%s%c%s%c%s", mx_user, '\0', mx_user, '\0', mx_pass);
CtdlEncodeBase64(encoded, buf, strlen(mx_user) + strlen(mx_user) + strlen(mx_pass) + 2, 0);
snprintf(buf, sizeof buf, "AUTH PLAIN %s\r\n", encoded);
- CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
+ syslog(LOG_DEBUG, ">%s", buf);
sock_write(&sock, buf, strlen(buf));
if (ml_sock_gets(&sock, buf, 30) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP AUTH");
goto bail;
}
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
+ syslog(LOG_DEBUG, "<%s", buf);
if (buf[0] != '2') {
if (buf[0] == '4') {
*status = 4;
/* previous command succeeded, now try the MAIL FROM: command */
snprintf(buf, sizeof buf, "MAIL FROM:<%s>\r\n", envelope_from);
- CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
+ syslog(LOG_DEBUG, ">%s", buf);
sock_write(&sock, buf, strlen(buf));
if (ml_sock_gets(&sock, buf, 30) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP MAIL");
goto bail;
}
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
+ syslog(LOG_DEBUG, "<%s", buf);
if (buf[0] != '2') {
if (buf[0] == '4') {
*status = 4;
/* MAIL succeeded, now try the RCPT To: command */
snprintf(buf, sizeof buf, "RCPT TO:<%s@%s>\r\n", user, node);
- CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
+ syslog(LOG_DEBUG, ">%s", buf);
sock_write(&sock, buf, strlen(buf));
if (ml_sock_gets(&sock, buf, 30) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP RCPT");
goto bail;
}
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
+ syslog(LOG_DEBUG, "<%s", buf);
if (buf[0] != '2') {
if (buf[0] == '4') {
*status = 4;
}
/* RCPT succeeded, now try the DATA command */
- CtdlLogPrintf(CTDL_DEBUG, ">DATA\n");
+ syslog(LOG_DEBUG, ">DATA");
sock_write(&sock, "DATA\r\n", 6);
if (ml_sock_gets(&sock, buf, 30) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP DATA");
goto bail;
}
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
+ syslog(LOG_DEBUG, "<%s", buf);
if (buf[0] != '3') {
if (buf[0] == '4') {
*status = 3;
msg_size,
(msg_size / 128) + 50);
if (msgtext[msg_size-1] != 10) {
- CtdlLogPrintf(CTDL_WARNING, "Possible problem: message did not "
- "correctly terminate. (expecting 0x10, got 0x%02x)\n",
+ syslog(LOG_WARNING, "Possible problem: message did not "
+ "correctly terminate. (expecting 0x10, got 0x%02x)",
buf[msg_size-1]);
sock_write(&sock, "\r\n", 2);
}
strcpy(dsn, "Connection broken during SMTP message transmit");
goto bail;
}
- CtdlLogPrintf(CTDL_DEBUG, "%s\n", buf);
+ syslog(LOG_DEBUG, "%s", buf);
if (buf[0] != '2') {
if (buf[0] == '4') {
*status = 4;
safestrncpy(dsn, &buf[4], 1023);
*status = 2;
- CtdlLogPrintf(CTDL_DEBUG, ">QUIT\n");
+ syslog(LOG_DEBUG, ">QUIT");
sock_write(&sock, "QUIT\r\n", 6);
ml_sock_gets(&sock, buf, 30);
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
- CtdlLogPrintf(CTDL_INFO, "SMTP client: delivery to <%s> @ <%s> (%s) succeeded\n",
- user, node, name);
+ syslog(LOG_DEBUG, "<%s", buf);
+ syslog(LOG_INFO, "SMTP client: delivery to <%s> @ <%s> (%s) succeeded", user, node, name);
bail: free(msgtext);
FreeStrBuf(&CCC->sReadBuf);
FreeStrBuf(&CCC->sMigrateBuf);
- if (sock != -1)
+ if (sock != -1) {
sock_close(sock);
-
- /* Write something to the syslog (which may or may not be where the
- * rest of the Citadel logs are going; some sysadmins want LOG_MAIL).
- */
- if (enable_syslog) {
- syslog((LOG_MAIL | LOG_INFO),
- "%ld: to=<%s>, relay=%s, stat=%s",
- msgnum,
- addr,
- mx_host,
- dsn
- );
}
+ /* Standard practice is to write DSN to LOG_MAIL which may or may not be where the
+ * rest of the Citadel logs are going.
+ */
+ syslog((LOG_MAIL | LOG_INFO), "%ld: to=<%s>, relay=%s, stat=%s", msgnum, addr, mx_host, dsn);
return;
}
StrBuf *BounceMB;
long omsgid = (-1);
- CtdlLogPrintf(CTDL_DEBUG, "smtp_do_bounce() called\n");
+ syslog(LOG_DEBUG, "smtp_do_bounce() called");
strcpy(bounceto, "");
boundary = NewStrBufPlain(HKEY("=_Citadel_Multipart_"));
StrBufAppendPrintf(boundary, "%s_%04x%04x", config.c_fqdn, getpid(), ++seq);
dsnlen = extract_token(dsn, buf, 3, '|', sizeof dsn);
bounce_this = 0;
- CtdlLogPrintf(CTDL_DEBUG, "key=<%s> addr=<%s> status=%d dsn=<%s>\n",
- key, addr, status, dsn);
+ syslog(LOG_DEBUG, "key=<%s> addr=<%s> status=%d dsn=<%s>", key, addr, status, dsn);
if (!strcasecmp(key, "bounceto")) {
strcpy(bounceto, addr);
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);
+ syslog(LOG_DEBUG, "num_bounces = %d", num_bounces);
if (num_bounces > 0) {
/* First try the user who sent the message */
- CtdlLogPrintf(CTDL_DEBUG, "bounce to user? <%s>\n", bounceto);
+ syslog(LOG_DEBUG, "bounce to user? <%s>", bounceto);
if (IsEmptyStr(bounceto)) {
- CtdlLogPrintf(CTDL_ERR, "No bounce address specified\n");
+ syslog(LOG_ERR, "No bounce address specified");
bounce_msgid = (-1L);
}
}
FreeStrBuf(&boundary);
CtdlFreeMessage(bmsg);
- CtdlLogPrintf(CTDL_DEBUG, "Done processing bounces\n");
+ syslog(LOG_DEBUG, "Done processing bounces");
}
time_t last_attempted = 0L;
time_t retry = SMTP_RETRY_INTERVAL;
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client: smtp_do_procmsg(%ld)\n", msgnum);
+ syslog(LOG_DEBUG, "SMTP client: smtp_do_procmsg(%ld)", msgnum);
strcpy(envelope_from, "");
msg = CtdlFetchMessage(msgnum, 1);
if (msg == NULL) {
- CtdlLogPrintf(CTDL_ERR, "SMTP client: tried %ld but no such message!\n", msgnum);
+ syslog(LOG_ERR, "SMTP client: tried %ld but no such message!", msgnum);
return;
}
* 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");
+ syslog(LOG_DEBUG, "SMTP client: Retry time not yet reached.");
free(instr);
return;
}
* 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");
+ syslog(LOG_ERR, "SMTP client: no 'msgid' directive found!");
free(instr);
return;
}
--i;
--lines;
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client: Trying <%s>\n", addr);
+ syslog(LOG_DEBUG, "SMTP client: Trying <%s>", addr);
smtp_try(key, addr, &status, dsn, sizeof dsn, text_msgid, envelope_from);
if (status != 2) {
if (results == NULL) {
*
* Run through the queue sending out messages.
*/
-void *smtp_queue_thread(void *arg) {
+void smtp_do_queue(void) {
+ static int is_running = 0;
int num_processed = 0;
- struct CitContext smtp_queue_CC;
- CtdlFillSystemContext(&smtp_queue_CC, "SMTP Send");
- citthread_setspecific(MyConKey, (void *)&smtp_queue_CC);
- CtdlLogPrintf(CTDL_DEBUG, "smtp_queue_thread() initializing\n");
+ if (is_running) return; /* Concurrency check - only one can run */
+ is_running = 1;
- while (!CtdlThreadCheckStop()) {
-
- CtdlLogPrintf(CTDL_INFO, "SMTP client: processing outbound queue\n");
+ syslog(LOG_INFO, "SMTP client: processing outbound queue");
- if (CtdlGetRoom(&CC->room, 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);
+ if (CtdlGetRoom(&CC->room, SMTP_SPOOLOUT_ROOM) != 0) {
+ syslog(LOG_ERR, "Cannot find room <%s>", SMTP_SPOOLOUT_ROOM);
}
-
- CtdlClearSystemContext();
- return(NULL);
+ else {
+ num_processed = CtdlForEachMessage(MSGS_ALL, 0L, NULL, SPOOLMIME, NULL, smtp_do_procmsg, NULL);
+ }
+ syslog(LOG_INFO, "SMTP client: queue run completed; %d messages processed", num_processed);
+ run_queue_now = 0;
+ is_running = 0;
}
if (!threading)
{
smtp_init_spoolout();
- CtdlThreadCreate("SMTP Send", CTDLTHREAD_BIGSTACK, smtp_queue_thread, NULL);
+ CtdlRegisterSessionHook(smtp_do_queue, EVT_TIMER);
CtdlRegisterProtoHook(cmd_smtp, "SMTP", "SMTP utility commands");
}
- /* return our Subversion id for the Log */
+ /* return our module name for the log */
return "smtp";
}