program-client.c revision 0d1b8b6bec79746c5d89d57dd8c1688946bd9237
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "lib.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "ioloop.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "array.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "str.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "safe-mkstemp.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "istream-private.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "istream-seekable.h"
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi#include "ostream-dot.h"
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi#include "istream-dot.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "ostream.h"
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi#include "lib-signals.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "program-client-private.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include <unistd.h>
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#define MAX_OUTPUT_BUFFER_SIZE 16384
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#define MAX_OUTPUT_MEMORY_BUFFER (1024*128)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomistatic
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_callback(struct program_client *pclient, int result, void
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi *context)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi{
f207fb0f2fd3113aa9a9f7911fb12d94dce19dffAki Tuomi /* do not call callback when destroying */
f207fb0f2fd3113aa9a9f7911fb12d94dce19dffAki Tuomi if (pclient->destroying) return;
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi program_client_callback_t *callback = pclient->callback;
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi i_assert(pclient->callback != NULL);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi callback(result, context);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi}
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_seekable_fd_callback(const char **path_r, void *context)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi struct program_client *pclient = (struct program_client *)context;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi string_t *path;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int fd;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi path = t_str_new(128);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi str_append(path, pclient->temp_prefix);
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd == -1) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("safe_mkstemp(%s) failed: %m", str_c(path));
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* we just want the fd, unlink it */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (i_unlink(str_c(path)) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* shouldn't happen.. */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_close_fd(&fd);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi *path_r = str_c(path);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return fd;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_timeout(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
17541ea25593c656060199715051db2c1eef221dAki Tuomi i_error("program `%s' execution timed out (> %u msecs)",
17541ea25593c656060199715051db2c1eef221dAki Tuomi pclient->path, pclient->set.input_idle_timeout_msecs);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_RUN_TIMEOUT);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_connect_timeout(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
17541ea25593c656060199715051db2c1eef221dAki Tuomi i_error("program `%s' socket connection timed out (> %u msecs)",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->path, pclient->set.client_connect_timeout_msecs);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_CONNECT_TIMEOUT);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_connect(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->set.client_connect_timeout_msecs != 0) {
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi pclient->to = timeout_add(pclient->set.client_connect_timeout_msecs,
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi program_client_connect_timeout, pclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
7c9ae3d919ba59af5be3193a80ece4871a0d700cAki Tuomi return pclient->connect(pclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_close_output(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int ret;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->program_output != NULL)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_destroy(&pclient->program_output);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if ((ret = pclient->close_output(pclient)) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->program_output = NULL;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return ret;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_disconnect_extra_fds(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client_extra_fd *efds;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi unsigned int i, count;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (!array_is_created(&pclient->extra_fds))
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efds = array_get_modifiable(&pclient->extra_fds, &count);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(i = 0; i < count; i++) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (efds[i].input != NULL)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_unref(&efds[i].input);
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&efds[i].io);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (efds[i].parent_fd != -1 && close(efds[i].parent_fd) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(fd=%d) failed: %m", efds[i].parent_fd);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomivoid program_client_disconnected(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->program_input != NULL) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi if (pclient->output_seekable ||
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->set.use_dotstream)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_unref(&pclient->program_input);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi else
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_destroy(&pclient->program_input);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->program_output != NULL)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_destroy(&pclient->program_output);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&pclient->io);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->fd_in != -1 && close(pclient->fd_in) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(%s) failed: %m", pclient->path);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->fd_out != -1 && pclient->fd_out != pclient->fd_in
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi && close(pclient->fd_out) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(%s/out) failed: %m", pclient->path);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->fd_in = pclient->fd_out = -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->disconnected = TRUE;
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi if (pclient->other_error && pclient->error == PROGRAM_CLIENT_ERROR_NONE) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->error = PROGRAM_CLIENT_ERROR_OTHER;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi program_client_callback(pclient,
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi pclient->error != PROGRAM_CLIENT_ERROR_NONE ?
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi -1 :
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi pclient->exit_code,
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi pclient->context);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomistatic
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomivoid program_client_disconnect(struct program_client *pclient, bool force)
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi{
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi int ret;
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi if (pclient->disconnected)
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi return;
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi pclient->disconnected = TRUE;
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&pclient->to);
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&pclient->io);
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi if ((ret = program_client_close_output(pclient)) < 0)
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi pclient->other_error = TRUE;
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi program_client_disconnect_extra_fds(pclient);
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi pclient->disconnect(pclient, force);
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi}
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_fail(struct program_client *pclient,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi enum program_client_error error)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->error != PROGRAM_CLIENT_ERROR_NONE)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->error = error;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_disconnect(pclient, TRUE);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomibool program_client_input_pending(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client_extra_fd *efds = NULL;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi unsigned int count, i;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->program_input != NULL &&
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi !pclient->program_input->closed &&
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi !i_stream_is_eof(pclient->program_input)) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return TRUE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (array_is_created(&pclient->extra_fds)) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efds = array_get_modifiable(&pclient->extra_fds, &count);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(i = 0; i < count; i++) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (efds[i].input != NULL &&
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi !efds[i].input->closed &&
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi !i_stream_is_eof(efds[i].input)) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return TRUE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return FALSE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_program_output(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct istream *input = pclient->input;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct ostream *output = pclient->program_output;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi enum ostream_send_istream_result res;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int ret = 0;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if ((ret = o_stream_flush(output)) <= 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (ret < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("write(%s) failed: %s",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_get_name(output),
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_get_error(output));
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return ret;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi if (!pclient->output_dot_created &&
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->set.use_dotstream &&
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi output != NULL) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->dot_output = o_stream_create_dot(output, FALSE);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->output_dot_created = TRUE;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi }
66761ea6a8f00006f28743b4bd2f5339f78c10e0Timo Sirainen if (pclient->dot_output != NULL)
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi output = pclient->dot_output;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (input != NULL && output != NULL) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi res = o_stream_send_istream(output, input);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi switch (res) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_unref(&pclient->input);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi input = NULL;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi break;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return 1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return 0;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("read(%s) failed: %s",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_get_name(input),
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_get_error(input));
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("write(%s) failed: %s",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_get_name(output),
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_get_error(output));
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
e6ba63471b1451b48e1185492c33d7bf58be884dAki Tuomi }
e6ba63471b1451b48e1185492c33d7bf58be884dAki Tuomi
e6ba63471b1451b48e1185492c33d7bf58be884dAki Tuomi if (input == NULL &&
e6ba63471b1451b48e1185492c33d7bf58be884dAki Tuomi output != NULL &&
66761ea6a8f00006f28743b4bd2f5339f78c10e0Timo Sirainen pclient->dot_output != NULL) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi if ((ret = o_stream_flush(pclient->dot_output)) <= 0) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi if (ret < 0) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi i_error("write(%s) failed: %s",
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi o_stream_get_name(output),
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi o_stream_get_error(output));
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi program_client_fail(pclient,
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi PROGRAM_CLIENT_ERROR_IO);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi }
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi return ret;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi }
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi o_stream_unref(&pclient->dot_output);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (input == NULL) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (!program_client_input_pending(pclient)) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_disconnect(pclient, FALSE);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi } else if (program_client_close_output(pclient) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi PROGRAM_CLIENT_ERROR_OTHER);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return 1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_program_input(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct istream *input = pclient->program_input;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct ostream *output = pclient->output;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi enum ostream_send_istream_result res;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi const unsigned char *data;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi size_t size;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int ret = 0;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->output_seekable && pclient->seekable_output == NULL) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct istream *input_list[2] = { input, NULL };
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi input = i_stream_create_seekable(input_list, MAX_OUTPUT_MEMORY_BUFFER,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_seekable_fd_callback,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_unref(&pclient->program_input);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->program_input = input;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->seekable_output = input;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_ref(pclient->seekable_output);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (input != NULL) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi if (!pclient->input_dot_created &&
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->set.use_dotstream) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->dot_input = i_stream_create_dot(input, FALSE);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->input_dot_created = TRUE;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi }
66761ea6a8f00006f28743b4bd2f5339f78c10e0Timo Sirainen if (pclient->dot_input != NULL)
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi input = pclient->dot_input;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi else if (pclient->set.use_dotstream) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi /* just read it empty */
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi while(i_stream_read_more(input, &data,
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi &size) > 0)
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi i_stream_skip(input, size);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi output = NULL;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (output != NULL) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi res = o_stream_send_istream(output, input);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi switch (res) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi if (pclient->set.use_dotstream &&
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->dot_input != NULL) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi i_stream_unref(&pclient->dot_input);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi input = pclient->program_input;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi break;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("read(%s) failed: %s",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_get_name(input),
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_get_error(input));
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi PROGRAM_CLIENT_ERROR_IO);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("write(%s) failed: %s",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_get_name(output),
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_get_error(output));
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi PROGRAM_CLIENT_ERROR_IO);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi } else {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi while ((ret =
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_read_more(input, &data, &size)) > 0 ||
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi ret == -2) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_skip(input, size);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (ret == 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (ret < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (input->stream_errno != 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("read(%s) failed: %s",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_get_name(input),
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_get_error(input));
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi PROGRAM_CLIENT_ERROR_IO);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi if (program_client_input_pending(pclient))
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi return;
9b7b07d70c25c51be54d3b070216872ddaab6e6eAki Tuomi if (pclient->program_input != NULL && !input->eof) {
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi program_client_fail(pclient,
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi PROGRAM_CLIENT_ERROR_IO);
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi return;
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi }
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi }
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi program_client_disconnect(pclient, FALSE);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_extra_fd_input(struct program_client_extra_fd *efd)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client *pclient = efd->pclient;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_assert(efd->callback != NULL);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efd->callback(efd->context, efd->input);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (efd->input->closed || i_stream_is_eof(efd->input)) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (!program_client_input_pending(pclient))
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_disconnect(pclient, FALSE);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_connected(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int ret = 1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
17541ea25593c656060199715051db2c1eef221dAki Tuomi pclient->start_time = ioloop_timeval;
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&pclient->to);
17541ea25593c656060199715051db2c1eef221dAki Tuomi if (pclient->set.input_idle_timeout_msecs != 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->to =
17541ea25593c656060199715051db2c1eef221dAki Tuomi timeout_add(pclient->set.input_idle_timeout_msecs,
17541ea25593c656060199715051db2c1eef221dAki Tuomi program_client_timeout, pclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* run output */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->program_output != NULL &&
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi (ret = program_client_program_output(pclient)) == 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->program_output != NULL) {
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi o_stream_set_flush_callback(pclient->program_output,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_program_output, pclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return ret;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_init(struct program_client *pclient, pool_t pool,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi const char *path,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi const char *const *args,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi const struct program_client_settings *set)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->pool = pool;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->path = p_strdup(pool, path);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (args != NULL)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->args = p_strarray_dup(pool, args);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->set = *set;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->debug = set->debug;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->fd_in = -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->fd_out = -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_set_input(struct program_client *pclient,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi struct istream *input)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->input != NULL)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_unref(&pclient->input);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (input != NULL)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_ref(input);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->input = input;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_set_output(struct program_client *pclient,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi struct ostream *output)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->output != NULL)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_unref(&pclient->output);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (output != NULL)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_ref(output);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->output = output;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->output_seekable = FALSE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_free(pclient->temp_prefix);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_set_output_seekable(struct program_client *pclient,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi const char *temp_prefix)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->output != NULL)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_unref(&pclient->output);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->temp_prefix = i_strdup(temp_prefix);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->output_seekable = TRUE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistruct istream *program_client_get_output_seekable(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct istream *input = pclient->seekable_output;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->seekable_output = NULL;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_seek(input, 0);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return input;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#undef program_client_set_extra_fd
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_set_extra_fd(struct program_client *pclient, int fd,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi program_client_fd_callback_t *callback,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi void *context)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client_extra_fd *efds;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client_extra_fd *efd = NULL;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi unsigned int i, count;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_assert(fd > 1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (!array_is_created(&pclient->extra_fds))
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi p_array_init(&pclient->extra_fds, pclient->pool, 2);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efds = array_get_modifiable(&pclient->extra_fds, &count);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(i = 0; i < count; i++) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (efds[i].child_fd == fd) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efd = &efds[i];
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi break;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (efd == NULL) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efd = array_append_space(&pclient->extra_fds);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efd->pclient = pclient;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efd->child_fd = fd;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efd->parent_fd = -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efd->callback = callback;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efd->context = context;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_set_env(struct program_client *pclient, const char *name,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi const char *value)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi const char *env;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (!array_is_created(&pclient->envs))
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi p_array_init(&pclient->envs, pclient->pool, 16);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi env = p_strdup_printf(pclient->pool, "%s=%s", name, value);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi array_append(&pclient->envs, &env, 1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_init_streams(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Create streams for normal program I/O */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->fd_out >= 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->program_output =
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_create_fd(pclient->fd_out,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi MAX_OUTPUT_BUFFER_SIZE);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_set_name(pclient->program_output, "program stdin");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->fd_in >= 0) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->program_input =
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi i_stream_create_fd(pclient->fd_in, (size_t)-1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_set_name(pclient->program_input, "program stdout");
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi pclient->io = io_add(pclient->fd_in, IO_READ,
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi program_client_program_input, pclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Create streams for additional output through side-channel fds */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (array_is_created(&pclient->extra_fds)) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client_extra_fd *efds = NULL;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi unsigned int count, i;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efds = array_get_modifiable(&pclient->extra_fds, &count);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(i = 0; i < count; i++) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_assert(efds[i].parent_fd >= 0);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efds[i].input = i_stream_create_fd
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi (efds[i].parent_fd, (size_t)-1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_set_name(efds[i].input,
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi t_strdup_printf("program output fd=%d",
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi efds[i].child_fd));
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi efds[i].io = io_add(efds[i].parent_fd, IO_READ,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi program_client_extra_fd_input,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi &efds[i]);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_destroy(struct program_client **_pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client *pclient = *_pclient;
f207fb0f2fd3113aa9a9f7911fb12d94dce19dffAki Tuomi *_pclient = NULL;
f207fb0f2fd3113aa9a9f7911fb12d94dce19dffAki Tuomi
f207fb0f2fd3113aa9a9f7911fb12d94dce19dffAki Tuomi pclient->destroying = TRUE;
f207fb0f2fd3113aa9a9f7911fb12d94dce19dffAki Tuomi pclient->callback = NULL;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_disconnect(pclient, TRUE);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi i_assert(pclient->callback == NULL);
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->input != NULL)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_unref(&pclient->input);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi if (pclient->dot_input != NULL)
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi i_stream_unref(&pclient->dot_input);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi if (pclient->program_input != NULL)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi i_stream_unref(&pclient->program_input);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi if (pclient->program_output != NULL)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi o_stream_unref(&pclient->program_output);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->output != NULL)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_unref(&pclient->output);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->seekable_output != NULL)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_unref(&pclient->seekable_output);
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&pclient->io);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_free(pclient->temp_prefix);
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi if (pclient->destroy != NULL)
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi pclient->destroy(pclient);
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pool_unref(&pclient->pool);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomivoid program_client_switch_ioloop(struct program_client *pclient)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi{
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi if (pclient->input != NULL)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi i_stream_switch_ioloop(pclient->input);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi if (pclient->program_input != NULL)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi i_stream_switch_ioloop(pclient->program_input);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi if (pclient->seekable_output != NULL)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi i_stream_switch_ioloop(pclient->seekable_output);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi if (pclient->output != NULL)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi o_stream_switch_ioloop(pclient->output);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi if (pclient->program_output != NULL)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi o_stream_switch_ioloop(pclient->program_output);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi if (pclient->to != NULL)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi pclient->to = io_loop_move_timeout(&pclient->to);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi if (pclient->io != NULL)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi pclient->io = io_loop_move_io(&pclient->io);
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi pclient->switch_ioloop(pclient);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi}
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainenint program_client_create(const char *uri, const char *const *args,
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen const struct program_client_settings *set,
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen bool noreply, struct program_client **pc_r,
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen const char **error_r)
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi{
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi if (strncmp(uri, "exec:", 5) == 0) {
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen *pc_r = program_client_local_create(
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi uri+5,
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi args,
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi set);
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen return 0;
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi } else if (strncmp(uri, "unix:", 5) == 0) {
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen *pc_r = program_client_unix_create(
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi uri+5,
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi args,
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi set, noreply);
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen return 0;
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi } else if (strncmp(uri, "tcp:", 4) == 0) {
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi const char *host;
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi in_port_t port;
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi if (net_str2hostport(uri+4, 0, &host, &port) < 0 || port == 0) {
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen *error_r = t_strdup_printf(
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen "Invalid tcp syntax, must be host:port in '%s'", uri+4);
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen return -1;
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi }
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen *pc_r = program_client_net_create(
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi host, port,
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi args,
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi set, noreply);
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen return 0;
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi } else {
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen *error_r = t_strdup_printf(
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen "Unsupported program client scheme '%s'",
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen t_strcut(uri, ':'));
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen return -1;
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi }
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi}
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomistatic
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomivoid program_client_run_callback(int result, int *context)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi{
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi *context = result;
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi io_loop_stop(current_ioloop);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi}
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_run(struct program_client *pclient)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi{
004be038dfe290f71e3d4a4b14d88673e8b55fb2Timo Sirainen int ret = -2;
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi struct ioloop *prev_ioloop = current_ioloop;
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi struct ioloop *ioloop = io_loop_create();
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi program_client_switch_ioloop(pclient);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi program_client_run_async(pclient, program_client_run_callback, &ret);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi
004be038dfe290f71e3d4a4b14d88673e8b55fb2Timo Sirainen if (ret == -2) {
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi io_loop_run(ioloop);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi }
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi io_loop_set_current(prev_ioloop);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi program_client_switch_ioloop(pclient);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi io_loop_set_current(ioloop);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi io_loop_destroy(&ioloop);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi if (pclient->error != PROGRAM_CLIENT_ERROR_NONE)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi return -1;
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi return pclient->exit_code;
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi}
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi#undef program_client_run_async
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_run_async(struct program_client *pclient,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi program_client_callback_t *callback,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi void *context)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi i_assert(callback != NULL);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->disconnected = FALSE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->exit_code = 1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->error = PROGRAM_CLIENT_ERROR_NONE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi pclient->callback = callback;
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi pclient->context = context;
67574bb43936e39d5be32626e986df6e787a296fAki Tuomi if (program_client_connect(pclient) < 0)
67574bb43936e39d5be32626e986df6e787a296fAki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}