Dune HD STB - PLUGINS MECHANISM AND PHP API



Overview

The mechanism of plugins provides a possibility to integrate applications
into the native Dune GUI. When an application is packaged as a plugin, it
can appear in the native Dune GUI just an an icon in Dune menu.

Such applications can be implemented using a variety of technologies
supported by Dune HD STB:
   - It can be an application based on the native Dune HD GUI framework and
     implemented using PHP language and PHP API provided by Dune HD STB.
   - It can include some web server functionality (e.g. CGI scripts running
     on the STB) providing HTTP API for external systems or providing a way
     for HTML or FlashLite application to execute native code on the STB.
   - It can include any Linux software executed on demand or running in the
     background, and it can even include custom Linux kernel modules (e.g.
     drivers for certain USB hardware or kernel modules implementing
     certain DRM systems).
   - The application can also use a mix of different technologies.
   - There is also a possibility to use DirectFB/Qt-based custom GUI
     implementation, but this requires to use special firmware versions
     ("Native GUI SDK" firmware versions) and is not supported by standard
     firmware versions.
   - It can be a full-screen HTML application (on models which support HTML
     applications).
   - It can be a full-screen FlashLite application (on models which support
     FlashLite applications).

A big part of the plugins mechanism is the PHP API for implementation of
GUI functionality based on the native Dune HD GUI framework. This approach
allows quick implementation of GUI functionality tightly integrated into
the native Dune GUI. It is especially suitable for quick creation of simple
IPTV/VOD applications. The following possibilities are provided:
   - HTML coding is NOT involved; the standard GUI (native Dune HD media
     player GUI) is used automatically. The PHP code is only responsible
     for the interaction with the server part of the service (typically
     via HTTP requests), and customizing the GUI look/behavior in some
     ways.
   - OSD GUI for IPTV and VOD playback is provided automatically
     (including TV channels navigation, TV channel categories, favorite
     channels management, EPG, series navigation, etc).
   - Plugin can easily visualize hierarchical catalogs of content (TV
     channel categories, VOD categories, etc).
   - Plugin can show various user interaction dialogs (login, movie
     purchase confirmation, settings, etc).

Plugin examples

IPTV/VOD applications implemented using PHP:
   - http://files.dune-hd.com/sdk/plugins/dune_plugin_demo2.2011_12_22.zip
   - http://files.dune-hd.com/sdk/plugins/dune_plugin_demo2_with_ad.zip

Simple digital signage application (endless playback of a media_url)
implemented using PHP:
   - http://files.dune-hd.com/sdk/plugins/dune_plugin_simple_presenter.2013_07_19.zip

HTML applications packaged as plugins:
   - See "HTML plugin examples" section here:
      - http://files.dune-hd.com/sdk/doc/html/html_apps.html

An application demonstrating deep Linux integration (daemon automatically
started on STB boot, HTTP API allowing to control the daemon and access the
data in Linux filesystem, simple HTML application interacting with this
HTTP API via AJAX):
   - http://files.dune-hd.com/sdk/plugins/dune_plugin_linux_code_demo.2014_03_20.zip

Historical note

When the mechanism of plugins was first introduced in Dune HD STB, it was
originally intended for the implementation of custom GUI applications using
the provided PHP API, and it was required that each plugin included at
least some PHP code. This was the reason why plugins were originally called
"PHP plugins". Later, various features allowing to use the mechanism of
plugins w/o the need to use PHP code were added, but the term "PHP plugin"
was still used. The documentation below refers to the term "PHP plugin",
but all the features which are not directly related to the use of PHP
language are also applicable to plugins which do not actually use any PHP
code.

Implementing GUI functionality using PHP API

The mechanism of PHP plugins allows to extend Dune GUI with custom
applications implemented using PHP programming language and PHP API
provided by Dune HD STB. PHP plugins created using this mechanism are
stored in the STB flash memory and are running on the STB.

This PHP API does not allow PHP plugins to directly render an arbitrary TV
GUI and directly handle events from the remote control in arbitrary ways.
Instead, there is a high-level GUI framework with a fixed set of
possibilities, and PHP plugins may use these possibilities for custom GUI
creation.

The main goal of the PHP plugins mechanism is to allow to implement custom
IPTV/VOD applications, but it also could be used for other similar
purposes.

