Added a very minimalistic SMTP client to send mails via a local Exim
authorMartin Willi <martin@revosec.ch>
Thu, 11 Mar 2010 09:51:16 +0000 (10:51 +0100)
committerMartin Willi <martin@revosec.ch>
Thu, 11 Mar 2010 09:51:16 +0000 (10:51 +0100)
src/libfast/Makefile.am
src/libfast/smtp.c [new file with mode: 0644]
src/libfast/smtp.h [new file with mode: 0644]

index 870dcd6..5a11936 100644 (file)
@@ -1,7 +1,7 @@
 lib_LTLIBRARIES = libfast.la
 
 libfast_la_SOURCES = context.h dispatcher.c request.h session.h \
-  controller.h dispatcher.h request.c session.c filter.h
+  controller.h dispatcher.h request.c session.c filter.h smtp.c smtp.h
 libfast_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \
   -lfcgi -lneo_cgi -lneo_cs -lneo_utl -lz $(PTHREADLIB)
 INCLUDES = -I$(top_srcdir)/src/libstrongswan -I/usr/include/ClearSilver
diff --git a/src/libfast/smtp.c b/src/libfast/smtp.c
new file mode 100644 (file)
index 0000000..51771b8
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "smtp.h"
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <debug.h>
+
+typedef struct private_smtp_t private_smtp_t;
+
+/**
+ * Private data of an smtp_t object.
+ */
+struct private_smtp_t {
+
+       /**
+        * Public smtp_t interface.
+        */
+       smtp_t public;
+
+       /**
+        * file stream to SMTP server
+        */
+       FILE *f;
+};
+
+/**
+ * Read the response code from an SMTP server
+ */
+static int read_response(private_smtp_t *this)
+{
+       char buf[256], *end;
+       int res = 0;
+
+       while (TRUE)
+       {
+               if (!fgets(buf, sizeof(buf), this->f))
+               {
+                       return 0;
+               }
+               res = strtol(buf, &end, 10);
+               switch (*end)
+               {
+                       case '-':
+                               continue;
+                       case ' ':
+                       case '\0':
+                       case '\n':
+                               break;
+                       default:
+                               return 0;
+               }
+               break;
+       }
+       return res;
+}
+
+/**
+ * write a SMTP command to the server, read response code
+ */
+static int write_cmd(private_smtp_t *this, char *fmt, ...)
+{
+       char buf[256];
+       va_list args;
+
+       va_start(args, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+
+       if (fprintf(this->f, "%s\n", buf) < 1)
+       {
+               DBG1("sending SMTP command failed");
+               return 0;
+       }
+       return read_response(this);
+}
+
+METHOD(smtp_t, send_mail, bool,
+       private_smtp_t *this, char *from, char *to, char *subject, char *fmt, ...)
+{
+       va_list args;
+
+       if (write_cmd(this, "MAIL FROM:<%s>", from) != 250)
+       {
+               DBG1("SMTP MAIL FROM failed");
+               return FALSE;
+       }
+       if (write_cmd(this, "RCPT TO:<%s>", to) != 250)
+       {
+               DBG1("SMTP RCPT TO failed");
+               return FALSE;
+       }
+       if (write_cmd(this, "DATA") != 354)
+       {
+               DBG1("SMTP DATA failed");
+               return FALSE;
+       }
+
+       fprintf(this->f, "From: %s\n", from);
+       fprintf(this->f, "To: %s\n", to);
+       fprintf(this->f, "Subject: %s\n", subject);
+       fprintf(this->f, "\n");
+       va_start(args, fmt);
+       vfprintf(this->f, fmt, args);
+       va_end(args);
+       fprintf(this->f, "\n.\n");
+       return read_response(this) == 250;
+}
+
+
+METHOD(smtp_t, destroy, void,
+       private_smtp_t *this)
+{
+       write_cmd(this, "QUIT");
+       fclose(this->f);
+       free(this);
+}
+
+/**
+ * See header
+ */
+smtp_t *smtp_create()
+{
+       private_smtp_t *this;
+       struct sockaddr_in addr;
+       int s;
+
+       INIT(this,
+               .public = {
+                       .send_mail = _send_mail,
+                       .destroy = _destroy,
+               },
+       );
+
+       s = socket(AF_INET, SOCK_STREAM, 0);
+       if (s < 0)
+       {
+               DBG1("opening SMTP socket failed: %s", strerror(errno));
+               free(this);
+               return NULL;
+       }
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       addr.sin_port = htons(25);
+       if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) < 0)
+       {
+               DBG1("connecting to SMTP server failed: %s", strerror(errno));
+               close(s);
+               free(this);
+               return NULL;
+       }
+       this->f = fdopen(s, "a+");
+       if (!this->f)
+       {
+               DBG1("opening stream to SMTP server failed: %s", strerror(errno));
+               close(s);
+               free(this);
+               return NULL;
+       }
+       if (read_response(this) != 220 ||
+               write_cmd(this, "EHLO localhost") != 250)
+       {
+               DBG1("SMTP EHLO failed");
+               fclose(this->f);
+               free(this);
+               return NULL;
+       }
+       return &this->public;
+}
+
diff --git a/src/libfast/smtp.h b/src/libfast/smtp.h
new file mode 100644 (file)
index 0000000..910f181
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup smtp smtp
+ * @{ @ingroup libfast
+ */
+
+#ifndef SMTP_H_
+#define SMTP_H_
+
+typedef struct smtp_t smtp_t;
+
+#include <library.h>
+
+/**
+ * Ultra-minimalistic SMTP client. Works at most with Exim on localhost.
+ */
+struct smtp_t {
+
+       /**
+        * Send an e-mail message.
+        *
+        * @param from          sender address
+        * @param to            receipient address
+        * @param subject       mail subject
+        * @param fmt           mail body format string
+        * @param ...           arguments for body format string
+        */
+       bool (*send_mail)(smtp_t *this, char *from, char *to,
+                                         char *subject, char *fmt, ...);
+
+       /**
+        * Destroy a smtp_t.
+        */
+       void (*destroy)(smtp_t *this);
+};
+
+/**
+ * Create a smtp instance.
+ */
+smtp_t *smtp_create();
+
+#endif /** SMTP_H_ @}*/