[client] spice: fixed copying large amounts of text to the clipboard

This commit is contained in:
Geoffrey McRae 2019-02-22 12:33:55 +11:00
parent 4098db039e
commit 0dfa7425c1

View File

@ -17,7 +17,6 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "spice.h" #include "spice.h"
#include "utils.h" #include "utils.h"
#include "debug.h" #include "debug.h"
@ -118,6 +117,10 @@ struct Spice
bool cbSupported; bool cbSupported;
bool cbSelection; bool cbSelection;
char *cbBuffer;
uint32_t cbRemain;
uint32_t cbSize;
}; };
// globals // globals
@ -140,9 +143,10 @@ bool spice_on_common_read (struct SpiceChannel * channel, SpiceMiniDataHe
bool spice_on_main_channel_read (); bool spice_on_main_channel_read ();
bool spice_on_inputs_channel_read(); bool spice_on_inputs_channel_read();
bool spice_agent_process (); bool spice_agent_process (uint32_t dataSize);
bool spice_agent_connect (); bool spice_agent_connect ();
bool spice_agent_send_caps(bool request); bool spice_agent_send_caps(bool request);
bool spice_agent_on_clipboard();
// thread safe read/write methods // thread safe read/write methods
bool spice_write_msg (struct SpiceChannel * channel, uint32_t type, const void * buffer, const ssize_t size); bool spice_write_msg (struct SpiceChannel * channel, uint32_t type, const void * buffer, const ssize_t size);
@ -546,6 +550,15 @@ bool spice_on_main_channel_read()
DEBUG_INFO("Spice agent disconnected, error: %u", error); DEBUG_INFO("Spice agent disconnected, error: %u", error);
spice.hasAgent = false; spice.hasAgent = false;
if (spice.cbBuffer)
{
free(spice.cbBuffer);
spice.cbBuffer = NULL;
spice.cbSize = 0;
spice.cbRemain = 0;
}
return true; return true;
} }
@ -560,7 +573,7 @@ bool spice_on_main_channel_read()
return true; return true;
} }
if (!spice_agent_process()) if (!spice_agent_process(header.size))
{ {
DEBUG_ERROR("failed to process spice agent message"); DEBUG_ERROR("failed to process spice agent message");
spice_disconnect(); spice_disconnect();
@ -569,6 +582,22 @@ bool spice_on_main_channel_read()
return true; return true;
} }
if (header.type == SPICE_MSG_MAIN_AGENT_TOKEN)
{
DEBUG_PROTO("SPICE_MSG_MAIN_AGENT_TOKEN");
uint32_t num_tokens;
if (!spice_read_nl(channel, &num_tokens, sizeof(num_tokens)))
{
DEBUG_ERROR("failed to read agent tokens");
spice_disconnect();
return false;
}
spice.serverTokens = num_tokens;
return true;
}
DEBUG_WARN("main channel unhandled message type %u", header.type); DEBUG_WARN("main channel unhandled message type %u", header.type);
spice_discard_nl(channel, header.size); spice_discard_nl(channel, header.size);
return true; return true;
@ -871,8 +900,30 @@ bool spice_agent_connect()
// ============================================================================ // ============================================================================
bool spice_agent_process() bool spice_agent_process(uint32_t dataSize)
{ {
if (spice.cbRemain)
{
const uint32_t r = spice.cbRemain > dataSize ? dataSize : spice.cbRemain;
if (!spice_read_nl(&spice.scMain, spice.cbBuffer + spice.cbSize, r))
{
DEBUG_ERROR("failed to read the clipboard data");
free(spice.cbBuffer);
spice.cbBuffer = NULL;
spice.cbRemain = 0;
spice.cbSize = 0;
return false;
}
spice.cbRemain -= r;
spice.cbSize += r;
if (spice.cbRemain == 0)
return spice_agent_on_clipboard();
return true;
}
VDAgentMessage msg; VDAgentMessage msg;
#pragma pack(push,1) #pragma pack(push,1)
@ -888,6 +939,7 @@ bool spice_agent_process()
DEBUG_ERROR("failed to read spice agent message"); DEBUG_ERROR("failed to read spice agent message");
return false; return false;
} }
dataSize -= sizeof(msg);
if (msg.protocol != VD_AGENT_PROTOCOL) if (msg.protocol != VD_AGENT_PROTOCOL)
{ {
@ -942,6 +994,7 @@ bool spice_agent_process()
return false; return false;
} }
remaining -= sizeof(selection); remaining -= sizeof(selection);
dataSize -= sizeof(selection);
} }
if (msg.type == VD_AGENT_CLIPBOARD_RELEASE) if (msg.type == VD_AGENT_CLIPBOARD_RELEASE)
@ -959,6 +1012,7 @@ bool spice_agent_process()
return false; return false;
} }
remaining -= sizeof(type); remaining -= sizeof(type);
dataSize -= sizeof(type);
if (msg.type == VD_AGENT_CLIPBOARD) if (msg.type == VD_AGENT_CLIPBOARD)
{ {
@ -969,29 +1023,33 @@ bool spice_agent_process()
return false; return false;
} }
char * text = malloc(remaining + 1); if (spice.cbBuffer)
if (!spice_read_nl(&spice.scMain, text, remaining))
{ {
DEBUG_ERROR("failed to read the clipboard data"); DEBUG_ERROR("cbBuffer was never freed");
free(text);
return false; return false;
} }
text[remaining] = '\0';
// dos2unix spice.cbSize = 0;
char * out = malloc(remaining + 1); spice.cbRemain = remaining;
char * p = out; spice.cbBuffer = (char *)malloc(remaining);
for(uint32_t i = 0; i < remaining; ++i) const uint32_t r = remaining > dataSize ? dataSize : remaining;
if (!spice_read_nl(&spice.scMain, spice.cbBuffer, r))
{ {
char c = text[i]; DEBUG_ERROR("failed to read the clipboard data");
if (c != '\r') free(spice.cbBuffer);
*p++ = c; spice.cbBuffer = NULL;
spice.cbRemain = 0;
spice.cbSize = 0;
return false;
} }
*p = '\0';
SDL_SetClipboardText(out);
free(text); spice.cbRemain -= r;
free(out); spice.cbSize += r;
if (spice.cbRemain == 0)
return spice_agent_on_clipboard();
return true; return true;
} }
else else
@ -1051,6 +1109,29 @@ bool spice_agent_process()
} }
// ============================================================================
bool spice_agent_on_clipboard()
{
// dos2unix
char * p = spice.cbBuffer;
for(uint32_t i = 0; i < spice.cbSize; ++i)
{
char c = spice.cbBuffer[i];
if (c != '\r')
*p++ = c;
}
*p = '\0';
SDL_SetClipboardText(spice.cbBuffer);
free(spice.cbBuffer);
spice.cbBuffer = NULL;
spice.cbSize = 0;
spice.cbRemain = 0;
return true;
}
// ============================================================================ // ============================================================================
bool spice_agent_send_caps(bool request) bool spice_agent_send_caps(bool request)