From 520f6b846ae3ece131c40b0be486d05d6ef957e0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 11 Mar 2010 10:51:16 +0100 Subject: [PATCH] Added a very minimalistic SMTP client to send mails via a local Exim --- src/libfast/Makefile.am | 2 +- src/libfast/smtp.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++ src/libfast/smtp.h | 56 +++++++++++++++ 3 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 src/libfast/smtp.c create mode 100644 src/libfast/smtp.h diff --git a/src/libfast/Makefile.am b/src/libfast/Makefile.am index 870dcd6..5a11936 100644 --- a/src/libfast/Makefile.am +++ b/src/libfast/Makefile.am @@ -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 index 0000000..51771b8 --- /dev/null +++ b/src/libfast/smtp.c @@ -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 . + * + * 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 +#include + +#include + +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 index 0000000..910f181 --- /dev/null +++ b/src/libfast/smtp.h @@ -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 . + * + * 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 + +/** + * 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_ @}*/ -- 2.7.4