lmtp-client.c revision 5f5870385cff47efd2f58e7892f251cf13761528
/* Copyright (c) 2009-2012 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "network.h"
#include "istream.h"
#include "ostream.h"
#include "dns-lookup.h"
#include "lmtp-client.h"
#include <ctype.h>
#define LMTP_MAX_LINE_LEN 1024
enum lmtp_input_state {
};
struct lmtp_rcpt {
const char *address;
void *context;
unsigned int data_called:1;
unsigned int failed:1;
};
struct lmtp_client {
int refcount;
struct lmtp_client_settings set;
const char *host;
unsigned int port;
enum lmtp_client_protocol protocol;
enum lmtp_input_state input_state;
const char *global_fail_string;
int fd;
void (*data_output_callback)(void *);
void *data_output_context;
void *finish_context;
const char *data_header;
unsigned int rcpt_next_receive_idx;
unsigned int rcpt_next_data_idx;
unsigned int rcpt_next_send_idx;
struct istream *data_input;
unsigned char output_last;
unsigned int rcpt_to_successes:1;
unsigned int output_finished:1;
unsigned int finish_called:1;
};
struct lmtp_client *
{
struct lmtp_client *client;
return client;
}
{
}
if (!client->finish_called) {
}
}
{
}
{
return;
}
{
}
{
switch (client->input_state) {
case LMTP_INPUT_STATE_GREET:
return "greeting";
case LMTP_INPUT_STATE_LHLO:
return "LHLO";
return "MAIL FROM";
case LMTP_INPUT_STATE_RCPT_TO:
return "RCPT TO";
return "DATA init";
case LMTP_INPUT_STATE_DATA:
if (client->output_finished)
return "DATA reply";
return t_strdup_printf(
} else {
}
}
return "??";
}
{
struct lmtp_rcpt *recipients;
unsigned int i, count;
recipients[i].context);
}
if (!recipients[i].failed) {
recipients[i].context);
}
}
}
static void
{
bool success;
if (success)
}
{
return 0;
return -1;
} else {
client->input_state++;
return 0;
}
}
static int
{
unsigned int i, count;
/* already called rcpt_to_callback with failure */
continue;
}
break;
}
if (i < count)
return 0;
return -1;
}
{
const unsigned char *data;
unsigned char add;
bool sent_bytes = FALSE;
int ret;
if (client->output_finished)
return;
add = '\0';
for (i = 0; i < size; i++) {
if (data[i] == '\n') {
/* missing CR */
add = '\r';
break;
}
} else if (data[i] == '.' &&
/* escape the dot */
add = '.';
break;
}
}
if (i > 0) {
break;
sent_bytes = TRUE;
}
break;
if (ret == 0) {
/* continue later */
return;
}
}
if (add != '\0') {
break;
}
}
/* -2 can happen with tee istreams */
return;
}
/* didn't end with CRLF */
}
}
{
t_strdup_printf("LHLO %s\r\n",
break;
t_strdup_printf("EHLO %s\r\n",
break;
}
}
{
return -1;
/* final reply */
return 1;
/* multiline reply. just ignore it. */
return 0;
} else {
/* invalid input */
return -1;
}
}
{
int ret, reply_code = 0;
if (ret == 0)
return 0;
return -1;
}
switch (client->input_state) {
case LMTP_INPUT_STATE_GREET:
if (reply_code != 220) {
return -1;
}
client->input_state++;
break;
case LMTP_INPUT_STATE_LHLO:
if (reply_code != 250) {
return -1;
}
t_strdup_printf("MAIL FROM:%s\r\n",
}
client->input_state++;
break;
case LMTP_INPUT_STATE_RCPT_TO:
break;
if (lmtp_client_send_data_cmd(client) < 0)
return -1;
break;
/* Start sending DATA */
return -1;
}
client->input_state++;
break;
case LMTP_INPUT_STATE_DATA:
/* DATA replies */
return -1;
break;
}
return 0;
}
{
const char *line;
return;
}
}
i_error("lmtp client: read() failed: %m");
" (read failure)");
" (disconnected in input)");
}
}
{
int err;
if (err != 0) {
i_error("lmtp client: connect(%s, %u) failed: %s",
" (connect)");
return;
}
}
{
int ret;
" (disconnected in output)");
return ret;
}
{
i_error("lmtp client: connect(%s, %u) failed: %m",
return -1;
}
/* we're already sending data in ostream, so can't use IO_WRITE here */
return 0;
}
struct lmtp_client *client)
{
i_error("lmtp client: DNS lookup of %s failed: %s",
" (DNS lookup)");
} else {
if (lmtp_client_connect(client) < 0) {
" (connect)");
}
}
}
enum lmtp_client_protocol protocol,
{
struct dns_lookup_settings dns_lookup_set;
unsigned int ips_count;
int ret;
if (*host == '\0') {
i_error("lmtp client: host not given");
return -1;
}
/* IP address */
/* no dns-client, use blocking lookup */
if (ret != 0) {
i_error("lmtp client: DNS lookup of %s failed: %s",
return -1;
}
} else {
lmtp_client_dns_done, client) < 0)
return -1;
return 0;
}
if (lmtp_client_connect(client) < 0)
return -1;
return 0;
}
{
}
{
unsigned int i, count;
}
client->rcpt_next_send_idx = i;
}
{
}
{
(void)lmtp_client_send_data_cmd(client);
}
{
}
}
void (*callback)(void *),
void *context)
{
}