Merge pull request #1996 from matt335672/investigate_paste_hang
Some copy-paste tidyups + Nautilus 3 compatibility (#1996)
This commit is contained in:
commit
85518a8157
@ -290,6 +290,14 @@ features:-
|
||||
.P
|
||||
- copying-and-pasting of files
|
||||
.RE
|
||||
.TP
|
||||
\fBUseNautilus3FlistFormat\fR=\fI[false|true]\fR
|
||||
Defaults to \fIfalse\fR.
|
||||
Set to \fItrue\fR to make file copy-paste compatible with Nautilus from
|
||||
GNOME 3 versions later than 3.29.92. Do not use this for any other reason.
|
||||
|
||||
This setting will be removed in a later version of xrdp, when GNOME 3 is
|
||||
no longer supported.
|
||||
|
||||
.SH "SESSIONS VARIABLES"
|
||||
All entries in the \fB[SessionVariables]\fR section are set as
|
||||
|
@ -39,7 +39,7 @@
|
||||
#define DEFAULT_ENABLE_FUSE_MOUNT 1
|
||||
#define DEFAULT_FUSE_MOUNT_NAME "xrdp-client"
|
||||
#define DEFAULT_FILE_UMASK 077
|
||||
|
||||
#define DEFAULT_USE_NAUTILUS3_FLIST_FORMAT 0
|
||||
/**
|
||||
* Type used for passing a logging function about
|
||||
*/
|
||||
@ -161,7 +161,7 @@ read_config_chansrv(log_func_t logmsg,
|
||||
{
|
||||
cfg->enable_fuse_mount = g_text2bool(value);
|
||||
}
|
||||
if (g_strcasecmp(name, "FuseMountName") == 0)
|
||||
else if (g_strcasecmp(name, "FuseMountName") == 0)
|
||||
{
|
||||
g_free(cfg->fuse_mount_name);
|
||||
cfg->fuse_mount_name = g_strdup(value);
|
||||
@ -176,6 +176,10 @@ read_config_chansrv(log_func_t logmsg,
|
||||
{
|
||||
cfg->file_umask = strtol(value, NULL, 0);
|
||||
}
|
||||
else if (g_strcasecmp(name, "UseNautilus3FlistFormat") == 0)
|
||||
{
|
||||
cfg->use_nautilus3_flist_format = g_text2bool(value);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
@ -206,6 +210,7 @@ new_config(void)
|
||||
cfg->restrict_outbound_clipboard = DEFAULT_RESTRICT_OUTBOUND_CLIPBOARD;
|
||||
cfg->fuse_mount_name = fuse_mount_name;
|
||||
cfg->file_umask = DEFAULT_FILE_UMASK;
|
||||
cfg->use_nautilus3_flist_format = DEFAULT_USE_NAUTILUS3_FLIST_FORMAT;
|
||||
}
|
||||
|
||||
return cfg;
|
||||
@ -290,6 +295,8 @@ config_dump(struct config_chansrv *config)
|
||||
g_bool2text(config->enable_fuse_mount));
|
||||
g_writeln(" FuseMountName: %s", config->fuse_mount_name);
|
||||
g_writeln(" FileMask: 0%o", config->file_umask);
|
||||
g_writeln(" Nautilus 3 Flist Format: %s",
|
||||
g_bool2text(config->use_nautilus3_flist_format));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -36,6 +36,9 @@ struct config_chansrv
|
||||
char *fuse_mount_name;
|
||||
/** FileUmask from sesman.ini */
|
||||
mode_t file_umask;
|
||||
|
||||
/** Whether to use nautilus3-compatible file lists for the clipboard */
|
||||
int use_nautilus3_flist_format;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1199,6 +1199,95 @@ clipboard_process_data_response_for_image(struct stream *s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Process a CB_FORMAT_DATA_RESPONSE for an X client requesting a file list
|
||||
*
|
||||
* @param s Stream containing CLIPRDR_FILELIST ([MS-RDPECLIP])
|
||||
* @param clip_msg_status msgFlags from Clipboard PDU Header
|
||||
* @param clip_msg_len dataLen from Clipboard PDU Header
|
||||
*
|
||||
* @return Status
|
||||
*/
|
||||
static int
|
||||
clipboard_process_data_response_for_file(struct stream *s,
|
||||
int clip_msg_status,
|
||||
int clip_msg_len)
|
||||
{
|
||||
XSelectionRequestEvent *lxev;
|
||||
int rv = 0;
|
||||
|
||||
LOG_DEVEL(LOG_LEVEL_TRACE, "clipboard_process_data_response_for_file: ");
|
||||
lxev = &g_saved_selection_req_event;
|
||||
|
||||
const int flist_size = 1024 * 1024;
|
||||
g_free(g_clip_c2s.data);
|
||||
g_clip_c2s.data = (char *)g_malloc(flist_size, 0);
|
||||
if (g_clip_c2s.data == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "clipboard_process_data_response_for_file: "
|
||||
"Can't allocate memory");
|
||||
rv = 1;
|
||||
}
|
||||
/* text/uri-list */
|
||||
else if (g_clip_c2s.type == g_file_atom1)
|
||||
{
|
||||
rv = clipboard_c2s_in_files(s, g_clip_c2s.data, flist_size,
|
||||
"file://");
|
||||
}
|
||||
/* x-special/gnome-copied-files */
|
||||
else if (g_clip_c2s.type == g_file_atom2)
|
||||
{
|
||||
g_strcpy(g_clip_c2s.data, "copy\n");
|
||||
rv = clipboard_c2s_in_files(s, g_clip_c2s.data + 5, flist_size - 5,
|
||||
"file://");
|
||||
}
|
||||
else if ((g_clip_c2s.type == XA_STRING) ||
|
||||
(g_clip_c2s.type == g_utf8_atom))
|
||||
{
|
||||
if (g_cfg->use_nautilus3_flist_format)
|
||||
{
|
||||
/*
|
||||
* This file list format is only used by GNOME 3
|
||||
* versions >= 3.29.92. It is not used by GNOME 4. Remove
|
||||
* this workaround when GNOME 3 is no longer supported by
|
||||
* long-term distros */
|
||||
#define LIST_PREFIX "x-special/nautilus-clipboard\ncopy\n"
|
||||
#define LIST_PREFIX_LEN (sizeof(LIST_PREFIX) - 1)
|
||||
g_strcpy(g_clip_c2s.data, LIST_PREFIX);
|
||||
rv = clipboard_c2s_in_files(s,
|
||||
g_clip_c2s.data + LIST_PREFIX_LEN,
|
||||
flist_size - LIST_PREFIX_LEN - 1,
|
||||
"file://");
|
||||
g_strcat(g_clip_c2s.data, "\n");
|
||||
#undef LIST_PREFIX_LEN
|
||||
#undef LIST_PREFIX
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = clipboard_c2s_in_files(s, g_clip_c2s.data, flist_size, "");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_ERROR,
|
||||
"clipboard_process_data_response_for_file: "
|
||||
"Unrecognised target");
|
||||
rv = 1;
|
||||
}
|
||||
|
||||
if (rv != 0 && g_clip_c2s.data != NULL)
|
||||
{
|
||||
g_clip_c2s.data[0] = '\0';
|
||||
}
|
||||
|
||||
g_clip_c2s.total_bytes =
|
||||
(g_clip_c2s.data == NULL) ? 0 : g_strlen(g_clip_c2s.data);
|
||||
g_clip_c2s.read_bytes_done = g_clip_c2s.total_bytes;
|
||||
clipboard_provide_selection_c2s(lxev, lxev->target);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* client to server */
|
||||
/* sent as a reply to CB_FORMAT_DATA_REQUEST; used to indicate whether
|
||||
@ -1227,26 +1316,8 @@ clipboard_process_data_response(struct stream *s, int clip_msg_status,
|
||||
}
|
||||
if (g_clip_c2s.xrdp_clip_type == XRDP_CB_FILE)
|
||||
{
|
||||
g_free(g_clip_c2s.data);
|
||||
g_clip_c2s.data = (char *)g_malloc(1024 * 1024, 1);
|
||||
/* text/uri-list */
|
||||
if (g_clip_c2s.type == g_file_atom1)
|
||||
{
|
||||
clipboard_c2s_in_files(s, g_clip_c2s.data);
|
||||
}
|
||||
/* x-special/gnome-copied-files */
|
||||
else if (g_clip_c2s.type == g_file_atom2)
|
||||
{
|
||||
g_strcpy(g_clip_c2s.data, "copy\n");
|
||||
clipboard_c2s_in_files(s, g_clip_c2s.data + 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_ERROR, "clipboard_process_data_response: error");
|
||||
}
|
||||
g_clip_c2s.total_bytes = g_strlen(g_clip_c2s.data);
|
||||
g_clip_c2s.read_bytes_done = g_clip_c2s.total_bytes;
|
||||
clipboard_provide_selection_c2s(lxev, lxev->target);
|
||||
clipboard_process_data_response_for_file(s, clip_msg_status,
|
||||
clip_msg_len);
|
||||
return 0;
|
||||
}
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_process_data_response: "
|
||||
@ -2168,11 +2239,24 @@ clipboard_event_selection_request(XEvent *xevent)
|
||||
}
|
||||
else if ((lxev->target == XA_STRING) || (lxev->target == g_utf8_atom))
|
||||
{
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = lxev->target;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_TEXT;
|
||||
clipboard_send_data_request(CB_FORMAT_UNICODETEXT);
|
||||
if (clipboard_find_format_id(g_file_format_id) >= 0)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_event_selection_request: "
|
||||
"text requested when files available");
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = lxev->target;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
|
||||
clipboard_send_data_request(g_file_format_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = lxev->target;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_TEXT;
|
||||
clipboard_send_data_request(CB_FORMAT_UNICODETEXT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (lxev->target == g_image_bmp_atom)
|
||||
|
@ -597,33 +597,41 @@ clipboard_c2s_in_file_info(struct stream *s, struct clip_file_desc *cfd)
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* See [MS-RDPECLIP] 2.2.5.2.3 */
|
||||
int
|
||||
clipboard_c2s_in_files(struct stream *s, char *file_list)
|
||||
clipboard_c2s_in_files(struct stream *s, char *file_list, int file_list_size,
|
||||
const char *fprefix)
|
||||
{
|
||||
int cItems;
|
||||
int citems;
|
||||
int lindex;
|
||||
int str_len;
|
||||
int file_count;
|
||||
struct clip_file_desc cfd;
|
||||
char *ptr;
|
||||
char *last; /* Last writeable char in buffer */
|
||||
int dropped_files = 0; /* # files we can't add to buffer */
|
||||
|
||||
if (!s_check_rem(s, 4))
|
||||
if (file_list_size < 1)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_ERROR, "clipboard_c2s_in_files: parse error");
|
||||
LOG(LOG_LEVEL_ERROR, "clipboard_c2s_in_files: No space in string");
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, cItems);
|
||||
if (cItems > 64 * 1024) /* sanity check */
|
||||
if (!s_check_rem(s, 4))
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_ERROR, "clipboard_c2s_in_files: error cItems %d too big", cItems);
|
||||
LOG(LOG_LEVEL_ERROR, "clipboard_c2s_in_files: parse error");
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, citems);
|
||||
if (citems < 0 || citems > 64 * 1024) /* sanity check */
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "clipboard_c2s_in_files: "
|
||||
"Bad number of files in list (%d)", citems);
|
||||
return 1;
|
||||
}
|
||||
xfuse_clear_clip_dir();
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_c2s_in_files: cItems %d", cItems);
|
||||
file_count = 0;
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_c2s_in_files: cItems %d", citems);
|
||||
ptr = file_list;
|
||||
for (lindex = 0; lindex < cItems; lindex++)
|
||||
last = file_list + file_list_size - 1;
|
||||
|
||||
for (lindex = 0; lindex < citems; lindex++)
|
||||
{
|
||||
g_memset(&cfd, 0, sizeof(struct clip_file_desc));
|
||||
if (clipboard_c2s_in_file_info(s, &cfd) != 0)
|
||||
@ -633,37 +641,62 @@ clipboard_c2s_in_files(struct stream *s, char *file_list)
|
||||
if ((g_pos(cfd.cFileName, "\\") >= 0) ||
|
||||
(cfd.fileAttributes & CB_FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_ERROR, "clipboard_c2s_in_files: skipping directory not "
|
||||
"supported [%s]", cfd.cFileName);
|
||||
LOG(LOG_LEVEL_WARNING, "clipboard_c2s_in_files: skipping "
|
||||
"directory not supported [%s]", cfd.cFileName);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Have we already run out of room in the list? */
|
||||
if (dropped_files > 0)
|
||||
{
|
||||
dropped_files += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Room for this file? */
|
||||
str_len = (ptr == file_list) ? 0 : 1; /* Delimiter */
|
||||
str_len += g_strlen(fprefix); /* e.g. "file://" */
|
||||
str_len += g_strlen(g_fuse_clipboard_path);
|
||||
str_len += 1; /* '/' */
|
||||
str_len += g_strlen(cfd.cFileName);
|
||||
if (str_len > (last - ptr))
|
||||
{
|
||||
dropped_files += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xfuse_add_clip_dir_item(cfd.cFileName, 0, cfd.fileSizeLow, lindex) == -1)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_ERROR, "clipboard_c2s_in_files: failed to add clip dir item");
|
||||
LOG(LOG_LEVEL_WARNING, "clipboard_c2s_in_files: "
|
||||
"failed to add clip dir item %s", cfd.cFileName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file_count > 0)
|
||||
if (ptr > file_list)
|
||||
{
|
||||
*ptr = '\n';
|
||||
ptr++;
|
||||
*ptr++ = '\n';
|
||||
}
|
||||
file_count++;
|
||||
|
||||
g_strcpy(ptr, "file://");
|
||||
ptr += 7;
|
||||
str_len = g_strlen(fprefix);
|
||||
g_strcpy(ptr, fprefix);
|
||||
ptr += str_len;
|
||||
|
||||
str_len = g_strlen(g_fuse_clipboard_path);
|
||||
g_strcpy(ptr, g_fuse_clipboard_path);
|
||||
ptr += str_len;
|
||||
|
||||
*ptr = '/';
|
||||
ptr++;
|
||||
*ptr++ = '/';
|
||||
|
||||
str_len = g_strlen(cfd.cFileName);
|
||||
g_strcpy(ptr, cfd.cFileName);
|
||||
ptr += str_len;
|
||||
}
|
||||
*ptr = 0;
|
||||
*ptr = '\0';
|
||||
|
||||
if (dropped_files > 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "clipboard_c2s_in_files: "
|
||||
"Dropped %d files from the clip buffer due to insufficient space",
|
||||
dropped_files);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -30,8 +30,26 @@ clipboard_process_file_request(struct stream *s, int clip_msg_status,
|
||||
int
|
||||
clipboard_process_file_response(struct stream *s, int clip_msg_status,
|
||||
int clip_msg_len);
|
||||
/**
|
||||
* Process a CLIPRDR_FILELIST - see [MS-RDPECLIP] 2.2.5.2.3
|
||||
*
|
||||
* Files in the list are added to the xfs filesystem in the clipboard
|
||||
* directory. The filenames names are added to the 'file_list' for the user.
|
||||
* Files are prefixed with '<fprefix><clipboard_dir>/' and separated by '\n'.
|
||||
*
|
||||
* If the list is not big enough, whole filenames are omitted, and a warning
|
||||
* message is logged. This is not an error.
|
||||
*
|
||||
* @param s Input stream containing CLIPRDR_FILELIST
|
||||
* @param file_list Output buffer for filenames
|
||||
* @param file_list_size Size of buffer, including space for '\0'.
|
||||
* @param fprefix Prefix for each file in the file list (e.g. "file://")
|
||||
*
|
||||
* @return Zero for success.
|
||||
*/
|
||||
int
|
||||
clipboard_c2s_in_files(struct stream *s, char *file_list);
|
||||
clipboard_c2s_in_files(struct stream *s, char *file_list, int file_list_size,
|
||||
const char *fprefix);
|
||||
|
||||
int
|
||||
clipboard_request_file_size(int stream_id, int lindex);
|
||||
|
@ -125,6 +125,10 @@ FuseMountName=thinclient_drives
|
||||
FileUmask=077
|
||||
; Can be used to disable FUSE functionality - see sesman.ini(5)
|
||||
#EnableFuseMount=false
|
||||
; Uncomment this line only if you are using GNOME 3 versions 3.29.92
|
||||
; and up, and you wish to cut-paste files between Nautilus and Windows. Do
|
||||
; not use this setting for GNOME 4, or other file managers
|
||||
#UseNautilus3FlistFormat=true
|
||||
|
||||
[ChansrvLogging]
|
||||
; Note: one log file is created per display and the LogFile config value
|
||||
|
Loading…
Reference in New Issue
Block a user