]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
LMTP client API changes. Should be easier to use now.
authorTimo Sirainen <tss@iki.fi>
Tue, 24 Nov 2009 19:17:06 +0000 (14:17 -0500)
committerTimo Sirainen <tss@iki.fi>
Tue, 24 Nov 2009 19:17:06 +0000 (14:17 -0500)
--HG--
branch : HEAD

src/lib-lda/lmtp-client.c
src/lib-lda/lmtp-client.h
src/lmtp/lmtp-proxy.c

index 9ac810b80c11f92d8a3a0d6410b1fc6838061862..2435bb2762257b696567b3c0a4b02a82ff20c2e0 100644 (file)
@@ -49,6 +49,9 @@ struct lmtp_client {
        struct io *io;
        int fd;
 
+       lmtp_finish_callback_t *finish_callback;
+       void *finish_context;
+
        const char *data_header;
        ARRAY_DEFINE(recipients, struct lmtp_rcpt);
        unsigned int rcpt_next_receive_idx;
@@ -57,14 +60,16 @@ struct lmtp_client {
        struct istream *data_input;
        unsigned char output_last;
 
-       unsigned int output_finished:1;
        unsigned int rcpt_to_successes:1;
+       unsigned int output_finished:1;
+       unsigned int finish_called:1;
 };
 
 static void lmtp_client_send_rcpts(struct lmtp_client *client);
 
 struct lmtp_client *
-lmtp_client_init(const char *mail_from, const char *my_hostname)
+lmtp_client_init(const char *mail_from, const char *my_hostname,
+                lmtp_finish_callback_t *finish_callback, void *context)
 {
        struct lmtp_client *client;
        pool_t pool;
@@ -78,6 +83,8 @@ lmtp_client_init(const char *mail_from, const char *my_hostname)
        client->pool = pool;
        client->mail_from = p_strdup(pool, mail_from);
        client->my_hostname = p_strdup(pool, my_hostname);
+       client->finish_callback = finish_callback;
+       client->finish_context = context;
        client->fd = -1;
        p_array_init(&client->recipients, pool, 16);
        return client;
@@ -98,6 +105,11 @@ void lmtp_client_close(struct lmtp_client *client)
        if (client->data_input != NULL)
                i_stream_unref(&client->data_input);
        client->output_finished = TRUE;
+
+       if (!client->finish_called) {
+               client->finish_called = TRUE;
+               client->finish_callback(client->finish_context);
+       }
 }
 
 static void lmtp_client_ref(struct lmtp_client *client)
@@ -201,7 +213,7 @@ static void lmtp_client_send_data_cmd(struct lmtp_client *client)
        }
 }
 
-static bool
+static int
 lmtp_client_data_next(struct lmtp_client *client, const char *line)
 {
        struct lmtp_rcpt *rcpt;
@@ -214,14 +226,18 @@ lmtp_client_data_next(struct lmtp_client *client, const char *line)
                        continue;
                }
 
+               client->rcpt_next_data_idx = i + 1;
                rcpt[i].failed = line[0] != '2';
                rcpt[i].data_callback(!rcpt[i].failed, line,
                                      rcpt[i].context);
-               client->rcpt_next_data_idx = i + 1;
                if (client->protocol == LMTP_CLIENT_PROTOCOL_LMTP)
                        break;
        }
-       return i < count;
+       if (i < count)
+               return 0;
+
+       lmtp_client_close(client);
+       return -1;
 }
 
 static void lmtp_client_send_data(struct lmtp_client *client)
@@ -379,7 +395,7 @@ static int lmtp_client_input_line(struct lmtp_client *client, const char *line)
                break;
        case LMTP_INPUT_STATE_DATA:
                /* DATA replies */
-               if (!lmtp_client_data_next(client, line))
+               if (lmtp_client_data_next(client, line) < 0)
                        return -1;
                break;
        }
@@ -521,11 +537,6 @@ void lmtp_client_send(struct lmtp_client *client, struct istream *data_input)
        lmtp_client_send_data_cmd(client);
 }
 
