bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "lib.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "strfuncs.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "str.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "array.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "istream.h"
d04f3e064ceb2ba1d734182937a7115739ebadbeTimo Sirainen#include "istream-sized.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "ostream.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "imap-url.h"
e98e8ba55a01427844b2d24becd791dde8b0178bTimo Sirainen#include "imap-quote.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "imap-common.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "imap-commands.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "imap-urlauth.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "imap-urlauth-fetch.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstruct cmd_urlfetch_context {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_urlauth_fetch *ufetch;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct istream *input;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool failed:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool finished:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool extended:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool in_io_handler:1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch};
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstruct cmd_urlfetch_url {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *url;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch enum imap_urlauth_fetch_flags flags;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch};
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
84a31ddebcf8c3aeaef7b9e54171a48ee1374c45Timo Sirainenstatic void cmd_urlfetch_finish(struct client_command_context *cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct cmd_urlfetch_context *ctx =
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (struct cmd_urlfetch_context *)cmd->context;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ctx->finished)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ctx->finished = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&ctx->input);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ctx->ufetch != NULL)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_urlauth_fetch_deinit(&ctx->ufetch);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ctx->failed) {
d2dd9b7365c8efb4e205d521c9d66758dbf7300aTimo Sirainen if (cmd->client->output_cmd_lock == cmd) {
d2dd9b7365c8efb4e205d521c9d66758dbf7300aTimo Sirainen /* failed in the middle of a literal.
d2dd9b7365c8efb4e205d521c9d66758dbf7300aTimo Sirainen we need to disconnect. */
d2dd9b7365c8efb4e205d521c9d66758dbf7300aTimo Sirainen cmd->client->output_cmd_lock = NULL;
d2dd9b7365c8efb4e205d521c9d66758dbf7300aTimo Sirainen client_disconnect(cmd->client, "URLFETCH failed");
d2dd9b7365c8efb4e205d521c9d66758dbf7300aTimo Sirainen } else {
d2dd9b7365c8efb4e205d521c9d66758dbf7300aTimo Sirainen client_send_internal_error(cmd);
d2dd9b7365c8efb4e205d521c9d66758dbf7300aTimo Sirainen }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_tagline(cmd, "OK URLFETCH completed.");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic bool cmd_urlfetch_cancel(struct client_command_context *cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct cmd_urlfetch_context *ctx =
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (struct cmd_urlfetch_context *)cmd->context;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!cmd->cancel)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ctx->ufetch != NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (cmd->client->user->mail_debug) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_debug("URLFETCH: Canceling command; "
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "aborting URLAUTH fetch requests prematurely");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_urlauth_fetch_deinit(&ctx->ufetch);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int cmd_urlfetch_transfer_literal(struct client_command_context *cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct client *client = cmd->client;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct cmd_urlfetch_context *ctx =
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (struct cmd_urlfetch_context *)cmd->context;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen enum ostream_send_istream_result res;
c1b9c4531186c6a7cd92d2c353273a834f8ee66fTimo Sirainen int ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* are we in the middle of an urlfetch literal? */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ctx->input == NULL)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* flush output to client if buffer is filled above optimum */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (o_stream_get_buffer_used_size(client->output) >=
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch CLIENT_OUTPUT_OPTIMAL_SIZE) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((ret = o_stream_flush(client->output)) <= 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* transfer literal to client */
84a31ddebcf8c3aeaef7b9e54171a48ee1374c45Timo Sirainen o_stream_set_max_buffer_size(client->output, 0);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen res = o_stream_send_istream(client->output, ctx->input);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch o_stream_set_max_buffer_size(client->output, (size_t)-1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen switch (res) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
84a31ddebcf8c3aeaef7b9e54171a48ee1374c45Timo Sirainen i_stream_unref(&ctx->input);
84a31ddebcf8c3aeaef7b9e54171a48ee1374c45Timo Sirainen return 1;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_unreached();
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return 0;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
6a67bcb469c615bd750542439b3242112aa50412Timo Sirainen i_error("read(%s) failed: %s (URLFETCH)",
6a67bcb469c615bd750542439b3242112aa50412Timo Sirainen i_stream_get_name(ctx->input),
6a67bcb469c615bd750542439b3242112aa50412Timo Sirainen i_stream_get_error(ctx->input));
84a31ddebcf8c3aeaef7b9e54171a48ee1374c45Timo Sirainen client_disconnect(client, "URLFETCH failed");
84a31ddebcf8c3aeaef7b9e54171a48ee1374c45Timo Sirainen return -1;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* client disconnected */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return -1;
84a31ddebcf8c3aeaef7b9e54171a48ee1374c45Timo Sirainen }
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_unreached();
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic bool cmd_urlfetch_continue(struct client_command_context *cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct client *client = cmd->client;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct cmd_urlfetch_context *ctx =
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (struct cmd_urlfetch_context *)cmd->context;
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch bool urls_pending;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch int ret = 1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (cmd->cancel)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return cmd_urlfetch_cancel(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(client->output_cmd_lock == NULL ||
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->output_cmd_lock == cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* finish a pending literal transfer */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ret = cmd_urlfetch_transfer_literal(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ret < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ctx->failed = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd_urlfetch_finish(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ret == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* not finished; apparently output blocked again */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ctx->extended)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_line(client, ")");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch else
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_line(client, "");
d2dd9b7365c8efb4e205d521c9d66758dbf7300aTimo Sirainen client->output_cmd_lock = NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch ctx->in_io_handler = TRUE;
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch urls_pending = imap_urlauth_fetch_continue(ctx->ufetch);
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch ctx->in_io_handler = FALSE;
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch if (urls_pending) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* waiting for imap urlauth service */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->state = CLIENT_COMMAND_STATE_WAIT_EXTERNAL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->func = cmd_urlfetch_cancel;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* retrieve next url */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* finished */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd_urlfetch_finish(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
31281f7ff3c17c3971de99cee666bb1c19f85627Aki Tuomistatic int cmd_urlfetch_url_success(struct client_command_context *cmd,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_urlauth_fetch_reply *reply)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct cmd_urlfetch_context *ctx = cmd->context;
b32b2375b68fed551b4efd786d1640f7d42bcebcTimo Sirainen string_t *response = t_str_new(256);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch int ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
b32b2375b68fed551b4efd786d1640f7d42bcebcTimo Sirainen str_append(response, "* URLFETCH ");
b32b2375b68fed551b4efd786d1640f7d42bcebcTimo Sirainen imap_append_astring(response, reply->url);
b32b2375b68fed551b4efd786d1640f7d42bcebcTimo Sirainen
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((reply->flags & IMAP_URLAUTH_FETCH_FLAG_EXTENDED) == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* simple */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ctx->extended = FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
b32b2375b68fed551b4efd786d1640f7d42bcebcTimo Sirainen str_printfa(response, " {%"PRIuUOFF_T"}", reply->size);
b32b2375b68fed551b4efd786d1640f7d42bcebcTimo Sirainen client_send_line(cmd->client, str_c(response));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(reply->size == 0 || reply->input != NULL);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch bool metadata = FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* extended */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ctx->extended = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append(response, " (");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((reply->flags & IMAP_URLAUTH_FETCH_FLAG_BODYPARTSTRUCTURE) != 0 &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch reply->bodypartstruct != NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append(response, "BODYPARTSTRUCTURE (");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append(response, reply->bodypartstruct);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_c(response, ')');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch metadata = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((reply->flags & IMAP_URLAUTH_FETCH_FLAG_BODY) != 0 ||
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (reply->flags & IMAP_URLAUTH_FETCH_FLAG_BINARY) != 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (metadata)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_c(response, ' ');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((reply->flags & IMAP_URLAUTH_FETCH_FLAG_BODY) != 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append(response, "BODY ");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append(response, "BINARY ");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (reply->binary_has_nuls)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_c(response, '~');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_printfa(response, "{%"PRIuUOFF_T"}", reply->size);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(reply->size == 0 || reply->input != NULL);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_c(response, ')');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ctx->extended = FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_line(cmd->client, str_c(response));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (reply->input != NULL) {
d04f3e064ceb2ba1d734182937a7115739ebadbeTimo Sirainen ctx->input = i_stream_create_sized(reply->input, reply->size);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ret = cmd_urlfetch_transfer_literal(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ret < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ctx->failed = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ret == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* not finished; apparently output blocked */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->func = cmd_urlfetch_continue;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->client->output_cmd_lock = cmd;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ctx->extended)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_line(cmd->client, ")");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch else
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_line(cmd->client, "");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschcmd_urlfetch_url_callback(struct imap_urlauth_fetch_reply *reply,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch bool last, void *context)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct client_command_context *cmd = context;
e4d51d29f9591e6efea8b34da4ec9a6c0ed557d2Timo Sirainen struct client *client = cmd->client;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct cmd_urlfetch_context *ctx = cmd->context;
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch bool in_io_handler = ctx->in_io_handler;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch int ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch if (!in_io_handler)
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch o_stream_cork(client->output);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (reply == NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* fatal failure */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ctx->failed = TRUE;
dfc3a20b33f265b54746c9c2768b997d5e1cf15eTimo Sirainen ret = -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else if (reply->succeeded) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* URL fetch succeeded */
31281f7ff3c17c3971de99cee666bb1c19f85627Aki Tuomi ret = cmd_urlfetch_url_success(cmd, reply);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* URL fetch failed */
b32b2375b68fed551b4efd786d1640f7d42bcebcTimo Sirainen string_t *response = t_str_new(128);
b32b2375b68fed551b4efd786d1640f7d42bcebcTimo Sirainen
b32b2375b68fed551b4efd786d1640f7d42bcebcTimo Sirainen str_append(response, "* URLFETCH ");
b32b2375b68fed551b4efd786d1640f7d42bcebcTimo Sirainen imap_append_astring(response, reply->url);
b32b2375b68fed551b4efd786d1640f7d42bcebcTimo Sirainen str_append(response, " NIL");
e4d51d29f9591e6efea8b34da4ec9a6c0ed557d2Timo Sirainen client_send_line(client, str_c(response));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (reply->error != NULL) {
e4d51d29f9591e6efea8b34da4ec9a6c0ed557d2Timo Sirainen client_send_line(client, t_strdup_printf(
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "* NO %s.", reply->error));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
dfc3a20b33f265b54746c9c2768b997d5e1cf15eTimo Sirainen ret = 1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
dfc3a20b33f265b54746c9c2768b997d5e1cf15eTimo Sirainen if ((last && cmd->state == CLIENT_COMMAND_STATE_WAIT_EXTERNAL) ||
dfc3a20b33f265b54746c9c2768b997d5e1cf15eTimo Sirainen ret < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd_urlfetch_finish(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_command_free(&cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch if (!in_io_handler)
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch o_stream_uncork(client->output);
dfc3a20b33f265b54746c9c2768b997d5e1cf15eTimo Sirainen return ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschcmd_urlfetch_parse_arg(struct client_command_context *cmd,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct imap_arg *arg,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct cmd_urlfetch_url *ufurl_r)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch enum imap_urlauth_fetch_flags url_flags = 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct imap_arg *params;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *url_text;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (imap_arg_get_list(arg, &params))
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch url_flags |= IMAP_URLAUTH_FETCH_FLAG_EXTENDED;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch else
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch params = arg;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* read url */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!imap_arg_get_astring(params++, &url_text)) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_command_error(cmd, "Invalid arguments.");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ufurl_r->url = t_strdup(url_text);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (url_flags == 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch while (!IMAP_ARG_IS_EOL(params)) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *fetch_param;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!imap_arg_get_atom(params++, &fetch_param)) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_command_error(cmd,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "Invalid URL fetch parameter.");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (strcasecmp(fetch_param, "BODY") == 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch url_flags |= IMAP_URLAUTH_FETCH_FLAG_BODY;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch else if (strcasecmp(fetch_param, "BINARY") == 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch url_flags |= IMAP_URLAUTH_FETCH_FLAG_BINARY;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch else if (strcasecmp(fetch_param, "BODYPARTSTRUCTURE") == 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch url_flags |= IMAP_URLAUTH_FETCH_FLAG_BODYPARTSTRUCTURE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_command_error(cmd,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch t_strdup_printf("Unknown URL fetch parameter: %s",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch fetch_param));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((url_flags & IMAP_URLAUTH_FETCH_FLAG_BODY) != 0 &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (url_flags & IMAP_URLAUTH_FETCH_FLAG_BINARY) != 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_command_error(cmd,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "URL cannot have both BODY and BINARY fetch parameters.");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (url_flags == IMAP_URLAUTH_FETCH_FLAG_EXTENDED)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch url_flags |= IMAP_URLAUTH_FETCH_FLAG_BODY;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ufurl_r->flags = url_flags;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschbool cmd_urlfetch(struct client_command_context *cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct client *client = cmd->client;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct cmd_urlfetch_context *ctx;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ARRAY(struct cmd_urlfetch_url) urls;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct cmd_urlfetch_url *url;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct imap_arg *args;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct cmd_urlfetch_url *ufurl;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (client->urlauth_ctx == NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_command_error(cmd, "URLAUTH disabled.");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!client_read_args(cmd, 0, 0, &args))
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (IMAP_ARG_IS_EOL(args)) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_command_error(cmd, "Invalid arguments.");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch t_array_init(&urls, 32);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* parse url arguments and group them per userid */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch for (; !IMAP_ARG_IS_EOL(args); args++) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ufurl = array_append_space(&urls);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (cmd_urlfetch_parse_arg(cmd, args, ufurl) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->context = ctx = p_new(cmd->pool, struct cmd_urlfetch_context, 1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->func = cmd_urlfetch_cancel;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->state = CLIENT_COMMAND_STATE_WAIT_INPUT;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ctx->ufetch = imap_urlauth_fetch_init(client->urlauth_ctx,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd_urlfetch_url_callback, cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch ctx->in_io_handler = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch array_foreach(&urls, url) {
620b60321d04006b32a116824d49b88b61be7131Stephan Bosch if (imap_urlauth_fetch_url(ctx->ufetch, url->url, url->flags) < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* fatal error */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ctx->failed = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
d3a3d31d1eb77c4d040ce77c9cd7babe3003901aStephan Bosch ctx->in_io_handler = FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
620b60321d04006b32a116824d49b88b61be7131Stephan Bosch if ((ctx->failed || !imap_urlauth_fetch_is_pending(ctx->ufetch))
620b60321d04006b32a116824d49b88b61be7131Stephan Bosch && cmd->client->output_cmd_lock != cmd) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* finished */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd_urlfetch_finish(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (cmd->client->output_cmd_lock != cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->state = CLIENT_COMMAND_STATE_WAIT_EXTERNAL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}