void send_fastpath_data(InStream & data) { StaticOutStream<TRANSPARENT_CHUNK_HEADER_SIZE> header; this->make_chunk_header(header, CHUNK_TYPE_FASTPATH, data.get_capacity()); assert(header.get_offset() == header.get_capacity()); this->t->send(header.get_data(), header.get_capacity()); this->t->send(data.get_data(), data.get_capacity()); }
void CopyPaste::send_to_mod_channel(InStream & chunk, uint32_t flags) { InStream stream(chunk.get_data(), chunk.get_capacity()); if (this->long_data_response_size) { size_t available_data_length = std::min<size_t>(this->long_data_response_size, stream.in_remain()); // if (this->long_data_response_size < stream.in_remain()) { // LOG( LOG_ERR // , "CopyPaste::send_to_mod_channel truncated CB_FORMAT_DATA_RESPONSE dataU16, need=%u remains=%u" // , this->long_data_response_size, stream.in_remain()); // throw Error(ERR_RDP_PROTOCOL); // } if (available_data_length) { // this->long_data_response_size -= stream.in_remain(); this->long_data_response_size -= available_data_length; // this->clipboard_str_.utf16_push_back(stream.p, stream.in_remain() / 2); this->clipboard_str_.utf16_push_back(stream.get_current(), available_data_length / 2); } // if (!this->long_data_response_size && this->paste_edit_) { if ((flags & CHANNELS::CHANNEL_FLAG_LAST) != 0) { if (this->paste_edit_) { this->paste_edit_->insert_text(this->clipboard_str_.c_str()); this->paste_edit_ = nullptr; } this->long_data_response_size = 0; } return ; } RDPECLIP::RecvPredictor rp(stream); switch (rp.msgType()) { case RDPECLIP::CB_FORMAT_LIST: { RDPECLIP::CliprdrHeader clipboard_header; clipboard_header.recv(stream); RDPECLIP::FormatListPDUEx format_list_pdu; const bool use_long_format_names = false; const bool in_ASCII_8 = (clipboard_header.msgFlags() & RDPECLIP::CB_ASCII_NAMES); format_list_pdu.recv(stream, use_long_format_names, in_ASCII_8); RDPECLIP::FormatListResponsePDU pdu; RDPECLIP::CliprdrHeader header(RDPECLIP::CB_FORMAT_LIST_RESPONSE, RDPECLIP::CB_RESPONSE_OK, pdu.size()); StaticOutStream<256> out_s; header.emit(out_s); pdu.emit(out_s); const size_t length = out_s.get_offset(); const size_t chunk_size = length; this->front_->send_to_channel( *this->channel_, out_s.get_data(), length, chunk_size, CHANNELS::CHANNEL_FLAG_FIRST | CHANNELS::CHANNEL_FLAG_LAST | CHANNELS::CHANNEL_FLAG_SHOW_PROTOCOL ); this->has_clipboard_ = false; this->clipboard_str_.clear(); } break; //case RDPECLIP::CB_FORMAT_LIST_RESPONSE: // break; //case RDPECLIP::CB_FORMAT_DATA_REQUEST: // RDPECLIP::FormatDataRequestPDU().recv(stream); // this->send_to_front_channel_and_set_buf_size( // this->clipboard_str_.size() * 2 /*utf8 to utf16*/ + sizeof(RDPECLIP::CliprdrHeader) + 4 /*data_len*/, // RDPECLIP::FormatDataResponsePDU(true), this->clipboard_str_.c_str() // ); // break; case RDPECLIP::CB_FORMAT_DATA_RESPONSE: { RDPECLIP::CliprdrHeader header(RDPECLIP::CB_FORMAT_DATA_RESPONSE, RDPECLIP::CB_RESPONSE_FAIL, 0); // TODO: format data response PDU is bypassed and the raw data is managed directly // we should not do that but reassemble data response packet from PDU before pasting // see also condition on this->long_data_response_size // RDPECLIP::FormatDataResponsePDU format_data_response_pdu; header.recv(stream); // format_data_response_pdu.recv(stream); if (header.msgFlags() == RDPECLIP::CB_RESPONSE_OK) { if ((flags & CHANNELS::CHANNEL_FLAG_LAST) != 0) { if (!stream.in_check_rem(header.dataLen())) { LOG( LOG_ERR , "CopyPaste::send_to_mod_channel truncated CB_FORMAT_DATA_RESPONSE dataU16, need=%" PRIu32 " remains=%zu" , header.dataLen(), stream.in_remain()); throw Error(ERR_RDP_PROTOCOL); } this->clipboard_str_.utf16_push_back(stream.get_current(), header.dataLen() / 2); if (this->paste_edit_) { this->paste_edit_->insert_text(this->clipboard_str_.c_str()); this->paste_edit_ = nullptr; } this->has_clipboard_ = true; } else { // Virtual channel data span in multiple Virtual Channel PDUs. if ((flags & CHANNELS::CHANNEL_FLAG_FIRST) == 0) { LOG(LOG_ERR, "CopyPaste::send_to_mod_channel flag CHANNEL_FLAG_FIRST expected"); throw Error(ERR_RDP_PROTOCOL); } this->long_data_response_size = header.dataLen() - stream.in_remain(); this->clipboard_str_.utf16_push_back(stream.get_current(), stream.in_remain() / 2); } } break; } default: if (this->verbose) { LOG(LOG_INFO, "CopyPaste::send_to_mod_channel msgType=%u", unsigned(rp.msgType())); } break; } }