-bool lmtp_client_is_data_input_finished(struct lmtp_client *client)
-{
-       return client->data_input != NULL;
-}
-
 void lmtp_client_send_more(struct lmtp_client *client)
 {
        if (client->input_state == LMTP_INPUT_STATE_DATA)
index 4b0c7b56e2674899c4dd9e81e6999fe20b68a121..60889b10fe2ea641a6e7cc8f53b18f73e1a6c81b 100644 (file)
@@ -13,9 +13,13 @@ enum lmtp_client_protocol {
 /* reply contains the reply coming from remote server, or NULL
    if it's a connection error. */
 typedef void lmtp_callback_t(bool success, const char *reply, void *context);
+/* called when session is finished, either because all RCPT TOs failed or
+   because all DATA replies have been received. */
+typedef void lmtp_finish_callback_t(void *context);
 
 struct lmtp_client *
-lmtp_client_init(const char *mail_from, const char *my_hostname);
+lmtp_client_init(const char *mail_from, const char *my_hostname,
+                lmtp_finish_callback_t *finish_callback, void *context);
 void lmtp_client_deinit(struct lmtp_client **client);
 
 int lmtp_client_connect_tcp(struct lmtp_client *client,
@@ -34,8 +38,6 @@ void lmtp_client_add_rcpt(struct lmtp_client *client, const char *address,
                          lmtp_callback_t *data_callback, void *context);
 /* Start sending input stream as DATA. */
 void lmtp_client_send(struct lmtp_client *client, struct istream *data_input);
-/* Returns TRUE if data_input is no longer needed. */
-bool lmtp_client_is_data_input_finished(struct lmtp_client *client);
 /* Call this function whenever input stream can potentially be read forward.
    This is useful with non-blocking istreams and tee-istreams. */
 void lmtp_client_send_more(struct lmtp_client *client);
index 5fe74b5784e548f958ec13761ef13856d1a976ca..2135bef7cc00b27312731ae9a9235b60366af5df 100644 (file)
@@ -25,10 +25,6 @@ struct lmtp_proxy_connection {
        struct lmtp_proxy *proxy;
        struct lmtp_proxy_settings set;
 
-       /* points to proxy->rcpt_to array. */
-       unsigned int rcpt_next_reply_low_idx;
-       unsigned int data_next_reply_low_idx;
-
        struct lmtp_client *client;
        struct istream *data_input;
        unsigned int failed:1;
@@ -39,7 +35,7 @@ struct lmtp_proxy {
        const char *mail_from, *my_hostname;
        ARRAY_DEFINE(connections, struct lmtp_proxy_connection *);
        ARRAY_DEFINE(rcpt_to, struct lmtp_proxy_recipient);
-       unsigned int rcpt_next_reply_idx;
+       unsigned int next_data_reply_idx;
 
        struct timeout *to, *to_data_idle;
        struct io *io;
@@ -55,6 +51,7 @@ struct lmtp_proxy {
        unsigned int finished:1;
 };
 
+static void lmtp_conn_finish(void *context);
 static void lmtp_proxy_data_input(struct lmtp_proxy *proxy);
 
 struct lmtp_proxy *
@@ -136,7 +133,8 @@ lmtp_proxy_get_connection(struct lmtp_proxy *proxy,
        conn->set.port = set->port;
        conn->set.timeout_msecs = set->timeout_msecs;
        array_append(&proxy->connections, &conn, 1);
-       conn->client = lmtp_client_init(proxy->mail_from, proxy->my_hostname);
+       conn->client = lmtp_client_init(proxy->mail_from, proxy->my_hostname,
+                                       lmtp_conn_finish, conn);
        if (lmtp_client_connect_tcp(conn->client, set->protocol,
                                    conn->set.host, conn->set.port) < 0)
                conn->failed = TRUE;
@@ -146,28 +144,21 @@ lmtp_proxy_get_connection(struct lmtp_proxy *proxy,
        return conn;
 }
 
-static void lmtp_proxy_conn_close(struct lmtp_proxy_connection *conn)
-{
-       lmtp_client_close(conn->client);
-       if (conn->data_input != NULL)
-               i_stream_unref(&conn->data_input);
-}
-
-static bool lmtp_proxy_send_replies(struct lmtp_proxy *proxy)
+static bool lmtp_proxy_send_data_replies(struct lmtp_proxy *proxy)
 {
        const struct lmtp_proxy_recipient *rcpt;
        unsigned int i, count;
 
        o_stream_cork(proxy->client_output);
        rcpt = array_get(&proxy->rcpt_to, &count);
-       for (i = proxy->rcpt_next_reply_idx; i < count; i++) {
+       for (i = proxy->next_data_reply_idx; i < count; i++) {
                if (!(rcpt[i].rcpt_to_failed || rcpt[i].data_reply_received))
                        break;
                o_stream_send_str(proxy->client_output,
                                  t_strconcat(rcpt[i].reply, "\r\n", NULL));
        }
        o_stream_uncork(proxy->client_output);
-       proxy->rcpt_next_reply_idx = i;
+       proxy->next_data_reply_idx = i;
 
        return i == count;
 }
@@ -182,10 +173,18 @@ static void lmtp_proxy_finish(struct lmtp_proxy *proxy)
 
 static void lmtp_proxy_try_finish(struct lmtp_proxy *proxy)
 {
-       if (lmtp_proxy_send_replies(proxy) && proxy->data_input->eof)
+       if (lmtp_proxy_send_data_replies(proxy) && proxy->data_input->eof)
                lmtp_proxy_finish(proxy);
 }
 
+static void lmtp_conn_finish(void *context)
+{
+       struct lmtp_proxy_connection *conn = context;
+
+       i_stream_unref(&conn->data_input);
+       lmtp_proxy_try_finish(conn->proxy);
+}
+
 static void lmtp_proxy_fail_all(struct lmtp_proxy *proxy, const char *reason)
 {
        struct lmtp_proxy_connection *const *conns;
@@ -229,57 +228,26 @@ static void lmtp_proxy_data_input_timeout(struct lmtp_proxy *proxy)
 static void
 lmtp_proxy_conn_rcpt_to(bool success, const char *reply, void *context)
 {
-       struct lmtp_proxy_connection *conn = context;
-       struct lmtp_proxy_recipient *rcpt;
-       unsigned int i, count;
+       struct lmtp_proxy_recipient *rcpt = context;
+       struct lmtp_proxy_connection *conn = rcpt->conn;
 
-       rcpt = array_get_modifiable(&conn->proxy->rcpt_to, &count);
-       for (i = conn->rcpt_next_reply_low_idx; i < count; i++) {
-               if (rcpt[i].conn == conn) {
-                       i_assert(rcpt[i].reply == NULL);
-                       rcpt[i].reply = p_strdup(conn->proxy->pool, reply);
-                       rcpt[i].rcpt_to_failed = !success;
-                       conn->rcpt_next_reply_low_idx = i + 1;
-                       break;
-               }
-       }
-       i_assert(i != count);
-
-       if (!success && conn->rcpt_next_reply_low_idx == count &&
-           lmtp_client_is_data_input_finished(conn->client))
-               lmtp_proxy_conn_close(conn);
+       i_assert(rcpt->reply == NULL);
 
-       /* send replies only if we've already sent DATA. */
-       if (conn->proxy->data_input != NULL)
-               lmtp_proxy_try_finish(conn->proxy);
+       rcpt->reply = p_strdup(conn->proxy->pool, reply);
+       rcpt->rcpt_to_failed = !success;
 }
 
 static void
 lmtp_proxy_conn_data(bool success ATTR_UNUSED, const char *reply, void *context)
 {
-       struct lmtp_proxy_connection *conn = context;
-       struct lmtp_proxy_recipient *rcpt;
-       unsigned int i, count;
+       struct lmtp_proxy_recipient *rcpt = context;
+       struct lmtp_proxy_connection *conn = rcpt->conn;
 
-       i_assert(conn->proxy->data_input != NULL);
+       i_assert(!rcpt->rcpt_to_failed);
+       i_assert(rcpt->reply != NULL);
 
-       rcpt = array_get_modifiable(&conn->proxy->rcpt_to, &count);
-       for (i = conn->data_next_reply_low_idx; i < count; i++) {
-               if (rcpt[i].conn == conn && !rcpt[i].rcpt_to_failed) {
-                       i_assert(rcpt[i].reply != NULL);
-                       rcpt[i].reply = p_strdup(conn->proxy->pool, reply);
-                       rcpt[i].data_reply_received = TRUE;
-                       conn->data_next_reply_low_idx = i + 1;
-                       break;
-               }
-       }
-       i_assert(i != count);
-
-       if (conn->data_next_reply_low_idx == count &&
-           lmtp_client_is_data_input_finished(conn->client))
-               lmtp_proxy_conn_close(conn);
-
-       lmtp_proxy_try_finish(conn->proxy);
+       rcpt->reply = p_strdup(conn->proxy->pool, reply);
+       rcpt->data_reply_received = TRUE;
 }
 
 int lmtp_proxy_add_rcpt(struct lmtp_proxy *proxy, const char *address,
@@ -297,7 +265,7 @@ int lmtp_proxy_add_rcpt(struct lmtp_proxy *proxy, const char *address,
        rcpt->address = p_strdup(proxy->pool, address);
 
        lmtp_client_add_rcpt(conn->client, address, lmtp_proxy_conn_rcpt_to,
-                            lmtp_proxy_conn_data, conn);
+                            lmtp_proxy_conn_data, rcpt);
        return 0;
 }