void HandlePollCompleteResponse(
        FSM & fsm,
        const mf::api::upload::poll_upload::Response & response
    )
{
    if (response.quickkey)
    {
        if (response.filename)
        {
            // Filename was changed
            fsm.ProcessEvent(event::PollComplete{
                *response.quickkey,
                *response.filename
                });
        }
        else
        {
            fsm.ProcessEvent(event::PollComplete{
                *response.quickkey,
                fsm.filename()
                });
        }
    }
    else
    {
        fsm.ProcessEvent(event::Error{
            make_error_code(api::api_code::ContentInvalidData),
            "Successful response missing quickkey"
            });
    }
}
void HandlePollResponse(const std::string & upload_key,
                        FSM & fsm,
                        const mf::api::upload::poll_upload::Response & response)
{
    if (!response.response_data)
    {
        auto timer = fsm.Timer();

        timer->expires_from_now(
                std::chrono::seconds(poll_upload_retry_timeout_seconds));

        timer->async_wait(boost::bind(&RetryPoll<FSM>, upload_key,
                                      fsm.AsFrontShared(),
                                      boost::asio::placeholders::error));
    }
    else
    {
        const auto & response_data = *response.response_data;
        // if result is negative, it indicates a failure
        if (response_data.result < 0)
        {
            fsm.ProcessEvent(
                    event::Error{std::error_code(response_data.result,
                                                 poll_result_category()),
                                 "Poll upload bad response"});
        }
        else if (response_data.fileerror != 0)
        {
            fsm.ProcessEvent(event::Error{
                    std::error_code(response_data.fileerror,
                                    poll_upload_file_error_category()),
                    "Poll upload file error received"});
        }
        else if (response_data.quickkey)
        {
            HandlePollCompleteResponse(fsm, response);
        }
        else
        {
            auto timer = fsm.Timer();

            timer->expires_from_now(
                    std::chrono::seconds(poll_upload_retry_timeout_seconds));

            timer->async_wait(boost::bind(&RetryPoll<FSM>, upload_key,
                                          fsm.AsFrontShared(),
                                          boost::asio::placeholders::error));
        }
    }
}
void HandlePollCompleteResponse(
        FSM & fsm,
        const mf::api::upload::poll_upload::Response & response)
{
    assert(response.response_data);
    const auto & response_data = *response.response_data;

    if (!response_data.quickkey)
    {
        fsm.ProcessEvent(
                event::Error{make_error_code(api::api_code::ContentInvalidData),
                             "Successful response missing quickkey"});
    }
    else if (!response_data.revision)
    {
        fsm.ProcessEvent(
                event::Error{make_error_code(api::api_code::ContentInvalidData),
                             "Successful response missing revision"});
    }
    else
    {
        if (response_data.filename)
        {
            // Filename was changed
            fsm.ProcessEvent(event::PollComplete{*response_data.quickkey,
                                                 *response_data.filename,
                                                 *response_data.revision});
        }
        else
        {
            fsm.ProcessEvent(event::PollComplete{*response_data.quickkey,
                                                 fsm.filename(),
                                                 *response_data.revision});
        }
    }
}
void StartPoll(const std::string & upload_key, FSM & fsm)
{
    if (upload_key.empty())
    {
        assert(!"Reached poll upload without upload key");
        fsm.ProcessEvent(
                event::Error{make_error_code(uploader::errc::LogicError),
                             "Filsize unavailable."});
        return;
    }

    auto fsmp = fsm.AsFrontShared();

    fsm.GetSessionMaintainer()->Call(
            mf::api::upload::poll_upload::Request(upload_key),
            [fsmp, upload_key](
                    const mf::api::upload::poll_upload::Response & response)
            {
                HandlePollResponse(upload_key, *fsmp, response);
            });
}