Begin of new feature: File Upload (#289).

The "Create" menu provides a new "Upload File" item. It opens a file upload dialog. The choosen file is uploaded to the server. It is not yet processed.

Plugin developers can invoke the file upload dialog programmatically:
    dm4c.upload_dialog.show(command, callback)
(Both parameters are not yet used.)

The REST API of the "Files" plugin provides a new method:
    void uploadFile(UploadedFile file, String command, ClientState clientState)

A multipart/form-data request with the file content as its body can be POSTed to /files/{command}
(The command is not yet used.)

1 class is moved from core "util" to "service" package:
    UploadedFile

The entire "Commands" concept is finally dropped from core.
2 classes are removed from the "service" package:
    CommandParams
    ComandResult
2 provider classes are removed from the "Webservice" plugin:
    CommandParamsProvider
    CommandResultProvider

See ticket 289
Merge branch 'master' into file-upload
Files plugin: store uploaded files (#289).

Try it via "Upload File" from the Create menu.
The uploaded file is stored in "deepamehta-files" (next to "deepamehta-db").
The server response is shown in an alert.

There is a new property in global POM:

    dm4.files.path

This is the path of the server-side file repository.
By default it is named "deepamehta-files" and stored next to "deepamehta-db".

The response of the upload request is an JSON object.
For the moment it contains just the name of the uploaded file.

    {
        filename: ...
    }

This JSON object is passed to the callback function that is passed to the show() method:

    dm4c.upload_dialog.show(callback)

The 2nd show() parameter ("command") is dropped.
The URI for POSTing a file is just /files (the "command" path parameter is dropped).

For the upcoming 4.0.12 release the file repository is not realized in a separate module (#291) but
an integral feature of the "Files" plugin. However, it is encapsulated in a new class: FileRepository

The class UploadedFile has moved from Core module to Files plugin.
Files plugin: avoid file repo name clashes (#289).

Every file stored in the file repository is represented by a File topic.
Its ID is prepended to the file's name. Thus file name clashes are avoided.
(Remember the file repository is flat.)

The File topic ID is included in the response of the upload request:
{{{
    {
        file_name: "Model.png",
        topic_id: 2857
    }
}}}

See ticket 289.
Files plugin: upload to arbitrary directory (#289)

The existing file repository (that is managed by the Proxy plugin) is used as the repository for uploaded files as well.
There are not two different repositories anymore.

So, the recently introduced dm4.files.path POM property is dropped.
Any location inside the Proxy plugin's file repository can be the upload target.
(The file repository's root directory is still configured by the dm4.proxy.files.path POM property.)

The "Upload File" menu item is dropped from the Create menu.
Instead every Folder topic (as revealed through the File Browser) provides an "Uplaod File" button. This button invokes the Upload Dialog. The uploaded file is stored in the directory represented by the respective Folder topic.

Hints for plugin developers:
The method for invoking the Upload Dialog is renamed and takes another mandatory parameter:
{{{
    dm4c.upload_dialog.open(storage_path, callback)
}}}
The new "storage_path" parameter is the storage location for the uploaded file.
The storage path is relative to dm4.proxy.files.path and must begin with a slash.

At REST API level the storage path is appended to the /files request path
{{{
    POST /files//store/file/here
}}}
Note the double slash. The first slash separates the storage_path parameter, the second slash is part of the storage_path parameter (which always begins with slash as aforesaid).

Example: assume this POM setting:
{{{
    <dm4.proxy.files.path>/home/terry/deepamehta-files</dm4.proxy.files.path>
}}}
When posting a multipart/form-data request with a single file part (let's say image.png) to the URI above the file will be stored at
{{{
    /home/terry/deepamehta-files/store/file/here/image.png
}}}

See ticket 289.
Webclient: revise GUIToolkit's Dialog API.

The dm4c.ui.dialog() call returns a Dialog object. This object provides these methods:
{{{
    open()
    close()
    empty()
    appen(element)
}}}
Thus, the plugin developer is provided with a high-level object-orientated API and must no longer (low-level) operate on the DOM.

Furthermore the dm4c.ui.dialog() call takes a single "config" parameter. So, the developer is no longer required to pass all the 6 parameters (in the proper order!). Instead the config object can have up to 6 properties, whereas all are optional. In particular the developer is no longer required to pass a unique ID for every dialog:
{{{
    id             - Optional: the dialog content div will get this ID. Useful to style the
                     dialog with CSS. If not specified no "id" attribute is set.
    title          - Optional: the dialog title. If not specified an empty string is used.
    content        - Optional: the dialog content (HTML or jQuery objects). If not specified
                     the dialog will be empty. It still can have a title and/or a button.
    width          - Optional: the dialog width (CSS value). If not specified "auto" is used.
    button_label   - Optional: the button label. If not specified no button appears.
                     Note: the button label and button handler must be set together.
    button_handler - Optional: the button handler function. If not specified no button appears.
                     Note: the button label and button handler must be set together.
}}}

IMPORTANT: if your plugin makes use of dm4c.ui.dialog() it must be adapted.

Another hint for plugin developers:
A plugin (with a client-side component) is not strictly required to have a main file (plugin.js)
This is perfect for plugins whose only purpose is to provide custom renderers.
This applies e.g. to the Icon Picker plugin.
Webclient GUIToolkit: new prompt() method.

{{{
dm4c.ui.prompt(title, input_label, button_label, callback)
}}}

Shows a prompt with a title, an input field, and a button.
User input is passed to the callback function.
Core: publishing a directory to the web (#292).

The Core's WebPublishingService provides a new feature for publishing a directory of the server's file system to the web.
A plugin can do so by calling:
{{{
    publishDirectory(String directoryPath, String uriNamespace)
}}}
(This method is located in the plugin base class, PluginActivator).
Unpublishing is automatic when the plugin shuts down.

This feature replaces that very feature of the Proxy plugin.
The remaining Proxy features are about to be transfered to the Files plugin and the Proxy plugin is about to be dropped.

The first plugin who uses this new feature is the Files plugin. It publishes its file repository to URI namespace /filerepo
The file repository is still be configured via the POM properties
{{{
    dm4.proxy.files.path
    dm4.proxy.net.filter
}}}
These are about to be renamed.

CAUTION: the Proxy plugin's security netfilter feature is not yet ported to the WebPublishingService, so for the moment the "file-repo" branch opens a huge security hole. Do NOT install it!

See ticket 292.
Transfer Proxy features to Files plugin (#292).

The Proxy plugin and the /proxy URI namespace are obsolete.
The Proxy plugin is removed.
Its functionality is taken over by the Files plugin.
URI namespaces for the files API and the actual file repository are respectively:
{{{
    files/
    filerepo/
}}}

The 2 dm4.proxy... config properties are obsolete.
The new properties are:
{{{
    dm4.filerepo.path
    dm4.filerepo.netfilter
}}}

CAUTION: access to the file repository is not yet secured by the netfilter setting.
For single-user installations do NOT install the "file-repo" branch.
For multi-user installations make shure dm4.filerepo.path is set to a directory whose contents are supposed to be public.

See ticket 292.
Files plugin: fix icons and map background (#292).

See ticket 292.
Files plugin: fix getResourceInfo() call (#292).

See ticket 292.
Files plugin: netfilter security (#292).

{{{
    dm4.filerepo.netfilter
}}}
This config property is respected.
Only clients belonging to the specified subnet have access to the file repository.

To restrict access to localhost:
{{{
    127.0.0.1/32
}}}
This is suitable for single-user installations.
This is the default.

To allow public access:
{{{
    127.0.0.1/0
}}}

See ticket 292.
Files plugin: consolidate security (#292, #289).

Both, the Files API (/files URI) and the file respository (/filerepo URI) are consistently secured.
Each of the respective requests is secured by 2 measures:
    - Subnet restriction: the request must originate from an allowed subnet (according to the dm4.filerepo.netfilter
      setting).
      Otherwise "403 Forbidden" is send back.
    - Fighting directory traversal attacks: once canonicalized (resolving ../ references) the request's "path"
      parameter must point inside the file repository (according to the dm4.filerepo.path setting).
      Otherwise "403 Forbidden" is send back.
Furthermore, if the request's "path" parameter refers to a non-existing resource (file or directory)
"404 Not Found" is send back.

Additionally the upload mechanism is revised: the ID of the respective File topic is not included in the name of the stored file anymore. The original (client-side) file name is only changed if such a file already exists in the file repository. In this case a -2, -3, -4, ... suffix is added to the file's basename.

See ticket 292.
See ticket 289.
Files plugin: fix opening files and folders (#292)

... via doubleclick in their origin application.

The REST API is changed:
    /files/open/<topicId>
topicId is the ID of a File or a Folder topic.

Note: opening files does not yet work in multi-user setup (that is client and server on different machines).

See ticket 292.
Files plugin: create folder in file repo (#292).

GUI:
To create a folder in the file repository a Folder topic provides a "Create Folder" button.
The new folder is created inside the directory represented by that origin Folder topic.

API:
The Files OSGi service provides a new method:
{{{
    void createFolder(String folderName, String path)
}}}
"path" is relative to the file repo root dir.
It points to the directory where to create the new folder.
It must begin with "/".

Note:
for the moment creating repo folders is different from creating repo files (through upload) in 3 regards:
1) Creating a folder doesn't involve searching for a "free" name.
   If such a folder already exists 500 Internal Server Error is returned.
2) Creating a folder doesn't automatically create a corresponding Folder topic.
   The Folder topic is created on-the-fly when browsing the repo interactively.
3) Creating a folder returns no response entity, just 204 No Content.

See ticket 292.
Webclient: polish upload dialog code (#289).

The upload dialog code is moved from Webclient to Files module.
The file upload_dislog.js is deleted.

IMPORTANT: if your plugin makes use of the upload dialog it must be adapted.
To open the dialog:
{{{
    dm4c.get_plugin("de.deepamehta.files").open_upload_dialog(...)
}}}

See ticket 289.