MEDIUM: Add parsing of mailers section

As mailer and mailers structures and allow parsing of
a mailers section into those structures.

These structures will subsequently be freed as it is
not yet possible to use reference them in the configuration.

Signed-off-by: Simon Horman <horms@verge.net.au>
diff --git a/Makefile b/Makefile
index 4671759..4e3e166 100644
--- a/Makefile
+++ b/Makefile
@@ -664,7 +664,7 @@
        src/session.o src/hdr_idx.o src/ev_select.o src/signal.o \
        src/acl.o src/sample.o src/memory.o src/freq_ctr.o src/auth.o \
        src/compression.o src/payload.o src/hash.o src/pattern.o src/map.o \
-       src/namespace.o
+       src/namespace.o src/mailers.o
 
 EBTREE_OBJS = $(EBTREE_DIR)/ebtree.o \
               $(EBTREE_DIR)/eb32tree.o $(EBTREE_DIR)/eb64tree.o \
diff --git a/include/types/mailers.h b/include/types/mailers.h
new file mode 100644
index 0000000..582bb94
--- /dev/null
+++ b/include/types/mailers.h
@@ -0,0 +1,65 @@
+/*
+ * include/types/mailer.h
+ * This file defines everything related to mailer.
+ *
+ * Copyright 2015 Horms Solutions Ltd., Simon Horman <horms@verge.net.au>
+ *
+ * Based on include/types/peers.h
+ *
+ * Copyright 2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, version 2.1
+ * exclusively.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _TYPES_EMAIL_ALERT_H
+#define _TYPES_EMAIL_ALERT_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+struct mailer {
+	char *id;
+	struct mailers *mailers;
+	struct {
+		const char *file;	/* file where the section appears */
+		int line;		/* line where the section appears */
+	} conf;				/* config information */
+	struct sockaddr_storage addr;	/* SMTP server address */
+	struct protocol *proto;		/* SMTP server address's protocol */
+	struct xprt_ops *xprt;		/* SMTP server socket operations at transport layer */
+	void *sock_init_arg;		/* socket operations's opaque init argument if needed */
+	struct mailer *next;		/* next mailer in the list */
+};
+
+
+struct mailers {
+	char *id;			/* mailers section name */
+	struct mailer *mailer_list;	/* mailers in this mailers section */
+	struct {
+		const char *file;	/* file where the section appears */
+		int line;		/* line where the section appears */
+	} conf;				/* config information */
+	struct mailers *next;	        /* next mailers section */
+	int count;			/* total number of mailers in this mailers section */
+	int users;			/* number of users of this mailers section */
+};
+
+
+extern struct mailers *mailers;
+
+#endif /* _TYPES_EMAIL_ALERT_H */
+
diff --git a/src/cfgparse.c b/src/cfgparse.c
index c5f20a3..2db5ed1 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -48,6 +48,7 @@
 #include <types/global.h>
 #include <types/obj_type.h>
 #include <types/peers.h>
+#include <types/mailers.h>
 
 #include <proto/acl.h>
 #include <proto/auth.h>
@@ -1916,6 +1917,145 @@
 	return err_code;
 }
 
