Merge pull request #49 from glyptodon/rdp-fs
GUAC-1172: Implement filesystem object support for RDP.
This commit is contained in:
commit
31e90bcdf4
@ -48,10 +48,10 @@ void guac_common_json_flush(guac_client* client, guac_stream* stream,
|
||||
|
||||
}
|
||||
|
||||
bool guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||
int guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||
guac_common_json_state* json_state, const char* buffer, int length) {
|
||||
|
||||
bool blob_written = false;
|
||||
int blob_written = 0;
|
||||
|
||||
/*
|
||||
* Append to and flush the JSON buffer as necessary to write the given
|
||||
@ -67,7 +67,7 @@ bool guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||
/* Flush if more room is needed */
|
||||
if (json_state->size + blob_length > sizeof(json_state->buffer)) {
|
||||
guac_common_json_flush(client, stream, json_state);
|
||||
blob_written = true;
|
||||
blob_written = 1;
|
||||
}
|
||||
|
||||
/* Append data to JSON buffer */
|
||||
@ -86,11 +86,11 @@ bool guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||
|
||||
}
|
||||
|
||||
bool guac_common_json_write_string(guac_client* client,
|
||||
int guac_common_json_write_string(guac_client* client,
|
||||
guac_stream* stream, guac_common_json_state* json_state,
|
||||
const char* str) {
|
||||
|
||||
bool blob_written = false;
|
||||
int blob_written = 0;
|
||||
|
||||
/* Write starting quote */
|
||||
blob_written |= guac_common_json_write(client, stream,
|
||||
@ -132,11 +132,11 @@ bool guac_common_json_write_string(guac_client* client,
|
||||
|
||||
}
|
||||
|
||||
bool guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
||||
int guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
||||
guac_common_json_state* json_state, const char* name,
|
||||
const char* value) {
|
||||
|
||||
bool blob_written = false;
|
||||
int blob_written = 0;
|
||||
|
||||
/* Write leading comma if not first property */
|
||||
if (json_state->properties_written != 0)
|
||||
@ -173,7 +173,7 @@ void guac_common_json_begin_object(guac_client* client, guac_stream* stream,
|
||||
|
||||
}
|
||||
|
||||
bool guac_common_json_end_object(guac_client* client, guac_stream* stream,
|
||||
int guac_common_json_end_object(guac_client* client, guac_stream* stream,
|
||||
guac_common_json_state* json_state) {
|
||||
|
||||
/* Write final brace of JSON object */
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/stream.h>
|
||||
|
||||
@ -97,9 +95,9 @@ void guac_common_json_flush(guac_client* client, guac_stream* stream,
|
||||
* The number of bytes in the buffer.
|
||||
*
|
||||
* @return
|
||||
* true if at least one blob was written, false otherwise.
|
||||
* Non-zero if at least one blob was written, zero otherwise.
|
||||
*/
|
||||
bool guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||
int guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||
guac_common_json_state* json_state, const char* buffer, int length);
|
||||
|
||||
/**
|
||||
@ -123,9 +121,9 @@ bool guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||
* The string to write.
|
||||
*
|
||||
* @return
|
||||
* true if at least one blob was written, false otherwise.
|
||||
* Non-zero if at least one blob was written, zero otherwise.
|
||||
*/
|
||||
bool guac_common_json_write_string(guac_client* client,
|
||||
int guac_common_json_write_string(guac_client* client,
|
||||
guac_stream* stream, guac_common_json_state* json_state,
|
||||
const char* str);
|
||||
|
||||
@ -152,9 +150,9 @@ bool guac_common_json_write_string(guac_client* client,
|
||||
* The value of the property to write.
|
||||
*
|
||||
* @return
|
||||
* true if at least one blob was written, false otherwise.
|
||||
* Non-zero if at least one blob was written, zero otherwise.
|
||||
*/
|
||||
bool guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
||||
int guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
||||
guac_common_json_state* json_state, const char* name,
|
||||
const char* value);
|
||||
|
||||
@ -192,9 +190,9 @@ void guac_common_json_begin_object(guac_client* client, guac_stream* stream,
|
||||
* The state object whose in-progress JSON object should be terminated.
|
||||
*
|
||||
* @return
|
||||
* true if at least one blob was written, false otherwise.
|
||||
* Non-zero if at least one blob was written, zero otherwise.
|
||||
*/
|
||||
bool guac_common_json_end_object(guac_client* client, guac_stream* stream,
|
||||
int guac_common_json_end_object(guac_client* client, guac_stream* stream,
|
||||
guac_common_json_state* json_state);
|
||||
|
||||
#endif
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
|
||||
#ifdef ENABLE_WINPR
|
||||
#include <winpr/stream.h>
|
||||
@ -152,5 +154,10 @@ void guac_rdpdr_register_fs(guac_rdpdrPlugin* rdpdr) {
|
||||
/* Init data */
|
||||
device->data = data->filesystem;
|
||||
|
||||
/* Announce filesystem to client */
|
||||
guac_protocol_send_filesystem(rdpdr->client->socket,
|
||||
data->filesystem->object, "Shared Drive");
|
||||
guac_socket_flush(rdpdr->client->socket);
|
||||
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "rdp_fs.h"
|
||||
#include "rdp_status.h"
|
||||
#include "rdp_stream.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
@ -36,6 +37,7 @@
|
||||
#include <sys/statvfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <guacamole/object.h>
|
||||
#include <guacamole/pool.h>
|
||||
|
||||
guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path) {
|
||||
@ -43,6 +45,10 @@ guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path) {
|
||||
guac_rdp_fs* fs = malloc(sizeof(guac_rdp_fs));
|
||||
|
||||
fs->client = client;
|
||||
fs->object = guac_client_alloc_object(client);
|
||||
fs->object->get_handler = guac_rdp_download_get_handler;
|
||||
fs->object->put_handler = guac_rdp_upload_put_handler;
|
||||
|
||||
fs->drive_path = strdup(drive_path);
|
||||
fs->file_id_pool = guac_pool_alloc(0);
|
||||
fs->open_files = 0;
|
||||
@ -52,6 +58,7 @@ guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path) {
|
||||
}
|
||||
|
||||
void guac_rdp_fs_free(guac_rdp_fs* fs) {
|
||||
guac_client_free_object(fs->client, fs->object);
|
||||
guac_pool_free(fs->file_id_pool);
|
||||
free(fs->drive_path);
|
||||
free(fs);
|
||||
@ -176,7 +183,7 @@ int guac_rdp_fs_open(guac_rdp_fs* fs, const char* path,
|
||||
path = "\\";
|
||||
|
||||
/* If path is relative, the file does not exist */
|
||||
else if (path[0] != '\\') {
|
||||
else if (path[0] != '\\' && path[0] != '/') {
|
||||
guac_client_log(fs->client, GUAC_LOG_DEBUG,
|
||||
"%s: Access denied - supplied path \"%s\" is relative.",
|
||||
__func__, path);
|
||||
@ -688,3 +695,65 @@ int guac_rdp_fs_get_info(guac_rdp_fs* fs, guac_rdp_fs_info* info) {
|
||||
|
||||
}
|
||||
|
||||
int guac_rdp_fs_append_filename(char* fullpath, const char* path,
|
||||
const char* filename) {
|
||||
|
||||
int i;
|
||||
|
||||
/* Disallow "." as a filename */
|
||||
if (strcmp(filename, ".") == 0)
|
||||
return 0;
|
||||
|
||||
/* Disallow ".." as a filename */
|
||||
if (strcmp(filename, "..") == 0)
|
||||
return 0;
|
||||
|
||||
/* Copy path, append trailing slash */
|
||||
for (i=0; i<GUAC_RDP_FS_MAX_PATH; i++) {
|
||||
|
||||
/*
|
||||
* Append trailing slash only if:
|
||||
* 1) Trailing slash is not already present
|
||||
* 2) Path is non-empty
|
||||
*/
|
||||
|
||||
char c = path[i];
|
||||
if (c == '\0') {
|
||||
if (i > 0 && path[i-1] != '/' && path[i-1] != '\\')
|
||||
fullpath[i++] = '/';
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy character if not end of string */
|
||||
fullpath[i] = c;
|
||||
|
||||
}
|
||||
|
||||
/* Append filename */
|
||||
for (; i<GUAC_RDP_FS_MAX_PATH; i++) {
|
||||
|
||||
char c = *(filename++);
|
||||
if (c == '\0')
|
||||
break;
|
||||
|
||||
/* Filenames may not contain slashes */
|
||||
if (c == '\\' || c == '/')
|
||||
return 0;
|
||||
|
||||
/* Append each character within filename */
|
||||
fullpath[i] = c;
|
||||
|
||||
}
|
||||
|
||||
/* Verify path length is within maximum */
|
||||
if (i == GUAC_RDP_FS_MAX_PATH)
|
||||
return 0;
|
||||
|
||||
/* Terminate path string */
|
||||
fullpath[i] = '\0';
|
||||
|
||||
/* Append was successful */
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/object.h>
|
||||
#include <guacamole/pool.h>
|
||||
|
||||
#include <dirent.h>
|
||||
@ -272,6 +273,11 @@ typedef struct guac_rdp_fs {
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* The underlying filesystem object.
|
||||
*/
|
||||
guac_object* object;
|
||||
|
||||
/**
|
||||
* The root of the filesystem.
|
||||
*/
|
||||
@ -422,5 +428,27 @@ int guac_rdp_fs_matches(const char* filename, const char* pattern);
|
||||
*/
|
||||
int guac_rdp_fs_get_info(guac_rdp_fs* fs, guac_rdp_fs_info* info);
|
||||
|
||||
/**
|
||||
* Concatenates the given filename with the given path, separating the two
|
||||
* with a single forward slash. The full result must be no more than
|
||||
* GUAC_RDP_FS_MAX_PATH bytes long, counting null terminator.
|
||||
*
|
||||
* @param fullpath
|
||||
* The buffer to store the result within. This buffer must be at least
|
||||
* GUAC_RDP_FS_MAX_PATH bytes long.
|
||||
*
|
||||
* @param path
|
||||
* The path to append the filename to.
|
||||
*
|
||||
* @param filename
|
||||
* The filename to append to the path.
|
||||
*
|
||||
* @return
|
||||
* Non-zero if the filename is valid and was successfully appended to the
|
||||
* path, zero otherwise.
|
||||
*/
|
||||
int guac_rdp_fs_append_filename(char* fullpath, const char* path,
|
||||
const char* filename);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -32,6 +32,14 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* Include any constants from winpr/file.h, if available */
|
||||
|
||||
#ifdef ENABLE_WINPR
|
||||
#include <winpr/file.h>
|
||||
#endif
|
||||
|
||||
/* Constants which MAY be defined within FreeRDP */
|
||||
|
||||
#ifndef STATUS_SUCCESS
|
||||
#define STATUS_SUCCESS 0x00000000
|
||||
#define STATUS_NO_MORE_FILES 0x80000006
|
||||
@ -53,6 +61,8 @@
|
||||
#define STATUS_FILE_CLOSED 0xC0000128
|
||||
#endif
|
||||
|
||||
/* Constants which are NEVER defined within FreeRDP */
|
||||
|
||||
#define STATUS_FILE_SYSTEM_LIMITATION 0xC0000427
|
||||
#define STATUS_FILE_TOO_LARGE 0xC0000904
|
||||
|
||||
|
@ -356,4 +356,216 @@ int guac_rdp_download_ack_handler(guac_client* client, guac_stream* stream,
|
||||
|
||||
}
|
||||
|
||||
int guac_rdp_ls_ack_handler(guac_client* client, guac_stream* stream,
|
||||
char* message, guac_protocol_status status) {
|
||||
|
||||
int blob_written = 0;
|
||||
const char* filename;
|
||||
|
||||
guac_rdp_stream* rdp_stream = (guac_rdp_stream*) stream->data;
|
||||
|
||||
/* If unsuccessful, free stream and abort */
|
||||
if (status != GUAC_PROTOCOL_STATUS_SUCCESS) {
|
||||
guac_rdp_fs_close(rdp_stream->ls_status.fs,
|
||||
rdp_stream->ls_status.file_id);
|
||||
guac_client_free_stream(client, stream);
|
||||
free(rdp_stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* While directory entries remain */
|
||||
while ((filename = guac_rdp_fs_read_dir(rdp_stream->ls_status.fs,
|
||||
rdp_stream->ls_status.file_id)) != NULL
|
||||
&& !blob_written) {
|
||||
|
||||
char absolute_path[GUAC_RDP_FS_MAX_PATH];
|
||||
|
||||
/* Skip current and parent directory entries */
|
||||
if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
|
||||
continue;
|
||||
|
||||
/* Concatenate into absolute path - skip if invalid */
|
||||
if (!guac_rdp_fs_append_filename(absolute_path,
|
||||
rdp_stream->ls_status.directory_name, filename)) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Skipping filename \"%s\" - filename is invalid or "
|
||||
"resulting path is too long", filename);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Attempt to open file to determine type */
|
||||
int file_id = guac_rdp_fs_open(rdp_stream->ls_status.fs, absolute_path,
|
||||
ACCESS_GENERIC_READ, 0, DISP_FILE_OPEN, 0);
|
||||
if (file_id < 0)
|
||||
continue;
|
||||
|
||||
/* Get opened file */
|
||||
guac_rdp_fs_file* file = guac_rdp_fs_get_file(rdp_stream->ls_status.fs,
|
||||
file_id);
|
||||
if (file == NULL) {
|
||||
guac_client_log(rdp_stream->ls_status.fs->client, GUAC_LOG_DEBUG,
|
||||
"%s: Successful open produced bad file_id: %i",
|
||||
__func__, file_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Determine mimetype */
|
||||
const char* mimetype;
|
||||
if (file->attributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
mimetype = GUAC_CLIENT_STREAM_INDEX_MIMETYPE;
|
||||
else
|
||||
mimetype = "application/octet-stream";
|
||||
|
||||
/* Write entry */
|
||||
blob_written |= guac_common_json_write_property(client, stream,
|
||||
&rdp_stream->ls_status.json_state, absolute_path, mimetype);
|
||||
|
||||
guac_rdp_fs_close(rdp_stream->ls_status.fs, file_id);
|
||||
|
||||
}
|
||||
|
||||
/* Complete JSON and cleanup at end of directory */
|
||||
if (filename == NULL) {
|
||||
|
||||
/* Complete JSON object */
|
||||
guac_common_json_end_object(client, stream,
|
||||
&rdp_stream->ls_status.json_state);
|
||||
guac_common_json_flush(client, stream,
|
||||
&rdp_stream->ls_status.json_state);
|
||||
|
||||
/* Clean up resources */
|
||||
guac_rdp_fs_close(rdp_stream->ls_status.fs,
|
||||
rdp_stream->ls_status.file_id);
|
||||
free(rdp_stream);
|
||||
|
||||
/* Signal of stream */
|
||||
guac_protocol_send_end(client->socket, stream);
|
||||
guac_client_free_stream(client, stream);
|
||||
|
||||
}
|
||||
|
||||
guac_socket_flush(client->socket);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_rdp_download_get_handler(guac_client* client, guac_object* object,
|
||||
char* name) {
|
||||
|
||||
/* Get filesystem, ignore request if no filesystem */
|
||||
guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem;
|
||||
if (fs == NULL)
|
||||
return 0;
|
||||
|
||||
/* Attempt to open file for reading */
|
||||
int file_id = guac_rdp_fs_open(fs, name, ACCESS_GENERIC_READ, 0,
|
||||
DISP_FILE_OPEN, 0);
|
||||
if (file_id < 0) {
|
||||
guac_client_log(client, GUAC_LOG_INFO, "Unable to read file \"%s\"",
|
||||
name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get opened file */
|
||||
guac_rdp_fs_file* file = guac_rdp_fs_get_file(fs, file_id);
|
||||
if (file == NULL) {
|
||||
guac_client_log(fs->client, GUAC_LOG_DEBUG,
|
||||
"%s: Successful open produced bad file_id: %i",
|
||||
__func__, file_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If directory, send contents of directory */
|
||||
if (file->attributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
|
||||
/* Create stream data */
|
||||
guac_rdp_stream* rdp_stream = malloc(sizeof(guac_rdp_stream));
|
||||
rdp_stream->type = GUAC_RDP_LS_STREAM;
|
||||
rdp_stream->ls_status.fs = fs;
|
||||
rdp_stream->ls_status.file_id = file_id;
|
||||
strncpy(rdp_stream->ls_status.directory_name, name,
|
||||
sizeof(rdp_stream->ls_status.directory_name));
|
||||
|
||||
/* Allocate stream for body */
|
||||
guac_stream* stream = guac_client_alloc_stream(client);
|
||||
stream->ack_handler = guac_rdp_ls_ack_handler;
|
||||
stream->data = rdp_stream;
|
||||
|
||||
/* Init JSON object state */
|
||||
guac_common_json_begin_object(client, stream,
|
||||
&rdp_stream->ls_status.json_state);
|
||||
|
||||
/* Associate new stream with get request */
|
||||
guac_protocol_send_body(client->socket, object, stream,
|
||||
GUAC_CLIENT_STREAM_INDEX_MIMETYPE, name);
|
||||
|
||||
}
|
||||
|
||||
/* Otherwise, send file contents */
|
||||
else {
|
||||
|
||||
/* Create stream data */
|
||||
guac_rdp_stream* rdp_stream = malloc(sizeof(guac_rdp_stream));
|
||||
rdp_stream->type = GUAC_RDP_DOWNLOAD_STREAM;
|
||||
rdp_stream->download_status.file_id = file_id;
|
||||
rdp_stream->download_status.offset = 0;
|
||||
|
||||
/* Allocate stream for body */
|
||||
guac_stream* stream = guac_client_alloc_stream(client);
|
||||
stream->data = rdp_stream;
|
||||
stream->ack_handler = guac_rdp_download_ack_handler;
|
||||
|
||||
/* Associate new stream with get request */
|
||||
guac_protocol_send_body(client->socket, object, stream,
|
||||
"application/octet-stream", name);
|
||||
|
||||
}
|
||||
|
||||
guac_socket_flush(client->socket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int guac_rdp_upload_put_handler(guac_client* client, guac_object* object,
|
||||
guac_stream* stream, char* mimetype, char* name) {
|
||||
|
||||
/* Get filesystem, return error if no filesystem */
|
||||
guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem;
|
||||
if (fs == NULL) {
|
||||
guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)",
|
||||
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
|
||||
guac_socket_flush(client->socket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Open file */
|
||||
int file_id = guac_rdp_fs_open(fs, name, ACCESS_GENERIC_WRITE, 0,
|
||||
DISP_FILE_OVERWRITE_IF, 0);
|
||||
|
||||
/* Abort on failure */
|
||||
if (file_id < 0) {
|
||||
guac_protocol_send_ack(client->socket, stream, "FAIL (CANNOT OPEN)",
|
||||
GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN);
|
||||
guac_socket_flush(client->socket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Init upload stream data */
|
||||
guac_rdp_stream* rdp_stream = malloc(sizeof(guac_rdp_stream));
|
||||
rdp_stream->type = GUAC_RDP_UPLOAD_STREAM;
|
||||
rdp_stream->upload_status.offset = 0;
|
||||
rdp_stream->upload_status.file_id = file_id;
|
||||
|
||||
/* Allocate stream, init for file upload */
|
||||
stream->data = rdp_stream;
|
||||
stream->blob_handler = guac_rdp_upload_blob_handler;
|
||||
stream->end_handler = guac_rdp_upload_end_handler;
|
||||
|
||||
/* Acknowledge stream creation */
|
||||
guac_protocol_send_ack(client->socket, stream, "OK (STREAM BEGIN)",
|
||||
GUAC_PROTOCOL_STATUS_SUCCESS);
|
||||
guac_socket_flush(client->socket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#define _GUAC_RDP_STREAM_H
|
||||
|
||||
#include "config.h"
|
||||
#include "guac_json.h"
|
||||
#include "rdp_svc.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
@ -68,6 +69,33 @@ typedef struct guac_rdp_upload_status {
|
||||
|
||||
} guac_rdp_upload_status;
|
||||
|
||||
/**
|
||||
* The current state of a directory listing operation.
|
||||
*/
|
||||
typedef struct guac_rdp_ls_status {
|
||||
|
||||
/**
|
||||
* The filesystem associated with the directory being listed.
|
||||
*/
|
||||
guac_rdp_fs* fs;
|
||||
|
||||
/**
|
||||
* The file ID of the directory being listed.
|
||||
*/
|
||||
int file_id;
|
||||
|
||||
/**
|
||||
* The absolute path of the directory being listed.
|
||||
*/
|
||||
char directory_name[GUAC_RDP_FS_MAX_PATH];
|
||||
|
||||
/**
|
||||
* The current state of the JSON directory object being written.
|
||||
*/
|
||||
guac_common_json_state json_state;
|
||||
|
||||
} guac_rdp_ls_status;
|
||||
|
||||
/**
|
||||
* All available stream types.
|
||||
*/
|
||||
@ -83,6 +111,11 @@ typedef enum guac_rdp_stream_type {
|
||||
*/
|
||||
GUAC_RDP_DOWNLOAD_STREAM,
|
||||
|
||||
/**
|
||||
* An in-progress stream of a directory listing.
|
||||
*/
|
||||
GUAC_RDP_LS_STREAM,
|
||||
|
||||
/**
|
||||
* The inbound half of a static virtual channel.
|
||||
*/
|
||||
@ -115,6 +148,11 @@ typedef struct guac_rdp_stream {
|
||||
*/
|
||||
guac_rdp_download_status download_status;
|
||||
|
||||
/**
|
||||
* The directory list status. Only valid for GUAC_RDP_LS_STREAM.
|
||||
*/
|
||||
guac_rdp_ls_status ls_status;
|
||||
|
||||
/**
|
||||
* Associated SVC instance. Only valid for GUAC_RDP_INBOUND_SVC_STREAM.
|
||||
*/
|
||||
@ -174,5 +212,76 @@ int guac_rdp_clipboard_end_handler(guac_client* client, guac_stream* stream);
|
||||
int guac_rdp_download_ack_handler(guac_client* client, guac_stream* stream,
|
||||
char* message, guac_protocol_status status);
|
||||
|
||||
/**
|
||||
* Handler for ack messages received due to receipt of a "body" or "blob"
|
||||
* instruction associated with a directory list operation.
|
||||
*
|
||||
* @param client
|
||||
* The client receiving the ack message.
|
||||
*
|
||||
* @param stream
|
||||
* The Guacamole protocol stream associated with the received ack message.
|
||||
*
|
||||
* @param message
|
||||
* An arbitrary human-readable message describing the nature of the
|
||||
* success or failure denoted by this ack message.
|
||||
*
|
||||
* @param status
|
||||
* The status code associated with this ack message, which may indicate
|
||||
* success or an error.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on error.
|
||||
*/
|
||||
int guac_rdp_ls_ack_handler(guac_client* client, guac_stream* stream,
|
||||
char* message, guac_protocol_status status);
|
||||
|
||||
/**
|
||||
* Handler for get messages. In context of downloads and the filesystem exposed
|
||||
* via the Guacamole protocol, get messages request the body of a file within
|
||||
* the filesystem.
|
||||
*
|
||||
* @param client
|
||||
* The client receiving the get message.
|
||||
*
|
||||
* @param object
|
||||
* The Guacamole protocol object associated with the get request itself.
|
||||
*
|
||||
* @param name
|
||||
* The name of the input stream (file) being requested.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on error.
|
||||
*/
|
||||
int guac_rdp_download_get_handler(guac_client* client, guac_object* object,
|
||||
char* name);
|
||||
|
||||
/**
|
||||
* Handler for put messages. In context of uploads and the filesystem exposed
|
||||
* via the Guacamole protocol, put messages request write access to a file
|
||||
* within the filesystem.
|
||||
*
|
||||
* @param client
|
||||
* The client receiving the put message.
|
||||
*
|
||||
* @param object
|
||||
* The Guacamole protocol object associated with the put request itself.
|
||||
*
|
||||
* @param stream
|
||||
* The Guacamole protocol stream along which the client will be sending
|
||||
* file data.
|
||||
*
|
||||
* @param mimetype
|
||||
* The mimetype of the data being send along the stream.
|
||||
*
|
||||
* @param name
|
||||
* The name of the input stream (file) being requested.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on error.
|
||||
*/
|
||||
int guac_rdp_upload_put_handler(guac_client* client, guac_object* object,
|
||||
guac_stream* stream, char* mimetype, char* name);
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user