diff --git a/libguac/include/protocol.h b/libguac/include/protocol.h index 087971a6..ba3a04ec 100644 --- a/libguac/include/protocol.h +++ b/libguac/include/protocol.h @@ -349,6 +349,80 @@ int guac_protocol_send_audio_data(guac_socket* socket, void* data, int count); */ int guac_protocol_send_audio_end(guac_socket* socket); +/** + * Sends a file instruction over the given guac_socket connection. + * + * If an error occurs sending the instruction, a non-zero value is + * returned, and guac_error is set appropriately. + * + * @param socket The guac_socket connection to use. + * @param name A name describing the file being sent. + * @param mimetype The mimetype of the data being sent. + * @param data The file data to be sent. + * @param size The number of bytes of file data to send. + * @return Zero on success, non-zero on error. + */ +int guac_protocol_send_file(guac_socket* socket, const char* name, + const char* mimetype, void* data, int size); + +/** + * Begins a file instruction over the given guac_socket connection. Only the + * initial non-data part of the instruction and the length of the data part + * of the instruction are sent. The actual contents of the data must be + * sent with guac_protocol_send_file_data(), and the instruction must be + * completed with guac_protocol_send_file_end(). + * + * Note that the size of the file to be sent MUST be known ahead of time, + * even though the data of the file may be sent in chunks. + * + * No further instruction data may be sent along the givven guac_socket + * except via guac_protocol_send_file_data() until the file instruction + * is completed with guac_protocol_send_file_end(). + * + * If an error occurs sending the instruction, a non-zero value is + * returned, and guac_error is set appropriately. + * + * @param socket The guac_socket connection to use. + * @param name A name describing the file being sent. + * @param mimetype The mimetype of the data being sent. + * @param size The number of bytes of file data to send. + * @return Zero on success, non-zero on error. + */ +int guac_protocol_send_file_header(guac_socket* socket, const char* name, + const char* mimetype, int size); + +/** + * Writes a block of file data to the currently in-progress file instruction + * which was started with guac_protocol_send_file_header(). Exactly the + * number of requested bytes are written unless an error occurs. This function + * may be called multiple times per file instruction for each chunk of file + * data being written, allowing the potentially huge file instruction to be + * split across multiple writes. + * + * If an error occurs sending the instruction, a non-zero value is + * returned, and guac_error is set appropriately. + * + * @param socket The guac_socket connection to use. + * @param data The file data to write. + * @param count The number of bytes within the given buffer of file data + * that must be written. + * @return Zero on success, non-zero on error. + */ +int guac_protocol_send_file_data(guac_socket* socket, void* data, int count); + +/** + * Completes the file instruction which was started with + * guac_protocol_send_file_header(), and whose data has been written with + * guac_protocol_send_file_data(). + * + * If an error occurs sending the instruction, a non-zero value is + * returned, and guac_error is set appropriately. + * + * @param socket The guac_socket connection to use. + * @return Zero on success, non-zero on error. + */ +int guac_protocol_send_file_end(guac_socket* socket); + /** * Sends a video instruction over the given guac_socket connection. * diff --git a/libguac/src/protocol.c b/libguac/src/protocol.c index ab28f3b5..4d4fd19a 100644 --- a/libguac/src/protocol.c +++ b/libguac/src/protocol.c @@ -665,6 +665,48 @@ int guac_protocol_send_error(guac_socket* socket, const char* error) { } +int guac_protocol_send_file(guac_socket* socket, const char* name, + const char* mimetype, void* data, int size) { + + return + guac_protocol_send_file_header(socket, name, + mimetype, size) + || guac_protocol_send_file_data(socket, data, size) + || guac_protocol_send_file_end(socket); + +} + +int guac_protocol_send_file_header(guac_socket* socket, const char* name, + const char* mimetype, int size) { + + int base64_length = (size + 2) / 3 * 4; + + return + guac_socket_write_string(socket, "4.file,") + || __guac_socket_write_length_string(socket, name) + || guac_socket_write_string(socket, ",") + || __guac_socket_write_length_string(socket, mimetype) + || guac_socket_write_string(socket, ",") + || guac_socket_write_int(socket, base64_length) + || guac_socket_write_string(socket, "."); + +} + +int guac_protocol_send_file_data(guac_socket* socket, void* data, int count) { + + return guac_socket_write_base64(socket, data, count); + +} + +int guac_protocol_send_file_end(guac_socket* socket) { + + return + guac_socket_flush_base64(socket) + || guac_socket_write_string(socket, ";"); + +} + + int guac_protocol_send_identity(guac_socket* socket, const guac_layer* layer) { return