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-2012 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.
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
49 #include <sys/types.h>
52 #if TIME_WITH_SYS_TIME
53 # include <sys/time.h>
57 # include <sys/time.h>
67 #include <sys/socket.h>
68 #include <netinet/in.h>
69 #include <arpa/inet.h>
70 #include <libcitadel.h>
73 #include "citserver.h"
80 #include "internet_addressing.h"
83 #include "clientsocket.h"
84 #include "locate_host.h"
85 #include "citadel_dirs.h"
87 #include "ctdl_module.h"
89 #include "smtp_util.h"
91 const char *smtp_get_Recipients(void)
93 citsmtp *sSMTP = SMTP;
97 else return ChrPtr(sSMTP->from);
102 * smtp_do_bounce() is caled by smtp_do_procmsg() to scan a set of delivery
103 * instructions for "5" codes (permanent fatal errors) and produce/deliver
104 * a "bounce" message (delivery status notification).
106 void smtp_do_bounce(char *instr, StrBuf *OMsgTxt)
119 time_t submitted = 0L;
120 struct CtdlMessage *bmsg = NULL;
123 int successful_bounce = 0;
128 syslog(LOG_DEBUG, "smtp_do_bounce() called\n");
129 strcpy(bounceto, "");
130 boundary = NewStrBufPlain(HKEY("=_Citadel_Multipart_"));
132 StrBufAppendPrintf(boundary,
138 lines = num_tokens(instr, '\n');
140 /* See if it's time to give up on delivery of this message */
141 for (i=0; i<lines; ++i) {
142 extract_token(buf, instr, i, '\n', sizeof buf);
143 extract_token(key, buf, 0, '|', sizeof key);
144 extract_token(addr, buf, 1, '|', sizeof addr);
145 if (!strcasecmp(key, "submitted")) {
146 submitted = atol(addr);
150 if ( (time(NULL) - submitted) > SMTP_GIVE_UP ) {
154 /* Start building our bounce message */
156 bmsg = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage));
157 if (bmsg == NULL) return;
158 memset(bmsg, 0, sizeof(struct CtdlMessage));
159 BounceMB = NewStrBufPlain(NULL, 1024);
161 bmsg->cm_magic = CTDLMESSAGE_MAGIC;
162 bmsg->cm_anon_type = MES_NORMAL;
163 bmsg->cm_format_type = FMT_RFC822;
164 CM_SetField(bmsg, eAuthor, HKEY("Citadel"));
165 CM_SetField(bmsg, eOriginalRoom, HKEY(MAILROOM));
166 CM_SetField(bmsg, eNodeName, CFG_KEY(c_nodename));
167 CM_SetField(bmsg, eMsgSubject, HKEY("Delivery Status Notification (Failure)"));
168 StrBufAppendBufPlain(
170 HKEY("Content-type: multipart/mixed; boundary=\""), 0);
171 StrBufAppendBuf(BounceMB, boundary, 0);
172 StrBufAppendBufPlain(BounceMB, HKEY("\"\r\n"), 0);
173 StrBufAppendBufPlain(BounceMB, HKEY("MIME-Version: 1.0\r\n"), 0);
174 StrBufAppendBufPlain(BounceMB, HKEY("X-Mailer: " CITADEL "\r\n"), 0);
176 StrBufAppendBufPlain(
178 HKEY("\r\nThis is a multipart message in MIME format."
181 StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
182 StrBufAppendBuf(BounceMB, boundary, 0);
183 StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
184 StrBufAppendBufPlain(BounceMB,
185 HKEY("Content-type: text/plain\r\n\r\n"), 0);
189 StrBufAppendBufPlain(
191 HKEY("A message you sent could not be delivered "
192 "to some or all of its recipients\ndue to "
193 "prolonged unavailability of its destination(s).\n"
194 "Giving up on the following addresses:\n\n"), 0);
198 StrBufAppendBufPlain(
200 HKEY("A message you sent could not be delivered "
201 "to some or all of its recipients.\n"
202 "The following addresses were undeliverable:\n\n"
207 * Now go through the instructions checking for stuff.
209 for (i=0; i<lines; ++i) {
212 extract_token(buf, instr, i, '\n', sizeof buf);
213 extract_token(key, buf, 0, '|', sizeof key);
214 addrlen = extract_token(addr, buf, 1, '|', sizeof addr);
215 status = extract_int(buf, 2);
216 dsnlen = extract_token(dsn, buf, 3, '|', sizeof dsn);
219 syslog(LOG_DEBUG, "key=<%s> addr=<%s> status=%d dsn=<%s>\n",
220 key, addr, status, dsn);
222 if (!strcasecmp(key, "bounceto")) {
223 strcpy(bounceto, addr);
226 if (!strcasecmp(key, "msgid")) {
230 if (!strcasecmp(key, "remote")) {
231 if (status == 5) bounce_this = 1;
232 if (give_up) bounce_this = 1;
238 StrBufAppendBufPlain(BounceMB, addr, addrlen, 0);
239 StrBufAppendBufPlain(BounceMB, HKEY(": "), 0);
240 StrBufAppendBufPlain(BounceMB, dsn, dsnlen, 0);
241 StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
243 remove_token(instr, i, '\n');
249 /* Attach the original message */
251 StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
252 StrBufAppendBuf(BounceMB, boundary, 0);
253 StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
255 StrBufAppendBufPlain(
257 HKEY("Content-type: message/rfc822\r\n"), 0);
259 StrBufAppendBufPlain(
261 HKEY("Content-Transfer-Encoding: 7bit\r\n"), 0);
263 StrBufAppendBufPlain(
265 HKEY("Content-Disposition: inline\r\n"), 0);
267 StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
269 if (OMsgTxt == NULL) {
270 CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
271 CtdlOutputMsg(omsgid,
277 StrBufAppendBuf(BounceMB, CC->redirect_buffer, 0);
278 FreeStrBuf(&CC->redirect_buffer);
281 StrBufAppendBuf(BounceMB, OMsgTxt, 0);
285 /* Close the multipart MIME scope */
286 StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
287 StrBufAppendBuf(BounceMB, boundary, 0);
288 StrBufAppendBufPlain(BounceMB, HKEY("--\r\n"), 0);
289 CM_SetAsFieldSB(bmsg, eMesageText, &BounceMB);
291 /* Deliver the bounce if there's anything worth mentioning */
292 syslog(LOG_DEBUG, "num_bounces = %d\n", num_bounces);
293 if (num_bounces > 0) {
295 /* First try the user who sent the message */
296 if (IsEmptyStr(bounceto))
297 syslog(LOG_ERR, "No bounce address specified\n");
299 syslog(LOG_DEBUG, "bounce to user <%s>\n", bounceto);
300 /* Can we deliver the bounce to the original sender? */
301 valid = validate_recipients(bounceto,
302 smtp_get_Recipients (),
305 if (valid->num_error == 0) {
306 CtdlSubmitMsg(bmsg, valid, "", QP_EADDR);
307 successful_bounce = 1;
311 /* If not, post it in the Aide> room */
312 if (successful_bounce == 0) {
313 CtdlSubmitMsg(bmsg, NULL, config.c_aideroom, QP_EADDR);
316 /* Free up the memory we used */
318 free_recipients(valid);
321 FreeStrBuf(&boundary);
323 syslog(LOG_DEBUG, "Done processing bounces\n");