summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortrystan trystan@31f1291d-b8d6-0310-a050-a5561fc1590b <trystan trystan@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864>2005-01-20 05:37:46 +0000
committertrystan trystan@31f1291d-b8d6-0310-a050-a5561fc1590b <trystan trystan@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864>2005-01-20 05:37:46 +0000
commit278a99ca2d54104ea880149657b960be26aa4ca0 (patch)
tree0da20f241cd3eec04608579f2fbc283249e678cf /src
parent1ef4a60c466c3be777863af32375f4a0489e6f79 (diff)
BUILD : 1.7.7 (550) BUGS : N/A NOTES : Anope SMTP client
git-svn-id: svn://svn.anope.org/anope/trunk@550 31f1291d-b8d6-0310-a050-a5561fc1590b git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@403 5417fbe8-f217-4b02-8779-1006273d7864
Diffstat (limited to 'src')
-rw-r--r--src/tools/Makefile34
-rw-r--r--src/tools/README19
-rw-r--r--src/tools/anopesmtp.c550
-rw-r--r--src/tools/smtp.h94
4 files changed, 697 insertions, 0 deletions
diff --git a/src/tools/Makefile b/src/tools/Makefile
new file mode 100644
index 000000000..54e3ca8e8
--- /dev/null
+++ b/src/tools/Makefile
@@ -0,0 +1,34 @@
+OBJS = anopesmpt.o
+SRCS = anopesmpt.c
+
+INCLUDES = ../../include/services.h
+
+MAKEARGS = 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'ANOPELIBS=${ANOPELIBS}' \
+ 'LDFLAGS=${LDFLAGS}' 'BINDEST=${BINDEST}' 'INSTALL=${INSTALL}' \
+ 'INCLUDEDIR=${INCLUDEDIR}' 'RM=${RM}' 'CP=${CP}' \
+ 'TOUCH=${TOUCH}' 'SHELL=${SHELL}' 'DATDEST=${DATDEST}' \
+ 'RUNGROUP=${RUNGROUP}'
+
+.c.o:
+ $(CC) $(CFLAGS) -I../include/ -c $<
+
+all: anopesmtp
+
+distclean: clean spotless
+
+anopesmpt: $(OBJS)
+ $(CC) $(CFLAGS) $(OBJS) $(ANOPELIBS) $(MLIBS) -o $@ $(LDFLAGS)
+
+$(OBJS): Makefile
+anopesmpt.o: anopesmpt.c $(INCLUDES)
+
+clean:
+ rm -f *.o anopesmtp a.out
+
+spotless: clean
+
+install: anopesmtp
+ test -d ${BINDEST} || mkdir ${BINDEST}
+ $(INSTALL) anopesmtp $(BINDEST)/anopesmtp
+
+DUMMY:
diff --git a/src/tools/README b/src/tools/README
new file mode 100644
index 000000000..ccfc69129
--- /dev/null
+++ b/src/tools/README
@@ -0,0 +1,19 @@
+Anope SMTP Client
+
+ - Provided with Anope is a simple SMTP client which can be used to replace programs like
+SendMail in some cases.
+
+ - To use the SMTP client find the line in your services.conf for the "SendMailPath", enter
+the path to your services installation directory, followed by the "anopesmtp" and the IP address
+of a valid SMTP server. It should look something like
+
+SendMailPath "/home/usersname/services/anopesmtp 194.97.50.135"
+
+ - If you run into a problem you can compile a debug into the code by opening smtp.h and at the
+bottom you should find "smtp_debug" change the 0 to a 1 and recompile the code. This should
+generate a log file of what happened when it attempted to connect to the SMTP server.
+
+
+Credits:
+Orginally written by Dominick Meglio <codemastr@unrealircd.com>
+Ported to *nix by Trystan Scott Lee <trystan@nomadirc.net>
diff --git a/src/tools/anopesmtp.c b/src/tools/anopesmtp.c
new file mode 100644
index 000000000..3b9eabe6c
--- /dev/null
+++ b/src/tools/anopesmtp.c
@@ -0,0 +1,550 @@
+/* smtp stuff handler for win32.
+ *
+ * (C) 2003 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ * Written by Dominick Meglio <codemastr@unrealircd.com>
+ * *nix port by Trystan Scott Lee <trystan@nomadirc.net>
+ *
+ */
+
+#include "smtp.h"
+
+static FILE *logfile;
+static int curday = 0;
+
+/*************************************************************************/
+
+static int get_logname(char *name, int count, struct tm *tm)
+{
+
+ char timestamp[32];
+
+ if (!tm) {
+ time_t t;
+
+ time(&t);
+ tm = localtime(&t);
+ }
+
+ strftime(timestamp, count, "%Y%m%d", tm);
+ snprintf(name, count, "logs/%s.%s", "anopesmtp", timestamp);
+ curday = tm->tm_yday;
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/* Close the log file. */
+
+void close_log(void)
+{
+ if (!logfile)
+ return;
+ fclose(logfile);
+ logfile = NULL;
+}
+
+/*************************************************************************/
+
+static void remove_log(void)
+{
+ time_t t;
+ struct tm tm;
+
+ char name[PATH_MAX];
+
+ time(&t);
+ t -= (60 * 60 * 24 * 30);
+ tm = *localtime(&t);
+
+ if (!get_logname(name, sizeof(name), &tm))
+ return;
+ unlink(name);
+}
+
+/*************************************************************************/
+
+static void checkday(void)
+{
+ time_t t;
+ struct tm tm;
+
+ time(&t);
+ tm = *localtime(&t);
+
+ if (curday != tm.tm_yday) {
+ close_log();
+ remove_log();
+ open_log();
+ }
+}
+
+/*************************************************************************/
+
+/* Open the log file. Return -1 if the log file could not be opened, else
+ * return 0. */
+
+int open_log(void)
+{
+ char name[PATH_MAX];
+
+ if (logfile)
+ return 0;
+
+ if (!get_logname(name, sizeof(name), NULL))
+ return 0;
+ logfile = fopen(name, "a");
+
+ if (logfile)
+ setbuf(logfile, NULL);
+ return logfile != NULL ? 0 : -1;
+}
+
+/*************************************************************************/
+
+/* Log stuff to the log file with a datestamp. Note that errno is
+ * preserved by this routine and log_perror().
+ */
+
+void alog(const char *fmt, ...)
+{
+ va_list args;
+ time_t t;
+ struct tm tm;
+ char buf[256];
+ int errno_save = errno;
+
+ if (!smtp_debug) {
+ return;
+ }
+
+ checkday();
+
+ if (!fmt) {
+ return;
+ }
+
+ va_start(args, fmt);
+ time(&t);
+ tm = *localtime(&t);
+ strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S %Y] ", &tm);
+ if (logfile && args) {
+ fputs(buf, logfile);
+ vfprintf(logfile, fmt, args);
+ fputc('\n', logfile);
+ }
+ va_end(args);
+ errno = errno_save;
+}
+
+/*************************************************************************/
+
+/* Remove a trailing \r\n */
+char *strip(char *buf)
+{
+ char *c;
+ if ((c = strchr(buf, '\n')))
+ *c = 0;
+ if ((c = strchr(buf, '\r')))
+ *c = 0;
+ return buf;
+}
+
+/*************************************************************************/
+
+/* Convert a trailing \n to \r\n
+ * The caller must free the allocated memory
+ */
+char *lftocrlf(char *buf)
+{
+ char *result = malloc(strlen(buf) + 2);
+ strip(buf);
+ strcpy(result, buf);
+ strcat(result, "\r\n");
+ return result;
+}
+
+/*************************************************************************/
+
+/* Add a header to the list */
+void smtp_add_header(char *header)
+{
+ struct smtp_header *head = malloc(sizeof(struct smtp_header));
+
+ head->header = lftocrlf(header);
+ head->next = NULL;
+
+ if (!mail.smtp_headers) {
+ mail.smtp_headers = head;
+ }
+ if (mail.smtp_headers_tail) {
+ mail.smtp_headers_tail->next = head;
+ }
+ mail.smtp_headers_tail = head;
+}
+
+/*************************************************************************/
+
+/* Is the buffer a header? */
+int smtp_is_header(char *buf)
+{
+ char *tmp = strchr(buf, ' ');
+
+ if (!tmp)
+ return 0;
+
+ if (*(tmp - 1) == ':')
+ return 1;
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Parse a header into a name and value */
+void smtp_parse_header(char *buf, char **header, char **value)
+{
+ strip(buf);
+
+ *header = strtok(buf, " ");
+ *value = strtok(NULL, "");
+ if (*header)
+ (*header)[strlen(*header) - 1] = 0;
+}
+
+/*************************************************************************/
+
+/* Have we reached the end of input? */
+int smtp_is_end(char *buf)
+{
+ if (*buf == '.')
+ if (*(buf + 1) == '\r' || *(buf + 1) == '\n')
+ return 1;
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Set who the email is from */
+void smtp_set_from(char *from)
+{
+ mail.from = strdup(from);
+}
+
+/*************************************************************************/
+
+/* Set who the email is to */
+void smtp_set_to(char *to)
+{
+ char *c;
+
+ if ((c = strrchr(to, '<')) && *(c + 1)) {
+ to = c + 1;
+ to[strlen(to) - 1] = 0;
+ }
+ mail.to = strdup(to);
+}
+
+/*************************************************************************/
+
+/* Add a line of body text */
+void smtp_add_body_line(char *line)
+{
+ struct smtp_body_line *body;
+
+ body = malloc(sizeof(struct smtp_body_line));
+
+ body->line = lftocrlf(line);
+ body->next = NULL;
+
+ if (!mail.smtp_body)
+ mail.smtp_body = body;
+ if (mail.smtp_body_tail)
+ mail.smtp_body_tail->next = body;
+ mail.smtp_body_tail = body;
+
+}
+
+/*************************************************************************/
+
+/* Establish a connection to the SMTP server */
+int smtp_connect(char *host, unsigned short port)
+{
+ struct sockaddr_in addr;
+
+ if ((mail.sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
+ return 0;
+
+ if ((addr.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
+ struct hostent *hent;
+ if (!(hent = gethostbyname(host)))
+ return 0;
+ memcpy(&addr.sin_addr, hent->h_addr, hent->h_length);
+ }
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port ? port : 25);
+ if (connect(mail.sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
+ ano_sockclose(mail.sock);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/* Send a line of text */
+int smtp_send(char *text)
+{
+ int result = ano_sockwrite(mail.sock, text, strlen(text));
+
+ alog("SMTP: sent %s",text);
+
+ if (result == SOCKET_ERROR)
+ ano_sockclose(mail.sock);
+
+ return result;
+}
+
+/*************************************************************************/
+
+/* Read a line of text */
+int smtp_read(char *buf, int len)
+{
+ int result;
+
+ memset(buf, 0, len);
+ result = ano_sockread(mail.sock, buf, len);
+
+ if (result == SOCKET_ERROR)
+ ano_sockclose(mail.sock);
+
+ return result;
+}
+
+/*************************************************************************/
+
+/* Retrieve a response code */
+int smtp_get_code(char *text)
+{
+ char *tmp = strtok(text, " ");
+
+ if (!tmp)
+ return 0;
+
+ return atol(tmp);
+}
+
+/*************************************************************************/
+
+/* Send the email */
+int smtp_send_email()
+{
+ char buf[1024];
+ struct smtp_header *head;
+ struct smtp_body_line *body;
+ int code;
+ int skip_done = 0;
+
+ if (!smtp_read(buf, 1024)) {
+ alog("SMTP: error reading buffer");
+ return 0;
+ }
+
+ code = smtp_get_code(buf);
+ if (code != 220) {
+ alog("SMTP: error expected code 220 got %d",code);
+ return 0;
+ }
+
+ if (!smtp_send("HELO anope\r\n")) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+
+ if (!smtp_read(buf, 1024)) {
+ alog("SMTP: error reading buffer");
+ return 0;
+ }
+
+ code = smtp_get_code(buf);
+ if (code != 250) {
+ alog("SMTP: error expected code 250 got %d",code);
+ return 0;
+ }
+
+ strcpy(buf, "MAIL FROM: <");
+ strcat(buf, mail.from);
+ strcat(buf, ">\r\n");
+
+ if (!smtp_send(buf)) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+
+ if (!smtp_read(buf, 1024)) {
+ alog("SMTP: error reading buffer");
+ return 0;
+ }
+
+ code = smtp_get_code(buf);
+ if (code != 250)
+ return 0;
+
+ strcpy(buf, "RCPT TO: <");
+ strcat(buf, mail.to);
+ strcat(buf, ">\r\n");
+
+ if (!smtp_send(buf)) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+
+ if (!smtp_read(buf, 1024)) {
+ alog("SMTP: error reading buffer");
+ return 0;
+ }
+
+ code = smtp_get_code(buf);
+ if (smtp_get_code(buf) != 250) {
+ alog("SMTP: error expected code 250 got %d",code);
+ return 0;
+ }
+
+ if (!smtp_send("DATA\r\n")) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+
+ if (!smtp_read(buf, 1024)) {
+ alog("SMTP: error reading buffer");
+ return 0;
+ }
+
+ code = smtp_get_code(buf);
+ if (code != 354) {
+ alog("SMTP: error expected code 354 got %d",code);
+ return 0;
+ }
+
+ for (head = mail.smtp_headers; head; head = head->next) {
+ if (!smtp_send(head->header)) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+ }
+
+ if (!smtp_send("\r\n")) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+
+ for (body = mail.smtp_body; body; body = body->next) {
+ if (skip_done) {
+ if (!smtp_send(body->line)) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+ } else {
+ skip_done = 1;
+ }
+ }
+
+ if (!smtp_send("\r\n.\r\n")) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*************************************************************************/
+
+void smtp_disconnect()
+{
+ smtp_send("QUIT\r\n");
+ ano_sockclose(mail.sock);
+}
+
+/*************************************************************************/
+
+int main(int argc, char *argv[])
+{
+ char buf[8192];
+ struct smtp_body_line *b;
+ struct smtp_header *h;
+ int headers_done = 0;
+/* Win32 stuff */
+#ifdef _WIN32
+ WSADATA wsa;
+#endif
+ char *server, *aport;
+ short port;
+
+ if (argc == 1)
+ return 0;
+
+ server = strtok(argv[1], ":");
+ if ((aport = strtok(NULL, ""))) {
+ port = atoi(aport);
+ } else {
+ port = 25;
+ }
+
+ if (!server) {
+ alog("No Server");
+ return;
+ } else {
+ alog("SMTP: server %s port %d",server,port);
+ }
+
+ memset(&mail, 0, sizeof(mail));
+
+/* The WSAStartup function initiates use of WS2_32.DLL by a process. */
+/* guessing we can skip it under *nix */
+#ifdef _WIN32
+ if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
+ return 0;
+#endif
+
+ /* Read the message and parse it */
+ while (fgets(buf, 8192, stdin)) {
+ if (smtp_is_header(buf) && !headers_done) {
+ char *header, *value;
+ smtp_add_header(buf);
+ smtp_parse_header(buf, &header, &value);
+ if (!strcasecmp(header, "from")) {
+ alog("SMTP: from: %s",value);
+ smtp_set_from(value);
+ } else if (!strcasecmp(header, "to")) {
+ alog("SMTP: to: %s",value);
+ smtp_set_to(value);
+ } else if (smtp_is_end(buf)) {
+ break;
+ } else {
+ headers_done = 1;
+ smtp_add_body_line(buf);
+ }
+ } else {
+ smtp_add_body_line(buf);
+ }
+ }
+
+ if (!smtp_connect(server, port)) {
+ alog("SMTP: failed to connect to %s:%d",server, port);
+ return 0;
+ }
+ if (!smtp_send_email()) {
+ alog("SMTP: error during sending of mail");
+ return 0;
+ }
+ smtp_disconnect();
+ return 1;
+}
diff --git a/src/tools/smtp.h b/src/tools/smtp.h
new file mode 100644
index 000000000..0dc0a0cbb
--- /dev/null
+++ b/src/tools/smtp.h
@@ -0,0 +1,94 @@
+/*
+ *
+ * (C) 2003 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#ifndef SMTP_H
+#define SMTP_H
+
+/*************************************************************************/
+
+/* Some Linux boxes (or maybe glibc includes) require this for the
+ * prototype of strsignal(). */
+#define _GNU_SOURCE
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#ifdef _AIX
+extern int strcasecmp(const char *, const char *);
+extern int strncasecmp(const char *, const char *, size_t);
+# if 0 /* These break on some AIX boxes (4.3.1 reported). */
+extern int socket(int, int, int);
+extern int connect(int, struct sockaddr *, int);
+# endif
+#endif /* _AIX */
+
+
+/*************************************************************************/
+
+#ifdef _WIN32
+#include <winsock.h>
+typedef SOCKET ano_socket_t;
+#define ano_sockclose(fd) closesocket(fd)
+#define ano_sockread(fd, buf, len) recv(fd, buf, len, 0)
+#define ano_sockwrite(fd, buf, len) send(fd, buf, len, 0)
+#else
+typedef int ano_socket_t;
+#define ano_sockclose(fd) close(fd)
+#define ano_sockread(fd, buf, len) read(fd, buf, len)
+#define ano_sockwrite(fd, buf, len) write(fd, buf, len)
+#define SOCKET_ERROR -1
+#endif
+
+
+/* Data structures */
+struct smtp_header {
+ char *header;
+ struct smtp_header *next;
+};
+
+struct smtp_body_line {
+ char *line;
+ struct smtp_body_line *next;
+};
+
+struct smtp_message {
+ struct smtp_header *smtp_headers, *smtp_headers_tail;
+ struct smtp_body_line *smtp_body, *smtp_body_tail;
+ char *from;
+ char *to;
+ ano_socket_t sock;
+};
+
+struct smtp_message mail;
+
+/* set this to 1 if you want to get a log otherwise it runs silent */
+int smtp_debug = 0;
+
+#endif /* SMTP_H */