# # # patch "cmd_automate.cc" # from [43f845ec3a6bf52d128f668f5b8bc671ee404ad7] # to [7f69cbb88920c6447952def2e84f13279d086977] # # patch "netcmd.cc" # from [f072c3a9f31c0a9b9ed8b8d84ec821c707e1ec4d] # to [2e20e0fd6908636771d11d4c984f33a8384b5e3e] # # patch "netcmd.hh" # from [d866df26f476f548f19a66165c64b0821f898b5a] # to [72ba96d114ba44ede161eafafcef43d9ebeb0946] # # patch "network/automate_session.cc" # from [502cdaa823c110fdaa6fcf9432a7ccf49c1ddfca] # to [8f4f14eec76351d1fcd5571ebbd25b228bb02800] # # patch "network/automate_session.hh" # from [1db9aaf5f363e0ca92826df64c36cc0678b157a0] # to [24767870966b9f24b4f1544c29900876e1c22c60] # ============================================================ --- cmd_automate.cc 43f845ec3a6bf52d128f668f5b8bc671ee404ad7 +++ cmd_automate.cc 7f69cbb88920c6447952def2e84f13279d086977 @@ -171,12 +171,15 @@ CMD_AUTOMATE_NO_STDIO(stdio, "", &os._M_autobuf); while (true) { - command const * cmd = 0; + automate const * acmd = 0; command_id id; args_vector args; + // FIXME: what follows is largely duplicated + // in network/automate_session.cc::do_work() + // // stdio decoding errors should be noted with errno 1, - // errno 2 is reserved for errors coming from the commands itself + // errno 2 is reserved for errors from the commands itself try { if (!ar.get_command(params, cmdline)) @@ -209,9 +212,15 @@ CMD_AUTOMATE_NO_STDIO(stdio, "", for (command_id::size_type i = 0; i < id.size(); i++) args.erase(args.begin()); - cmd = CMD_REF(automate)->find_command(id); + command const * cmd = CMD_REF(automate)->find_command(id); I(cmd != NULL); + acmd = dynamic_cast< automate const * >(cmd); + I(acmd != NULL); + + E(acmd->can_run_from_stdio(), origin::network, + F("sorry, that can't be run remotely or over stdio")); + if (cmd->use_workspace_options()) { // Re-read the ws options file, rather than just copying @@ -250,18 +259,11 @@ CMD_AUTOMATE_NO_STDIO(stdio, "", try { - automate const * acmd = dynamic_cast< automate const * >(cmd); - I(acmd); - - E(acmd->can_run_from_stdio(), origin::network, - F("sorry, that can't be run remotely or over stdio")); - acmd->exec_from_automate(app, id, args, os); - // set app.opts to the originally given options - // so the next command has an identical setup + // restore app.opts app.opts = original_opts; } - catch(recoverable_failure & f) + catch (recoverable_failure & f) { os.set_err(2); os._M_autobuf.write_out_of_band('e', f.what()); ============================================================ --- netcmd.cc f072c3a9f31c0a9b9ed8b8d84ec821c707e1ec4d +++ netcmd.cc 2e20e0fd6908636771d11d4c984f33a8384b5e3e @@ -669,7 +669,7 @@ netcmd::read_automate_packet_cmd(int & c void netcmd::read_automate_packet_cmd(int & command_num, int & err_code, - bool & last, + char & stream, string & packet_data) const { size_t pos = 0; @@ -678,8 +678,8 @@ netcmd::read_automate_packet_cmd(int & c "automate_packet netcmd, command_num")); err_code = int(extract_datum_uleb128(payload, pos, "automate_packet netcmd, err_code")); - last = (extract_datum_uleb128(payload, pos, - "automate_packet netcmd, last") == 1); + stream = char(extract_datum_uleb128(payload, pos, + "automate_packet netcmd, stream")); extract_variable_length_string(payload, packet_data, pos, "automate_packet netcmd, packet_data"); assert_end_of_buffer(payload, pos, "automate_packet netcmd payload"); @@ -688,14 +688,14 @@ netcmd::write_automate_packet_cmd(int co void netcmd::write_automate_packet_cmd(int command_num, int err_code, - bool last, + char stream, string const & packet_data) { cmd_code = automate_packet_cmd; insert_datum_uleb128(size_t(command_num), payload); insert_datum_uleb128(size_t(err_code), payload); - insert_datum_uleb128(last?1:0, payload); + insert_datum_uleb128(size_t(stream), payload); insert_variable_length_string(packet_data, payload); } ============================================================ --- netcmd.hh d866df26f476f548f19a66165c64b0821f898b5a +++ netcmd.hh 72ba96d114ba44ede161eafafcef43d9ebeb0946 @@ -214,11 +214,11 @@ public: std::vector > const & opts); void read_automate_packet_cmd(int & command_num, int & err_code, - bool & last, + char & stream, std::string & packet_data) const; void write_automate_packet_cmd(int command_num, int err_code, - bool last, + char stream, std::string const & packet_data); void read_usher_cmd(utf8 & greeting) const; ============================================================ --- network/automate_session.cc 502cdaa823c110fdaa6fcf9432a7ccf49c1ddfca +++ network/automate_session.cc 8f4f14eec76351d1fcd5571ebbd25b228bb02800 @@ -12,8 +12,9 @@ #include "app_state.hh" #include "automate_reader.hh" -#include "work.hh" +#include "ui.hh" #include "vocab_cast.hh" +#include "work.hh" using std::make_pair; using std::ostringstream; @@ -91,6 +92,22 @@ void automate_session::prepare_to_confir remote_identity = remote_key; } +static void out_of_band_to_netcmd(char stream, std::string const & text, void * opaque) +{ + automate_session * sess = reinterpret_cast(opaque); + // FIXME: is it really correct to set the error always to 0? + sess->write_out_of_band_cmd(stream, text, 0); +} + +void automate_session::write_out_of_band_cmd(char stream, + std::string const & text, + unsigned int errcode) +{ + netcmd net_cmd(get_version()); + net_cmd.write_automate_packet_cmd(command_number, errcode, stream, text); + write_netcmd(net_cmd); +} + bool automate_session::do_work(transaction_guard & guard, netcmd const * const cmd_in) { @@ -101,15 +118,27 @@ bool automate_session::do_work(transacti { case automate_command_cmd: { + options original_opts = app.opts; + vector in_args; vector > in_opts; cmd_in->read_automate_command_cmd(in_args, in_opts); ++command_number; + global_sanity.set_out_of_band_handler(&out_of_band_to_netcmd, this); + + automate const * acmd = 0; + command_id id; + args_vector args; + ostringstream oss; bool have_err = false; - string err; + // FIXME: what follows is largely duplicated + // in cmd_automate.cc::CMD(stdio) + // + // stdio decoding errors should be noted with errno 1, + // errno 2 is reserved for errors from the commands itself try { E(app.lua.hook_get_remote_automate_permitted(remote_identity, @@ -118,7 +147,6 @@ bool automate_session::do_work(transacti origin::user, F("Sorry, you aren't allowed to do that.")); - args_vector args; for (vector::iterator i = in_args.begin(); i != in_args.end(); ++i) { @@ -129,7 +157,6 @@ bool automate_session::do_work(transacti opts = options::opts::all_options() - options::opts::globals(); opts.instantiate(&app.opts).reset(); - command_id id; for (args_vector::const_iterator iter = args.begin(); iter != args.end(); iter++) id.push_back(typecast_vocab(*iter)); @@ -165,8 +192,8 @@ bool automate_session::do_work(transacti command const * cmd = CMD_REF(automate)->find_command(id); I(cmd != NULL); - automate const * acmd = dynamic_cast< automate const * >(cmd); - I(acmd); + acmd = dynamic_cast< automate const * >(cmd); + I(acmd != NULL); E(acmd->can_run_from_stdio(), origin::network, F("sorry, that can't be run remotely or over stdio")); @@ -183,30 +210,45 @@ bool automate_session::do_work(transacti } opts.instantiate(&app.opts).from_key_value_pairs(in_opts); - acmd->exec_from_automate(app, id, args, oss); + + ui.set_tick_write_stdio(); } - catch (recoverable_failure & f) + // FIXME: we need to re-package and rethrow this special exception + // since it is not based on informative_failure + catch (option::option_error & e) { + write_out_of_band_cmd('e', e.what(), 1); have_err = true; - err = f.what(); - err += "\n"; } - - if (!oss.str().empty() || !have_err) + catch (recoverable_failure & f) { - netcmd out_cmd(get_version()); - out_cmd.write_automate_packet_cmd(command_number, 0, - !have_err, oss.str()); - write_netcmd(out_cmd); + write_out_of_band_cmd('e', f.what(), 1); + have_err = true; } - if (have_err) + + if (!have_err) { - netcmd err_cmd(get_version()); - err_cmd.write_automate_packet_cmd(command_number, 2, - true, err); - write_netcmd(err_cmd); + try + { + acmd->exec_from_automate(app, id, args, oss); + // restore app.opts + app.opts = original_opts; + } + catch (recoverable_failure & f) + { + write_out_of_band_cmd('e', f.what(), 2); + have_err = true; + } } + netcmd out_cmd(get_version()); + out_cmd.write_automate_packet_cmd( + command_number, have_err ? 2 : 0, 'l', oss.str() + ); + write_netcmd(out_cmd); + + global_sanity.set_out_of_band_handler(); + return true; } @@ -214,20 +256,25 @@ bool automate_session::do_work(transacti { int command_num; int err_code; - bool last; + char stream; string packet_data; cmd_in->read_automate_packet_cmd(command_num, err_code, - last, packet_data); + stream, packet_data); I(output_stream); output_stream->set_err(err_code); - (*output_stream) << packet_data; - if (last) - output_stream->end_cmd(); - if (last) - send_command(); + if (stream == 'm' || stream == 'l') + (*output_stream) << packet_data; + else + output_stream->_M_autobuf.write_out_of_band(stream, packet_data); + if (stream == 'l') + { + output_stream->end_cmd(); + send_command(); + } + return true; } default: ============================================================ --- network/automate_session.hh 1db9aaf5f363e0ca92826df64c36cc0678b157a0 +++ network/automate_session.hh 24767870966b9f24b4f1544c29900876e1c22c60 @@ -38,9 +38,12 @@ public: std::istream * const is, automate_ostream * const os); + void write_out_of_band_cmd(char stream, + std::string const & text, + unsigned int errcode); bool do_work(transaction_guard & guard, netcmd const * const in_cmd); - bool have_work() const; + bool have_work() const; void request_service(); void accept_service(); std::string usher_reply_data() const;