Files
smmapdfw/smmapdfw/libsmmapdfw/smtp.c
2004-09-27 13:38:53 +00:00

405 lines
10 KiB
C

#include <stdlib.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <syslog.h>
#include <string.h>
#include "smtp.h"
#define BUFSIZE 1024
#define BUFSIZE2 1024
smtp_t *smtp_init(unsigned int address, int port, int timeout) {
smtp_t *handle = (smtp_t*) malloc(sizeof(smtp_t));
handle->address = address;
handle->port = port;
handle->timeout = timeout;
handle->response_text = NULL;
handle->response_code = 0;
handle->got_timeout = 0;
handle->buffer = (char*) malloc(BUFSIZE+5);
return handle;
}
smtp_t *smtp_init2(char *host_address, int port, int timeout) {
unsigned int a = inet_addr(host_address);
if (-1 == a) {
syslog(LOG_DEBUG, "smtp_init2: invalid host_address %s", host_address);
return NULL;
}
return smtp_init(a, port, timeout);
}
void smtp_destroy(smtp_t *handle) {
free(handle->buffer);
free(handle);
}
static int _smtp_strip_crlf(char *s) {
char *c;
int cnt = 0;
if ((10 == s[strlen(s)-1]) && (13 == s[strlen(s)-2]))
s[strlen(s)-2] = '\0';
/* for (c = s; *c != '\0'; c++) { */
/* if ((10 == *c) || (13 == *c)) { */
/* *c = 'X'; */
/* cnt++; */
/* } */
/* } */
return cnt;
}
static int _smtp_read(smtp_t *handle) {
int res;
fd_set rdfs;
struct timeval tv;
FD_ZERO(&rdfs);
FD_SET(handle->socket, &rdfs);
tv.tv_sec = handle->timeout;
tv.tv_usec = 0;
res = select(handle->socket+1, &rdfs, NULL, NULL, &tv);
if (0 == res) {
syslog(LOG_DEBUG, "_smtp_read: timeout in select");
handle->got_timeout = 1;
return SMTP_TIMEOUT;
} else if (-1 == res) {
syslog(LOG_DEBUG, "_smtp_read: error in select, errno: %d (%s)", errno, strerror(errno));
return -1;
} else {
if (FD_ISSET(handle->socket, &rdfs)) {
res = read(handle->socket, handle->buffer, BUFSIZE);
if (-1 == res) {
syslog(LOG_DEBUG, "read error: %d, %s\n", errno, strerror(errno));
return -1;
}
handle->buffer[res] = '\0';
return 0;
}
}
return -1;
}
static int _smtp_write(smtp_t *handle) {
int res;
fd_set wrfs;
struct timeval tv;
FD_ZERO(&wrfs);
FD_SET(handle->socket, &wrfs);
tv.tv_sec = handle->timeout;
tv.tv_usec = 0;
res = select(handle->socket+1, NULL, &wrfs, NULL, &tv);
if (0 == res) {
syslog(LOG_DEBUG, "_smtp_write: timeout in select");
handle->got_timeout = 1;
return SMTP_TIMEOUT;
} else if (-1 == res) {
syslog(LOG_DEBUG, "_smtp_write: error in select, errno: %d (%s)", errno, strerror(errno));
return -1;
} else {
if (FD_ISSET(handle->socket, &wrfs)) {
if (-1 == write(handle->socket, handle->buffer, strlen(handle->buffer))) {
syslog(LOG_DEBUG, "read error: %d, %s\n", errno, strerror(errno));
return -1;
}
return 0;
}
}
return -1;
}
static int _smtp_parse_response(smtp_t *handle) {
char *first_space;
char *last_crlf;
int l;
_smtp_strip_crlf(handle->buffer);
if (NULL == (last_crlf = strrchr(handle->buffer, 10)))
last_crlf = handle->buffer;
if (NULL == (first_space = strchr(last_crlf, ' ')))
return -1;
*first_space = '\0';
handle->response_code = atoi(last_crlf);
*first_space = ' ';
handle->response_text = handle->buffer;
return 0;
}
int smtp_response(smtp_t *handle, char **response) {
if (handle->got_timeout) {
handle->got_timeout = 0;
return SMTP_TIMEOUT;
}
if (0 != _smtp_parse_response(handle)) {
syslog(LOG_DEBUG, "smtp_response: failed to parse response\n");
return -1;
}
if (NULL != response)
*response = handle->response_text;
return handle->response_code;
}
int smtp_command(smtp_t *handle, char *command, char *arg) {
int err;
*handle->buffer = '\0';
strcat(handle->buffer, command);
if (NULL != arg) {
/* strcat(handle->buffer, " "); */
strcat(handle->buffer, arg);
}
strcat(handle->buffer, "\r\n");
if (0 != (err = _smtp_write(handle))) {
syslog(LOG_DEBUG, "smtp_command: failed to send %s\n", handle->buffer);
return err;
}
if (0 != (err = _smtp_read(handle))) {
syslog(LOG_DEBUG, "smtp_command: failed to read response\n");
return err;
}
return 0;
}
int smtp_connect(smtp_t *handle) {
int err;
int c;
int res;
fd_set wrfs;
struct timeval tv;
handle->socket = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == handle->socket) {
syslog(LOG_DEBUG, "smtp_connect: unable to create socket");
return -1;
}
c = fcntl(handle->socket, F_GETFL);
if (-1 == c) {
syslog(LOG_DEBUG, "smtp_connect: unable to get flags, errno: %d (%s)", errno, strerror(errno));
return -1;
}
err = fcntl(handle->socket, F_SETFL, c | O_NONBLOCK);
if (-1 == err) {
syslog(LOG_DEBUG, "smtp_connect: unable to set O_NONBLOCK flag, errno: %d (%s)", errno, strerror(errno));
return -1;
}
memset(&handle->addr, 0, sizeof(handle->addr));
handle->addr.sin_addr.s_addr = handle->address;
handle->addr.sin_port = htons(handle->port);
handle->addr.sin_family = AF_INET;
c = connect(handle->socket, (struct sockaddr *) &handle->addr, sizeof(handle->addr));
if (-1 == c) {
if (EINPROGRESS == errno) {
FD_ZERO(&wrfs);
FD_SET(handle->socket, &wrfs);
tv.tv_sec = handle->timeout;
tv.tv_usec = 0;
res = select(handle->socket+1, NULL, &wrfs, NULL, &tv);
if (0 == res) {
syslog(LOG_DEBUG, "smtp_connect: timeout in select");
handle->got_timeout = 1;
return SMTP_TIMEOUT;
} else if (-1 == res) {
syslog(LOG_DEBUG, "smtp_connect: error in select, errno: %d (%s)", errno, strerror(errno));
return -1;
} else {
if (FD_ISSET(handle->socket, &wrfs)) {
// debug("smtp_connect: here we go");
}
}
} else {
syslog(LOG_DEBUG, "smtp_connect: unable to connect to socket, errno: %d (%s)", errno, strerror(errno));
return -1;
}
}
err = _smtp_read(handle);
if (0 != err)
return -1;
return 0;
}
int smtp_helo(smtp_t *handle, char *arg) {
return smtp_command(handle, "helo ", arg);
}
int smtp_ehlo(smtp_t *handle, char *arg) {
return smtp_command(handle, "ehlo ", arg);
}
int smtp_lhlo(smtp_t *handle, char *arg) {
return smtp_command(handle, "lhlo ", arg);
}
int smtp_mailfrom(smtp_t *handle, char *arg) {
return smtp_command(handle, "mail from:", arg);
}
int smtp_rcptto(smtp_t *handle, char *arg) {
return smtp_command(handle, "rcpt to:", arg);
}
int smtp_data(smtp_t *handle) {
return smtp_command(handle, "data", NULL);
}
int smtp_datasend(smtp_t *handle, char *data) {
char *d = data;
int cnt;
int ssize;
while (d < data + strlen(data)) {
ssize = (strlen(d) < BUFSIZE2) ? strlen(d) : BUFSIZE2;
if (-1 == write(handle->socket, d, ssize))
return -1;
d += BUFSIZE2;
}
return 0;
}
int smtp_dataend(smtp_t *handle) {
return smtp_command(handle, "\r\n.", NULL);
}
int smtp_rset(smtp_t *handle) {
return smtp_command(handle, "rset", NULL);
}
int smtp_quit(smtp_t *handle) {
return smtp_command(handle, "quit", NULL);
}
int smtp_close(smtp_t *handle) {
close(handle->socket);
}
#ifdef _TEST_MODE_
int main() {
int res;
char *res_text;
char data[] = "Hallo Wolfgang\r\n"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"abaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaagaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaahaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaajaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaakaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaamaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaaaaoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaaaaapaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaaaaaaqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaaaaaaaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaaaaaaaasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaaaaaaaaataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaaaaaaaaaauaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaaaaaaaaaaavaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaaaaaaaaaaaawaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaaaaaaaaaaaaaxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"\r\n"
"dies ist eine Testmail.\r\n"
"\r\n";
smtp_t *h = smtp_init2("213.70.191.212", 25, 10);
printf("got handle\n");
res = smtp_connect(h);
printf("connected: %d\n", res);
res = smtp_response(h, &res_text);
printf("response: %d, %s\n", res, res_text);
res = smtp_helo(h, "local");
printf("ehlo: %d\n", res);
res = smtp_response(h, &res_text);
printf("response: %d, %s\n", res, res_text);
res = smtp_mailfrom(h, "<xyx@test.de>");
printf("mail from: %d\n", res);
res = smtp_response(h, &res_text);
printf("response: %d, %s\n", res, res_text);
res = smtp_rcptto(h, "<wn@kja-essen.de>");
printf("rcpt to: %d\n", res);
res = smtp_response(h, &res_text);
printf("response: %d, %s\n", res, res_text);
res = smtp_data(h);
printf("data: %d\n", res);
res = smtp_response(h, &res_text);
printf("response: %d, %s\n", res, res_text);
res = smtp_datasend(h, data);
printf("datasend: %d\n", res);
res = smtp_dataend(h);
printf("dataend: %d\n", res);
res = smtp_response(h, &res_text);
printf("response: %d, %s\n", res, res_text);
smtp_close(h);
smtp_destroy(h);
}
#endif /* _TEST_MODE_ */