The possibilities provided by the PHP plugins mechanism include:
    - Showing custom screens listing various objecs (e.g. TV channels,
      movies, categories, etc). The possibilities for the customizing the
      GUI of these screens are similar to those provided by the
      "dune_folder.txt" mechanism (see
      http://dune-hd.com/support/misc/dune_folder_howto.txt).
    - Showing "movie information" screens.
    - Showing custom screens and dialogs with some GUI controls for user
      input (e.g. text fields, buttons, etc).
    - Launching playback of TV and VOD content in a special mode (with
      special TV and VOD OSD GUI).

The advantages for implementing custom applications (e.g. custom IPTV/VOD
applications) using PHP plugins mechanism are the following:
    - Reduced implementation effort.
        - No need to implement the GUI from the scratch, a high-level GUI
          framework allows to very quickly and easily implement standard
          IPTV and VOD functionality.
        - Just feed the proper data into the GUI and everything is working
          automatically.
    - Smooth integration into Dune GUI.
        - The look and feel of the custom application is the same as the
          look and feel of other STB functions.
        - Choosing a different GUI skin automatically affects the custom
          application as well.
     - All features of Dune GUI are automatically provided for the custom
       application.
        - High-quality graphics with FullHD (1920x1080) resolution.
        - Fast GUI.
        - Animation effects.
        - GUI structure with 4 screen areas (path bar, widget zone with
          date/time and weather information, main content box, optional
          details panel at the right).
        - Ability to integrate custom screens into STB Setup menu.
    - PHP plugin is stored in the STB flash memory and runs on the STB.
        - This allows to integrate with the existing server-side IPTV
          middleware APIs, w/o the need to host anything on the web server.
        - This allows to reduce the amount of the functionality that should
          be hosted/executed on the web server.
        - This allows to implement client-side caching and improve the
          performance in other ways.

Installing plugins

One STB may have one or several plugins installed. plugins may be
preinstalled (included into STB firmware), or installed by the user (using
plugin installer).

For manual installation of a plugin, a special "plugin installer" file is
needed. The plugin installer file is just a ZIP archive containing
"dune_plugin.xml" file at the top level and other files (according to
plugins needs).

To install a plugin, just launch the plugin installer file
(dune_plugin*.zip) from any media (e.g. from USB flash drive). The plugin
will be installed into the flash memory of the STB. If plugin with the same
name was already installed manually, then an option will appear allowing to
overwrite plugin or cancel installation. Note, that the preinstalled
(included into STB firmware) plugins cannot be overwritten.

Note, the STB typically requires "Flash memory storage" (a special
partition in the flash memory of the STB) or "System storage" (an external
storage device used for system needs) to be activated in order to manually
install plugins. If neither is activated yet, the STB will propose to
activate "Flash memory storage" during plugin installation. For more
information about "Flash memory storage" and "System storage", please see
http://dune-hd.com/support/usb_flash_drive .

All installed plugins are listed in "Setup / Misc / Plugins" menu. This
menu allows to delete the previously manually installed plugins (select the
plugin, press ENTER, choose "Delete").

Providing additional plugins via "dune_plugins" folder

There is a special possibility which allows to add plugins to
the list of registered plugins, using a special "dune_plugins" folder. This
folder should be located at the top-level of the "main" storage device.
This folder should contain one or several subfolders, where each subfolder
should contain the data of one plugin (i.e. the dune_plugin.xml and other
plugin data).

NOTE: In order to ensure that the storage device is recognized as the
"main" one, it should be either the only storage device connected to the
player at the moment, or the only storage device connected to the player at
the moment when the player is switched on.

NOTE: This possibility is not recommended for normal users; it is mostly
intended for the development needs (e.g. when it is needed to edit the
plugin PHP code and look at the result).
NOTE: to apply changes made in "dune_plugins" folder one should press POWER
remote button twice: first to turn STB into standby mode and second to turn
it on again.

Redirecting plugin logs to "dune_plugin_logs" folder

There is a special possibility which allows to redirect logs produced by
all plugins which were installed manually to the special "dune_plugin_logs"
folder. This folder should be located at the top-level of the "main"
storage device. Normally, all logs are written to some temporary folder not
accessible from the outside. If "dune_plugin_logs" exists all logs from the
non-built-in plugins will be written to this folder.

NOTE: In order to ensure that the storage device is recognized as the
"main" one, it should be either the only storage device connected to the
player at the moment, or the only storage device connected to the player at
the moment when the player is switched on.

NOTE: This possibility is not recommended for normal users; it is mostly
intended for the development needs. It is recommended to use HDD instead of
Flash drive as "main" storage device for writing logs to.

Plugin files structure

The plugin contains the following files:

1. dune_plugin.xml (required)
    - This is plugin manifest in XML format. This is the only file required
      by the STB in order to load the plugin. All other plugin files (if
      any) are specified in the plugin manifest, and can have any names.

2. For PHP plugins: the PHP program containing hd_create_plugin() function.
   (required)
    - The path to the file with this PHP program is specified in
      "dune_plugin.xml".

3. Translation tables
    - The files translations/dune_language_<lang>.txt will be automatically
      loaded to the global STB translation table on STB start or when
      interface language is changed by user. The keys provided in
      translation files can be accessed using special syntax in public
      string of PHP API.
      See the "Interface language translations" section for more details.

4. Some resources accessible by HTTP in web and web/cgi-bin directories.
    - These resources will be accessible using the following url schema:
        http://<STB-address>/plugins/<plugin-name>/<path-from-www>
        http://<STB-address>/cgi-bin/plugins/<plugin-name>/<path-from-cgi-bin>
      See "HTTP server extension" section for more details.

5. Any other files, e.g. some resources (e.g. images/icons) (optional)
    - These files may be referenced by "dune_plugin.xml" or other files, or
      used in other ways by the PHP program.

Plugin manifest

The sample manifest of plugin called 'sample' may look as following:

<dune_plugin>
  <name>sample</name>
  <caption>Sample</caption>
  <type>php</type>
  <params>
     <program>sample.php</program>
  </params>
  <entry_points>
    <entry_point>
        <parent_media_url>root://applications</parent_media_url>
        <section_index>0</section_index>
        <is_default_section>yes<is_default_section>
        <icon_url>plugin_file://icons/logo_big.png</icon_url>
        <small_icon_url>plugin_file://icons/logo_small.png</small_icon_url>
        <caption>Sample Section</caption>
        <actions>
          <key_enter>
            <type>plugin_handle_user_input</type>
            <params>
              <handler_id>root</handler_id>
              <control_id>enter_from_section_screen</control_id>
            </params>
          </key_enter>
        </actions>
    </entry_point>
    <entry_point>
        <parent_media_url>root://tv</parent_media_url>
        <media_url>main_tv</media_url>
        <caption>Sample.TV</caption>
        <icon_url>plugin_file://icons/sample_tv.png</icon_url>
        <icon_margins><left>0</left><top>30</top><right>0</right><bottom>20</bottom></icon_url>
        <icon_fit_scale_factor>1.0</icon_fit_scale_factor>
        <badge_icon_url>gui_skin://large_icons/4.png</badge_icon_url>
        <small_icon_url>plugin_file://icons/logo_small.png</small_icon_url>
        <override_default_badge>no</override_default_badge>
        <actions>
          <key_enter>
            <type>plugin_open_folder</type>
          </key_enter>
          <key_play>
            <type>plugin_tv_play</type>
          </key_play>
        </actions>
        <popup_menu>
          <menu_items>
            <item>
                <caption>Clear TV Cache</caption>
                <action>
                    <type>plugin_handle_user_input</type>
                    <params>
                        <op>clear_cache</op>
                    </params>
                </action>
            </item>
          </menu_items>
        </popup_menu>
        <show_by_default>yes</show_by_default>
        <show_cookie_name>show_tv_entry_point</show_cookie_name>
        <ip_address_required>yes</ip_address_required>
        <valid_time_required>yes</valid_time_required>
    </entry_point>
    <entry_point>
        <parent_media_url>root://applications</parent_media_url>
        <media_url>main_vod</media_url>
        <caption>Sample.VOD</caption>
        <icon_url>plugin_file://icons/sample_vod.png</icon_url>
        <small_icon_url>plugin_file://icons/logo_small.png</small_icon_url>
        <actions>
          <key_enter>
            <type>plugin_open_folder</type>
          </key_enter>
        </actions>
        <show_by_default>yes</show_by_default>
        <show_cookie_name>show_vod_entry_point</show_cookie_name>
        <ip_address_required>yes</ip_address_required>
        <valid_time_required>yes</valid_time_required>
    </entry_point>
  </entry_points>
  <auto_resume>
     <enable>yes</enable>
     <ip_address_required>yes</ip_address_required>
     <valid_time_required>yes</valid_time_required>
  </auto_resume>
  <operation_timeout>
    <default>20</default>
    <get_epg_day>30</get_epg_day>
  </operation_timeout>
</dune_plugin>

Details:

- dune_plugin->name: plugin identifier. It should be nonempty and may
  contain only alphanumeric and ('-', '.', '_') characters. Length is
  limited by 64.

- dune_plugin->caption: caption used in Setup / Misc / Plugins

- dune_plugin->type and dune_plugin->params: the type of engine used to
  execute plugin and it's parameters. Currently only the 'php' type is
  supported having single mandatory 'program' parameter pointing to the
  main php file of plugin.

- dune_plugin->entry_points: list of the plugin entry points in the Dune
  menu. Each dune_plugin->entry_points->entry_point may contain the
  following fields:

  - 'parent_media_url': the URL of folder containing this entry
    point. Now the following folders are allowed to contain plugin
    items:
      root://tv
      root://applications
      setup://applications
      root://video              (*) available in firmware 130424_b6+
      root://music_and_radio    (*) available in firmware 130424_b6+
      root://news_and_weather   (*) available in firmware 130424_b6+
      root://social_networks    (*) available in firmware 130424_b6+
      root://games              (*) available in firmware 130424_b6+
      root://setup              (*) available in firmware 130424_b6+

  - 'section_index'             (*) available in firmware 120901+
    'is_default_section'        (*) available in firmware 120901+
    Specify the visualization of entry point in cas main screen style is
    "Folders". Other main screen styles are not affected.
    If 'section_index' is specified, then entry point is shown on the main
    screen (together with sections 'TV', 'Applications', 'Sources', 'Setup'
    etc...). The value of 'section_index' specifies the index number. The
    'is_default_section' allows to force the entry point to be focused when
    main screen is entered first time.
      NOTE: in firmware versions other than 130906_b8+ the options
      'section_index' and 'is_default_section' take effect only if
      'parent_media_url' is root://applications.

  - 'caption': entry point caption.

  - 'icon_url'
    'icon_margins'              (*) available in firmware 120606+
    'icon_fit_scale_factor'     (*) available in firmware 120606+
    'badge_icon_url'            (*) available in firmware 120901+
    'override_default_badge'    (*) available in firmware 141005_b9+
    visualization parameters of entry point in parent folder. For more
    details see the description of similar ViewItemParams properties in
    "Regular folder GUI customization" section.

  - 'small_icon_url'
    Specifies URL to small icon of plugin. Depending on appearance
    settings, the plugin small icon can be shown in path box and, more
    rarely, in content box of type 'List'.
    The URLs of type plugin_file:// and gui_skin:// are supported.
      NOTE: Available in firmware 131106_b6+

  - 'media_url': identifier of menu node of the plugin menu hierarchy
    Identifier should be unique in scope of plugin. The 'media_url'
    will be used in some plugin operations.

  - 'actions': the event->action mapping. The list of pairs: event_id =>
    action specification. If entry point is focused and the specified key
    is pressed then the corresponding action will be executed by Dune GUI.
    See the "Plugin PHP program main features overview" section for more
    details about how the Dune GUI works with the entry points.
    See the "GUI Actions" section for more details about the concept of GUI
    action and for the list of available GUI actions.

  - 'popup_menu': the list of additional popup menu items to be addded to
    the context menu of entry point.

  - 'show_by_default' and 'show_cookie_name': this is a way for
   plugin to show/hide entry points.
   The 'show_cookie_name' is a name of plugin cookie (e.g. the
      persistent property name) whose value is used as boolean
      expression. The expression is evaluated to decide whether to
      show entry point in Dune menu. The expression syntax is the
      following:
        yes
        no
        lang(<lang1>,...,<langN>).
      The 'show_by_default' is used if 'show_cookie_name' is not set.

  - 'show_action'
    Allows to specify GUI action to be executed each time GUI framework
    determines whether entry point is shown or not. The exit status of
    action is used to decide whether to show entry point: zero status is
    "yes", other status is "no". It is not recommended to use this way of
    hiding entry points, use 'show_cookie_name' instead when possible.
      NOTE: Available in firmware 130315_b6+

  - 'ip_address_required': yes | no. If 'yes' is specified and the IP address
    is not available yet then opening of this entry point will cause the
    WaitIpAddress dialog to appear until the IP address is got or user
    presses Cancel button or dialog is cancelled by timeout.

  - 'valid_time_required': yes | no. If 'yes' is specified and the valid time
    is not synchronized from internet yet then opening of this entry point
    will cause the WaitValidTime dialog to appear until the valid time is
    got or user presses Cancel button or dialog is cancelled by timeout.

- auto_resume: the specification of auto-resume feature which is disabled
  by default. The following fields supported:

    - enable: yes/no. This enables auto-resume feature. The default
          implementations supporting all use-cases (live TV playback,
          archive TV playback, VOD playback) will be used.

    - action: GUI action. This GUI action will be executed in case of
          auto-resume instead of the default algorithm.

    - ip_address_required: yes/no. If yes => the wait_ip_address dialog is
      shown if needed in auto-resume use-case.

    - valid_time_required: yes/no. If yes => the wait_valid_time dialog is
      shown if needed in auto-resume use-case.

- operation_timeout: allows to change the default timeout for plugin
  operations. The operation timeout is 10 seconds by default. The default
  operation timeout can be changed to N using <default>N<default>. Also the
  operation timeout can be specified for each operation type. To change the
  timeout for operation 'op' to N use construction: <op>N</op>. Exapmle:
    <operation_timeout>
      <default>20</default>
      <get_epg_day>30</get_epg_day>
      <handle_user_input>40</handle_user_input>
    </operation_timeout>
  As a result, all operations has timeout 20 seconds, except the
  get_epg_day() (30 seconds) and handle_user_input() (40 seconds).

High-level design overview for PHP plugins

There is central Dune GUI component, that does all the job to handle remote
control, draw graphics, show video streams and so on.

The Dune GUI can also manage multiple PHP plugins.

Every PHP plugin runs in a separate process, where PHP engine is
initialized.

The Dune GUI communicates to PHP plugins using IPC (inter-process
communication), in particular: UNIX pipes. The protocol is in plain text
and uses JSON to represent structured data.

The communication is actually one-way: Dune GUI makes a request (or a
call) and asynchronously waits for a PHP plugin to reply. If the PHP plugin
failed to reply within pre-defined timeout, an error is reported.

PHP plugins are not able to initiate a call to Dune GUI.

Basically, a call from the Dune GUI to a PHP plugin can be formulated
by the following meta-declaration:

    string call_plugin(in string call_ctx_json);

  - The Dune GUI prepares a structure of some sort, where it specifies
    operation code and operation parameters (so called "input-data");

  - This structure is then encoded (serialized) to a string using JSON;

  - The string is passed to the PHP plugin using IPC;

  - PHP plugin deserializes the string to a structure, retrieves operation
    code and operations parameters, executes the operation to get another
    structure (so called "output-data") to be passed back to the Dune GUI;

  - The output structure is again serialized to a string using JSON, and
    is passed back to the Dune GUI;

  - The Dune GUI deserializes the string into a structure and uses the data
    to do needed actions.

Thus, ultimately, the PHP plugin need to implement the only one function:

    string call_plugin(in string call_ctx_json);
    (actual name see below in the "System PHP files" section)

However, it's too cumbersome and error-prone to implement the same logic
for every plugin over and over again, so SDK provides a framework, which
does all the job of marshalling data and invoking the right operation.

System PHP files

STB includes several system PHP files which are automatically sourced by
the PHP engine instance before plugin PHP program loading. PHP definitions
and symbols provided by these system PHP files are automatically available
to plugin PHP program.

In the STB firmware, these PHP files are located in "/firmware_ext/php"
directory.

These files basically defines an interface between Dune GUI and plugin PHP
programs.

The files are:

    - bootstrap.php

      - Setups error reporting within PHP engine so that all errors are
        logged to the internal log file.

      - Setups correct (current) timezone.

      - Provides the following global functions:

        - hd_print($text_message)

          This function should be used instead of PHP functions 'echo',
          'print', 'printf' etc.

          By using this function developer makes sure the text gets to the
          log file in the proper format.

          This function uses global $HD_NEW_LINE contant, which is an empty
          string ('') by default.

        - hd_silence_warnings()

          This function should be used to temporarily disable warning from
          system PHP functions.

        - hd_restore_warnings()

          This function restores warning logging after
          hd_silence_warnings().

      - The following global functions are also defined in bootstrap.php,
        but usually should not be used explicitly in PHP plugins:
        - hd_error_handler()
        - hd_shutdown_handler()
        - hd_error_silencer()

    - dune_plugin.php

      - Defines high-level interface between the Dune GUI and plugin PHP
        programs -- DunePlugin interface -- a set of operations, which
        the Dune GUI can call against the PHP program.

        If default framework (see below) is in use, all calls from the Dune
        GUI to a plugin PHP program are dispatched to an instance of
        DunePlugin interface.

    - dune_plugin_fw.php

      - Provides low-level interface (in terms of strings) between the Dune
        GUI and plugin PHP programs.

      - Provides utility functions.

    - dune_api.php

      - Contains definitions of various string constants which are
        helpful for passing the data between the plugin PHP program and
        Dune GUI.

Plugin PHP program basics

Every plugin PHP program eventually must do the following steps:
  - Provide a class derived from DunePluginFw;
  - Implement DunePluginFw::call_plugin() in the derived class;
  - Assign an instance of the new class to DunePluginFw::$instance;

DunePlugin interface

On the high-level, the interface between the Dune GUI and a plugin PHP
program is specified by the DunePlugin interface, declared in
dune_plugin.php file.

Currently the DunePlugin interface looks as follows:

interface DunePlugin
{
    // PluginFolderView
    public function get_folder_view(
        /* [in]     String                      */  $media_url,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    // PluginFolderView
    public function get_next_folder_view(
        /* [in]     String                      */  $media_url,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    // PluginTvInfo
    public function get_tv_info(
        /* [in]     String                      */  $media_url,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    // String
    public function get_tv_stream_url(
        /* [in]     String                      */  $playback_url,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    // PluginVodInfo 
    public function get_vod_info(
        /* [in]     String                      */  $media_url,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    // String
    public function get_vod_stream_url(
        /* [in]     String                      */  $media_url,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    // PluginRegularFolderRange 
    public function get_regular_folder_items(
        /* [in]     String                      */  $media_url,
        /* [in]     int                         */  $from_ndx,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    // List<PluginTvEpgProgram>
    public function get_day_epg(
        /* [in]     String                      */  $channel_id,
        /* [in]     int                         */  $day_start_tm_sec,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    // String 
    public function get_tv_playback_url(
        /* [in]     String                      */  $channel_id,
        /* [in]     int                         */  $archive_tm_sec,
        /* [in]     String                      */  $protect_code,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    // void
    public function change_tv_favorites(
        /* [in]     String                      */  $op_type,
        /* [in]     String                      */  $channel_id,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    // GuiAction
    public function handle_user_input(
        /* [in]     Map: Key -> Value           */  &$user_input,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);
}

The output type of plugin operation:

class PluginOutputData
{
    Boolean                 has_data;
    PluginOutputDataType    data_type;
    Object                  data;
    Map<String, String>     plugin_cookies;
    Boolean                 is_error;
    GuiAction               error_action;
}

Each plugin operation should return one of the following:
    - normal output: 'is_error' is false, 'error_action is null, 'has_data'
      is true, 'data' contains the normal output data of type specified in
      'data_type';
    - error output: 'is_error' is true, error_action may be set to some GUI
      action to be executed.

Plugin PHP program lifecycle

Each PHP plugin is executed in its own instance of PHP engine (running in a
its own separate process). The PHP engine instance for each PHP plugin is
created when the PHP plugin is used for the first time.

PHP plugin always handles just one call from Dune GUI at a time. Multiple
calls from Dune GUI to PHP plugin are always serialized.

Typically, subsequent calls from Dune GUI to PHP plugin are delivered to
the same PHP engine instance. Thus, global PHP variables are preserved
between subsequent calls.

However, each PHP engine instance may be destroyed/recreated at any moment
(between calls from Dune GUI to PHP plugin) when this is needed by Dune
GUI. When this happens, global PHP variables are not preserved.

So, PHP plugin must not assume that global PHP variables are preserved
between subsequent calls from Dune GUI to PHP plugin. PHP plugin is allowed
to use global PHP variables e.g. for the implementation of some caches (may
be helpful for performance reasons), but it must be prepared that these
global variables disappear between subsequent calls and implement a proper
strategy for repopulating the caches when needed.

When possible, PHP plugin should be designed as a stateless program. When
some transient global state is needed and it is critical to preserve this
state between subsequent calls to PHP plugin, this should be implemented in
a special way, e.g.:
    - The state should be encoded in parameters which are passed between
      PHP plugin and Dune GUI, so Dune GUI keeps the state.
    - The state should be stored in the directory for temporary transient
      data (RAM disk in the STB).
    - The state should be stored on the Internet server (if PHP plugin
      interacts with some Internet server).

Plugin PHP program environment

1. Cookies.

    - each plugin has a list of persistent string settings known as plugin
    cookies. This map(string => string) is passed by reference to each plugin
    operation. So, operations may use cookie values and can modify them.
    The cookies keep their values between operations and even survive the
    STB restart.
    NOTE: plugin cookies are not supposed to keep large amount of data

2. System properties.

    - the PHP plugin code has access to the DuneSystem::$properties array.
      Currently the following properties are provided:

      'plugin_name' - current plugin name;
      'install_dir_path' - path to directory where plugin is installed to;
      'tmp_dir_path' - path to directory under /tmp which is designed for
          storing plugin's temporary data. Dune GUI ensures that directory
          exists.
      'data_dir_path' - path to directory for storing persistent data.
          NOTE: this directory is not available on STBs without System
          Storage and Flash Memory Storage. In the latter case
          'data_dir_path' is unset.
      'plugin_www_url' - the common HTTP prefix for WWW-files included into
          plugin (for local access);
      'plugin_cgi_url' - the common HTTP prefix for CGI scripts included
          into plugin (for local access).
       In particular, the 'plugin_www_url' and 'plugin_cgi_url' contains
          strings:
          http://127.0.0.1/plugins/<plugin_name>/
          http://127.0.0.1/cgi-bin/plugins/<plugin_name>/

NOTE: After each write into persistent location, "sync" UNIX command or
system call should be performed immediately.

Plugin PHP program main features overview

Each method in DunePlugin interface corresponds to the so-called plugin
operation. Each operation has input type (simple) and output type
(sometimes considerably complex). The output data should be returned from
DunePlugin method as PHP array. The keys for output PHP arrays are defined
in the dune_api.php.

The PHP plugin may extend the base Dune functionality in the following
ways:

  - extend Dune menu hierarchy (the Dune menus also known as 'folders').
    Some of general Dune folders (in particular, the 'TV', 'Applications'
    and 'Setup->Applications') may be extended by adding new elements which
    are called 'plugin entry points'. Each entry point is owned by one
    plugin. Typically entry points contain folder hierarchy managed by
    plugin.

  - launch plugin-TV playback. Plugin-TV playback is the special playback
    mode allowing to play TV channels, browse list of channels united into
    categories (also known as groups), browse channel EPG etc.

  - launch plugin-VOD playback. Plugin-VOD playback is the special playback
    mode allowing to play movie or a series (list of episodes united by
    single title).

The default look and behaviour of general Dune folders is extended by
plugins in the following way:
  - new folder element is added for each registered plugin and each entry
    point in plugin manifest. The icon URL and caption for each entry point
    are taken from manifest;
  - the owner plugin takes control over user input when entry point is
    focused. Currently plugin may override the standard behaviour of the
    following remote keys in general folders: ENTER, PLAY.

The technique used by plugins to affect the behaviour of Dune GUI is base
on the concept of GUI actions. For more details about GUI actions see the
"GUI actions" section.

Briefly the GUI action is the instruction for Dune GUI what to do when user
presses remote button in particular state of GUI. GUI action is typically
created in PHP code as array with the following fields:
  - handler_string_id : [string] type of action
  - data: [array] PHP array of type-specific action parameters.

There is a number of GUI action types including:
  - PLUGIN_OPEN_FOLDER. Browses into some GUI element. Opens a new folder
    (submenu) fully managed by plugin. Such folders are called 'plugin
    folders'.
  - PLUGIN_TV_PLAY. Launches the plugin-TV playback.
  - PLUGIN_VOD_PLAY. Launches the plugin-VOD playback.
Also there is one special action type called HANDLE_USER_INPUT. Execution
of HANDLE_USER_INPUT involves:
  - running some arbitrary plugin code. Specifically, the
    handle_user_input() plugin operation is executed having current Dune
    GUI state as a parameter;
  - immediate execution of another GUI action specified by plugin.
    Actually, the return value of handle_user_input() operation is
    executed as GUI action.

The plugin folder has string identifier which is non-obviously called
'media_url'. So let's assume that every plugin folder (including entry
point) has 'media_url' value unique in scope of plugin.

The plugin folders are divided into 3 general types:

1. Regular folder.

   The most common type of folder used to show the list of objects of any
   kind as table with fixed number of rows and columns. Each table cell may
   contain image and text. The visualization of regular folder can be
   adjusted using large number of settings. Also plugin may specify several
   variants of folder representation; these variants can be switched by
   pressing A_RED remote button. Let's call variant of regular folder
   representation 'folder view'.

   The regular plugin folder behaves similar to general Dune folders but
   the effect of pressing several remote keys should be explicitly
   specified by plugin; otherwise they will be ignored. These remote keys
   are: ENTER, PLAY, INFO, POPUP_MENU, B_GREEN, C_YELLOW, D_BLUE. In other
   words plugin may assign GUI actions to the listed keys.

   The regular folders can be divided into:
    - simple (preloaded): the whole content of folder is returned at once;
    - lazy loaded with known size: the number of folder elements is known
      but it is considerably big and folder content is loaded by chunks
      when user scrolls;
    - lazy loaded with unknown size: the same as before but the number of
      total elements is unknown until end is reached.

   The most regular folders are simple; however Dune plugin framework
   have support for lazy-loading of regular folders.

2. Control folder.

   The folder type designed to be used in setup. The control folder looks
   as vertical list of GUI controls and constant text strings.

   The following controls are supported:
     - button.
     - combobox
     - text field

   Plugin may assign specific GUI actions to the following events:
     - button pressed;
     - combobox value changed;
     - text field value changed.

   The HANDLE_USER_INPUT GUI action should be used to apply/save changes.

3. Movie folder.

   The special layout for representing the detailed information about
   movie. The following movie properties can be shown in such folder:
    - movie name
    - movie name in the original language
    - poster image
    - list of genres
    - country
    - year
    - director(s)
    - actors
    etc..

   The layout also includes one or two buttons:
     - mandatory button 'PLAY' in the left-bottom corner with the following
       predefined handling. When pressed the number of movie series is
       cheched:'
       - (number_of_series > 1) => folder with list of series is opened;
       - (number_of_series = 1) => VOD-playback is launched for movie.
     - optional button with custom caption and GUI action in the
       right-bottom corner. This button may be used to implement 'Add to
       favorites' and 'Remove from favorites' use-cases.

To support the folder hierarchy the plugin PHP program should implement at
least the DunePlugin::get_folder_view($media_url).

To support the multiple folder views the plugin PHP program should
implement DunePlugin::get_next_folder_view($media_url).

To support lazy-loading of regular folders the plugin PHP program should
implement DunePlugin::get_regular_folder_items($media_url) consistently
with the DunePlugin::get_folder_view($media_url).

To apply/save changes in setup settings the plugin PHP program should
implement DunePlugin::handle_user_input($params).

The TV playback has optional features:
  - EPG browsing;
  - archive playback;
  - protected channels;
  etc.

Both TV and VOD playback modes have optional feature:
  - variable stream URLs.

To support minimal TV playback the plugin PHP program should implement
DunePlugin::get_tv_info($media_url) and
DunePlugin::get_tv_playback_url($media_url, $archive_tm_sec, $protect_code).

To support EPG browsing the plugin PHP program should implement
DunePlugin::get_day_epg($channel_id, $day_start_tm_sec);

To support archive playback the DunePlugin::get_tv_playback_url(...) should
accept non-zero $archive_tm_sec argument (consistently with the returned
data from get_tv_info());

To support protected channels feature the
DunePlugin::get_tv_playback_url(...) should accept non-empty $protect_code.

To support variable TV stream URLs the plugin PHP progam should implement
DunePlugin::get_tv_stream_url($playback_url).

To support VOD playback the plugin PHP program should implement
DunePlugin::get_vod_info($media_url).

To support variable VOD stream URLs the plugin PHP progam should implement
DunePlugin::get_vod_stream_url($playback_url).

Typical PHP program notes

The typical plugin PHP consists of the following.

1. The manifest file dune_plugin.xml containing:

    - plugin name
    - plugin caption
    - plugin type (php) and the main PHP program file (<plugin_name>.php)
    - the list of entry points
    - the auto_resume specification

If plugin provides IPTV service then it adds entry point to the TV menu.
This entry point reacts as PLUGIN_OPEN_FOLDER to the ENTER remote key and
PLUGIN_TV_PLAY to the PLAY remote key.

If plugin provides some non-IPTV services then it adds one or more entry
points to the Applications menu.

Also typical plugin adds one entry point to the Setup->Applications menu.

The plugins providing playback of video/audio streams should usually turn
on the 'auto_resume' feature to allow the automatic resume of playback
state after STB restart.

2. Folder hierarchy.

Usually the TV entry point contains 2-level regular folder hierarchy:
  - 1st level contains list of TV channel categories. Each category item
    acts as folder when ENTER pressed. The TV playback is launched when
    PLAY is pressed;
  - 2ns level contains channels. Each channel item react as TV_PLAY to the
    both ENTER and PLAY remote keys.

The entry points providing access to VOD services may have folder hierarchy
of arbitrary depth splitting the movie database into categories. Each
category is represented as regular folder having subcategories and movies
as elements. The movie element opens the folder or Movie type. Movie
playback can be launched from inside the movie folder.

3. Playback.

Typically the TV playback is launched:
    - by pressing ENTER/PLAY remote button on the regular folder
      element representing channel;
    - by pressing PLAY on the regular folder element representing channel
      category;
    - by pressing PLAY on the TV entry point.

Typically the VOD playback is launched:
    - by pressing ENTER/PLAY remote button on the regular folder element
      representing movie or movie series;
    - by pressing ENTER/PLAY on the PLAY button in the movie folder.

Also the TV/VOD playback can be launched automatically on STB power-on in
the autoresume use-case.

4. Setup screen.

The entry point to the setup screen is located in Setup->Applications menu.
Setup screen is implemented as plugin folder of 'Control folder' type.

Typically setup screen contains 'Show in main screen' combobox with Yes/No
values. 

The HANDLE_USER_INPUT GUI action and the corresponding handle_user_input()
plugin operation should be used to apply changes and save settings in the
persistent location.
Typically the plugin cookies are used to keep setup settings locally.

Plugin operations

The short description of the plugin operations.
NOTE: see the dune_api.php for the complete list of fields for each output
data type.

1. Get_folder_view()

    // PluginFolderView
    public function get_folder_view(
        /* [in]     String                      */  $media_url,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    Returns current folder content representation data for the plugin menu
    folder identified by $media_url.

    This operation is called when Dune GUI executes PLUGIN_OPEN_FOLDER GUI
    action.

    Output data:
    class PluginFolderView
    {
        PluginFolderViewKind         view_kind;
        union (PluginFolderViewKind) data;
        Boolean                      multiple_views_supported;
        PluginArchiveDef             archive;
    }

    The 'archive' is the optional specification of the plugin archive used
    with this folder. See "Plugin archives" section for more details about
    plugin archives.

    The 'multiple_views_supported' specifies whether the multiple views are
    are available for this folder. See description of GET_NEXT_FOLDER_VIEW
    plugin operation for more details.

    The 'view_kind' can be one of the following:
      - PLUGIN_FOLDER_VIEW_REGULAR
      - PLUGIN_FOLDER_VIEW_CONTROLS
      - PLUGIN_FOLDER_VIEW_MOVIE

    The 'data' is specific for view_kind:
      - regular folders: PluginRegularFolderView
      - control folders: PluginControlsFolderView
      - movie folders: PluginMovieFolderView

    Regular folder data
    ~~~~~~~~~~~~~~~~~~~

    class PluginRegularFolderView
    {
        ViewParams               view_params;
        ViewItemParams           base_view_item_params;
        ViewItemParams           not_loaded_view_item_params;
        GuiActionMap             actions;
        GuiTimerDef              timer;
        Boolean                  async_icon_loading;
        Boolean                  async_icon_loading_pipelining;
        int                      async_icon_loading_max_connects;
        PluginRegularFolderRange initial_range;
    }

    The 'initial_range' specifies the initial range of folder elements.
    The initial range for simple (preloaded) folders should contain all
    folder elements. The initial range for lazy-loaded folders should
    contain the first chunk of data or even the empty list. See the
    description of Get_regular_folder_items() plugin operation.

    The 'view_params' specifies the whole folder representation paramsters
    such as num_cols, num_rows, async_icon_loading etc..

    The 'async_icon_loading' specifies whether to use asynchronous icon
    loading by default. See "Asynchronous image loading" section for more
    details.

    The 'async_icon_loading_pipelining' specifies value used as
    CURLMOPT_PIPELINING for asynchronous image loading (see libcurl
    documentation for more details). The default value is true.
      NOTE: Available in firmware 120616+.

    The 'async_icon_loading_max_connects' specifies value used as
    CURLMOPT_MAXCONNECTS for asynchronous image loading (see
    libcurl documentation for more details). The default value is 8.
      NOTE: Available in firmware 120616+.

    The 'base_view_item_params' specifies the default values for
    representation parameters of each folder element.

    The 'not_loaded_view_item_params' specifies the representation of the
    special state of each folder element. It is used when element's image
    is (1) not yet loaded or (2) loaded with error (loading failed).
    NOTE: currently this value is ignored if
    ViewParams::async_icon_loading == false.

    The 'actions' specifies the {event -> GUI action} mapping for interaction
    with user.

    The 'timer' allows to specify timer event delay. The timer event will
    be generated only once, but timer can be reset using ChangeBehaviour
    GUI action.

    Control folder data
    ~~~~~~~~~~~~~~~~~~~

    class PluginControlsFolderView
    {
        Array<GuiControlDef>    defs;
        int                     initial_sel_ndx;
        PluginFolderViewParams  params;
    }

    class PluginFolderViewParams
    {
        Boolean     paint_path_box;
        Boolean     paint_content_box_background;
        String      background_url;
    }

    The 'defs' specifies list of GUI control definitions. See the
    "GUI controls" section for more details.

    The 'initial_sel_ndx' specifies the 0-based index of GUI control to
    gain focus first. The special value of -1 value indicates that default
    (first) GUI control should be focused first.

    Movie folder data
    ~~~~~~~~~~~~~~~~~

    class PluginMovieFolderView
    {
        PluginMovie             movie;

        String                  left_button_caption;
        GuiAction               left_button_action;

        Boolean                 has_right_button; String
        String                  right_button_caption;
        GuiAction               right_button_action;

        Boolean                 has_multiple_series;
        Boolean                 series_media_url;

        VAlign                  poster_valign;

        PluginFolderViewParams  params;
    }

    class PluginFolderViewParams
    {
        Boolean     paint_path_box;
        Boolean     paint_content_box_background;
        String      background_url;
    }

    The 'movie' specifies a number of movie properties. See the list of
    movie properties below.

    The 'left_button_caption' specifies caption of the left button. This
    property is optional, the 'Play' is used by default.

    The 'left_button_action' specifies GUI action assigned with left
    button. This value is optional, the VOD_PLAY gui action is used by
    default.

    The 'has_right_button' specifies whether button in the right-bottom
    corner of movie folder page should be painted.

    The 'right_button_caption' specifies caption of the right button.

    The 'right_button_action' specifies GUI action assigned with right
    button.

    The 'has_multiple_series' specifies the effect of pressing ENTER remote
    key on the PLAY GUI button located in the left-bottom corner of movie
    folder page:
        - when FALSE => PLUGIN_VOD_PLAY GUI action is executed
        - when TRUE => PLUGIN_OPEN_FOLDER GUI action is executed with
          explicit media_url taken from 'series_media_url' parameter.
    This scheme is designed to implement use-case of series, i.e. movie
    divided into series. In this case pressing ENTER remote key should have
    effect of opening the list of series.

    The 'series_media_url' is used with 'has_multiple_series' = true. It
    identifies the folder which should be opened when user press ENTER
    remote button having PLAY button focused.

    The 'poster_valign' specifies vertical alignment of poster. It is used
    when poster aspect ratio does not respect the default poster
    placeholder.
      NOTE: Available in firmware 120610+.

    class PluginMovie
    {
        String  name;
        String  name_original;
        String  description;
        String  poster_url;
        int     length_min;
        int     year;
        String  directors_str;
        String  scenarios_str;
        String  actors_str;
        String  genres_str;
        String  rate_imdb;
        String  rate_kinopoisk;
        String  rate_mpaa;
        String  country;
        String  budget;
        Map<String,String> details;
        Map<String,String> rate_details;
    }

    - The 'details': additional pars in the main (scrollable) area.

    - The 'rate_details': additional lines in the ratings area (under
      poster).

2. Get_next_folder_view()

    // PluginFolderView
    public function get_next_folder_view(
        /* [in]     String                      */  $media_url,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    Returns next folder view for the plugin menu folder identified by
    $media_url.

    Some regular folders may have several views (e.g. with different
    num_rows, num_cols, different size of icons etc..). Such views can be
    switched by pressing A_RED remote button. To enable this feature for
    particular folder, plugin should specify
    PluginFolderView::multiple_views_supported == true. In this case
    pressing A_RED will cause Get_next_folder_view() to be called.

    See Get_folder_view() plugin operation description for more details.

3. Get_regular_folder_items()

    // PluginRegularFolderRange 
    public function get_regular_folder_items(
        /* [in]     String                      */  $media_url,
        /* [in]     int                         */  $from_ndx,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    Returns the specified chunk of folder element for the folder identified
    by $media_url.

    This is part of lazy-loading feature of regular folders.

    Dune GUI never calls this operation for simple (preloaded) folder. 

    The Get_regular_folder_items() operation is called for lazy-loaded
    folder each time some not yet loaded elements should be visualized
    (typically when user scrolls though the folder elements). The folders
    element are cached in memory until folder is exitted.

    See Get_folder_view() operation description for more details.

4. Get_tv_info()

    // PluginTvInfo
    public function get_tv_info(
        /* [in]     String                      */  $media_url,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    Returns data needed to launch plugin TV playback. The $media_url
    argument is used as hint about what channel should be played first.

    This operation is called when Dune GUI executes PLUGIN_TV_PLAY GUI
    action.

    The output data of get_tv_info:

    class PluginTvInfo
    {
        unixtime_t              server_time;
        List<PluginTvGroup>     groups;
        List<PluginTvChannel>   channels;
        Boolean                 show_group_channels_only;
        Boolean                 favorites_supported;
        List<String>            favorite_channel_ids;
        String                  favorites_icon_url;
        String                  initial_group_id;
        String                  initial_channel_id;
        Boolean                 initial_favorites;
        unixtime_t              initial_archive_tm;
        GuiActionMap            actions;
        GuiTimerDef             timer;
        Boolean                 ip_address_required;
        Boolean                 valid_time_required;
        EpgMode                 epg_mode;
        PluginFontSize          epg_font_size;
        Boolean                 epg_day_use_local_tz;
        int                     epg_day_shift_sec;
        Boolean                 custom_protect_code_handling;
        Boolean                 subtitles_osd_enabled;
        PluginArchiveDef        archive;
    }

    The 'server_time' specify the current time to be used during TV
    playback. The local time is used if server time is non-positive.

    The 'groups' and 'channels' specify the list of channels and the list
    of channel groups. See the description of group and channel properties
    below.

    The 'show_group_channels_only' specifies the way channels are grouped.

    The plugin TV browser OSD consists of 3 columns:
      - 1st column contains list of groups;
      - 2nd column contains list of channels for the selected group;
      - 3rd column contains list of EPG programs for the selected
        channel and the choosen day.

        - if ['show_group_channels_only' == false] the 2nd column contains
          all channels sorted by groups not depending on what group is
          selected. This mode requires the 1-to-N relationship between
          groups and channels, i.e. each channel should belong to exactly
          one group. The group selection in 1st column is adjusted
          automatically when user scrolls channel list in 2nd column.

        - if ['show_group_channels_only' == true] the 2nd column contains
          channels of the selected group only. This mode suports N-to-N
          relationship between groups and channals: channal can be included
          into multiple groups. As a consequence user has to move focus
          between 2nd and 1st columns by pressing LEFT/RIGHT to select
          channel from another group.

    When 'favorites_supported' enables *favorites* feature including:
        - special "favorites" group added to the list of groups;
        - special key handling for modification of the list of favorite
          channels. In particular Dune GUI calls Change_tv_favorites()
          operation when user press D_BLUE, B_GREEN, C_YELLOW remote keys.
          The implementation of Change_tv_favorites() should write the
          list of favorite channels to the persistent storage (e.g. by
          means of cookies).

    The 'favorite_channel_ids' specify the list of favorite channels.

    The 'favorites_icon_url' specify the icon for "favorites" group.

    The 'initial_group_id', 'initial_channel_id', 'initial_favorites' and
    'initial_archive_tm' specify the initial state of playback and selection.
    All these properties are optional; if property is unset then it is
    automatically set to the appropriate value.
    If positive value given, the 'initial_archive_tm' specify that archive
    playback should be started from the given timestamp (GMT unixtime).

    The 'actions' specifies the {event -> GUI action} mapping for interaction
    with user.
      NOTE: Available in firmware 131029_b9+.

    The 'timer' allows to specify timer event delay. The timer event will
    be generated only once, but timer can be reset using ChangeBehaviour
    GUI action.
      NOTE: Available in firmware 131029_b9+.

    The 'ip_address_required' and 'valid_time_required' specify the
    additional requirements for the TV playback. See the desciption of the
    similar fields in plugin manifest for more details. In particular, it
    is common that some plugins do not require valid current time for
    browsing groups/channels in Dune menu but they do requre valid time for
    TV playback.

    The 'epg_mode' it can take 3 values:
        - "disabled":
            the get_day_epg() calls are avoided, but EPG-column is still
            shown with "No program available." text. This mode should be
            used if no EPG is available at all. The concrete
            behaviour may be changed in future.
            (*) update in firmware 130726_b6+: EPG column not shown at all
        - "use_day_request": the default mode.
        - "get_from_stream": not implemented yet.

    The 'epg_font_size' specify EPG font size.
      PHP constants available: FONT_SIZE_NORMAL, FONT_SIZE_SMALL

    The 'epg_day_use_local_tz', 'epg_day_shift_sec' specify a start of EPG
    day. If epg_day_use_local_tz is false, EPG day is started from 00:00
    (GMT) + epg_day_shift_sec, otherwise it is started from 00:00 (current
    time zone) + epg_day_shift_sec.
      NOTE: Available in firmware 121114+.

    The 'custom_protect_code_handling' enables the more flexible protect
    code handling for channels with 'is_protected'=true: if
    get_tv_playback_url() return string 'protected' then protect-code
    dialog is shown, if return other string => stream is considered
    non-protected.
      NOTE: Available in firmware 121116+.

    The 'subtitles_osd_enabled' enables/disables the subtitles OSD feature:
    OSD control which shows the list of available subtitles and allows to
    switch between them. Enabled by default.
      NOTE: Available in firmware 140521_b9+.
      NOTE: The subtitles OSD was not available for plugins in earlier
      firmware versions.

    Each group has the following properties:

    class PluginTvGroup
    {
        String id;
        String caption;
        String icon_url;
    }

    The 'id' specifies group identifier.

    The 'caption' and 'icon_url' specify group representation.

    Each channel has the following properties:

    class PluginTvChannel
    {
        String          id;
        String          caption;
        List<String>    group_ids;
        String          icon_url;
        int             number;
        Boolean         have_archive;
        Boolean         is_protected;
        Boolean         recording_enabled;
        int             buffering_ms;
        int             timeshift_hours;
        int             past_epg_days;
        int             future_epg_days;
        int             epg_icon_width;
        int             epg_icon_height;
        int             epg_icon_x_offset;
        int             epg_icon_y_offset;
        int             archive_past_sec;
        int             archive_delay_sec;
        Boolean         playback_url_is_stream_url;
    }

    The 'id' specifies channel identifier.

    The 'caption' and 'icon_url' specify channel representation.

    The 'group_ids' specifies groups this channel belongs to. There should be
    at least one group specified. Some plugins allow channel to belong to
    multiple groups, the others are not. See the description of
    PluginTvInfo::show_group_channels_only for more details.

    The 'number' allows to assign the concrete number to TV channel. If
    number <= 0 => the number will be assigned automaticaly to the first
    unused positive integer.

    The 'have_archive' enables archive feature for this channel. If
    enabled, the corresponding support in the implementation of
    Get_tv_playback_url() operation whould be provided. See "Plugin TV
    archive playback" section for more details about TV archive playback.

    The 'is_protected' marks this channel as protected, i.e. restricted for
    users who do not know the key. If plugin have some protected channels,
    the corresponding support in the Get_tv_playback_url() should be
    provided.

    The 'recording_enabled' specifies whether recording is enabled for this
    channel.

    The 'buffering_ms' specify the prebuffering time for channel playback.

    The 'timeshift_hours' specify the timeshift in hours. NOTE: not
    implemented yet.

    The 'past_epg_days', 'future_epg_days' specify the limits of
    scrolling the EPG. The default values are 14.

    The 'epg_icon_width', 'epg_icon_height': positive integers, dimensions
    for the EPG program icons.
    The 'epg_icon_x_offset', 'epg_icon_y_offset': signed integers allowing
    to adjust position of EPG program icons.
    See description of PluginTvEpgProgram::icon_url for more details.
      NOTE: the 'epg_icon_*' properties available in firmware 150527_r10+.

    The 'archive_past_sec' specifies the maximum time interval from current
    moment and the last moment in the past the archive is available for.
    See "Plugin TV archive playback" section feature for more details about
    TV archive playback.

    The 'archive_delay_sec' specifies the time interval in seconds between
    the current moment and the nearest moment in past the archive is
    available for. See "Plugin TV archive playback" section feature for
    more details about TV archive playback.

    So EPG program is considered to have archive if it has
    EpgProgram::have_archive flag set or if EpgProgram::start_tm_sec
    belongs to range [ current_time - PluginTvChannel::archive_past_sec,
    current_time - PluginTvChannel::archive_delay_sec ]

    The 'playback_url_is_stream_url' specifies whether the playback URL is
    stream URL for this channel.

5. Get_day_epg()

    // List<PluginTvEpgProgram>
    public function get_day_epg(
        /* [in]     String                      */  $channel_id,
        /* [in]     int                         */  $day_start_tm_sec,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    Returns list of EPG program structures for the given channel and given
    day.

    The day is specified by the unixtime of it's beginning (0:00). I.e. the
    $day_start_tm_sec is always divisible by 86400.

    The output should be a (possibly empty) list of structures sorted by
    time in ascending order:

    class PluginTvEpgProgram
    {
        unixtime_t start_tm_sec;
        unixtime_t end_tm_sec;
        String     name;
        String     description;
        Boolean    have_archive; // Optional, default: false.
        String     icon_url;     // Optional.
    }

    The 'start_tm_sec' and 'end_tm_sec' are the program start/end time in
    unixtime format.

    The 'end_tm_sec' is optional (the -1 value means unset).

    The 'name' is required non-empty program name.

    The 'description' is optional program description.

    The 'have_archive' whether archive is available for program.
    This flag is used together with pair of properties
    'archive_past_sec' and 'archive_delay_sec' of PluginTvChannel: the
    program is considered to have archive if it has 'have_archive' flag or
    it's 'start_tm_sec' belongs to range
    [ current_time - archive_past_sec, current_time - archive_delay_sec ]
         NOTE: 'have_archive' property is available in firmware
         150526_r10+.

    The 'icon_url': URL of the small image to be painted in the EPG program
    block. This icon replaces the standard 'R' sign of the archived
    program, but can be used for non-archived programs too.
    This property is used together with 'epg_icon_width',
    'epg_icon_height', 'epg_icon_x_offset', 'epg_icon_y_offset' of
    PluginTvChannel. The icon_url is ignored until epg_icon_width and
    epg_icon_height are specified.
         NOTE: 'icon_url' property is available in firmware 150527_r10+.

6. Change_tv_favorites()

    // GuiAction
    public function change_tv_favorites(
        /* [in]     String                      */  $op_type,
        /* [in]     String                      */  $channel_id,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    Updates the list of favorite TV channels.

    Is called from TV playback mode when user press B_GREEN, C_YELLOW,
    D_BLUE remote buttons.

    The return value is the optional GUI action to be executed immediately.

    The following update operations supported:
      - PLUGIN_FAVORITES_OP_ADD
      - PLUGIN_FAVORITES_OP_REMOVE
      - PLUGIN_FAVORITES_OP_MOVE_UP
      - PLUGIN_FAVORITES_OP_MOVE_DOWN

    The implementation of change_tv_favorites() should update it's own
    persistent copy of favorites. There list of favorites inside Dune GUI
    will be updated automatically.

7. Get_tv_playback_url()

    // String 
    public function get_tv_playback_url(
        /* [in]     String                      */  $channel_id,
        /* [in]     int                         */  $archive_tm_sec,
        /* [in]     String                      */  $protect_code,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    Returns the playback URL for the given channel as string.

    This operation is called for getting playback URL of:
        - live playback if $archive_tm_sec <= 0;
        - archive playback if $archive_tm_sec > 0.
    See "Plugin TV archive playback" section for more details about TV
    archive playback.

    The nonempty protect_code can be specified for protected channels. See
    "Protected TV channels" section for more details about protected TV
    channels.

    This operation is called each time the playback of particular channel
    is started or resumed.

    NOTE: some channels require to perform additional call to
    Get_tv_stream_url() for getting the actual stream URL having playback
    URL as the parameter. This use-case is indicated by
    PluginTvChannel::playback_url_is_stream_url == false.

8. Get_tv_stream_url()

    // String
    public function get_tv_stream_url(
        /* [in]     String                      */  $playback_url,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    Returns the TV stream url having the TV playback url as input.

    Examples of possible TV stream urls:
        - Multicast TS-over-UDP stream (raw-UDP or RTP-over-UDP):
            - udp:/@ip-address:port
        - Unicast TS-over-HTTP stream:
            - http://ts://host[:port][/path]

    The reason for separation of terms 'playback URL' and 'stream URL' is
    the following. Sometimes plugin is unable to provide fixed URL for IPTV
    stream playback and can only provide a way of receiving this URL by
    means of remote call. And each call will return different result. To
    implement such plugins one should do the followig:
      - for each such channel the
        PluginTvChannel::playback_url_is_stream_url should be set to false
      - the Get_tv_playback_url() should return string which:
          1. will be used for default playback engine initialization. So it
             must have correct prefix (e.g. http://ts://);
          2. will be passed to the Get_tv_stream_url() operation as
             parameter.
      - the Get_tv_stream_url() should be implemented to decode the
        playback URL, perform the remote call, parse the results and return
        the actual IPTV stream URL.

    So lets call 'playback URL' such intermediate URL which is used for
    playback engine pre-initiallization and for being passed to
    Get_tv_stream_url() operation.
    Lets call 'stream URL' the result of Get_tv_stream_url() operation
    which is used for actual playback.

    NOTE: if PluginTvChannel::playback_url_is_stream_url is set to TRUE
    then playback URL is interpreted as stream URL and Get_tv_stream_url()
    is never called. 

9. Get_vod_info()

    // PluginVodInfo 
    public function get_vod_info(
        /* [in]     String                      */  $media_url,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    Returns data for launching plugin VOD playback using the given optional
    $media_url as the hint about what series to start from.

    This operation is typically called when user presses PLAY or ENTER
    remote button on some plugin folder item having the 'plugin_vod_play'
    action registered for the corresponding key event.

    This operation launches the playback of the list of movie series.
    Number of series >= 1.

    The output data of get_vod_info:

    class PluginVodInfo
    {
        String                      name;
        String                      description;
        String                      poster_url;
        List<PluginVodSeriesInfo>   series;
        int                         initial_series_ndx;
        int                         initial_position_ms;
        int                         buffering_ms;
        Boolean                     advert_mode;
        GuiActionMap                actions;
        GuiTimerDef                 timer;
        Boolean                     ip_address_required;
        Boolean                     valid_time_required;
        Boolean                     subtitles_osd_enabled;
    }

    class PluginVodSeriesInfo
    {
        String  name;
        String  playback_url;
        Boolean playback_url_is_stream_url;
    }

    The 'name', 'description', 'poster_url' and 'series[i]->name' are used
    for OSD representation.

    The 'series' specifies the list of series to play. They form a some
    sort of playlist.

    The 'initial_series_ndx' specifies the index of series to start
    playback from.

    The 'initial_position_ms' specifies the initial playback position in
    milliseconds. If negative value specified then the default initial
    position will be chosen (resume is possible).

    The 'advert_mode': if TRUE, the VOD playback will be started with the
    following limitations:
        - some features disabled: seek, jump, change playback speed and
          similar;
        - very limited OSD is shown (e.g. the info block and status never
          shown). However, some features are enabled: image setup, zoom,
          audio/subtitles setup etc.

    The 'ip_address_required' and 'valid_time_required' specify correct
    behaviour in the case of unavailable IP address and/or valid time. See
    the description of GET_TV_INFO operation output data for more details.

    The 'buffering_ms' specify the prebuffering time in milliseconds. NOTE:
    not implemented now.

    The 'actions' allows to specify actions to be executed in the following
    use-cases during VOD playback:
      - particular key is pressed. Currently only color-keys are supported
        (A_RED, B_GREEN, C_YELLOW and D_BLUE); The events of the following
        kinds can be used: GUI_EVENT_KEY_A_RED, GUI_EVENT_KEY_B_GREEN,
        GUI_EVENT_KEY_C_YELLOW, GUI_EVENT_KEY_D_BLUE.
      - timer event occured. The event of kind GUI_EVENT_TIMER should be
        used for the case.
      - playback stopped, or playback of another media_url started, or
        power off requested. The event of kind GUI_EVENT_PLAYBACK_STOP
        should be used for the case. If action is specified for playback
        stop, the actual playback stop/switch/shutdown will be delayed
        until action execution is finished. However, the additional
        STOP/POWER-OFF key press will cancel the action execution.
      - playback

    The 'timer' allows to specify timer event delay. The timer event will
    be generated only once, but timer can be reset using ChangeBehaviour
    GUI action.

    The 'series->playback_url' specify the playback URL for specific
    series.

    The 'series->playback_url_is_stream_url':
      - true => playback URL should be used as stream URL;
      - false => Get_vod_stream_url() operation should be called to get
        stream URL each time it is needed.
    See the descripton of GET_TV_STREAM_URL and GET_VOD_STREAM_URL for more
    details.

    The 'subtitles_osd_enabled' enables/disables the subtitles OSD feature:
    OSD control which shows the list of available subtitles and allows to
    switch between them. Enabled by default.
      NOTE: Available in firmware 140521_b9+.
      NOTE: The subtitles OSD was not available for plugins in earlier
      firmware versions.

10. Get_vod_stream_url()

    // String
    public function get_vod_stream_url(
        /* [in]     String                      */  $playback_url,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    Returns the VOD stream url having the VOD playback url as input.

    Examples of possible VOD stream urls:
        - MP4 container over HTTP (the most recommended one):
            - http://mp4://host[:port][/path]
        - TS container over HTTP:
            - http://ts://host[:port][/path]
        - Other container over HTTP (support/performance is limited):
            - http://host[:port][/path]
        - MMS (support is limited)
            - mms://host[/path]

    This operation is called each time the playback should be
    stared or resumed and the
    PluginVodInfo::series[ndx]->playback_url_is_stream_url is false. The
    PluginVodInfo::series[ndx]->playback_url is passed as a parameter.

    See description of Get_tv_stream_url() operation for more details.

11. Handle_user_input()

    // GuiAction
    public function handle_user_input(
        /* [in]     Map: Key -> Value           */  &$user_input,
        /* [inout]  Map: Key -> Value           */  &$plugin_cookies);

    This operation is called during execution of HANDLE_USER_INPUT GUI
    action.

    Handle_user_input() operation may return another GuiAction object which
    will be executed immediately.

    This operation allows to implement many complex use-cases. Here are
    some of them:
      - regular folders with elements of different types: the
        HANDLE_USER_INPUT GUI action is mapped to some keys in definition
        of such folders.
      - setup screens with possibility to edit list of settings; the
        HANDLE_USER_INPUT is specified as confirm/apply action to
        text_fields/comboboxes or assigned to some "Apply" button.
      - implementing 'Control dialogs': flexible dialogs with custom list
        of controls. The behaviour of control dialogs is very close to the
        behaviour of control folders. 

GUI actions

GUI action concept is an important part of plugin PHP API. It is used by
plugins to specify the behaviour of Dune GUI in many use-cases.

In particular, GUI action is often assigned to the event of pressing remote
key by user. Also GUI action can be produced as a result of execution of
another GUI action. Also GUI action can be returned by every operation
instead of normal output in case of error.

Each GUI action implies some algorithm to be performed by Dune GUI.

The GUI action is received from plugin in form of GuiAction:

class GuiAction
{
    String              handler_string_id;
    Any                 data;
    Map<String, String> params;
}

The 'handler_string_id' specifies string identifier of the action type.
Each action type will be described below.

The 'data' specifies parameters of action. The 'data' is object of class,
specific for the action type. The data classes for all supported action
types will be described below.

The 'params' specify additional action parameters of String type. These
parameters are automatically filled with some kind of 'execution context'
in particular use-cases desribed below.

The GUI action is created to be executed by Dune GUI when some event occur.
Here is the details of action execution:

1. First the Dune GUI chooses the executor according to the current GUI state.
Now there are 3 types of executors:
    - Main executor. It is used during browsing of the Dune menu (browsing
      of the folder hierarchy), including the popup menus and dialogs. This
      executor can handle all types of actions.
    - Playback executor. This executor is used during plugin TV/VOD
      playback. Currently it may perform only the following action types:
        - PluginHandleUserInput
        - PluginShowError
        - ChangeBehaviour
        - PluginInvalidateFolders
        - PluginVodPlay (currently with some limitations: vod_info
              parameter is mandatory).
    - Light executor. It is used when handling the error-actions produced
      by plugin operations during plugin TV/VOD playback. Currently this
      executor may perform only PluginShowError action.

2. Executor analyzes type of the action. If type is not known for executor
then execution is finished with status 'Action not recognized'. The actual
not recognized action is also provided.

3. Executor performs actual execution of the given action. As a result of
   this step the following data is produced:
    - [int] execution status (Ok = 0, Error = -1, etc..)
    - [GuiAction] post action. Optional.
   If post action is not null then it should be executed immediately; so we
   replace the old action with new one and go to the step (2).
   Otherwise execution is finished with execution status returned from the
   last executed action.

GUI event kinds

There is a number of GuiEventKind constants, allowing to assign GuiAction
to some GUI event. The most of them represent some remote buttons. Here is
the list:

    - GUI_EVENT_KEY_ENTER
    - GUI_EVENT_KEY_PLAY
    - GUI_EVENT_KEY_A_RED
    - GUI_EVENT_KEY_B_GREEN
    - GUI_EVENT_KEY_C_YELLOW
    - GUI_EVENT_KEY_D_BLUE
    - GUI_EVENT_KEY_POPUP_MENU
    - GUI_EVENT_KEY_INFO

    - GUI_EVENT_TIMER - special event kind, representing a periodic
      activity. This event is generated once after a time-out specified in
      GuiTimerDef::delay_ms. Typically, new timer is specified by means of
      ChangeBehaviour GUI action.

    - GUI_EVENT_PLAYBACK_STOP - special event kind, representin playback
      stop. This event is generated on playback stop or power-off or before
      playback switch. In case some action is registered for event, the
      player first suspends playback, executes the action, waits for
      completion of the action chain, and then proceeds with actual stop,
      power-off or switch.

(*) update in firmware 120902+ 

The following key events added available only in control dialogs:

    - GUI_EVENT_KEY_LEFT
    - GUI_EVENT_KEY_RIGHT
    - GUI_EVENT_KEY_UP
    - GUI_EVENT_KEY_DOWN
    - GUI_EVENT_KEY_P_PLUS
    - GUI_EVENT_KEY_P_MINUS
    - GUI_EVENT_KEY_NEXT
    - GUI_EVENT_KEY_PREV
    - GUI_EVENT_KEY_0
    - GUI_EVENT_KEY_1
    - GUI_EVENT_KEY_2
    - GUI_EVENT_KEY_3
    - GUI_EVENT_KEY_4
    - GUI_EVENT_KEY_5
    - GUI_EVENT_KEY_6
    - GUI_EVENT_KEY_7
    - GUI_EVENT_KEY_8
    - GUI_EVENT_KEY_9

(*) update in firmware 130315_b6+

The following special event kinds added for "Global plugin actions":

    - GUI_EVENT_BOOT
    - GUI_EVENT_INSTALL
    - GUI_EVENT_UPDATE
    - GUI_EVENT_UNINSTALL

(*) update in firmware 130819_b8+

All previously specified key events now can be used in plugin regular
folders. NOTE: GUI_EVENT_KEY_ENTER cannot be overridden for empty plugin
regular folders.
The following event kinds added to be used in control dialogs and plugin
regular folders:

    - GUI_EVENT_KEY_SETUP
    - GUI_EVENT_KEY_RETURN
    - GUI_EVENT_KEY_SELECT
    - GUI_EVENT_KEY_CLEAR

(*) update in firmware 130904_b8+

The following event kinds added to be used in control dialogs and plugin
regular folders:

    - GUI_EVENT_KEY_PAUSE

(*) update in firmware 131029_b9+

All previously specified key events now can be used in plugin TV playback
and plugin VOD playback.
Also, the timer event can be in plugin TV playback (in the same way as in
plugin VOD playback).

The following event kinds added to be used in control dialogs, plugin
regular folders, plugin TV playback, plugin VOD playback (with some
restrictions described below):

    - GUI_EVENT_KEY_FWD
    - GUI_EVENT_KEY_REW
    - GUI_EVENT_KEY_SLOW

    - GUI_EVENT_KEY_STOP
    - GUI_EVENT_KEY_TOP_MENU
    - GUI_EVENT_KEY_POWER
    - GUI_EVENT_KEY_EJECT
    - GUI_EVENT_KEY_MODE
    - GUI_EVENT_KEY_VENDOR

    - GUI_EVENT_KEY_MUTE
    - GUI_EVENT_KEY_V_PLUS
    - GUI_EVENT_KEY_V_MINUS

    - GUI_EVENT_KEY_SEARCH
    - GUI_EVENT_KEY_ZOOM
    - GUI_EVENT_KEY_SUBTITLE
    - GUI_EVENT_KEY_REPEAT
    - GUI_EVENT_KEY_AUDIO
    - GUI_EVENT_KEY_REC
    - GUI_EVENT_KEY_DUNE
    - GUI_EVENT_KEY_URL

(*) update in firmware 150529+

    - GUI_EVENT_PLAYBACK_SWITCHED - this event is generated after switching
    playback to new media URL (including the very first one).

    - GUI_EVENT_PLAYBACK_GOING_TO_SWITCH - this event is generated before
    switching playback to new media URL playback. Unlike
    GUI_EVENT_PLAYBACK_STOP, this event is not generated in case of
    stop/power-off. Another difference from GUI_EVENT_PLAYBACK_STOP is that
    player does not wait for completion of action, registered for
    GUI_EVENT_PLAYBACK_GOING_TO_SWITCH event.

NOTE: the following events cannot be overridden in plugin regular folders:
    - ZOOM, POWER, EJECT
NOTE about control dialogs: some RC buttons have special meaning when text
    editor is active or combobox drop-down is shown and cannot be
    overridden by control dialog 'actions' map.

List of GUI action types

The full list of GUI action types and their explicit properties is provided
below:

1. PluginOpenFolderAction
    Data:
        class PluginOpenFolderActionData
        {
            String caption; // optional; default = null (auto)
            String media_url; // optional; default = null (auto)
        }

    Action:
        browses into plugin folder. In more details:
            - folder caption is added to path block;
            - the Get_folder_view($media_url) plugin operation executed;
            - the output data is used to show contents of folder.
    Params:
        'media_url':
            - if not null it is used as identifier of folder to be opened;
              otherwise media_url of the currently selected folder element
              is used. If no element is selected => action is ignored.
        'caption':
            - is used as path element if not null; otherwise caption of
              currently selected folder element is used.
    Returns:
        post action: never
        status: ok/failed

2. PluginTvPlayAction
    Data:
        class PluginTvPlayActionData
        {
            String initial_group_id; // optional, default = null (auto)
            String initial_channel_id; // optional, default = null (auto)
            Boolean initial_is_favorite; // optional, default = false;
            unixtime_t initial_archive_tm; // optional, default = -1 (unset)
        }

    Action:
        launches TV playback. The selection and playback state is
        initialized using the given parameters. In more details:
            - media_url of currently selected folder element is taken; if
              none is selected then $media_url is null;
            - Get_tv_info($media_url) plugin operation is executed;
            - if output is invalid => action is failed;
            - TV playback state is initialized using received PluginTvInfo;
            - if some of initial_XXX parameters are set => they override
              the default selection and playback state.
    Returns:
        post action: never
        status: ok/failed

3. PluginVodPlayAction
    Data:
        class PluginVodPlayActionData
        {
            PluginVodInfo vod_info; // optional, default = null.
        }

    Action:
        launches VOD playback. If 'vod_info' is specified, it is used to
        initialize VOD playback. Otherwise, the
        get_vod_info($current_media_url) will be called and the result vod
        info will be used. The $current_media_url is the media_url of
        currently selected folder element; if none is selected then
        $media_url is null.

    Returns:
        post action: never
        status: ok/failed

4. PluginHandleUserInputAction
    Data:
        [none]

    Action:
        runs Handle_user_input(GuiAction::$params) plugin operation.
        The output data from Handle_user_input() is returned as
        post action.

    Returns:
        post action: the action returned from Handle_user_input()
        operation
        status: ok/failed

5. PluginShowErrorAction
    Data:
        class PluginShowErrorActionData
        {
            Boolean fatal;
            String title;
            List<String> msg_lines; [optional]
        }

    Action:
        - shows error to the user. In playback state the single text line
          is shown in the center of the screen; in Dune menu state the
          dialog is shown with given title and message lines;
        - if (fatal == true) => the exit from plugin by fatal error is
          scheduled. In this case playback is stopped and Dune browser is
          moved to the top menu;
        - returns error status.

    Returns:
        post action: never
        status: failed

6. ShowDialogAction
    Data:
         class ShowDialogActionData
         {
             String title;
             List<GuiControlDef> defs;
             GuiActionMap actions; // optional
             GuiTimerDef timer; // optional
             Boolean close_by_return; // optional, default = false
             int preferred_width; // optional, default = 0 (auto)
             int max_height; // optional, default = 0 (auto)
             int min_item_title_width; // optional, default = 0 (auto)
             int initial_sel_ndx; // optional, default = -1 (auto)
             Map<String,String> params; // optional params
         }

         class GuiTimerDef
         {
             // Timer delay in milliseconds. Zero value is allowed here.
             int delay_ms;
         }

     Action:
         shows the specified control dialog and interacts with user until
         dialog is closed.
         The dialog shows the vertical list of controls, each control may
         be preceeded with optional title text. So dialog may consist of
         1 or 2 columns.
         The special "vgap" control can be used to increase or decrease
         vertical gaps between controls.
         The vertical scrollbar appears when needed.
            - actions: allows to specify actions to be executed when
            particular key is pressed or timer event occured. The
            GUI_EVENT_KEY_ENTER behaviour cannot be changed.
            - timer: allows to specify the timer event. The timer event
              will be generated only once, but the timer can be reset using
              ChangeBehaviour GUI action.
            - close_by_return: whether to close dialog by pressing RETURN.
            - preferred_width: preferred dialog content width, including
              titles. When set to 0 (default), the dialog preferred width
              is automatically calculated using the preferred width of
              listed controls.
            - max_height: maximum dialog height.
            - min_item_title_width: minimum width resered for control
              titles.
               NOTE: Available in firmware 121201+.
            - initial_sel_ndx: index of focusable control to select first
              (index in list of all focusable controls: comboboxes, buttons
              and text fields).
            - params: additional customization parameters in form of
              key/value map. Supported keys:
                - frame_style=default|glass (PHP constants available:
                  DIALOG_FRAME_STYLE_DEFAULT, DIALOG_FRAME_STYLE_GLASS).
                     NOTE: Available in firmware 130824_b8+.
                - exit_seq=<string>
                  Sequence allowing to close dialog.
                  Syntax of 'exit_seq' string: comma-separated list of GUI
                  event kinds. Example:
                  "key_1,key2,key3,key9,key_c_yellow".
                     NOTE: Available in firmware 130904_b8+.

     Returns:
         post action: if dialog is closed by means of CloseDialogAndRun GUI
             action => the CloseDialogAndRunActionData::post_action is
             returned as post action
         status: ok

 7. CloseDialogAndRunAction
     Data:
         class CloseDialogAndRunActionData
         {
             GuiAction post_action; // optional, default = null (none)
         }

     Action:
         Closes current control dialog and returns 'post_action' as a result
         of caller SHOW_DIALOG GUI action.
         This action is ignored when executed outside of control dialog.
     Returns:
         post action: none
         status: ok

 8. ResetControlsAction
     Data:
         class ResetControlsActionData
         {
             List<GuiControlDef> defs;
             int initial_sel_ndx; // optional, default = -1 (do not change selection)
             GuiAction post_action; // optional, default = null (none)
         }

     Action:
         replaces state of current control dialog or control folder.

         This action is ignored when executed outside of control dialog or
         folder.
     Returns:
         post action: from action data
         status: ok

 9. ShowPopupMenuAction
     Data:
         class ShowPopupMenuActionData
         {
             List<GuiMenuItemDef> menu_items;
             int selected_menu_item_index; // optional, default = 0
         }

     Action:
         shows the specified popup menu and interacts with user until popup
         menu is closed. If user chooses popup menu item then the
         corresponding action is returned as post action.
     Returns:
         post action: the action assigned to menu item chosen by user
         status: ok

 10. StatusAction
     Data:
         class StatusActionData
         {
             int status;
         }

     Action:
         just returns the given status.
     Returns:
         post action: none
         status: ok

 11. PluginUpdateFolderAction
     Data:
         class PluginUpdateFolderAction
         {
             PluginRegularFolderRange range;
             Boolean need_refresh;
             int sel_ndx; // optional, default = -1 (do not change current)
         }

     Action:
         Partially replaces state of current plugin regular folder:
             - if need_refresh is TRUE => cached folder state is cleared;
             - the given range is applied/replaced;
             - if sel_ndx >= 0 then focus is moved to element with given
               index.
         This action is ignored when executed outside of regular folder.
     Returns:
         post action: none
         status: ok

 12. PluginInvalidateFolders
     Data:
         class PluginInvalidateFoldersActionData
         {
             List<String> media_urls;
             GuiAction post_action; // optional, default = null (none)
         }

     Action:
         clears the cached data about plugin folders identified by given
         media_urls forcing them to be fully reloaded.
         This action is needed for the case when some actions inside child
         folder changed state of parent folder. Using this action one is
         able to force parent folder to reload it's state.
         If mentioned media_url is not cached => it is ignored.

     Returns:
         post action: from action data
         status: ok

 13. PluginRunNativeCode GUI action.
     Data:
         [none]

     Action:
         loads native library 'native_code.so' from plugin installation
         directory and tries to invoke some function from this library.

     Returns:
         post action: none
         status: ok/failed

 14. PluginClearArchiveCache GUI action.
     Data:
         class PluginClearArchiveCacheActionData
         {
             String archive_id; // optional, default = null (all)
             GuiAction post_action; // optional, default = null (none)
         }

     Action:
         deletes the cached data of the plugin archives from file system (if
         exist). If 'archive_id' is set => only the specified archive is
         cleared; otherwise all archives of the current plugin are cleared.
     Returns:
         post action: from action data
         status: ok

 15. DvdPlay
     Data:
         class DvdPlayActionData
         {
             String url;
         }

     Action:
         launches DVD playback of the given url.
     Returns:
         post action: never
         status: ok/failed

 16. BlurayPlay
     Data:
         class BlurayPlayActionData
         {
             String url;
         }

     Action:
         launches Blu-Ray playback of the given url. This action is
         available in firmware supports blu-ray playback.
     Returns:
         post action: never
         status: ok/failed

 17. FilePlay
     Data:
         class FilePlayActionData
         {
             String url;
         }

    Action:
        launches normal playback on the single file pointed by given URL.
        URL should point to audio or video file or stream of supported
        format.
    Returns:
        post action: never
        status: ok/failed

18. PlaylistPlay
    Data:
        class PlaylistPlayActionData
        {
            String url;
            int start_index;
        }

    Action:
        launches normal file playback on the playlist built from the file
        or folder pointed by the given URL. URL may point to:
        - single local/network/http audio/video file or other supported
          network resource;
        - local/network/http playlist file (m3u, pls);
        - local/network folder containing audio/video/playlist files.
        The first played playlist item will be selected using the given
        "start_index", if valid.
    Returns:
        post action: never
        status: ok/failed

19. LaunchMediaUrl
    Data:
        class LaunchMediaUrlActionData
        {
            String url;
            GuiAction post_action;
        }

    Action:
        1. build playlist recursively using the given URL as root element
           of hierarchy;
        2. analyze the content of playlist and choose the actual executor;
        3. run the chosen executor against the playlist.

        The recursive algorithm does the following:
            - enters recursively into local/network folders, local/network/http
              playlists (m3u, pls);
            - adds to the playlist audio/video/image files and streams,
              DVD/Bluray files and folders, Flash-applications (swf://* and
              local *.swf), WWW-urls (www://*, *.url, *.URL)
        Possible playlist executors are:
            - DVD player; it is chosen if playlist contains only one
              element which is either DVD folder or DVD disk image file;
            - Blu-ray player; it is chosen if playlist contains only one
              element which is either Blu-ray folder or Blu-ray disk image file;
            - Flash player; it is chosen if playlist contains only one
              element: either *.swf file or swf://* url;
            - Web browser; it is chosen if playlist contains only one
              element: either *.url/*.URL file or www://* URL;
            - Photo viewer: it is chosen if playlist contains only image
              files of known types (jpg, png, bmp, gif);
            - Plugin installer: it is chosen if playlist contains only one
              element: plugin_installer://* URL.
            - Plugin uninstaller: it is chosen if playlist contains only one
              element: plugin_uninstaller://* URL.
            - Plugin launcher: it is chosen if playlist contains only one
              element: plugin_launcher://* URL.
            - general file playback: otherwise.

    Returns:
        post action: from action data.
            NOTE: post-playback action execution now is not fully
            implemented; currently post action will be taken into account
            only if actual playlist executor is one of the following:
                - plugin installer;
                - plugin uninstaller;
                - plugin launcher;
                - general file playback (some restrictions are possible).
            In future, support for action post-execution will be added for
            more playlist executors.
        status: ok/failed

20. ShowMainScreen
    Data:
        class ShowMainScreenActionData
        {
            GuiAction post_action;
        }

    Action:
        switches to the main screen.
        This action is added to improve some auto_start use-cases.
        NOTE: current implementation has limitations.
    Returns:
        post action: from action data
        status: ok/failed

21. ShowBlackScreen
    Data:
        class ShowBlackScreenActionData
        {
            String bg_url;
            GuiAction post_action;
        }

    Action:
        Switches to the black screen with optional background picture.
        If 'bg_url' if specified, it is used as background picture instead of
        solid black background.
         NOTE: 'bg_url' available in firmware 130914_b8+.
    Returns:
        post action: from action data
        status: ok/failed

22. ChangeBehaviour
    Data:
        class ChangeBehaviourActionData
        {
            GuiActionMap actions; // Optional.
            GuiTimerDef timer; // Optional.
            GuiAction post_action; // Optional.
        }

        class GuiTimerDef
        {
            // Timer delay in milliseconds.
            int delay_ms;
        }

    Action:
        changes the behaviour in the current GUI container. Currently the
        following GUI containers supported:
            - regular folder;
            - control dialog;
            - VOD playback.
        In future, other containers will be supported too (control/movie
        folder, TV playback, general playback).
        If 'actions' is set, it replaces the existing one.
        If 'timer_ms' is set, the timer is restarted from the current time
        moment.
    Returns:
        post action: from action data
        status: ok/failed

23. OpenFolder
    Data:
        class OpenFolderActionData
        {
            String media_url; // optional; default = null (auto)
        }

    Action:
        browses into general folder. If media_url is not specified, the
        currently selected folder item will be opened in general way.
    Params:
        'media_url':
            - if not null it is used as URL of folder to be opened.
            The URL can point local folders using smb://, nfs://,
            storage_name://, main_storage:// -- see
            http://dune-hd.com/firmware/misc/media_url.txt for more
            details.
            Also there can be dune_http:// URl (see
            http://dune-hd.com/firmware/misc/dune_folder_howto.txt for more
            details).
            Also there can be dune_setup://<setup_id> URLs. For example,
            setup://applications, setup://video.

    Returns:
        post action: never
        status: ok/failed
    Note: Available in firmware 130315_b6+.

24. CloseAndRunAction
     Data:
         class CloseAndRunActionData
         {
             GuiAction post_action; // optional, default = null (none)
         }

     Action:
         If control dialog is active, then it works in the same way as
         CloseDialogAndRunAction.
         Does nothing, if some other kind of dialog is opened.
         If no dialogs is currently opened and some folder is active, then
         it closes folder (goes to the upper folder) and returns
         'post_action'.
     Returns:
         post action: from action data when folder is acti
         status: ok
     Note: Available in firmware 121114+.
     Update in firmware 131029_b9+:
         Now this action works as 'stop playback' when called from TV
         playback / plugin VOD playback when no dialog is active.

24. PluginSystemAction
     Data:
         class PluginSystemActionData
         {
             String run_string;
             GuiAction post_action; // optional, default = null (none)
         }

     Action:
         Prepares a command for unix shell interpreter by prepending the
         plugin installation path to the 'run_string'. Then command is
         executed by running system(<command>). Command can be run in
         background if 'run_string' ends with '&' character.
         For example, if plugin installation directory contains the
         bin/prepare.sh script, then it can be called by specifying it as
         global action 'boot' in plugin manifest and setting the
         'run_string' to
         "bin/script.sh param1 param2" or
         "bin/script.sh param1 param2 &".

     Returns:
         post action: from action data
         status: ok

     Note: Available in firmware 130315_b6+.

25. RunBuiltinAction
     Data:
         class RunBuiltinActionData
         {
             String builtin_action_id;
             Map<String,String> params;
             GuiAction post_action; // optional, default = null (none)
         }

     Action:
        This action is introduced for internal purposes. It runs some
        built-in functionality, identified by 'builtin_action_id' with
        parameters 'params'. The list of available public "built-in
        actions" depends on firmware and currently is empty.

     Returns:
         post action: from action data
         status: ok

     Note: Available in firmware 130315_b6+.

26. WaitForIpAddressAction
     Data:
         class WaitForIpAddressActionData
         {
             int timeout_sec;
             GuiAction post_action; // optional, default = null (none)
         }

     Action:
         If IP-address is not yet received by DHCP (in case of DHCP network
         configuration), then standard "Wait For IP Address" dialog is
         shown until IP address is received or 'timeout_sec' seconds
         passed.

     Returns:
         post action: from action data
         status: ok

     Note: Available in firmware 130914_b8+.

27. WgetAction
     Data:
         class WgetActionData
         {
             String url;
             String post_data;
             String result_key_prefix;
             GuiAction post_action; // optional, default = null (none)
         }

     Action:
         Performs HTTP request to 'url' with 'post_data', passing result
         status and data to the 'post_action'.
         This action is strongly not recommended to be used from PHP
         plugins; it was introduced for internal reasons.
         PHP plugins should use native 'curl' methods for performing HTTP
         requests.

     Returns:
         post action: from action data
         status: ok

     Note: Available in firmware 130924_b9+.

28. ChangeSettingsAction
     Data:
         class ChangeSettingsActionData
         {
             Map<String,String> settings;
             Boolean reboot;
             Boolean restart_gui;
             GuiAction post_action; // optional, default = null (none)
         }

     Action:
         Changes internal Dune settings.

         The 'settings' specifies the setting_name -> setting_value
         key/value pairs to be changed. The list of available setting names
         and possible setting values is out of the current document's
         scope. The current settings are always stored in
         /config/settings.properties.

         The 'reboot' specifies whether to reboot STB immediately.
         The 'restart_gui' specifies whether to reboot STB immediately.

         NOTE: currently the 'reboot' is the only reliable way to apply
         setting from PHP plugin. This may change in future firmware
         versions.

         This action has no effect in plugin TV/VOD playback mode.

     Returns:
         post action: from action data
         status: ok

     Note: Available in firmware 140905_r10+.

29. PluginUpdateInfoBlockAction
     Data:
         class PluginUpdateInfoBlockActionData
         {
             String text_above;
             String text_color; // optional, default is 15
             Boolean text_halo; // optional, default is false
             int text_y_offset; // optional, default is 0
             GuiAction post_action; // optional, default = null (none)
         }

     Action:
         Updates current state of the information block. The information is
         shown sometimes in the lower part of screen, typically it is
         toggled by pressing INFO button. The changes are only visible when
         information block itself is visible.
         The following properties specifies the multi-line text message
         shown just above the upper bound of the information block. Once
         specified using PluginUpdateInfoBlock action, this message will
         always adjoin the information block until playback stops or
         another PluginUpdateInfoBlock adjusts or hides message.
         Action has no effect unless called in plugin TV or VOD playback
         mode.

         The 'text_above': multi-line message text. The text string is
         split automatically to fit the information block width. Special LF
         character ('\n') can be used to force line break. The empty or
         missing value can be used to hide message.

         The 'text_color': color index (integer 0..23, default=15)

         The 'text_halo': whether to draw black shade ('halo') around text
         to make it visible on the bright background.

         The 'text_y_offset': signed integer, allows to adjust vertical
         position of message.

     Returns:
         post action: from action data
         status: ok

     Note: Available in firmware 150526_r10+.

30. PluginUpdateEpgAction
     Data:
         class PluginUpdateEpgActionData
         {
             String channel_id;
             Boolean clear;
             int day_start_tm_sec;
             PluginTvEpgProgramList programs;
             GuiAction post_action; // optional, default = null (none)
         }

     Action:
         Updates the EPG information cached in player memory.
         There are 3 useful cases covered by this action:
            1. Clear all cached EPG information: 'clear' is TRUE;
            'channel_id', 'day_start_tm_sec', 'programs' not specified.
            2. Clear cached EPG information for a particular channel and
            (optionally) put a specified program list for a specified day
            into cache instead: 'clear' is TRUE, 'channel_id',
            'day_start_tm_sec', 'programs' are set correspondingly.
            3. Just update EPG program list for the specified channel and
            day: 'clear' is FALSE, 'channel_id', 'day_start_tm_sec',
            'programs' are set correspondingly.
         Action has no effect unless called in plugin TV playback mode.

         The 'channel_id': identifier of channel to be cleared/updated. Can
         be avoided allowing to clear EPG data for all channels.

         The 'clear': whether to clear EPG data.

         The 'day_start_tm_sec': day specification, the unix timestamp of
         day's beginning. Used together with 'channel_id' and 'programs'.
         Optional.

         The 'programs': list of EPG program data to be cached and used in
         GUI for given channel and day. Used together with 'channel_id' and
         'day_start_tm_sec'. Optional.

     Returns:
         post action: from action data
         status: ok

     Note: Available in firmware 150528_r10+.

30. PluginUpdateOsdAction
     Data:
         class PluginUpdateOsdActionData
         {
             PluginOsdComponenetList components;
             GuiAction post_action; // optional, default = null (none)
         }

         class PluginOsdComponent
         {
            int             x;
            int             y;
            String          image_url;
            int             image_width; // optional, default is actual image size
            int             image_height; // optional, default is actual image size
            String          text;
            PluginFontSize  text_font_size; // optional, default = FONT_SIZE_NORMAL
            String          text_color; // optional, default = 15
            Boolean         text_halo; // optional, default = false
         }

     Action:
         Updates the state related with the new feature: possibility to
         paint the arbitrary number of custom images and text messages in
         plugin TV/VOD playback mode. These images/messages are painted
         under (before) the standard native OSD GUI components/controls:
         playlist browser, information block, etc..
         The PluginUpdateOsdAction acts by replacing old sequence of OSD
         compenents with the new sequence. Once set by
         PluginUpdateOsdAction action execution, these components remain
         onscreen until removed/replaced by means of another
         PluginUpdateOsdAction execution or when playback stops.

         The PluginOsdComponent specifies either image or single-line text
         message, depending on whether 'image_url' or 'text' is set.
         The order of components specifies the actual order of their
         painting.
         Action has no effect unless called in plugin TV or VOD playback
         mode.

         The 'components': list of plugin OSD components. Empty list or
         null value specifies empty list of components (nothing to paint).

         PluginOsdComponent properties:

         The 'x', 'y': top left corner of image or text.

         The 'image_url', 'image_width', 'image_height': specify image to
         be shown. The actual image dimension are used in case of zero
         values of image_width/heigh, which is the default. The image
         loading is performed asynchronously.

         The 'text': single-line text message. It is not clipped except for
         screen bounds.

         The 'text_font_size': PLUGIN_FONT_NORMAL or PLUGIN_FONT_SMALL.
         Optional, default is PLUGIN_FONT_NORMAL.

         The 'text_color': color index (integer 0..23, default=15)

         The 'text_halo': whether to draw black shade ('halo') around text
         to make it visible on the bright background.

     Returns:
         post action: from action data
         status: ok

     Note: Available in firmware 150528_r10+.

GUI controls

GUI controls may appear in the following GUI control containers:
    - plugin control folders;
    - control dialogs.

The look and behaviuor of control folders and control dialogs is very
similar. GUI controls are positioned from top to the bottom, have 1 or
2 columns and each column is left-aligned. Each control may have optional
'title' text string. When title is specified, it is located in 1st column
and control itself is located in 2nd column. When title is not specified,
GUI control is located in 1st column and nothing is placed into 2nd column.
The width of GUI controls in 2nd column can be automatically arranged (if
GUI control does not specify width explicitly).

Control folder is opened by means of PLUGIN_OPEN_FOLDER GUI action. The
subsequent call to Get_folder_view() operation returns, among the other
data, the control folder specification:

    class PluginControlsFolderView
    {
        Array<GuiControlDef>    defs;
        int                     initial_sel_ndx;
    }

The plugin control folders can be closed in the same way as other Dune
folders: by means of RETURN, TOP_MENU.

Control dialog is opened by means of SHOW_DIALOG GUI action:

    class ShowDialogActionData
    {
        String title;
        List<GuiControlDef> defs;
        Boolean close_by_return; // optional, default = false
        int preferred_width; // optional, default = 0 (auto)
    }

If 'close_by_return' is true => dialog can be closed by RETURN; otherwise
it cannot.
The only other way to close dialog is to provoke execution of
CLOSE_DIALOG_AND_RUN GUI action. Normally actions of this type are assigned
to at least one button in control dialog.

The core of control folder and dialog's specification is the list of GUI
control definitions of type:

    class GuiControlDef
    {
        String name;
        String title;
        GuiControlKind kind;
        Object specific_def;
        Map<String,String> params;
    }

The 'name' specify identifier of GUI control. It is used for passing the
current value of GUI control to the GUI actions invoked inside the
container.

The 'title' specify optional string title.

The 'kind' specify kind of GUI action:

    enum GuiControlKind
    {
        GUI_CONTROL_LABEL,
        GUI_CONTROL_COMBOBOX,
        GUI_CONTROL_TEXT_FIELD,
        GUI_CONTROL_BUTTON,
        GUI_CONTROL_VGAP
    }

The 'specific_def' contains GUI control parameters specific for the
particular GUI control kind.

The 'params' contains additional parameters in form of key/value string
map.

Label

Data:
    class GuiLabelDef
    {
        String caption;
    }

Supported GuiControlDef::params keys:
    'smart', 'max_lines', 'lines_vgap', 'pars_vgap'.
   NOTE: Available in firmware 130820_b8+.

Details:
    GUI label is painted as fixed single-line text string. If string is too
    long, it is truncated in center.

Parameters:
    'caption' - the text string.

Additional parameters:
    NOTE: Available in firmware 130820_b8+.

    'max_lines' - if > 1 then label is auto-split into paragraphs by ASCII
    character 0xA (LF) and auto-split into lines by spaces.

    'lines_vgap' - vertical gap between lines, in pixels. Default is 0.

    'pars_vgap' - vertical gap between paragraphs, in pixels. Default is
    'lines_vgap'.

    'smart' - if '1' => the smart mode is turned on. In smart mode label is
    assumed to be a single line containing small icons and text strings.
    The 'caption' is assumed to be specific XML; see below the example.

Smart label example:
    <icon>gui_skin://special_icons/controls_button_green.aai</icon>
    <text dy="7" size="small">Next</text>
    <gap width="50"/>
    <icon>gui_skin://special_icons/controls_button_yellow.aai</icon>
    <text dy="7" size="small">Cancel</text>
    <gap width="50"/>
    <icon>gui_skin://special_icons/controls_button_blue.aai</icon>
    <text dy="7" size="small">Keyboard</text>

Smart label syntax:
    The <icon> takes url from element body, and 'width', 'height', 'dy'
    from attributes.
    The <text> takes text from element body, and 'color', 'size', 'dy' from
    attributes. The 'color' shall be integer from '0' to '23', the 'size'
    shall be one of the 'normal', 'small', 'tiny'.
    The <gap> has only 'width' attribute.

Combobox

Data:
    class GuiComboboxDef
    {
        String initial_value; // Optional, default = null (first)
        List<Pair<String, String>> value_caption_pairs;
        int width; // optional; default = -1 (auto)
        GuiAction confirm_action; // optional; default = null (none)
        GuiAction apply_action; // optional; default = null (none)
    }

Details:
    GUI combobox is painted as standard Dune combobox. It can reside in 3
    states:
        - unfocused: main component painted without focus;
        - focused: main component painted with focus; ENTER key is
          intercepted to swith to active state;
        - active; main component painted with focus and the drop-down menu
          component is painted; the arrow keys, ENTER and RETURN are
          intercepted.

Parameters:
    'value_caption_pairs' - the combobox model: the list of pairs
    {choice_value, choice_caption}. The choice_caption is painted on screen and
    the choice_value is used as choice identifier.

    'initial_value' - the choice_value to be selected first.

    'width' - the width of combobox; if not specified => the default width
    is used; actually combobox width cannot be less than the default value.

    'confirm_action' - if specified, it is executed when user press ENTER
    in the drop-down menu. During confirm_action's execution the choice is
    not applied and combobox remains in 'active' state. If execution status
    is OK => choice is applied (combobox is switched into 'focused' state,
    main component is updated); othewise the choice is not applied and
    combobox remains in 'active' state.

    'apply_action' - if specified, it is executed after changes are
    applied. The action execution status is ignored.

Text field

Data:
    class GuiTextFieldDef
    {
        String initial_value; // Optional, default = null (first)
        Boolean numeric; // Optional, default = false
        Boolean password; // Optional, default = false
        Boolean has_osk; // Optional, default = false
        Boolean always_active; // Optional, default = false
        int width; // optional; default = -1 (auto)
        GuiAction confirm_action; // optional; default = null (none)
        GuiAction apply_action; // optional; default = null (none)
    }

Details:
    GUI text field is painted as standard Dune text field. It can reside in
    states:
        - unfocused: text field painted without focus;
        - focused: text field painted with focus; ENTER key is
          intercepted to switch to the active state;
        - active; text field painted with focus and some additional
          graphics; the arrow keys, ENTER, RETURN and some other keys are
          intercepted.

Parameters:
    'initial_value' - the initial string.

    'numeric' - if true => only number characters can be added;

    'pasword' - if true => all characters are visualized as '*';

    'has_osk' - if true => the on-screen keyboard is painted under the text
    field; NOTE: currenly the OSK height is not taken into account when
    components are layouted; so one should add VGapis to achieve nice
    looking of container.

    'always_active' - if true => the 'focused' state of text field is
    avoided, i.e. text field is automatically switched to 'active' state
    when it gains focus.

    'width' - the width of text field; if not specified => some predefined
    width is used.

    'confirm_action' - if specified, it is executed when user press ENTER
    in the active state of control. During confirm_action's execution the
    changes in text string are not applied and text field remains in
    'active' state. If execution status is OK => changes are applied and
    text field is switched to 'focused' state; othewise the changes are
    reverted and text field remains in 'active' state.

    'apply_action' - if specified, it is executed after changes are
    applied. The action execution status is ignored.

Button

Data:
    class GuiButtonDef
    {
        String caption;
        int width; // optional; default = -1 (auto)
        GuiAction push_action; // optional; default = null (none)
    }
    Map<String,String> params;

Supported GuiControlDef::params keys:
    'button_caption_centered'

Details:
    GUI button is painted as standard Dune button. It can reside in
    states:
        - unfocused: button painted without focus;
        - focused: button painted with focus; ENTER key is
          intercepted to execute the push_action;

Parameters:
    'capiton' - the text over the button;

    'width' - the width of button; if not specified => the default width
    is used;

    'push_action' - if specified, it is executed when user press ENTER on
    focused button.

Additional parameters:
    'button_caption_centered' - boolean specifies whether button caption
    should be centered instead of being left-aligned.

VGap

Data:
    class GuiVGapDef
    {
        int vgap;
    }

Details:
    This pseudo-control is used to change the default distances between GUI
    controls. It is not painted at all.

Parameters:
    'vgap' - the integer value to be added to the default distance between
    neighbour controls. If positive => distance increased, if negative =>
    distance reduced.

Gui action execution in GUI control containers

Every action executed from GUI control takes additional parameters in the
'params' key-value maps

The value of 'selected_control_id' is set to GuiControlDef::name of the currently
selected control. This control is always the action producer.

For each GUI control of type (combobox | text_field) the value of
'GuiControlDef::name' is set to the current state-value of this control.
The state-value of text field is the current state of edited text; the
state-value of comobox is the currently selected choice_value.

Actually, the only GUI action which is used in GUI control containers is
HANDLE_USER_INPUT. When plugin creates HANDLE_USER_INPUT action to be
assigned to some GUI control, it should preliminary add some additional
marks to 'params' map in order to be able to further recognize the context
of action invocation from the implementation of Handle_user_input()
operation. So, the implementation of Handle_user_input() can distinguish
the different GUI control containers and have all information about the
current state of all GUI controls in the current container.

Preinstalled plugin resources

- Each plugin's installation may contain some resources (images). These
  images may be accessed using special url syntax:

  plugin_file://path/to/resource
  or
  plugin_file://%plugin_name%/path/to/resource

  The 1st syntax accesses the resources of the 'current' plugin
  (context-dependent).
  The 2nd syntax allows to use preinstalled resources of plugin with
  specified name.

Plugin archives

- Currently there is a way of caching the images used for representation of
  plugin menu folders in the system storage or flash memory storage
  (if supported). The PluginFolderView and PluginTvInfo may have the
  'archive' field of type PluginArchiveDef:
  {
    string $id;
    map(string,string) $urls_with_keys;
    string $all_tgz_url; // optional
    long long total_size;
    # etc..
  }

  So if one does NOT use plugin archive for folder, it leaves the
  PluginFolderView::archive as null, and writes the http://xxx/yyy.png
  image url to the corresponding ViewItemParams::icon_path. In this case,
  image will be http-downloaded many times.

  To use plugin archive, one should specify as PluginFolderView::archive:
    array(
      'id' => 'myarchive',
      'urls_with_keys' =>
        array(
          'xxx_key.png' => 'http://xxx/yyy.png',
          # etc
        ),
      'all_tgz_url' => 'http://xxx/all.tgz', // optional
      'total_size' => '1234567',
        )
  and use special syntax for ViewItemParams::icon_path:
    plugin_archive://myarchive/xxx_key.png

  The execution of the PLUGIN_OPEN_FOLDER/PLUGIN_TV_PLAY operation first
  checks whether archive is specified and launches the 'Update Archive'
  dialog if needed. The Update Archive dialog checks whether archive is
  changed. Then it checks whether suitable storage exists and has enough
  free space. Then it and performes synchronization of the remote archive
  state with local cache (the extra files are deleted, missing files are
  downloaded). The keys are used as file names in the local cache. The
  'total_size' value is trusted to be the cumulated size of all files in
  archive.

  The files can be downloaded by 2 different methods:

    - first, if number of images to download is more than some limit (now
      50) => then gzipped tarball is downloaded from 'all_tgz_url' URL,
      unpacked and used as new local cache. The tarball's content should be
      consistent with keys of the 'urls_with_keys' map: it should contain
      the same set of files.

    - Otherwise (if < 50 files have to be downloaded or 'all_tgz_url' is
      unset) => the needed files are downloaded from their remote locations
      specified in 'urls_with_keys'.

  The handling of the icon URLs of type 'plugin_archive://<archive>/<key>'
  work correctly even when Dune GUI was unable to keep local copy of
  archive. In this case plugin_archive:// URLs work as http:// URLs.

Asynchronous image loading

The asynchronous image loading is used in regular folders with
FolderViewParams::async_icon_loading == true.
If async_icon_loading == false then GUI is blocked until all visible icons
are loaded.
If async_icon_loading == true then icon files are downloaded in separate
thread. During the download process the
PluginRegularFolderView::not_loaded_view_item_params is used for
representing the element and therefore another image may be used instead.
NOTE: some image resources are never loaded asynchronously:
  1. standard Dune skin resources, e.g. urls gui_skin://xxx
  2. preinstalled plugin resources, e.g. urls plugin_file://xxx
  3. resources from the already cached plugin archive, e.g.
     urls plugin_archive://<archive_name>/path

Plugin TV archive playback

Each plugin TV channel may have support for archive playback.

To enable archive playback:
  - PluginTvChannel::have_archive should be set to true;
  - Get_tv_playback_url() + Get_tv_stream_url() should accept real
    unixtime values of 'archive_tm_sec' parameter and return the correct
    archive stream URL;
  - archive_past_days and archive_delay_sec of PluginTvChannel should be
    set appropriately. The default is 14 days and 31 minutes
    correspondingly.

Protected TV channels

Currently the only way to enable the protect code checking for some
channels one should do the following:
  - set PluginTvChannel::is_protected to true;
  - set PluginTvChannel::playback_url_is_stream_url to false if not done
    yet;
  - encode given protect_code into the result playback_url in the
    implementation of Get_tv_playback_url();
  - ensure that Get_tv_stream_url() returns string 'protected' each time the
    protect code is incorrect and the actual stream url otherwise.

Auto-resume

The auto-resume feature is enabled by setting
<auto_resume>
    <enable>yes</enable>
    ...
</auto_resume>
in the plugin manifest.

The auto-resume procedure is triggered when STB is turned on or resumed
from standby mode. This procedure tries to restore the last state of Dune
GUI before STB was turned off or sent to standby. Currently only the
following GUI states can be auto-resumed:

    - Live TV playback of the particular channel;
    - Archive TV playback of the particular channel and timestamp.
    - VOD playback of the particular movie.

NOTE: the position of Dune GUI in folder hierarchy is not remembered now
and therefore cannot be restored.

It is possible to add the standard IP address and valid time requirements
for the auto-resume:
<auto_resume>
    ...
    <ip_address_required>yes</ip_address_required>
    <valid_time_required>yes</valid_time_required>
</auto_resume>

Also there is a way to specify custom GUI action to be executed instead of
the default auto-resume procedure. Example:
<auto_resume>
    <enable>yes</enable>
    <action>
        <type>plugin_handle_user_input</type>
    </action>
</auto_resume>
The all values of the resume_state.properties will be passed to the
auto-resume actions as parameters.

Including executable Linux programs into plugin

If plugin archive contains 'bin' directory (at the same level as the plugin
manifest), all files and subdirectories in the 'bin' directory will be made
executable during installation. In other words, if the plugin needs
executable files, they should be put under the 'bin' directory.

Note, that ZIP-archives don't support UNIX file attributes, thus, even if
an archive has been created from the executable files, those files will not
have executable attribute after extracting from the archive.

Files in 'www/cgi-bin' directory are processed the same way.

Executables for SMP87xx ARM platforms should be put into the following
directories, files in these directories are processed the same way:
   .platform.87xx/bin/
   .platform.87xx/www/cgi-bin/

Interface language translations

Each plugin may provide additional local translation tables located in
$install_dir_path/translations directory and having names
dune_language_<lang>.txt. These files will be loaded to the global STB
translation table on STB start or when interface language is changed by
user.

The local plugin translation files have the same format as global Dune
translation files. They define additional keys to be added to the global
table. The local translation keys are added to the plugin's own namescope
and cannot conflict with the global keys. Only the owner plugin can access
translation keys provided by itself.

The translation keys can be used in so-called public strings. Such strings
can be:
1. returned from DunePlugin interface calls;
2. declared in dune_plugin.xml.
Public strings are easily recognized: they are intended to be painted on
screen in some use-cases. For example, the plugin caption, entry point
caption, and all other "captions" are the public strings.

Each public string may be:
1. Just fixed string (not translated)
    "Movie"
2. Simple reference:
    "%tr%movie_caption"
   For example, if current interface language is "english" and plugin has
   the following record in it's translations/dune_language_english.txt:
    movie_caption = Movie
   and another on in translations/dune_language_french.txt:
    movie_caption = Film
   then this string will be dereferenced to
    "Movie" or "Film" depending on current interface language setting.
3. Extended public string syntax:
    extended_public_string ::= "%ext%" string_with_refs
    string_with_refs ::= string {ref string}
    ref ::= "<key_local>" key_name {param} "</key_local>"
    param ::= "<" param_name ">" string_with_refs "</" param_name ">";
    key_name ::= string
    param_name ::= string
   Examples:
    1) Using of positional parameters:
       String:
        "%ext%<key_local>movie_folder_contains__1<p>20</p></key_local>"
       Translation record:
        movie_folder_contains__1 = Folder contains %s movies.
       Result string:
        "Folder contains 20 movies."
    2) Using of named parameters:
       String:
        "%ext%<key_local>cur_time3<h>21</h><m>38</m><s>00</s></key_local>"
       Translation record:
        cur_time3 = Current time is %{h}:%{m}:%{s}.
       Result string:
        "Current time is 21:38:00."

HTTP server extension

The local STB HTTP server is configured to provide access to files in the
following directories in plugin file structure:
    $install_dir_path/www/*           - normal access;
    $install_dir_path/www/cgi-bin/*   - access with CGI execution enabled.
The following HTTP urls are mapped to these directories:
    http://<STB-address>/plugins/<plugin_name>/*
    http://<STB-address>/cgi-bin/plugins/<plugin_name>/*
The following language constructions are provided for convenience in PHP
code:
DuneSystem::$properties['plugin_www_url'] =
        http://127.0.0.1/plugins/<plugin_name>/
DuneSystem::$properties['plugin_cgi_url'] =
        http://127.0.0.1/cgi-bin/plugins/<plugin_name>/

Auto-start specification in plugin manifest

The auto start specification in the plugin manifest dune_plugin.xml allows
to enable automatic startup of the plugin when the plugin is declared as
"main" plugin (there may be at most one plugin declared as "main" plugin).

For more information about "main plugin", see the description of
"/firmware/config/main_plugin_name.txt" here:
   http://files.dune-hd.com/sdk/doc/html/dune_custom_firmware.html

The auto_start section in plugin manifest affects the following use-cases:
    - STB power-on;
    - resume from the stand-by mode.

For "main" plugin the <auto_start> section in dune_plugin.xml is taken into
account; the <auto_start> section of other plugins is just ignored. The
example of the auto_start section:

<dune_plugin>
  ...
  <auto_start>
    <entry_point_media_url>main_tv</entry_point_media_url>
    <action>
        <type>plugin_open_folder</type>
    </action>
  </auto_start>
  ...
</dune_plugin>

NOTE: the 'plugin_open_folder' is just an example. Typically, the
auto_start action should be the same as 'key_enter' action in the
corresponding entry point.

This specification will cause STB to enter the "main_tv" plugin folder on
each startup (of course, if the described plugin is "main" plugin).

Details:

    - entry_point_media_url (optional, default = unset)
        the media_url of the plugin entry point. On STB startup the folder
        containing the specified entry point will be entered and the entry
        point itself will be focused. If not set, the default folder will
        be opened on startup.

    - action (optional, default = unset)
        the action to be executed on startup (just after entry point is
        selected, if specified).

    - ip_address_required = yes|no (optional, default = no)
    - valid_time_required = yes|no (optional, default = no)
        if yes, the standard dialog will appear waiting for IP address or
        valid  time.

    - run_action_before_auto_resume = yes|no (optional, default = no)
        By default, the auto-start action will not be executed when STB
        tries to auto-resume playback. Setting the
        'run_action_before_auto_resume' to 'yes' will force STB to execute
        auto-start action even in the auto-resume use-case. See the details
        about the auto-resume feature in the corresponding section
        ('Auto-resume').

    - skip_initial_dialogs = yes|no (optional, default = no)
        if yes, the action will be executed before the initial STB setup
        wizard; otherwise action will be executed after setup wizard. This
        only affects the use-case of first STB power-on after
        the Reset Settings procedure.

    - force_on_start = none|main_screen|black_screen
    - force_on_finish = none|main_screen|black_screen
        allows to specify the background for auto_start action execution.

Configuring plugin auto-start via menu

The user can manually configure the STB to automatically launch a certain
plugin on STB boot.

To do it:
   - First, add the plugin into the favorites menu (choose the plugin,
     press "POP UP MENU" RC button, choose "Add to favorites").
   - Then, go into the favorites menu and enable autostart for the plugin
     (choose the plugin, press "POP UP MENU" RC button, choose "Enable
     autostart").

Image file formats (for icons etc)

- JPEG
- PNG with alphachannel
- BMP with alphachannel
- AAI with alphachannel
   - This is Dune HD proprietary format.
   - See:
      - http://dune-hd.com/firmware/misc/
      - http://dune-hd.com/firmware/misc/AAImageGen-README.txt

Ways to reference image files from plugins

- Image file from web server:
   - Icon path/URL: http://host[:port][path]

- Image file from web server, preloaded/cached via plugin archive:
   - Icon path/URL: plugin_archive://archive-name/path

- Image file built-in into plugin (part of plugin):
   - Icon path/URL: plugin_file://path-to-file
   - Example: plugin_file://plugin_icon.png

- Image file built-in into firmware (part of standard GUI skin):
   - Icon path/URL: gui_skin://path-to-file
   - Example: gui_skin://large_icons/tv.aai
   - More information about GUI skins:
      - http://dune-hd.com/support/skins

Features added in firmware version 120531_2200_beta

Starting with the firmware version 120531_2200_beta, the following Dune PHP
Plugins API extensions and improvements were added:
   - New GUI actions:
      - file_play
      - dvd_play
      - bluray_play
      - playlist_play
      - launch_media_url
      - change_behavior
      - show_black_screen
      - show_main_screen
   - New GUI events:
      - timer
      - playback_stop
   - New properties in existing data structures:
      - GuiAction::params
      - PluginInvalidateFoldersActionData::details
      - PluginInvalidateFoldersActionData::rate_details
      - PluginMovieFolderView::left_button_caption
      - PluginMovieFolderView::left_button_action
      - PluginMovieFolderView::params
      - PluginRegularFolderView::timer
      - PluginTvInfo::epg_mode
      - PluginVodInfo::initial_position_ms
      - PluginVodInfo::advert_mode
      - PluginVodInfo::actions
      - PluginVodInfo::timer
      - ShowDialogActionData::actions
      - ShowDialogActionData::timer
      - ShowDialogActionData::max_height
      - ShowDialogActionData::initial_sel_ndx
      - ViewItemParams::item_caption_color
      - ViewItemParams::item_sandwich_icon_scale_factor
      - ViewParams::paint_details_box_background
      - ViewParams::help_line_text_color
      - ViewParams::item_detailed_info_title_color
      - ViewParams::item_detailed_info_text_color
   - New data structures and their properties:
      - BlurayPlayActionData::url
      - ChangeBehaviourActionData::actions
      - ChangeBehaviourActionData::timer
      - ChangeBehaviourActionData::post_action
      - DvdPlayActionData::url
      - FilePlayActionData::url
      - GuiTimerDef::delay_ms
      - LaunchMediaUrlActionData::url
      - LaunchMediaUrlActionData::post_action
      - PlaylistPlayActionData::url
      - PlaylistPlayActionData::start_index
      - PluginFolderViewParams::paint_path_box
      - PluginFolderViewParams::paint_content_box_background
      - PluginFolderViewParams::background_url
      - PluginVodPlayActionData::vod_info
      - ShowBlackScreenActionData::post_action
      - ShowMainScreenActionData::post_action
   - New features related to plugin file structure:
      - {plugin_install_dir}/bin/
         - The player automatically sets executable permissions on all
           files in this directory during plugin installation.
      - {plugin_install_dir}/www/{path}
         - The player automatically makes these files accessible via
           HTTP (locally inside the player, and from the local network):
            - http://localhost-or-dune-ip-address/plugins/{plugin_name}/{path}
      - {plugin_install_dir}/www/cgi-bin/{path}
         - The player automatically makes these CGI applications
           accessible via HTTP (locally inside the player, and from the
           local network):
            - http://localhost-or-dune-ip-address/cgi-bin/plugins/{plugin_name}/{path}
   - Other new features:
      - Ability to package FlashLite application into plugin and launch
        it when the user enters plugin entry point, or when PHP plugin
        code decides to call it. Supported via the new "launch_media_url"
        action.
      - Ability to package HTML page/application into plugin and launch
        it in web browser when the user enters plugin entry point, or
        when PHP plugin decides to call it. Supported via the new
        "launch_media_url" action.
      - If the plugin is pure FlashLite or HTML application and does not
        need to execute any PHP code, "plain" plugin type can be
        specified in plugin manifest instead of "php"; in this case,
        there is no need to include PHP program into the plugin and
        specify "program" parameter in plugin manifest.

Implementing advanced playback control in PHP plugins

The following features of PHP API (introduced in firmware version
120531_2200_beta) can be used to implement advanced playback control use
cases in PHP plugins.

   PluginVodInfo::timer
   PluginVodInfo::initial_position_ms
   PluginVodInfo::advert_mode
   GUI_EVENT_TIMER
   GUI_EVENT_PLAYBACK_STOP

Examples:

1) Playback AD video before and after main video.

   First perform PluginVodPlay action with media_url pointing to AD
   pre-roll video, PluginVodInfo::advert_mode == TRUE, and
   GUI_EVENT_PLAYBACK_STOP event registered in PluginVodInfo::actions.

   When GUI_EVENT_PLAYBACK_STOP event occurs, another PluginVodPlay action
   should be performed: media_url pointing to main video,
   PluginVodInfo::advert_mode == FALSE, and GUI_EVENT_PLAYBACK_STOP event
   registered in PluginVodInfo::actions.

   When GUI_EVENT_PLAYBACK_STOP event occurs, another PluginVodPlay action
   should be performed: media_url pointing to AD post-roll video,
   PluginVodInfo::advert_mode == TRUE.

   The following plugin demonstrates this approach:
      dune_plugin_demo2_with_ad.zip

2) Playback AD video in the middle of main video.

   There is no direct support for this, but the following approach can be
   potentially used (not really tested, but should work if there are no
   bugs).

   Start main video playback with PluginVodInfo::timer specified with
   appropriate timer delay (one second or a few seconds), and
   GUI_EVENT_TIMER registered in PluginVodInfo::actions.

   When GUI_EVENT_TIMER event occurs, the plugin code should check the
   current playback position, and, if needed (it is time to show ad),
   request playback of AD media url: perform PluginVodPlay action with
   PluginVodInfo::advert_mode == TRUE and GUI_EVENT_PLAYBACK_STOP event
   registered in PluginVodInfo::actions.

   When GUI_EVENT_PLAYBACK_STOP event occurs, another PluginVodPlay action
   should be performed: media_url pointing to main video,
   PluginVodInfo::advert_mode == FALSE, and
   PluginVodInfo::initial_position_ms pointing to the position where the
   main video was interrupted by the ad.

   Checking the current playback position can be performed in the following
   way:
      Read "playback_position" field in the file
      "/tmp/run/ext_command.state".
      NOTE: this is not part of official PHP API, but can be used as a
      temporary solution.

3) Rememebering and resuming VOD playback position.

   Approach A:
   ~~~~~~~~~~~

   Specify "auto_resume" feature in plugin manifest.

   If "action" is not specified, PHP engine will automatically resume VOD
   playback.

   If "action" is specified (required if PHP plugin needs to do some
   checking/processing before resuming VOD playback), see Approach B.

   Approach B:
   ~~~~~~~~~~~

   Specify "auto_resume" feature in plugin manifest, and specify
   PluginHandleUserInputAction "action".

   Instead of standard auto resume processing, the specified action will be
   executed.

   Then, in PHP code, read the information required for auto-resume from
   the following file:
      /config/resume_state.properties

      NOTE: this is not part of official PHP API, but can be used as a
      temporary solution.

      Sample content of this file:
         mode = PLUGIN_VOD_PLAYBACK
         plugin_name = some_plugin
         plugin_entry_media_url = vod_category_list
         plugin_media_url = {"screen_id":"vod_scene_info","scene_id":"193115"}
         plugin_vod_id = 193115
         plugin_vod_series_ndx = 0
         plugin_vod_position_seconds = 37
         plugin_tv_group = 1
         plugin_tv_channel = 5
         plugin_tv_is_favorite = 0
         plugin_tv_archive_tm = 1343834591

   Then, perform VOD playback with PluginVodInfo::initial_position_ms
   specified.

   Approach C:
   ~~~~~~~~~~~

   The same as Approach B, but w/o using "auto_resume" feature in plugin
   manifest. The file "/config/resume_state.properties" is created by the
   system even if "auto_resume" feature is not used, and this file can be
   read and handled by PHP plugin code.

   Approach D:
   ~~~~~~~~~~~

   Start main video playback with PluginVodInfo::timer specified with
   appropriate timer delay (one second or a few seconds), and
   GUI_EVENT_TIMER registered in PluginVodInfo::actions, and
   GUI_EVENT_PLAYBACK_STOP registered in PluginVodInfo::actions.

   When GUI_EVENT_TIMER event occurs, the plugin code should check the
   current playback position and remember it.
   (See above for the info how to do it.)

   When GUI_EVENT_PLAYBACK_STOP event occurs, the plugin code should
   persistently remember the latest playback position remembered when
   handling GUI_EVENT_TIMER events.

   Then, use the persistently remembered position when starting playback
   next time, by specifying PluginVodInfo::initial_position_ms.

Plugin online update mechanism

Dune STB firmware includes support for online update of plugins. Each
plugin may specify that it should be updated from from the given HTTP URL.
When the user launches any entry point of the plugin, the system checks for
available updates using this URL. If an update is available, it is
automatically proposed for installation to the user. After the update is
installed, the originally requested plugin entry point is launched.

To enable online update for a plugin, the plugin manifest file
("dune_plugin.xml") should include the following XML specification inside
the root ("dune_plugin") XML-element:
   <version_index>5</version_index>
   <version>130528_1700</version>
   <check_update>
      <schema>2</schema>
      <url>http://some-server/some-path/update_info.xml</url>
      <timeout>0</timeout>
      <required>no</required>
      <auto>no</auto>
   </check_update>

Here, the semantics of XML-elements is the following:
   version_index
      The numeric version index, which should increase each time a new
      plugin version is published on the server. Is not shown in the UI.
   version
      The version caption, which is shown in the UI when the system
      proposes/performs update to this version.
   check_update / schema
      Update schema version. The version 1 is legacy and must not be used.
      The version 2 must be used.
   url
      The HTTP URL pointing to "update_info" XML document.
   timeout
      The timeout (in seconds). It specifies minimum timeout between
      attempts to check available updates performed. If the value is 0, the
      system checks for available updates everytime when the user launches
      any entry point of the plugin.
   required
      The flag indicating if the update is required or not. Possible values
      are "yes" and "no".
   auto
      The flag indicating whether background autocheck for updates is
      enabled for plugin. It is disabled by default.
      NOTE: 'auto' feature is available in firmwares 150430_r10+.

The "update_info" XML document has the following structure:
   <dune_plugin_update_info>
     <schema>2</schema>
     <name>plugin_name</name>
     <plugin_version_descriptor>
       <version_index>5</version_index>
       <version>130528_1700</version>
       <beta>no</beta>
       <critical>no</critical>
       <url>http://some-server/some-path/5.tgz</url>
       <md5>a209a234fc9c518d3a165750a1f0dde4</md5>
       <size>2244608</size>
       <caption>plugin_caption</caption>
     </plugin_version_descriptor>
   </dune_plugin_update_info>

Here, the semantics of XML-elements is the following:
   schema
      The value must be 2.
   name
      Plugin name.
   caption
      Plugin caption.
   plugin_version_descriptor / version_index
      Plugin version index corresponding to the plugin available on the
      server. Must be the same as the plugin version index specified in the
      plugin archive available on the server.
   plugin_version_descriptor / version
      Plugin version caption corresponding to the plugin available on the
      server. Must be the same as the plugin version caption specified in
      the plugin archive available on the server.
   plugin_version_descriptor / beta
      The flag indicating if this plugin update is beta or non-beta
      (stable). Possible values: "yes" (beta), "no" (non-beta). Reserved
      for future use, currently the value is ignored; it is recommended to
      use "no" value.
   plugin_version_descriptor / critical
      The flag indicating if this plugin update is critical. Possible
      values: "yes" (critical), "no" (non-critical). The value "yes" can be
      used for plugins which specify "check_update / timeout" = 0 and
      "required" = "yes" in their manifest file; in this case, the system
      does not allow to launch the old version of the plugin if plugin
      update is available on the server and this plugin update is critical.
   plugin_version_descriptor / url
      HTTP URL pointing to the plugin archive in the .tar.gz format. The
      content of the .tar.gz archive must be exactly the same as the
      content of the regular plugin installed archive (dune_plugin*.zip
      file).
   plugin_version_descriptor / md5
      MD5 checksum of the .tar.gz file specified in
      "plugin_version_descriptor / url" element.
   plugin_version_descriptor / size
      Specifies the storage space (in bytes) occupied by the plugin after
      it is installed into the flash memory of the STB. Can be computed
      using the following algorithm: "du -sk /path/to/folder" * 1024.
   plugin_version_descriptor / caption
      Plugin caption. This caption will be used in the UI dialogs shown
      during plugin update. If plugin caption does not change between
      plugin versions, it should be the same as plugin caption specified in
      the plugin manifest file.

NOTE: The "update-info" XML document may contain multiple
"plugin_version_descriptor" elements. Only the one with the biggest value
of version_index is actually used; the rest are ignored.

Signed plugins

Plugins preinstalled in the standard retail Dune firmware or available in the
standard retail Dune firmware via Dune Store are specially signed by Dune HD.

Signed plugins include the following additional files:
   dune_plugin.sign
      This file contains the plugin signature.
   dune_plugin_signer_id.txt
      This file contains "signer ID" -- an identifier of the key used for
      plugin signing. Allowed values are:
         - The string "com.dune-hd" -- reserved for the use by Dune HD only.
         - Customer ID of the custom firmware build.
            (*) Available in firmware 150326_r10+.

When a plugin is signed, the system verifies the signature of the plugin
and refuses to use it if the signature does not match the plugin or if the
specified signer ID is not allowed.

Custom firmware versions (e.g. used by operators) may be configured to
allow only signed plugins (provided/approved by Dune HD and/or the
customer) and disallow unsigned plugins (provided by 3-parties and not
approved by the customer).

Using custom signing keys

NOTE: This functionality is available in firmware 150326_r10+.

To sign plugins using a custom signing key, perform the following steps:

1. Generate a pair of private and public DSA keys for plugin signing and
   vertification.

   Perform the following commands on a Linux PC:
      openssl dsaparam -out dsaparam.pem 2048
      openssl gendsa dsaparam.pem -out plugin_private_key.pem
      openssl dsa -in plugin_private_key.pem -pubout -out plugin_public_key.pem

2. Sign plugins using private plugin key.

   Download "plugin_sign" utility, using one of the following options:

      http://files.dune-hd.com/sdk/misc/plugin_sign.x86
         A precompiled executable for Linux PC (x86), dynamically
         linked. Requires libcrypto 0.9.8 to be installed in the system.

      http://files.dune-hd.com/sdk/misc/plugin_sign_static.x86
         A precompiled executable for Linux PC (x86), statically linked.

   Use the utility in the following way (on a Linux PC):
      /path/to/plugin_sign.x86 /path/to/plugin/dir {signer_id} plugin_private_key.pem

   Here, {signer_id} should be the customer ID of the custom firmware.

   The utility will generate "dune_plugin.sign" and
   "dune_plugin_signer_id.txt" files in the plugin directory.

3. Include the public plugin key into the custom firmware.

   Put the file "pluging_public_key.pem" into the following location:
      /firmware/config/plugin_key.pem

   Plugins signed by the corresponding private key and using the value of
   "signer ID" equal to the value of "customer ID" of the custom firmware
   will be allowed by this custom firmware.

Global plugin actions

NOTE: Available in firmware 130315_b6+.

The mechanism of "global plugin actions" allows a plugin to force the STB to
perform certain actions (e.g. launch a shell script shipped within a
plugin) on certain system events (e.g. on STB boot or plugin
install/uninstall).

This mechanism is available in firmware versions 130515_2104_b6+.

Supported system events:
   boot
      Is launched on cold STB boot immediately after the STB engine
      initializes plugins. Is launched in all cases, even if custom
      stb_home application is started instead of the native Dune GUI. At
      this moment, /tmp/sysinfo.txt is not available yet and other parts of
      the STB engine may not be initialized yet. Can modify visibility of
      plugin entry points. Cannot launch dialogs, playback and other
      GUI-related actions.
   boot_end
      Is launched on cold STB boot at the very end of the STB boot process.
      Is launched in all cases, even if custom stb_home application is
      started instead of the native Dune GUI. At this moment, it is
      guaranteed that /tmp/sysinfo.txt file is already available. Cannot
      launch dialogs, playback and other GUI-related actions.
         NOTE: Available in firmware 130917_b9+.
   gui_start
      Is launched during startup of the native Dune GUI -- on STB boot or
      when the STB exists software standby mode. Is not launched if custom
      stb-home application is started instead of native Dune GUI. Is
      launched after the initial setup wizard of the native Dune GUI.
         NOTE: Available in the firmware 130914_b8+.
   install:
      Is launched immediately after plugin has been installed.
   update:
      Is launched immediately after plugin has been updated.
   uninstall:
      Is launched before plugin is deleted.

To perform an action on a system event, the plugin should declare
corresponding global action in the plugin manifest file. The action can be
any standard plugin GUI action, or "plugin_system" action which allows to
launch an executable file shipped within the plugin. For "boot" system
event, only "plugin_system" action is supported.

Example of defining global actions in the plugin manifest file:
   <dune_plugin>
   ...
     <global_actions>
       <boot>
         <type>plugin_system</type>
         <data>
           <run_string>bin/smbserver_ctl.sh start &amp;</run_string>
         </data>
       </boot>
       <install>
         <type>plugin_system</type>
         <data>
           <run_string>bin/smbserver_ctl.sh start &amp;</run_string>
         </data>
       </install>
       <update>
         <type>plugin_system</type>
         <data>
           <run_string>bin/smbserver_ctl.sh start &amp;</run_string>
         </data>
       </update>
       <uninstall>
         <type>plugin_system</type>
         <data>
           <run_string>bin/smbserver_ctl.sh stop &amp;</run_string>
         </data>
       </uninstall>
     </global_actions>
   ...
   </dune_plugin>

Regular folder GUI customization

Here are some specific notes about ViewParams and ViewItemParams used for
regular folder GUI customizataion.

Additional information can be found here: 
http://dune-hd.com/support/misc/dune_folder_howto.txt

The ViewParams are assigned with some regular folder and specify different
aspects of folder content visualisation.
The ViewItemParams are assigned with each folder element and (together with
folder's ViewParams) affect it's visualication inside parent folder.

Normally regular folder screen is divided into 3 areas:
  - "path block" in the top (optional)
  - "content block" in the bottom-left
  - "details block" in the bottom-right

The rectangular content block of regular folder is divided into small 'item'
rectangles of equal dimentions, using number of rows/columns as parameter.
Each non-empty item rect normally contains and icon and a caption text.

The details block normally contains additional information about currently
selected content item: some icon in the top and a structured text below.

List of ViewParams properties

   - num_cols (positive integer, mandatory)
   - num_rows (positive integer, mandatory)
      Content area grid parameters.

   - animation_enabled (boolean, default=yes)
      Whether to enable cursor animation.

   - scroll_animation_enabled (boolean, default=yes)
      Whether to enable content scrolling animation. Currently has effect
      only on horizontal orientation.
         NOTE: Available in firmware 131203_b9+.

   - orientation (vertical|horizontal, default=vertical)
         NOTE: Available in firmware 131203_b9+

   - cycle_mode_enabled (boolean, default=no)
      When enabled, selection rectangle is always in center while folder
      elements are scrolled left/right. Has effect only on horizontal
      orientation with single row and odd number of columns >= 5.
         NOTE: Available in firmware 131203_b9+

   - cycle_mode_gap (yes|no|auto, default=no)
      Specifies whether to paint additional horizontal gap between last and
      first folder elements. "Auto" means to paint gap when number of
      element greater then number of columns. Has effect only when
      cycle_mode is effectively enabled.
         NOTE: Available in firmware 131203_b9+

   - cycle_mode_gap_width (integer, default=auto=half item width)
      Specifies horizontal gap width. Has effect only when
      cycle_mode is effectively enabled.
         NOTE: Available in firmware 131203_b9+

   - cycle_mode_gap_icon_path (image URL string, default=unset)
      Specifies icon to be painted in the middle of horizontal gap. Has
      effect only when cycle_mode is effectively enabled.
         NOTE: Available in firmware 131203_b9+

   - background_path (image URL string, default=unset)
   - background_x (non-negative integer, default=0)
   - background_y (non-negative integer, default=0)
   - background_width (positive integer, default=real image width)
   - background_height (positive integer, default=real image height)
   - optimize_full_screen_background (boolean, default=false)
   - background_order (before_all|before_icons|after_all,
         default=before_icons)
      If background_path is set, then specifies custom background which is
      painted after the default full-screen background. The background
      properties have effect only when backgroun_path is set. The
      'optimize_full_screen_background' allows to avoid paining of the
      skin's background; in this case background_order should be before_all
      and the effective custom background rectangle should cover all
      screen. The 'backgroun_order' allows to specify backround painting
      order:
         - before_all: before all other graphics;
         - before_icons: after glasses, but before icons/captions/focuses.
         - after_all: after all other graphics.

   - scroll_path (image URL string, default=unset)
   - scroll_x (non-negative integer, default=auto)
   - scroll_y (non-negative integer, default=auto)
   - scroll_height (positive integer, default=auto)
      Allows to override default skin scrollbar graphics.

   - mark_path (image URL string, default=unset)
   - mark_dx (integer, default=0)
   - mark_dy (integer, default=0)
   - mark_scale_factor (double, default=1.0)
      Allows to override default skin folder element mark icon. The mark_dx
      and mark_dy: if mark_path is set => offset from the top-left corner
      of icon; otherwise => offset from the default position near the
      right-top corner of icon.

   - paint_path_box (boolean, default=true)
   - paint_path_box_background (boolean, default=true)
         NOTE: Available in firmware 130818+
   - paint_widget (boolean, default=true)
         NOTE: Available in firmware 130818+
   - paint_widget_background (boolean, default=true)
         NOTE: Available in firmware 130818+
   - paint_content_box_background (boolean, default=true)
   - paint_scrollbar (boolean, default=true)
   - paint_icon_selection_box (boolean, default=true)
   - paint_help_line (boolean, default=true)
   - paint_details (boolean, default=true)
   - paint_details_box_background (boolean, default=true)
      Allows to hide some graphics.

   - help_line_text_color (integer color index, currently from 0 to 23;
         default is 23)
      Color of text in help line.

   - icon_selection_box_dx (integer, default=auto)
   - icon_selection_box_dy (integer, default=auto)
   - icon_selection_box_width (positive integer, default=auto)
   - icon_selection_box_height (positive integer, default=auto)
      Allows to adjust the icon_selection_box size and position. By default
      the selection is painted over content item rectangle.

   - paint_icon_badge_box (boolean, default=false)
      Enables badge mode. In badge mode the "badge" cut-image from skin is
      painted under icon and icons are automatically downscaled and
      centered into the badge box.

   - hidden_badge_box (boolean, default=false)
      When true, the badge is not painted but the additional graphics (marks
      and stars) are painted in the badge-mode locations.
         NOTE: Available in firmware 120819+.

   - icon_badge_box_dx (integer, default=auto)
   - icon_badge_box_dy (integer, default=auto)
   - icon_badge_box_width (positive integer, default=auto)
   - icon_badge_box_height (positive integer, default=auto)
   - icon_badge_box_sel_dx (integer, default=auto)
   - icon_badge_box_sel_dy (integer, default=auto)
   - icon_badge_box_sel_width (positive integer, default=auto)
   - icon_badge_box_sel_height (positive integer, default=auto)
      Allow to adjust the badge rectangle location, separately in selected
      and unselected state.

   - content_box_x (non-negative integer, default=auto)
   - content_box_y (non-negative integer, default=auto)
   - content_box_width (positive integer, default=auto)
   - content_box_height (positive integer, default=auto)
      Allow to specify the content block rectangle.

   - content_box_padding_left (non-negative integer, default=20)
   - content_box_padding_top (non-negative integer, default=20)
   - content_box_padding_right (non-negative integer, default=20)
   - content_box_padding_bottom (non-negative integer, default=20)
      Allow to specify the content block padding.

   - extra_content_objects (string, default=null)
      Allows to paint some fixed graphics in the content block. Currently
      only text labels in normal font are supported. Example string:
           label{x=50}{y=600}{text=Text:}{color=7}label{x=70}{y=659}{text=Some text.}{color=15}
      The x,y are specified relatively to the content block rectangle.
      Extra content objects normally should not cross the content block
      bounds.
         NOTE: Available in firmware 121201+.

   - paint_item_info_in_details (boolean, default=true)
      Whether to paint text in details block. If false => only icon is
      painted in details block.

   - item_detailed_info_rel_y (non-negative integer, default=auto)
      Specifies the Y-position of details text relative to the top of the
      details block, if specified.
      If not specified, then icon scale_factor is calculated w/o
      height-limitations and the text is placed just below the icon.
      If specified, then text is painted at the specified Y-coordinate, and
      the icon's scale_factor/position are calculated respectively.

   - zoom_detailed_icon (boolean, default=false)
   - detailed_icon_scale_factor (double, default=auto)
      If 'zoom_detailed_icon' is true => the detailed icon is scaled to fit
      into details block by width (even upscaled if needed).
      Otherwise, if 'detailed_icon_scale_factor' is specified => the
      detailed icon is scaled using this factor. Otherwise, the detailed
      icon scale-factor is calculated automatically to fit into details
      block width and into 'item_detailed_info_rel_y', if specified.

   - detailed_icon_valign (top|center|bottom, default=top)
      Vertical alignment of the detailed icon in case
      'item_detailed_info_rel_y' is specified and is greater than actual
      detailed icon height.
      PHP constants available: VALIGN_TOP, VALIGN_CENTER, VALIGN_BOTTOM.
         NOTE: Available in firmware 120606+.

   - item_detailed_info_font_size (normal|small, default=normal)
      PHP constants available: FONT_SIZE_NORMAL, FONT_SIZE_SMALL

   - item_detailed_info_title_color (integer color index 0..23, default=8)
   - item_detailed_info_text_color (integer color index 0..23, default=7)
      The text color index for detailed info 'title' and 'text'. See
      description of ViewItemParams::item_detailed_info for more details.

   - item_detailed_info_auto_line_break (boolean, default=false)
      Whether to automatically break detailed info text into lines, when
      line does not fit into width. Also see the
      ViewItemParams::item_detailed_info for more details.
         NOTE: Available in firmware 120605+.

   - paint_sandwich (boolean, default=false)
      Whether to paint all item using "sandwich". Sandwich consists of 4
      components:
         Base (icon or cut-image)
         Mask (icon or cut-image, only alpha channel is used)
         Cover (icon or cut-image)
         Icon (icon)
      Sandwich is painted using following sequence:
         - first, Base is painted as background into buffer.
         - next, Icon is painted into buffer; typically centered if
            smaller or downscaled if bigger.
         - next, alpha from Mask is merged with alpha from buffer.
         - finally, cover is painted into buffer.

   - sandwich_base (string, image URL or cut_icon URL string,
      default=unset)
   - sandwich_mask (string, image URL or cut_icon URL string,
      default=unset)
   - sandwich_cover (string, image URL or cut_icon URL string,
      default=unset)
      Sandwich Base, Mask and Cover components, as images or cut-icons.
      The following URLs can be used, taken from skin:
         sandwich_base=gui_skin://special_icons/sandwich_base.aai
         sandwich_mask=cut_icon://{name=sandwich_mask}
         sandwich_cover=cut_icon://{name=sandwich_cover}

   - sandwich_width (non-negative integer, default=0 meaning "auto")
   - sandwich_height (non-negative integer, default=0 meaning "auto")
   - sandwich_sel_width (non-negative integer, default=0 meaning "auto")
   - sandwich_sel_height (non-negative integer, default=0 meaning "auto")
      Sandwich dimensions in selected and non-selected state.

   - sandwich_icon_keep_aspect_ratio (boolean, default=true)
      Whether to keep icon aspect ratio when scaling.

   - sandwich_icon_upscale_enabled (boolean, default=false)
      Whether to upscale icon to fit sandwich bounds. NOTE: the downscale
      is always performed when needed.

   - sandwich_icon_scale_factor (positive double in range (0..1], default=1)
      Specifies how to scale icon relative to the sandwich bounds. Can be
      overridden by ViewItemParams::item_sandwich_icon_scale_factor.

List of ViewItemParams properties

   - item_paint_icon (boolean, default=true)
      Whether to paint current item's icon in content block.

   - item_paint_caption (boolean, default=true)
      Whether to paint item caption text in content block.

   - item_paint_unselected_caption (boolean, default=true)
      Whether to paint captions for currently non-selected items.
         NOTE: Available in firmware 130818+.

   - item_caption_font_size (normal|small, default=normal)
      Item caption font size.
      PHP constants available: FONT_SIZE_NORMAL, FONT_SIZE_SMALL.

   - item_paint_caption_within_icon (boolean, default=false)
      If true, the caption is painted inside icon. This option typically is
      used together with item_paint_caption=0.

   - item_caption_within_icon_color (string representing color, the
      following values allowed: white, black, 0, 1, 2, ... 23;
      default=white)
      Specifies color of caption text within icon.

   - item_padding_top (non-negative integer, default=0)
   - item_padding_bottom (non-negative integer, default=0)
      Specifies vertical padding of icon+caption area inside the item
      block. Normally caption is painted in the bottom and icon is
      Y-aligned in the rest of vertical space above caption.

   - icon_path (image URL string, mandatory)
   - icon_sel_path (image URL string, by default equals to icon_path)
      Icon URL in selected and non-selected state.

   - icon_width (non-negative integer, default=0 meaning auto)
   - icon_height (non-negative integer, default=0 meaning auto)
   - icon_sel_width (non-negative integer, default=0 meaning auto)
   - icon_sel_height (non-negative integer, default=0 meaning auto)
      Icon dimensions in selected and non-selected state. If not specified,
      the real icon image dimensions will be used.

   - icon_keep_aspect_ratio (boolean, default=yes)
      Whether to keep icon aspect ratio when scaling to the predefined
      dimensions (see ViewItemParams::icon_width and
         ViewItemParams::icon_height).

   - icon_scale_factor (positive double, default=1.0)
   - icon_sel_scale_factor (positive double, default=auto)
      Icon scale factor in selected and non-selected state.

   - icon_margin_top (integer, default=0)
   - icon_margin_bottom (integer, default=0)
   - icon_margin_left (integer, default=0)
   - icon_margin_right (integer, default=0)
   - icon_sel_margin_top (integer, default=0)
   - icon_sel_margin_bottom (integer, default=0)
   - icon_sel_margin_left (integer, default=0)
   - icon_sel_margin_right (integer, default=0)
      Icon margins in selected and non-selected state.

   - item_layout (left|center, default=center)
      The default layout is "center", meaning that icon and caption are
      horizontally centered, icon is painted above caption. When "left" is
      chosen, the icon and caption are vertically centered, icon is aligned
      to the left of rectangle and caption text is painted starting from
      the left bound of text area block. The text area block is
      right-aligned but normally it occupies all item rectangle width. So,
      to avoid painting text over icon, it is needed to change
      ViewItemParams::item_caption_dx or ViewItemParams::item_caption_width
      respectively. PHP constants available: HALIGN_CENTER, HALIGN_LEFT.

   - icon_valign (top|center|bottom, default=top)
      The method of vertical alignment of icon (between the upper bound of
         item rectangle from top and the caption from bottom). It is used
      only when ViewItemParams::item_layout = HALIGN_CENTER. PHP constants
      available: VALIGN_TOP, VALIGN_CENTER, VALIGN_BOTTOM.

   - icon_dx (integer, default=0)
   - icon_dy (integer, default=0)
   - icon_sel_dx (integer, default=0)
   - icon_sel_dy (integer, default=0)
      The additional icon horizontal/vertical offset in selected and
      non-selected state.

   - icon_fit_scale_factor (double in range (0..1], default=0.9)
      Used only when ViewParams::paint_icon_badge_box = true.
      In badge mode icon is downscaled and centered into badge box, using
      this scale factor as parameter.
         NOTE: Available in firmware 120605+.

   - item_caption_wrap_enabled (boolean, default=false)
      Allows to show the long captions in 2 rows. If 2 rows are not
      enough then caption is painted in 1 row with scrolling.
      The overall content block layout must ensure that 2-row caption
      does not cross the content block bounds.

   - item_caption_width (non-negative integer, default=0 meaning auto)
      Allows to change the default width of caption text block. By default
      the text block occupies all item rectangle width.

   - item_caption_dx (integer, default=0)
      Moves the left bound of caption text block, the right bound remains
      unchanged.

   - item_caption_dy (integer, default=0)
   - item_caption_sel_dy (integer, default=0)
      Additionally changes the vertical position of caption in selected and
      non-selected states separately.

   - item_caption_color (integer color index 0..23, default=auto)
      Caption text color. By default 15 is used (white).

   - item_detailed_info (string, default=unset)
      Structured text to be painted in the details block when current item
      is selected (focused). It may contain several paragraphs, each
      paragraph may have separated single-line title and a multiline text.
      The paragraphs are separated by '||'; the title and text lines are
      separated by '|'. The auto line breaking can also be used instead of
      '|' to separate text lines (see
         ViewParams::item_detailed_info_auto_line_break). Example of
      item_detailed_info:
      Title 1|line 1.1|line 1.2|line 1.3||Title 2|line2.1|line2.2

   - item_detailed_icon_path (image URL string, default=icon_path)
      Allows to specify icon to be painted in details block; by default the
      same icon is used for content block and for details block.

   - item_badge_icon_path (image URL string, default=unset)
      Specifies icon to be pained instead of the default skin badge cut
      image. Affects only badge mode
      (ViewParams::paint_icon_badge_box=true).
      This property is ignored in GUI skins having enable_badge_icons=no
      unless ViewItemParams::item_override_default_badge is set to true.
         NOTE: Available in firmware 120830+.

   - item_override_default_badge (boolean, default=false)
      When true, the ViewItemParams::item_badge_icon_path overrides the
      default GUI skin badge even for skins with enable_badge_icons=no.
         NOTE: Available in firmware 131005+.

   - item_sandwich_icon_scale_factor (double in range (0..1], default=auto)
      Specifies how to scale icon relative to the sandwich bounds. If not
      set, the ViewParams::sandwich_icon_scale_factor used instead.

Other functionality

The GComponents framework (gcomp*) is currently unfinished and is currently
reserved for internal use only.

Porting plugins to SMP87xx platforms

Please see the following sections:
   - "Differences between SMP86xx and SMP87xx platforms"
   - "Including platform-specific files for SMP87xx platforms"

Also please see the following:
   - http://files.dune-hd.com/sdk/doc/html/smp875x.html
   - http://files.dune-hd.com/sdk/doc/html/dune_devel_info.html#toolchain_for_smp87xx_arm_platforms

Differences between SMP86xx and SMP87xx platforms

All the features PHP plugins framework and the plugins mechanism in general
(manifest files, www/ and www/cgi-bin folders, etc) are fully supported on
SMP87xx platforms the same way as on SMP86xx platforms.

The main differences between SMP86xx and SMP87xx platforms which affect
plugins are the following:

   - SMP87xx platforms do not support outdated FlashLite technology.

   - SMP87xx plarforms do support HTML applications and Dune STB JS API,
     but a slightly different version of the web browser engine is used
     (QtWebkit based), and there may be slight differences in the behavior
     and supported features of the web browser engine and in the behavior
     and supported features of Dune STB JS API implementation. So it is
     recommended to carefully test if HTML application works correctly on
     SMP87xx platform, and some adaptation/porting may be required.

   - The playback engine on SMP87xx platform is based on the playback
     engine of SMP86xx platforms and supports the same streaming protocols
     and media formats and features (and even more, e.g. DASH streaming
     protocol and H.265 video codec), but some incompatibilities and slight
     differences potentially may take place. So it is recommended to
     carefully test if the media content is played OK on SMP87xx platform,
     and some adaptation/porting may be required.

   - If the plugin includes native binary code (such as binary executables
     or libraries, Linux kernel drivers, or other platform-specific files),
     the plugin should carry two versions of such platform-specific files
     -- one version for SMP86xx platform, another version for SMP87xx
     platform; for more details, see "Including platform-specific files for
     SMP87xx platforms" section.

   - SMP87xx platforms support background playback feature -- by pressing
     TOP MENU RC button, the user can return to the main menu, keeping
     video or audio playback in background (to return to the playback, TOP
     MENU RC button can be pressed again, or "Now playing" POP UP MENU item
     can be used). When navigating the main menu, the user can navigate
     through the screens of the same plugin which controls the current
     playback session; to ensure that this works correctly, the plugin
     should take this use case into account.

Including platform-specific files for SMP87xx platforms

If the plugin includes files specific to SMP86xx platforms which can not be
used on SMP87xx platforms (such as executable binary files for MIPS CPU),
the following approach should be used to add support for SMP87xx platform.

At the top level of the plugin, folder ".platform.87xx" should be created,
and for each platform-specific file, the version of the file for SMP87xx
platform should be put under this folder.

For example:
   bin/some_exe                        -- SMP86xx (MIPS) version of "some_exe"
   www/cgi-bin/cgi_exe                 -- SMP86xx (MIPS) version of "cgi_exe"
   .platform.87xx/bin/some_exe         -- SMP87xx (ARM) version of "some_exe"
   .platform.87xx/www/cgi-bin/cgi_exe  -- SMP87xx (ARM) version of "cgi_exe"

When such a plugin is installed on SMP86xx platform, the content of
".platform.87xx" folder is automatically deleted from the plugin
installation directory.

When such a plugin is installed on SMP87xx platform, the content of
".platform.87xx" folder is automatically moved to the top level of the
plugin installation directory.

Toolchain to build native binaries for SMP87xx platforms can be found here:
   - http://files.dune-hd.com/sdk/doc/html/dune_devel_info.html#toolchain_for_smp87xx_arm_platforms

Porting plugins to Android platforms

Please see the following sections:
   - "Differences between Sigma and Android platforms"
   - "Including platform-specific files for Android platforms"

Also please see the following:
   - http://files.dune-hd.com/sdk/doc/html/dune_devel_info.html#toolchain_for_android_platforms
   - http://files.dune-hd.com/sdk/doc/html/dune_devel_info.html#launching_executables_from_user_storages_on_android_platforms

Differences between Sigma and Android platforms

All the features PHP plugins framework and the plugins mechanism in general
(manifest files, www/ and www/cgi-bin folders, etc) are fully supported on
Android platforms the same way as on Sigma (SMP87xx) platforms.

The main differences between Sigma and Android platforms which affect
plugins are the following:

   - Android platforms do not support outdated FlashLite technology.

   - Android plarforms do support HTML applications and Dune STB JS API,
     but a slightly different version of the web browser engine is used,
     and there may be slight differences in the behavior and supported
     features of the web browser engine and in the behavior and supported
     features of Dune STB JS API implementation. So it is recommended to
     carefully test if HTML application works correctly on Android
     platform, and some adaptation/porting may be required.

   - The playback engine on Android platform is similar to the playback
     engine of Sigma platforms and in general supports the same streaming
     protocols and media formats and features (and even more, e.g. 4Kp60
     video, Widevine DRM, etc), but the core part of the playback engine is
     different and some incompatibilities and slight differences
     potentially may take place. So it is recommended to carefully test if
     the media content is played OK on Android platform, and some
     adaptation/porting may be required.

   - If the plugin includes native binary code (such as binary executables
     or libraries, or other platform-specific files), the plugin should
     carry several versions of such platform-specific files -- one or two
     version for Sigma SMP86xx/SMP87xx platforms, and another version for
     Android platform; for more details, see "Including platform-specific
     files for Android platforms" section.

   - On Android platforms, user storages are mounted with "noexec" flag,
     which may complicate the use of "dune_plugins" folder mechanism. See
     the following for more information and possible workaround:
      - http://files.dune-hd.com/sdk/doc/html/dune_devel_info.html#launching_executables_from_user_storages_on_android_platforms

Including platform-specific files for Android platforms

If the plugin includes files specific to Sigma platforms which can not be
used on Android platforms (such as executable binary files), the following
approach should be used to add support for Android platform.

At the top level of the plugin, folder ".platform.android" should be
created, and for each platform-specific file, the version of the file for
Android platform should be put under this folder.

For example:
   bin/some_exe                           -- SMP86xx (MIPS) version of "some_exe"
   www/cgi-bin/cgi_exe                    -- SMP86xx (MIPS) version of "cgi_exe"
   .platform.87xx/bin/some_exe            -- SMP87xx (ARM) version of "some_exe"
   .platform.87xx/www/cgi-bin/cgi_exe     -- SMP87xx (ARM) version of "cgi_exe"
   .platform.android/bin/some_exe         -- Android version of "some_exe"
   .platform.android/www/cgi-bin/cgi_exe  -- Android version of "cgi_exe"

When such a plugin is installed on Android platform, the content of
".platform.android" folder is automatically deleted from the plugin
installation directory.

When such a plugin is installed on Android platform, the content of
".platform.87xx" folder is automatically moved to the top level of the
plugin installation directory.

Toolchain to build native binaries for Android platforms can be found here:
   - http://files.dune-hd.com/sdk/doc/html/dune_devel_info.html#toolchain_for_android_platforms

Debugging plugins

Here are some hints which can be helpful to debug plugins during
development.

During plugin development/debugging, it is recommended to create
convenience scripts for typical repetitive actions which can include some
of the below commands (or similar commands).

See the logs of the plugin:
   On Sigma platforms (in telnet session):
      tail -F /tmp/run/<plugin_name>.log
   On Android platforms (in telnet or ADB session):
      busybox tail -F /tmp/run/<plugin_name>.log
   On Android platforms (on remote PC via ADB):
      adb shell busybox tail -F /tmp/run/<plugin_name>.log

Copy plugin files from PC into STB flash memory via ADB on Android platforms:
   # local folder <plugin_name> should contain files to deploy to the STB
   adb shell rm -rf /flashdata/plugins/<plugin_name>
   adb push <plugin_name> /flashdata/plugins/
   adb shell chmod -R +x /flashdata/plugins/<plugin_name>/bin
   adb shell chmod -R +x /flashdata/plugins/<plugin_name>/www/cgi-bin

Restart shell process (to reload all plugins):
   On Sigma platforms (in telnet session):
      killall shell
   On Android platforms (in telnet or ADB session):
      killall com.dunehd.shell
   On Android platforms (on remote PC via ADB):
      adb shell killall com.dunehd.shell

Request shell process to reload plugins w/o restarting shell process:
   Go to the top menu of the shell and press "ANGLE/ROTATE" button on the
   old Dune HD RCU (or choose "Refresh" action in POP UP MENU), or navigate
   to the top menu and send "ANGLE/ROTATE" IR code (00 BF 4D B2) via IP
   Control:
      curl 'http://dune-ip-address/cgi-bin/do?cmd=main_screen'
      curl 'http://dune-ip-address/cgi-bin/do?cmd=ir_code&ir_code=B24DBF00'