2 * This module is an SMTP and ESMTP implementation for the Citadel system.
3 * It is compliant with all of the following:
5 * RFC 821 - Simple Mail Transfer Protocol
6 * RFC 876 - Survey of SMTP Implementations
7 * RFC 1047 - Duplicate messages and SMTP
8 * RFC 1652 - 8 bit MIME
9 * RFC 1869 - Extended Simple Mail Transfer Protocol
10 * RFC 1870 - SMTP Service Extension for Message Size Declaration
11 * RFC 2033 - Local Mail Transfer Protocol
12 * RFC 2197 - SMTP Service Extension for Command Pipelining
13 * RFC 2476 - Message Submission
14 * RFC 2487 - SMTP Service Extension for Secure SMTP over TLS
15 * RFC 2554 - SMTP Service Extension for Authentication
16 * RFC 2821 - Simple Mail Transfer Protocol
17 * RFC 2822 - Internet Message Format
18 * RFC 2920 - SMTP Service Extension for Command Pipelining
20 * The VRFY and EXPN commands have been removed from this implementation
21 * because nobody uses these commands anymore, except for spammers.
23 * Copyright (c) 1998-2015 by the citadel.org team
25 * This program is open source software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License version 3.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
43 #include <sys/types.h>
46 #if TIME_WITH_SYS_TIME
47 # include <sys/time.h>
51 # include <sys/time.h>
61 #include <sys/socket.h>
62 #include <netinet/in.h>
63 #include <arpa/inet.h>
64 #include <libcitadel.h>
67 #include "citserver.h"
74 #include "internet_addressing.h"
77 #include "clientsocket.h"
78 #include "locate_host.h"
79 #include "citadel_dirs.h"
81 #include "ctdl_module.h"
83 #include "smtp_util.h"
85 const char *smtp_get_Recipients(void)
87 citsmtp *sSMTP = SMTP;
91 else return ChrPtr(sSMTP->from);
96 * smtp_do_bounce() is caled by smtp_do_procmsg() to scan a set of delivery
97 * instructions for "5" codes (permanent fatal errors) and produce/deliver
98 * a "bounce" message (delivery status notification).
100 void smtp_do_bounce(char *instr, StrBuf *OMsgTxt)
113 time_t submitted = 0L;
114 struct CtdlMessage *bmsg = NULL;
117 int successful_bounce = 0;
122 syslog(LOG_DEBUG, "smtp_do_bounce() called\n");
123 strcpy(bounceto, "");
124 boundary = NewStrBufPlain(HKEY("=_Citadel_Multipart_"));
126 StrBufAppendPrintf(boundary, "%s_%04x%04x", CtdlGetConfigStr("c_fqdn"), getpid(), ++seq);
128 lines = num_tokens(instr, '\n');
130 /* See if it's time to give up on delivery of this message */
131 for (i=0; i<lines; ++i) {
132 extract_token(buf, instr, i, '\n', sizeof buf);
133 extract_token(key, buf, 0, '|', sizeof key);
134 extract_token(addr, buf, 1, '|', sizeof addr);
135 if (!strcasecmp(key, "submitted")) {
136 submitted = atol(addr);
140 if ( (time(NULL) - submitted) > SMTP_GIVE_UP ) {
144 /* Start building our bounce message */
146 bmsg = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage));
147 if (bmsg == NULL) return;
148 memset(bmsg, 0, sizeof(struct CtdlMessage));
149 BounceMB = NewStrBufPlain(NULL, 1024);
151 bmsg->cm_magic = CTDLMESSAGE_MAGIC;
152 bmsg->cm_anon_type = MES_NORMAL;
153 bmsg->cm_format_type = FMT_RFC822;
154 CM_SetField(bmsg, eAuthor, HKEY("Citadel"));
155 CM_SetField(bmsg, eOriginalRoom, HKEY(MAILROOM));
156 CM_SetField(bmsg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
157 CM_SetField(bmsg, eMsgSubject, HKEY("Delivery Status Notification (Failure)"));
158 StrBufAppendBufPlain(BounceMB, HKEY("Content-type: multipart/mixed; boundary=\""), 0);
159 StrBufAppendBuf(BounceMB, boundary, 0);
160 StrBufAppendBufPlain(BounceMB, HKEY("\"\r\n"), 0);
161 StrBufAppendBufPlain(BounceMB, HKEY("MIME-Version: 1.0\r\n"), 0);
162 StrBufAppendBufPlain(BounceMB, HKEY("X-Mailer: " CITADEL "\r\n"), 0);
164 StrBufAppendBufPlain(
166 HKEY("\r\nThis is a multipart message in MIME format."
169 StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
170 StrBufAppendBuf(BounceMB, boundary, 0);
171 StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
172 StrBufAppendBufPlain(BounceMB,
173 HKEY("Content-type: text/plain\r\n\r\n"), 0);
177 StrBufAppendBufPlain(
179 HKEY("A message you sent could not be delivered "
180 "to some or all of its recipients\ndue to "
181 "prolonged unavailability of its destination(s).\n"
182 "Giving up on the following addresses:\n\n"), 0);
186 StrBufAppendBufPlain(
188 HKEY("A message you sent could not be delivered "
189 "to some or all of its recipients.\n"
190 "The following addresses were undeliverable:\n\n"
195 * Now go through the instructions checking for stuff.
197 for (i=0; i<lines; ++i) {
200 extract_token(buf, instr, i, '\n', sizeof buf);
201 extract_token(key, buf, 0, '|', sizeof key);
202 addrlen = extract_token(addr, buf, 1, '|', sizeof addr);
203 status = extract_int(buf, 2);
204 dsnlen = extract_token(dsn, buf, 3, '|', sizeof dsn);
207 syslog(LOG_DEBUG, "key=<%s> addr=<%s> status=%d dsn=<%s>\n",
208 key, addr, status, dsn);
210 if (!strcasecmp(key, "bounceto")) {
211 strcpy(bounceto, addr);
214 if (!strcasecmp(key, "msgid")) {
218 if (!strcasecmp(key, "remote")) {
219 if (status == 5) bounce_this = 1;
220 if (give_up) bounce_this = 1;
226 StrBufAppendBufPlain(BounceMB, addr, addrlen, 0);
227 StrBufAppendBufPlain(BounceMB, HKEY(": "), 0);
228 StrBufAppendBufPlain(BounceMB, dsn, dsnlen, 0);
229 StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
231 remove_token(instr, i, '\n');
237 /* Attach the original message */
239 StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
240 StrBufAppendBuf(BounceMB, boundary, 0);
241 StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
243 StrBufAppendBufPlain(
245 HKEY("Content-type: message/rfc822\r\n"), 0);
247 StrBufAppendBufPlain(
249 HKEY("Content-Transfer-Encoding: 7bit\r\n"), 0);
251 StrBufAppendBufPlain(
253 HKEY("Content-Disposition: inline\r\n"), 0);
255 StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
257 if (OMsgTxt == NULL) {
258 CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
259 CtdlOutputMsg(omsgid,
265 StrBufAppendBuf(BounceMB, CC->redirect_buffer, 0);
266 FreeStrBuf(&CC->redirect_buffer);
269 StrBufAppendBuf(BounceMB, OMsgTxt, 0);
273 /* Close the multipart MIME scope */
274 StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
275 StrBufAppendBuf(BounceMB, boundary, 0);
276 StrBufAppendBufPlain(BounceMB, HKEY("--\r\n"), 0);
277 CM_SetAsFieldSB(bmsg, eMesageText, &BounceMB);
279 /* Deliver the bounce if there's anything worth mentioning */
280 syslog(LOG_DEBUG, "num_bounces = %d\n", num_bounces);
281 if (num_bounces > 0) {
283 /* First try the user who sent the message */
284 if (IsEmptyStr(bounceto))
285 syslog(LOG_ERR, "No bounce address specified\n");
287 syslog(LOG_DEBUG, "bounce to user <%s>\n", bounceto);
288 /* Can we deliver the bounce to the original sender? */
289 valid = validate_recipients(bounceto,
290 smtp_get_Recipients (),
293 if (valid->num_error == 0) {
294 CtdlSubmitMsg(bmsg, valid, "", QP_EADDR);
295 successful_bounce = 1;
299 /* If not, post it in the Aide> room */
300 if (successful_bounce == 0) {
301 CtdlSubmitMsg(bmsg, NULL, CtdlGetConfigStr("c_aideroom"), QP_EADDR);
304 /* Free up the memory we used */
306 free_recipients(valid);
309 FreeStrBuf(&boundary);
311 syslog(LOG_DEBUG, "Done processing bounces\n");