This is the thing which will be used by clients to request file sizes
and ranges from wClipboard and by wClipboard to report the results of
the requests to the clients.
wClipboard and the client will fill in the (currently absent) callbacks
with their implementations of the request-report interface and will be
using them accordingly.
Initially I thought that wClipbardDelegate would be dynamically
allocated by the client and set into wClipboard (as this would be the
case with a delegate interface implementation in OOP langauges), but
after some thought I ended up with storing the delegate in wClipboard
and using the 'void* custom' field for client-private data.
So the idea is for the subsystem to fill in its callbacks during
wClipboard construction and for the client to get access to
wClipboardDelegate with a getter and fill in its callbacks during its
clipboard initialization. The subsystem will use wClipboard* pointer to
access its data and the client will have its void* pointer to store its
context.
Here you can see an outline of our approach to handling file lists put
on the clipboard. Typical usage of wClipboard by the clients sums up to
doing a ClipboardSetData() call followed by a ClipboardGetData() call
with appropriate format ID passed to them. Thus for files we would
expect the clients to first set the local format (like "text/uri-list")
and then to get the remote format (the "FileGroupDescriptorW").
MS-RDPECLIP has a concept of locally-stored list of files on the
clipboard. This is modeled by clipboard->localFiles ArrayList. We need
to populate this list before we serialize it into CLIPRDR_FILELIST and
send it to the server. The easiest way to achieve this is a bit hacky,
but it works: we populate the file list from inside the synthesizer
callback registered for text/uri-list -> FileGroupDescriptorW
conversion.
So the client would first set the data it received from local clipboard
as "text/uri-list" format, then it gets a "FileGroupDescriptorW" format,
during that conversion we will prepare to serve file content requests,
and in the end we provide a FILEDESCRIPTOR array to the client as the
conversion result. The client will then serialize the array into
CLIPRDR_FILELIST and sent it to the server. (We cannot do serialization
in WinPR as WinPR should not know about cliprdr and its data formats.)
The subsystems are expected to store their private structures in the
clipboard->localFiles array. POSIX subsystem uses struct posix_file
which currently has bare minimum of fields: the local file name (for
open() and the like) and the remote file name (the one to put into
FILEDESCRIPTOR).
This adds some initial skeleton for local file subsystems of wClipboard.
The idea is to delegate handling of local file formats to dedicated
subsystems selected at runtime based on the compiled-in support code.
This is somewhat similar to the approach used by audin, rdpsnd, rdpgfx
channels in FreeRDP.
Only one subsystem is actually used by wClipboard during runtime. It is
selected by the ClipboardInitLocalFileSubsystem() function which will
try initializing the compiled-in subsystems in the preferred order. Thus
when adding new subsystems one must make sure to 1) return as soon as
any initialization succeeds, 2) leave wClipboard in usable state if the
initialization fails.
A POSIX file subsystem is added as a pioneer. It will handle local file
format "text/uri-list" and will use POSIX API to access the files. This
is the combination one would expect to be supported by Linux systems
which can run the XFreeRDP client.
The POSIX subsystem is enabled only when CMake detects <unistd.h> as
available. This is the core POSIX include file so we can reasonably
expect the rest of the POSIX API to be available along with that file.
We also define a new configuration option WITH_DEBUG_WCLIPBOARD which
will be used to guard some debug-only verbose logging in wClipboad.
Unify error handling in ClipboardInitFormats() and actually handle the
return value of ClipboardInitSynthesizers(). Currently it always returns
TRUE, but this may change, so we'd better be clean.
Declare 'formatName' in wClipboardFormat as non-const. It is customary
in C to declare owned pointers as non-const because various deallocation
functions like free() take non-const pointers as arguments. Furthermore,
const char* is tightly associated with "string literals" which must not
be freed. Thus declaring this field as non-const is more accurate, and
removes that ugly void* cast from ClipboardInitFormats().
Unify error handling in ClipboardCreate(). The cleanup snippet should
not be repeated as it's prone to errors, like leaking the allocation of
clipboard->formats when ClipboardInitFormats() fails. Unified error
handling makes it much harder to forget resource cleanup on errors.