6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "lib.h"
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher#include "str.h"
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher#include "net.h"
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek#include "istream.h"
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek#include "write-full.h"
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek#include "module-context.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "rfc822-parser.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "rfc2231-parser.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "message-parser.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "mail-user.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "fts-parser.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define SCRIPT_USER_CONTEXT(obj) \
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek MODULE_CONTEXT(obj, fts_parser_script_user_module)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek#define SCRIPT_HANDSHAKE "VERSION\tscript\t4\t0\nalarm=10\nnoreply\n"
ad805face83ba7d67b1cf2067a1982c7e63d1060Jakub Hrozek
ad805face83ba7d67b1cf2067a1982c7e63d1060Jakub Hrozekstruct content {
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek const char *content_type;
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek const char *const *extensions;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher};
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstruct fts_parser_script_user {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher union mail_user_module_context module_ctx;
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek
36b56482ca1e53d832accef0354124fd79711172Jakub Hrozek ARRAY(struct content) content;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher};
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstruct script_fts_parser {
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek struct fts_parser parser;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek int fd;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek char *path;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek unsigned char outbuf[IO_BLOCK_SIZE];
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek bool failed;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek bool shutdown;
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek};
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic MODULE_CONTEXT_DEFINE_INIT(fts_parser_script_user_module,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher &mail_user_module_register);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int script_connect(struct mail_user *user, const char **path_r)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const char *path;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher int fd;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher path = mail_user_plugin_getenv(user, "fts_decoder");
f10ebaa51ecdcbbd10f171d19fe8e680e5bc74aaJakub Hrozek if (path == NULL)
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek return -1;
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek if (*path != '/')
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek path = t_strconcat(user->set->base_dir, "/", path, NULL);
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek fd = net_connect_unix_with_retries(path, 1000);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (fd == -1)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_error("net_connect_unix(%s) failed: %m", path);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher else
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher net_set_nonblock(fd, FALSE);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher *path_r = path;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return fd;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int script_contents_read(struct mail_user *user)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct fts_parser_script_user *suser = SCRIPT_USER_CONTEXT(user);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher const char *path, *cmd, *line;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher char **args;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher struct istream *input;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct content *content;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher bool eof_seen = FALSE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher int fd, ret = 0;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher i_assert(suser != NULL);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher fd = script_connect(user, &path);
f10ebaa51ecdcbbd10f171d19fe8e680e5bc74aaJakub Hrozek if (fd == -1)
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek return -1;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek cmd = t_strdup_printf(SCRIPT_HANDSHAKE"\n");
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek if (write_full(fd, cmd, strlen(cmd)) < 0) {
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek i_error("write(%s) failed: %m", path);
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek i_close_fd(&fd);
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek return -1;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek }
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek input = i_stream_create_fd_autoclose(&fd, 1024);
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek while ((line = i_stream_read_next_line(input)) != NULL) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* <content-type> <extension> [<extension> ...] */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher args = p_strsplit_spaces(user->pool, line, " ");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (args[0] == NULL) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher eof_seen = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher break;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (args[0][0] == '\0' || args[1] == NULL) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_error("parser script sent invalid input: %s", line);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher continue;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher content = array_append_space(&suser->content);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher content->content_type = args[0];
f10ebaa51ecdcbbd10f171d19fe8e680e5bc74aaJakub Hrozek content->extensions = (const void *)(args+1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (input->stream_errno != 0) {
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek i_error("parser script read(%s) failed: %s", path,
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek i_stream_get_error(input));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ret = -1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher } else if (!eof_seen) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (input->v_offset == 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher i_error("parser script didn't send any data");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher else
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_error("parser script didn't send empty EOF line");
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher i_stream_destroy(&input);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return ret;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic bool script_support_content(struct mail_user *user,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher const char **content_type,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const char *filename)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher struct fts_parser_script_user *suser = SCRIPT_USER_CONTEXT(user);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher const struct content *content;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher const char *extension;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (suser == NULL) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher suser = p_new(user->pool, struct fts_parser_script_user, 1);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher p_array_init(&suser->content, user->pool, 32);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher MODULE_CONTEXT_SET(user, fts_parser_script_user_module, suser);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (array_count(&suser->content) == 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (script_contents_read(user) < 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return FALSE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (strcmp(*content_type, "application/octet-stream") == 0) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (filename == NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher extension = strrchr(filename, '.');
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (extension == NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher extension = filename + 1;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher array_foreach(&suser->content, content) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (content->extensions != NULL &&
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher str_array_icase_find(content->extensions, extension)) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher *content_type = content->content_type;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher } else {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher array_foreach(&suser->content, content) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(content->content_type, *content_type) == 0)
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek return TRUE;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek }
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek }
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek return FALSE;
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic void parse_content_disposition(const char *content_disposition,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const char **filename_r)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek struct rfc822_parser_context parser;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek const char *const *results, *filename2;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek string_t *str;
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek *filename_r = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (content_disposition == NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek rfc822_parser_init(&parser, (const unsigned char *)content_disposition,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher strlen(content_disposition), NULL);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher rfc822_skip_lwsp(&parser);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* type; param; param; .. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher str = t_str_new(32);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (rfc822_parse_mime_token(&parser, str) < 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher rfc2231_parse(&parser, &results);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher filename2 = NULL;
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek for (; *results != NULL; results += 2) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (strcasecmp(results[0], "filename") == 0) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek *filename_r = results[1];
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek break;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcasecmp(results[0], "filename*") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher filename2 = results[1];
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (*filename_r == NULL) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* RFC 2231 style non-ascii filename. we don't really care
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher much about the filename actually, just about its extension */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher *filename_r = filename2;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic struct fts_parser *
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherfts_parser_script_try_init(struct fts_parser_context *parser_context)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct script_fts_parser *parser;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const char *filename, *path, *cmd;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher int fd;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher parse_content_disposition(parser_context->content_disposition, &filename);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!script_support_content(parser_context->user, &parser_context->content_type, filename))
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher fd = script_connect(parser_context->user, &path);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (fd == -1)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return NULL;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher cmd = t_strdup_printf(SCRIPT_HANDSHAKE"%s\n\n", parser_context->content_type);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (write_full(fd, cmd, strlen(cmd)) < 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_error("write(%s) failed: %m", path);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_close_fd(&fd);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher parser = i_new(struct script_fts_parser, 1);
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek parser->parser.v = fts_parser_script;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek parser->path = i_strdup(path);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher parser->fd = fd;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return &parser->parser;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic void fts_parser_script_more(struct fts_parser *_parser,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct message_block *block)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct script_fts_parser *parser = (struct script_fts_parser *)_parser;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher ssize_t ret;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (block->size > 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* first we'll send everything to the script */
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher if (!parser->failed &&
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher write_full(parser->fd, block->data, block->size) < 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_error("write(%s) failed: %m", parser->path);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher parser->failed = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher block->size = 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher } else {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!parser->shutdown) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (shutdown(parser->fd, SHUT_WR) < 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_error("shutdown(%s) failed: %m", parser->path);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher parser->shutdown = TRUE;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek }
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek /* read the result from the script */
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek ret = read(parser->fd, parser->outbuf, sizeof(parser->outbuf));
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (ret < 0)
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek i_error("read(%s) failed: %m", parser->path);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek else {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek block->data = parser->outbuf;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek block->size = ret;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek }
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek }
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek}
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozekstatic int fts_parser_script_deinit(struct fts_parser *_parser,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek const char **retriable_err_msg_r ATTR_UNUSED)
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek{
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek struct script_fts_parser *parser = (struct script_fts_parser *)_parser;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek int ret = parser->failed ? -1 : 1;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (close(parser->fd) < 0)
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek i_error("close(%s) failed: %m", parser->path);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek i_free(parser->path);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek i_free(parser);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek return ret;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek}
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozekstruct fts_parser_vfuncs fts_parser_script = {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek fts_parser_script_try_init,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek fts_parser_script_more,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek fts_parser_script_deinit,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek NULL
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek};
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek