* 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"
*/
if ( (config.c_rbl_at_greeting) && (SMTP->is_msa == 0) ) {
if (rbl_check(message_to_spammer)) {
- cprintf("550 %s\r\n", message_to_spammer);
+ if (CtdlThreadCheckStop())
+ cprintf("421 %s\r\n", message_to_spammer);
+ else
+ cprintf("550 %s\r\n", message_to_spammer);
CC->kill_me = 1;
/* no need to free_recipients(valid), it's not allocated yet */
return;
* Implement HELP command.
*/
void smtp_help(void) {
- cprintf("214-Commands accepted:\r\n");
- cprintf("214- DATA\r\n");
- cprintf("214- EHLO\r\n");
- cprintf("214- HELO\r\n");
- cprintf("214- HELP\r\n");
- cprintf("214- MAIL\r\n");
- cprintf("214- NOOP\r\n");
- cprintf("214- QUIT\r\n");
- cprintf("214- RCPT\r\n");
- cprintf("214- RSET\r\n");
- cprintf("214 \r\n");
+ cprintf("214 RTFM http://www.ietf.org/rfc/rfc2821.txt\r\n");
}
void smtp_get_pass(char *argbuf) {
char password[SIZ];
+ memset(password, 0, sizeof(password));
CtdlDecodeBase64(password, argbuf, SIZ);
/* CtdlLogPrintf(CTDL_DEBUG, "Trying <%s>\n", password); */
if (CtdlTryPassword(password) == pass_ok) {
}
/*
- * Implements the "MAIL From:" command
+ * Implements the "MAIL FROM:" command
*/
void smtp_mail(char *argbuf) {
char user[SIZ];
&& (!SMTP->is_lmtp) ) { /* Don't RBL LMTP clients */
if (config.c_rbl_at_greeting == 0) { /* Don't RBL again if we already did it */
if (rbl_check(message_to_spammer)) {
- cprintf("550 %s\r\n", message_to_spammer);
+ if (CtdlThreadCheckStop())
+ cprintf("421 %s\r\n", message_to_spammer);
+ else
+ cprintf("550 %s\r\n", message_to_spammer);
/* no need to free_recipients(valid), it's not allocated yet */
return;
}
datestring(nowstamp, sizeof nowstamp, time(NULL), DATESTRING_RFC822);
body = malloc(4096);
- if (body != NULL) snprintf(body, 4096,
- "Received: from %s (%s [%s])\n"
- " by %s; %s\n",
- SMTP->helo_node,
- CC->cs_host,
- CC->cs_addr,
- config.c_fqdn,
- nowstamp);
-
+ if (body != NULL) {
+ if (SMTP->is_lmtp && (CC->cs_UDSclientUID != -1)) {
+ snprintf(body, 4096,
+ "Received: from %s (Citadel from userid %ld)\n"
+ " by %s; %s\n",
+ SMTP->helo_node,
+ CC->cs_UDSclientUID,
+ config.c_fqdn,
+ nowstamp);
+ }
+ else {
+ snprintf(body, 4096,
+ "Received: from %s (%s [%s])\n"
+ " by %s; %s\n",
+ SMTP->helo_node,
+ CC->cs_host,
+ CC->cs_addr,
+ config.c_fqdn,
+ nowstamp);
+ }
+ }
body = CtdlReadMessageBody(".", config.c_maxmsglen, body, 1, 0);
if (body == NULL) {
cprintf("550 Unable to save message: internal error.\r\n");
}
else { /* Ok, we'll accept this message. */
- msgnum = CtdlSubmitMsg(msg, valid, "");
+ msgnum = CtdlSubmitMsg(msg, valid, "", 0);
if (msgnum > 0L) {
sprintf(result, "250 Message accepted.\r\n");
}
CC->kill_me = 1;
return;
}
- CtdlLogPrintf(CTDL_INFO, "SMTP: %s\n", cmdbuf);
+ CtdlLogPrintf(CTDL_INFO, "SMTP server: %s\n", cmdbuf);
while (strlen(cmdbuf) < 5) strcat(cmdbuf, " ");
if (SMTP->command_state == smtp_user) {
*
*/
void smtp_try(const char *key, const char *addr, int *status,
- char *dsn, size_t n, long msgnum)
+ char *dsn, size_t n, long msgnum, char *envelope_from)
{
int sock = (-1);
char mxhosts[1024];
char *ptr;
size_t msg_size;
int scan_done;
-
+
+
/* Parse out the host portion of the recipient address */
process_rfc822_addr(addr, user, node, name);
- CtdlLogPrintf(CTDL_DEBUG, "Attempting SMTP delivery to <%s> @ <%s> (%s)\n",
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP client: Attempting delivery to <%s> @ <%s> (%s)\n",
user, node, name);
/* Load the message out of the database */
CC->redirect_buffer = malloc(SIZ);
CC->redirect_len = 0;
CC->redirect_alloc = SIZ;
- CtdlOutputMsg(msgnum, MT_RFC822, HEADERS_ALL, 0, 1, NULL);
+ CtdlOutputMsg(msgnum, MT_RFC822, HEADERS_ALL, 0, 1, NULL, ESC_DOT);
msgtext = CC->redirect_buffer;
msg_size = CC->redirect_len;
CC->redirect_buffer = NULL;
CC->redirect_len = 0;
CC->redirect_alloc = 0;
- /* Extract something to send later in the 'MAIL From:' command */
- strcpy(mailfrom, "");
- scan_done = 0;
- ptr = msgtext;
- do {
- if (ptr = memreadline(ptr, buf, sizeof buf), *ptr == 0) {
- scan_done = 1;
- }
- if (!strncasecmp(buf, "From:", 5)) {
- safestrncpy(mailfrom, &buf[5], sizeof mailfrom);
- striplt(mailfrom);
- for (i=0; mailfrom[i]; ++i) {
- if (!isprint(mailfrom[i])) {
- strcpy(&mailfrom[i], &mailfrom[i+1]);
- i=0;
- }
+ /* If no envelope_from is supplied, extract one from the message */
+ if ( (envelope_from == NULL) || (IsEmptyStr(envelope_from)) ) {
+ strcpy(mailfrom, "");
+ scan_done = 0;
+ ptr = msgtext;
+ do {
+ if (ptr = memreadline(ptr, buf, sizeof buf), *ptr == 0) {
+ scan_done = 1;
}
-
- /* Strip out parenthesized names */
- lp = (-1);
- rp = (-1);
- for (i=0; mailfrom[i]; ++i) {
- if (mailfrom[i] == '(') lp = i;
- if (mailfrom[i] == ')') rp = i;
- }
- if ((lp>0)&&(rp>lp)) {
- strcpy(&mailfrom[lp-1], &mailfrom[rp+1]);
- }
-
- /* Prefer brokketized names */
- lp = (-1);
- rp = (-1);
- for (i=0; mailfrom[i]; ++i) {
- if (mailfrom[i] == '<') lp = i;
- if (mailfrom[i] == '>') rp = i;
- }
- if ( (lp>=0) && (rp>lp) ) {
- mailfrom[rp] = 0;
- strcpy(mailfrom, &mailfrom[lp]);
+ if (!strncasecmp(buf, "From:", 5)) {
+ safestrncpy(mailfrom, &buf[5], sizeof mailfrom);
+ striplt(mailfrom);
+ for (i=0; mailfrom[i]; ++i) {
+ if (!isprint(mailfrom[i])) {
+ strcpy(&mailfrom[i], &mailfrom[i+1]);
+ i=0;
+ }
+ }
+
+ /* Strip out parenthesized names */
+ lp = (-1);
+ rp = (-1);
+ for (i=0; mailfrom[i]; ++i) {
+ if (mailfrom[i] == '(') lp = i;
+ if (mailfrom[i] == ')') rp = i;
+ }
+ if ((lp>0)&&(rp>lp)) {
+ strcpy(&mailfrom[lp-1], &mailfrom[rp+1]);
+ }
+
+ /* Prefer brokketized names */
+ lp = (-1);
+ rp = (-1);
+ for (i=0; mailfrom[i]; ++i) {
+ if (mailfrom[i] == '<') lp = i;
+ if (mailfrom[i] == '>') rp = i;
+ }
+ if ( (lp>=0) && (rp>lp) ) {
+ mailfrom[rp] = 0;
+ strcpy(mailfrom, &mailfrom[lp]);
+ }
+
+ scan_done = 1;
}
-
- scan_done = 1;
- }
- } while (scan_done == 0);
- if (IsEmptyStr(mailfrom)) strcpy(mailfrom, "someone@somewhere.org");
- stripallbut(mailfrom, '<', '>');
+ } while (scan_done == 0);
+ if (IsEmptyStr(mailfrom)) strcpy(mailfrom, "someone@somewhere.org");
+ 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\n", node, num_mxhosts);
+ CtdlLogPrintf(CTDL_DEBUG, "Number of MX hosts for <%s> is %d [%s]\n", 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, "Trying %s : %s ...\n", mx_host, mx_port);
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP client: connecting to %s : %s ...\n", mx_host, mx_port);
sock = sock_connect(mx_host, mx_port, "tcp");
snprintf(dsn, SIZ, "Could not connect: %s", strerror(errno));
- if (sock >= 0) CtdlLogPrintf(CTDL_DEBUG, "Connected!\n");
+ if (sock >= 0) CtdlLogPrintf(CTDL_DEBUG, "SMTP client: connected!\n");
if (sock < 0) {
if (errno > 0) {
snprintf(dsn, SIZ, "%s", strerror(errno));
}
}
- /* previous command succeeded, now try the MAIL From: command */
- snprintf(buf, sizeof buf, "MAIL From: <%s>\r\n", mailfrom);
+ /* 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);
sock_write(sock, buf, strlen(buf));
if (ml_sock_gets(sock, buf) < 0) {
}
/* MAIL succeeded, now try the RCPT To: command */
- snprintf(buf, sizeof buf, "RCPT To: <%s@%s>\r\n", user, node);
+ snprintf(buf, sizeof buf, "RCPT TO:<%s@%s>\r\n", user, node);
CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
sock_write(sock, buf, strlen(buf));
if (ml_sock_gets(sock, buf) < 0) {
}
}
- /* If we reach this point, the server is expecting data */
+ /* If we reach this point, the server is expecting data.*/
sock_write(sock, msgtext, msg_size);
if (msgtext[msg_size-1] != 10) {
CtdlLogPrintf(CTDL_WARNING, "Possible problem: message did not "
sock_write(sock, "QUIT\r\n", 6);
ml_sock_gets(sock, buf);
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
- CtdlLogPrintf(CTDL_INFO, "SMTP delivery to <%s> @ <%s> (%s) succeeded\n",
+ CtdlLogPrintf(CTDL_INFO, "SMTP client: delivery to <%s> @ <%s> (%s) succeeded\n",
user, node, name);
bail: free(msgtext);
CC->redirect_buffer = malloc(SIZ);
CC->redirect_len = 0;
CC->redirect_alloc = SIZ;
- CtdlOutputMsg(omsgid, MT_RFC822, HEADERS_ALL, 0, 1, NULL);
+ CtdlOutputMsg(omsgid, MT_RFC822, HEADERS_ALL, 0, 1, NULL, 0);
omsgtext = CC->redirect_buffer;
omsgsize = CC->redirect_len;
CC->redirect_buffer = NULL;
valid = validate_recipients(bounceto, smtp_get_Recipients (), 0);
if (valid != NULL) {
if (valid->num_error == 0) {
- CtdlSubmitMsg(bmsg, valid, "");
+ 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);
+ CtdlSubmitMsg(bmsg, NULL, config.c_aideroom, QP_EADDR);
}
/* Free up the memory we used */
char key[1024];
char addr[1024];
char dsn[1024];
+ char envelope_from[1024];
long text_msgid = (-1);
int incomplete_deliveries_remaining;
time_t attempted = 0L;
time_t last_attempted = 0L;
time_t retry = SMTP_RETRY_INTERVAL;
- CtdlLogPrintf(CTDL_DEBUG, "smtp_do_procmsg(%ld)\n", msgnum);
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP client: smtp_do_procmsg(%ld)\n", msgnum);
+ strcpy(envelope_from, "");
msg = CtdlFetchMessage(msgnum, 1);
if (msg == NULL) {
- CtdlLogPrintf(CTDL_ERR, "SMTP: tried %ld but no such message!\n", msgnum);
+ CtdlLogPrintf(CTDL_ERR, "SMTP client: tried %ld but no such message!\n", msgnum);
return;
}
if (!strcasecmp(key, "msgid")) {
text_msgid = extract_long(buf, 1);
}
+ if (!strcasecmp(key, "envelope_from")) {
+ extract_token(envelope_from, buf, 1, '|', sizeof envelope_from);
+ }
if (!strcasecmp(key, "retry")) {
/* double the retry interval after each attempt */
retry = extract_long(buf, 1) * 2L;
* Postpone delivery if we've already tried recently.
*/
if (((time(NULL) - last_attempted) < retry) && (run_queue_now == 0)) {
- CtdlLogPrintf(CTDL_DEBUG, "Retry time not yet reached.\n");
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP client: Retry time not yet reached.\n");
free(instr);
return;
}
* Bail out if there's no actual message associated with this
*/
if (text_msgid < 0L) {
- CtdlLogPrintf(CTDL_ERR, "SMTP: no 'msgid' directive found!\n");
+ CtdlLogPrintf(CTDL_ERR, "SMTP client: no 'msgid' directive found!\n");
free(instr);
return;
}
--i;
--lines;
- CtdlLogPrintf(CTDL_DEBUG, "SMTP: Trying <%s>\n", addr);
- smtp_try(key, addr, &status, dsn, sizeof dsn, text_msgid);
+ CtdlLogPrintf(CTDL_DEBUG, "SMTP client: Trying <%s>\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);
+ results = realloc(results, strlen(results) + 1024);
}
snprintf(&results[strlen(results)], 1024,
"%s|%s|%d|%s\n",
"attempted|%ld\n"
"retry|%ld\n",
SPOOLMIME, instr, (long)time(NULL), (long)retry );
- CtdlSubmitMsg(msg, NULL, SMTP_SPOOLOUT_ROOM);
+ CtdlSubmitMsg(msg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR);
CtdlFreeMessage(msg);
}
*/
void smtp_do_queue(void) {
static int doing_queue = 0;
+ int num_processed = 0;
/*
* This is a simple concurrency check to make sure only one queue run
/*
* Go ahead and run the queue
*/
- CtdlLogPrintf(CTDL_INFO, "SMTP: processing outbound queue\n");
+ CtdlLogPrintf(CTDL_INFO, "SMTP client: processing outbound queue\n");
if (getroom(&CC->room, SMTP_SPOOLOUT_ROOM) != 0) {
CtdlLogPrintf(CTDL_ERR, "Cannot find room <%s>\n", SMTP_SPOOLOUT_ROOM);
return;
}
- CtdlForEachMessage(MSGS_ALL, 0L, NULL,
- SPOOLMIME, NULL, smtp_do_procmsg, NULL);
+ num_processed = CtdlForEachMessage(MSGS_ALL, 0L, NULL, SPOOLMIME, NULL, smtp_do_procmsg, NULL);
- CtdlLogPrintf(CTDL_INFO, "SMTP: queue run completed\n");
+ CtdlLogPrintf(CTDL_INFO, "SMTP client: queue run completed; %d messages processed\n", num_processed);
run_queue_now = 0;
doing_queue = 0;
}