+
+/*
+ * Parse a line in a <listen>, <frontend>, <backend> or <ruleset> section.
+ * Returns the error code, 0 if OK, or any combination of :
+ *  - ERR_ABORT: must abort ASAP
+ *  - ERR_FATAL: we can continue parsing but not start the service
+ *  - ERR_WARN: a warning has been emitted
+ *  - ERR_ALERT: an alert has been emitted
+ * Only the two first ones can stop processing, the two others are just
+ * indicators.
+ */
+int cfg_parse_mailers(const char *file, int linenum, char **args, int kwm)
+{
+	static struct mailers *curmailers = NULL;
+	struct mailer *newmailer = NULL;
+	const char *err;
+	int err_code = 0;
+	char *errmsg = NULL;
+
+	if (strcmp(args[0], "mailers") == 0) { /* new mailers section */
+		if (!*args[1]) {
+			Alert("parsing [%s:%d] : missing name for mailers section.\n", file, linenum);
+			err_code |= ERR_ALERT | ERR_ABORT;
+			goto out;
+		}
+
+		err = invalid_char(args[1]);
+		if (err) {
+			Alert("parsing [%s:%d] : character '%c' is not permitted in '%s' name '%s'.\n",
+			      file, linenum, *err, args[0], args[1]);
+			err_code |= ERR_ALERT | ERR_ABORT;
+			goto out;
+		}
+
+		for (curmailers = mailers; curmailers != NULL; curmailers = curmailers->next) {
+			/*
+			 * If there are two proxies with the same name only following
+			 * combinations are allowed:
+			 */
+			if (strcmp(curmailers->id, args[1]) == 0) {
+				Warning("Parsing [%s:%d]: mailers '%s' has same name as another mailers (declared at %s:%d).\n",
+					file, linenum, args[1], curmailers->conf.file, curmailers->conf.line);
+				err_code |= ERR_WARN;
+			}
+		}
+
+		if ((curmailers = (struct mailers *)calloc(1, sizeof(struct mailers))) == NULL) {
+			Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
+			err_code |= ERR_ALERT | ERR_ABORT;
+			goto out;
+		}
+
+		curmailers->next = mailers;
+		mailers = curmailers;
+		curmailers->conf.file = strdup(file);
+		curmailers->conf.line = linenum;
+		curmailers->id = strdup(args[1]);
+	}
+	else if (strcmp(args[0], "mailer") == 0) { /* mailer definition */
+		struct sockaddr_storage *sk;
+		int port1, port2;
+		struct protocol *proto;
+
+		if (!*args[2]) {
+			Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
+			      file, linenum, args[0]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+
+		err = invalid_char(args[1]);
+		if (err) {
+			Alert("parsing [%s:%d] : character '%c' is not permitted in server name '%s'.\n",
+			      file, linenum, *err, args[1]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+
+		if ((newmailer = (struct mailer *)calloc(1, sizeof(struct mailer))) == NULL) {
+			Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
+			err_code |= ERR_ALERT | ERR_ABORT;
+			goto out;
+		}
+
+		/* the mailers are linked backwards first */
+		curmailers->count++;
+		newmailer->next = curmailers->mailer_list;
+		curmailers->mailer_list = newmailer;
+		newmailer->mailers = curmailers;
+		newmailer->conf.file = strdup(file);
+		newmailer->conf.line = linenum;
+
+		newmailer->id = strdup(args[1]);
+
+		sk = str2sa_range(args[2], &port1, &port2, &errmsg, NULL);
+		if (!sk) {
+			Alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+
+		proto = protocol_by_family(sk->ss_family);
+		if (!proto || !proto->connect) {
+			Alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
+			      file, linenum, args[0], args[1]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+
+		if (port1 != port2) {
+			Alert("parsing [%s:%d] : '%s %s' : port ranges and offsets are not allowed in '%s'\n",
+			      file, linenum, args[0], args[1], args[2]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+
+		if (!port1) {
+			Alert("parsing [%s:%d] : '%s %s' : missing or invalid port in '%s'\n",
+			      file, linenum, args[0], args[1], args[2]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+
+		newmailer->addr = *sk;
+		newmailer->proto = proto;
+		newmailer->xprt  = &raw_sock;
+		newmailer->sock_init_arg = NULL;
+	} /* neither "mailer" nor "mailers" */
+	else if (*args[0] != 0) {
+		Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
+		err_code |= ERR_ALERT | ERR_FATAL;
+		goto out;
+	}
+
+out:
+	free(errmsg);
+	return err_code;
+}
+
 int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
 {
 	static struct proxy *curproxy = NULL;
@@ -5942,6 +6082,7 @@
 	    !cfg_register_section("global",   cfg_parse_global) ||
 	    !cfg_register_section("userlist", cfg_parse_users)  ||
 	    !cfg_register_section("peers",    cfg_parse_peers)  ||
+	    !cfg_register_section("mailers",  cfg_parse_mailers) ||
 	    !cfg_register_section("namespace_list",    cfg_parse_netns))
 		return -1;
 
@@ -7653,6 +7794,42 @@
 		}
 	}
 
+	if (mailers) {
+		struct mailers *curmailers = mailers, **last;
+		struct mailer *m, *mb;
+
+		/* Remove all mailers sections which don't have a valid listener.
+		 * This can happen when a mailers section is never referenced.
+		 */
+		last = &mailers;
+		while (*last) {
+			curmailers = *last;
+			if (curmailers->users) {
+				last = &curmailers->next;
+				continue;
+			}
+
+			Warning("Removing incomplete section 'mailers %s'.\n",
+				curmailers->id);
+
+			m = curmailers->mailer_list;
+			while (m) {
+				mb = m->next;
+				free(m->id);
+				free(m);
+				m = mb;
+			}
+
+			/* Destroy and unlink this curmailers section.
+			 * Note: curmailers is backed up into *last.
+			 */
+			free(curmailers->id);
+			curmailers = curmailers->next;
+			free(*last);
+			*last = curmailers;
+		}
+	}
+
 	pool2_hdr_idx = create_pool("hdr_idx",
 				    global.tune.max_http_hdr * sizeof(struct hdr_idx_elem),
 				    MEM_F_SHARED);
diff --git a/src/mailers.c b/src/mailers.c
new file mode 100644
index 0000000..4335453
--- /dev/null
+++ b/src/mailers.c
@@ -0,0 +1,17 @@
+/*
+ * Mailer management.
+ *
+ * Copyright 2015 Horms Solutions Ltd, Simon Horman <horms@verge.net.au>
+ *
+ * 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.
+ *
+ */
+
+#include <stdlib.h>
+
+#include <types/mailers.h>
+
+struct mailers *mailers = NULL;