aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2021-06-14 14:39:50 +0300
committerSergey Poznyakoff <gray@gnu.org>2021-06-14 15:06:50 +0300
commitb911a3907229f057c7ad45b9cb6459f0c4864338 (patch)
treeb8d3168ee3545c01d29506e4b750db975afa2519
parent2f97aefb938cd941caef98b2ed898d431634a414 (diff)
downloadmockmta-b911a3907229f057c7ad45b9cb6459f0c4864338.tar.gz
mockmta-b911a3907229f057c7ad45b9cb6459f0c4864338.tar.bz2
Save mail to temporary file first, then copy it to the mailbox
-rw-r--r--mockmta.c145
1 files changed, 77 insertions, 68 deletions
diff --git a/mockmta.c b/mockmta.c
index 2b47176..17ec344 100644
--- a/mockmta.c
+++ b/mockmta.c
@@ -7,7 +7,8 @@
DESCRIPTION
Starts a mock MTA, which behaves almost identically to the real one,
- except that it delivers all messages to the given MAILBOX file.
+ except that it listens on localhost only and delivers all messages
+ to the given MAILBOX file.
No attempts are made to interpret the data supplied during the STMP
transaction, such as domain names, email addresses, etc, neither is
@@ -28,10 +29,6 @@
PORT (default 25).
To support TLS, the program must be compiled with the GnuTLS library.
- To do so, make sure the library and its headers are properly installed
- and:
-
- cc -omockmta -opthread -DWITH_TLS mockmta.c -lgnutls
To enable the STARTTLS ESMTP command, supply the names of the certificate
(-c CERT) and certificate key (-k KEY) files.
@@ -867,9 +864,7 @@ struct smtp
char *sender;
char *rcpt[MAX_RCPT];
int nrcpt;
- char *data_buf;
- size_t data_len;
- size_t data_size;
+ int tempfd;
};
enum
@@ -905,9 +900,6 @@ smtp_create (int ifd, int ofd)
smtp->helo = NULL;
smtp->sender = NULL;
smtp->nrcpt = 0;
- smtp->data_buf = NULL;
- smtp->data_len = 0;
- smtp->data_size = 0;
pthread_mutex_lock (&msgid_mutex);
smtp->sid = msgid++;
@@ -944,7 +936,7 @@ smtp_io_send (struct smtp *smtp, int code, char *fmt, ...)
if (iobase_writeln (smtp->iob, buf, n) < 0)
{
terror ("iobase_writeln: %s", iobase_strerror (smtp->iob));
- exit (EX_FAILURE);//FIXME
+ pthread_exit (NULL);
}
smtp_timer_dequeue (pthread_self ());
}
@@ -965,7 +957,7 @@ smtp_io_mlsend (struct smtp *smtp, int code, char const **av)
if (iobase_writeln (smtp->iob, buf, n) < 0)
{
terror ("iobase_writeln: %s", iobase_strerror (smtp->iob));
- exit (EX_FAILURE);
+ pthread_exit (NULL);
}
smtp_timer_dequeue (pthread_self ());
}
@@ -993,10 +985,8 @@ smtp_reset (struct smtp *smtp, int state)
}
/* FALL THROUGH */
case STATE_DATA:
- free (smtp->data_buf);
- smtp->data_buf = NULL;
- smtp->data_len = 0;
- smtp->data_size = 0;
+ //FIXME: Clean up any collected mail?
+ break;
}
}
@@ -1127,7 +1117,7 @@ smtp_starttls (struct smtp *smtp)
else
{
free (iob);
- exit (EX_FAILURE);
+ pthread_exit (NULL);
}
return 0;
}
@@ -1223,34 +1213,6 @@ smtp_rcpt (struct smtp *smtp)
return 0;
}
-static void
-smtp_data_save (struct smtp *smtp)
-{
- size_t len = strlen (smtp->buf);
- while (smtp->data_len + len > smtp->data_size)
- {
- char *p;
- size_t n = smtp->data_size;
- if (!smtp->data_buf)
- {
- n = smtp->data_len + len;
- }
- else
- {
- if ((size_t)-1 / 3 * 2 <= n)
- nomemory ();
- n += (n + 1) / 2;
- }
- p = realloc (smtp->data_buf, n);
- if (!p)
- nomemory ();
- smtp->data_buf = p;
- smtp->data_size = n;
- }
- memcpy (smtp->data_buf + smtp->data_len, smtp->buf, len);
- smtp->data_len += len;
-}
-
static int
begins_with_from (char const *p)
{
@@ -1260,23 +1222,20 @@ begins_with_from (char const *p)
}
static int
-smtp_data (struct smtp *smtp)
+mailbox_append (FILE *tf)
{
- ssize_t n;
int fd;
FILE *fp;
struct flock lk;
- time_t t;
- int in_body = 0;
off_t length;
int res = 0;
+ int c;
/* Open the mailbox */
fd = open (mailbox_name, O_CREAT|O_WRONLY|O_APPEND, 0600);
if (fd == -1)
{
terror ("can't open %s: %s", mailbox_name, strerror (errno));
- smtp_io_send (smtp, 451, "Local filesystem error");
return -1;
}
lk.l_type = F_WRLCK;
@@ -1286,7 +1245,6 @@ smtp_data (struct smtp *smtp)
if (fcntl (fd, F_SETLKW, &lk)) /* FIXME: ttl */
{
terror ("can't lock %s: %s", mailbox_name, strerror (errno));
- smtp_io_send (smtp, 451, "Local filesystem error");
close (fd);
return -1;
}
@@ -1297,11 +1255,68 @@ smtp_data (struct smtp *smtp)
if (!fp)
{
terror ("fdopen: %s", strerror (errno));
+ close (fd);
+ return -1;
+ }
+
+ while ((c = fgetc (tf)) != EOF)
+ fputc (c, fp);
+
+ if (ferror (fp) || ferror (tf))
+ {
+ res = -1;
+ fflush (fp);
+ ftruncate (fd, length);
+ }
+
+ lk.l_type = F_UNLCK;
+ lk.l_whence = SEEK_SET;
+ lk.l_start = 0;
+ lk.l_len = 0;
+ if (fcntl (fd, F_SETLK, &lk))
+ terror ("can't unlock %s: %m", mailbox_name);
+ fclose (fp);
+
+ return res;
+}
+
+static void
+tempfile_cleanup (void *ptr)
+{
+ fclose ((FILE*)ptr);
+}
+
+static int
+smtp_data (struct smtp *smtp)
+{
+ char template[] = "/tmp/mockmta.XXXXXX";
+ int fd;
+ FILE *fp;
+ ssize_t n;
+ time_t t;
+ int res;
+ int in_body = 0;
+
+ fd = mkstemp (template);
+ if (fd == -1)
+ {
+ terror ("can't create temporary: %m");
+ smtp_io_send (smtp, 451, "Local filesystem error");
+ return -1;
+ }
+
+ fp = fdopen (fd, "w+");
+ if (!fp)
+ {
+ terror ("fdopen: %m");
smtp_io_send (smtp, 451, "Local filesystem error");
close (fd);
return -1;
}
+ unlink (template);
+
+ pthread_cleanup_push (tempfile_cleanup, fp);
smtp_io_send (smtp, 354,
"Enter mail, end with \".\" on a line by itself");
@@ -1363,21 +1378,19 @@ smtp_data (struct smtp *smtp)
}
fputc ('\n', fp);
- if (res)
+ if (res == 0)
{
- fflush (fp);
- ftruncate (fd, length);
+ rewind (fp);
+ res = mailbox_append (fp);
}
- lk.l_type = F_UNLCK;
- lk.l_whence = SEEK_SET;
- lk.l_start = 0;
- lk.l_len = 0;
- if (fcntl (fd, F_SETLK, &lk))
- terror ("can't unlock %s: %s", mailbox_name, strerror (errno));
- fclose (fp);
+ pthread_cleanup_pop (1);
- smtp_io_send (smtp, 250, "%x Message accepted for delivery", smtp->sid);
+ if (res)
+ smtp_io_send (smtp, 451, "Local filesystem error");
+ else
+ smtp_io_send (smtp, 250, "%x Message accepted for delivery", smtp->sid);
+
return res;
}
@@ -1628,11 +1641,7 @@ mta_open (int port)
memset (&address, 0, sizeof (address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-
- if (port)
- address.sin_port = htons (port);
- else
- address.sin_port = 0;
+ address.sin_port = htons (port);
if (bind (fd, (struct sockaddr *) &address, sizeof (address)) < 0)
{

Return to:

Send suggestions and report system problems to the System administrator.